6 Commits e93962195e ... 053475e484

Autore SHA1 Messaggio Data
  sebastian 053475e484 Make it installable as web application 1 mese fa
  sebastian ab3780e4bd Adding gitignore and fixing syntax in config.php 1 mese fa
  sebastian 01ac476af2 Keeping the layout and colums when editing items in the lists 1 mese fa
  sebastian 7896f57702 Updating README.md 1 mese fa
  sebastian eaa0d140a9 Updating sample configuration file 1 mese fa
  sebastian 92f780c795 Removing poc file 1 mese fa

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+deploy.sh

+ 7 - 0
.htaccess

@@ -0,0 +1,7 @@
+# Ensure the PWA manifest is served with the correct MIME type.
+AddType application/manifest+json .webmanifest
+
+# Never serve config.php over HTTP (defense in depth — deploy.sh already excludes it).
+<Files "config.php">
+    Require all denied
+</Files>

+ 18 - 4
README.md

@@ -38,13 +38,27 @@ PackIt is a smart packing list generator for outdoor activities. Select the acti
 3. Serve the project with any PHP-capable web server (Apache, Nginx, PHP built-in server).
 4. Open the site in a browser and start selecting activities.
 
-### Default admin credentials
+### Admin password
 
-| Username | Password      |
-|----------|---------------|
+Admin credentials live in the `admin_users` table, not in `config.php`. The `password_hash` column stores a bcrypt hash produced by PHP's `password_hash()`; `admin/login.php` verifies the submitted password against it with `password_verify()`.
+
+`schema.sql` seeds a default account:
+
+| Username | Password       |
+|----------|----------------|
 | `admin`  | `packit-admin` |
 
-**Change the password after first login.**
+**Change it after first login.** There is no UI for this yet, so update the row directly — generate a new hash and replace it in the database:
+
+```
+php -r "echo password_hash('your-new-password', PASSWORD_BCRYPT), PHP_EOL;"
+```
+
+```sql
+UPDATE admin_users
+SET password_hash = '<paste-hash-here>'
+WHERE username = 'admin';
+```
 
 ## Project structure
 

+ 42 - 30
admin/activities.php

@@ -94,40 +94,52 @@ show_alerts();
 </form>
 <?php endforeach; ?>
 
-<table class="tbl">
+<table class="tbl tbl-fixed">
+  <colgroup>
+    <col style="width:60px">
+    <col>
+    <col style="width:180px">
+    <col style="width:100px">
+    <col style="width:200px">
+  </colgroup>
   <thead><tr><th>#</th><th>Name</th><th>Group</th><th>Sort</th><th></th></tr></thead>
   <tbody>
   <?php foreach ($activities as $a):
     $id = $a['activityID'];
   ?>
-  <tr id="view-<?= $id ?>">
+  <tr id="row-<?= $id ?>" data-editing="false">
     <td style="color:var(--muted)"><?= $id ?></td>
-    <td><?= htmlspecialchars($a['activityName']) ?></td>
-    <td><span class="badge badge-group"><?= htmlspecialchars($a['groupName']) ?></span></td>
-    <td><?= $a['sortOrder'] ?></td>
-    <td style="display:flex;gap:.4rem;justify-content:flex-end;">
-      <button type="button" onclick="startEdit(<?= $id ?>)" class="btn btn-sm btn-teal">Edit</button>
-      <form method="POST" onsubmit="return confirm('Delete this activity?')">
-        <input type="hidden" name="action" value="delete">
-        <input type="hidden" name="activityID" value="<?= $id ?>">
-        <button class="btn btn-sm btn-danger">Delete</button>
-      </form>
+    <td>
+      <div class="view"><?= htmlspecialchars($a['activityName']) ?></div>
+      <div class="edit"><input type="text" name="activityName" form="edit-form-<?= $id ?>" value="<?= htmlspecialchars($a['activityName']) ?>" required></div>
+    </td>
+    <td>
+      <div class="view"><span class="badge badge-group"><?= htmlspecialchars($a['groupName']) ?></span></div>
+      <div class="edit">
+        <select name="groupID" form="edit-form-<?= $id ?>" required>
+          <?php foreach ($groups as $g): ?>
+          <option value="<?= $g['groupID'] ?>" <?= $a['groupID'] == $g['groupID'] ? 'selected' : '' ?>><?= htmlspecialchars($g['groupName']) ?></option>
+          <?php endforeach; ?>
+        </select>
+      </div>
     </td>
-  </tr>
-  <tr id="edit-<?= $id ?>" style="display:none;background:rgba(79,209,197,.04);">
-    <td style="color:var(--muted)"><?= $id ?></td>
-    <td><input type="text" name="activityName" form="edit-form-<?= $id ?>" value="<?= htmlspecialchars($a['activityName']) ?>" required style="margin:0;width:100%;"></td>
     <td>
-      <select name="groupID" form="edit-form-<?= $id ?>" required style="margin:0;width:100%;">
-        <?php foreach ($groups as $g): ?>
-        <option value="<?= $g['groupID'] ?>" <?= $a['groupID'] == $g['groupID'] ? 'selected' : '' ?>><?= htmlspecialchars($g['groupName']) ?></option>
-        <?php endforeach; ?>
-      </select>
+      <div class="view"><?= $a['sortOrder'] ?></div>
+      <div class="edit"><input type="number" name="sortOrder" form="edit-form-<?= $id ?>" value="<?= (int)$a['sortOrder'] ?>" min="0"></div>
     </td>
-    <td><input type="number" name="sortOrder" form="edit-form-<?= $id ?>" value="<?= (int)$a['sortOrder'] ?>" min="0" style="margin:0;width:100%;max-width:80px;"></td>
-    <td style="display:flex;gap:.4rem;justify-content:flex-end;">
-      <button type="submit" form="edit-form-<?= $id ?>" class="btn btn-sm btn-primary">💾 Save</button>
-      <button type="button" onclick="cancelEdit(<?= $id ?>)" class="btn btn-sm btn-secondary">Cancel</button>
+    <td>
+      <div class="view actions-buttons">
+        <button type="button" onclick="startEdit(<?= $id ?>)" class="btn btn-sm btn-teal">Edit</button>
+        <form method="POST" onsubmit="return confirm('Delete this activity?')">
+          <input type="hidden" name="action" value="delete">
+          <input type="hidden" name="activityID" value="<?= $id ?>">
+          <button class="btn btn-sm btn-danger">Delete</button>
+        </form>
+      </div>
+      <div class="edit actions-buttons">
+        <button type="submit" form="edit-form-<?= $id ?>" class="btn btn-sm btn-primary">💾 Save</button>
+        <button type="button" onclick="cancelEdit(<?= $id ?>)" class="btn btn-sm btn-secondary">Cancel</button>
+      </div>
     </td>
   </tr>
   <?php endforeach; ?>
@@ -136,13 +148,13 @@ show_alerts();
 
 <script>
 function startEdit(id) {
-  document.getElementById('view-' + id).style.display = 'none';
-  document.getElementById('edit-' + id).style.display = '';
-  document.querySelector('#edit-' + id + ' input[name="activityName"]').focus();
+  var row = document.getElementById('row-' + id);
+  row.dataset.editing = 'true';
+  var input = row.querySelector('.edit input[name="activityName"]');
+  if (input) input.focus();
 }
 function cancelEdit(id) {
-  document.getElementById('edit-' + id).style.display = 'none';
-  document.getElementById('view-' + id).style.display = '';
+  document.getElementById('row-' + id).dataset.editing = 'false';
 }
 </script>
 

+ 34 - 25
admin/activity_groups.php

@@ -77,7 +77,14 @@ show_alerts();
 </form>
 <?php endforeach; ?>
 
-<table class="tbl">
+<table class="tbl tbl-fixed">
+  <colgroup>
+    <col style="width:60px">
+    <col>
+    <col style="width:100px">
+    <col style="width:100px">
+    <col style="width:200px">
+  </colgroup>
   <thead><tr><th>#</th><th>Name</th><th>Sort</th><th>Activities</th><th></th></tr></thead>
   <tbody>
   <?php foreach ($groups as $g):
@@ -86,28 +93,30 @@ show_alerts();
     $actCount = $cnt->fetchColumn();
     $id = $g['groupID'];
   ?>
-  <tr id="view-<?= $id ?>">
+  <tr id="row-<?= $id ?>" data-editing="false">
     <td style="color:var(--muted)"><?= $id ?></td>
-    <td><?= htmlspecialchars($g['groupName']) ?></td>
-    <td><?= $g['sortOrder'] ?></td>
-    <td><span class="badge badge-group"><?= $actCount ?></span></td>
-    <td style="text-align:right;display:flex;gap:.4rem;justify-content:flex-end;">
-      <button type="button" onclick="startEdit(<?= $id ?>)" class="btn btn-sm btn-teal">Edit</button>
-      <form method="POST" onsubmit="return confirm('Delete this group and ALL its activities?')">
-        <input type="hidden" name="action" value="delete">
-        <input type="hidden" name="groupID" value="<?= $id ?>">
-        <button type="submit" class="btn btn-sm btn-danger">Delete</button>
-      </form>
+    <td>
+      <div class="view"><?= htmlspecialchars($g['groupName']) ?></div>
+      <div class="edit"><input type="text" name="groupName" form="edit-form-<?= $id ?>" value="<?= htmlspecialchars($g['groupName']) ?>" required></div>
+    </td>
+    <td>
+      <div class="view"><?= $g['sortOrder'] ?></div>
+      <div class="edit"><input type="number" name="sortOrder" form="edit-form-<?= $id ?>" value="<?= (int)$g['sortOrder'] ?>" min="0"></div>
     </td>
-  </tr>
-  <tr id="edit-<?= $id ?>" style="display:none;background:rgba(79,209,197,.04);">
-    <td style="color:var(--muted)"><?= $id ?></td>
-    <td><input type="text" name="groupName" form="edit-form-<?= $id ?>" value="<?= htmlspecialchars($g['groupName']) ?>" required style="margin:0;width:100%;"></td>
-    <td><input type="number" name="sortOrder" form="edit-form-<?= $id ?>" value="<?= (int)$g['sortOrder'] ?>" min="0" style="margin:0;width:100%;max-width:80px;"></td>
     <td><span class="badge badge-group"><?= $actCount ?></span></td>
-    <td style="display:flex;gap:.4rem;justify-content:flex-end;">
-      <button type="submit" form="edit-form-<?= $id ?>" class="btn btn-sm btn-primary">💾 Save</button>
-      <button type="button" onclick="cancelEdit(<?= $id ?>)" class="btn btn-sm btn-secondary">Cancel</button>
+    <td>
+      <div class="view actions-buttons">
+        <button type="button" onclick="startEdit(<?= $id ?>)" class="btn btn-sm btn-teal">Edit</button>
+        <form method="POST" onsubmit="return confirm('Delete this group and ALL its activities?')">
+          <input type="hidden" name="action" value="delete">
+          <input type="hidden" name="groupID" value="<?= $id ?>">
+          <button type="submit" class="btn btn-sm btn-danger">Delete</button>
+        </form>
+      </div>
+      <div class="edit actions-buttons">
+        <button type="submit" form="edit-form-<?= $id ?>" class="btn btn-sm btn-primary">💾 Save</button>
+        <button type="button" onclick="cancelEdit(<?= $id ?>)" class="btn btn-sm btn-secondary">Cancel</button>
+      </div>
     </td>
   </tr>
   <?php endforeach; ?>
@@ -116,13 +125,13 @@ show_alerts();
 
 <script>
 function startEdit(id) {
-  document.getElementById('view-' + id).style.display = 'none';
-  document.getElementById('edit-' + id).style.display = '';
-  document.querySelector('#edit-' + id + ' input[name="groupName"]').focus();
+  var row = document.getElementById('row-' + id);
+  row.dataset.editing = 'true';
+  var input = row.querySelector('.edit input[name="groupName"]');
+  if (input) input.focus();
 }
 function cancelEdit(id) {
-  document.getElementById('edit-' + id).style.display = 'none';
-  document.getElementById('view-' + id).style.display = '';
+  document.getElementById('row-' + id).dataset.editing = 'false';
 }
 </script>
 

+ 34 - 25
admin/item_groups.php

@@ -66,7 +66,14 @@ show_alerts();
 </form>
 <?php endforeach; ?>
 
-<table class="tbl">
+<table class="tbl tbl-fixed">
+  <colgroup>
+    <col style="width:60px">
+    <col>
+    <col style="width:100px">
+    <col style="width:100px">
+    <col style="width:200px">
+  </colgroup>
   <thead><tr><th>#</th><th>Name</th><th>Sort</th><th>Items</th><th></th></tr></thead>
   <tbody>
   <?php foreach ($groups as $g):
@@ -75,28 +82,30 @@ show_alerts();
     $cnt = $stmt->fetchColumn();
     $id = $g['groupID'];
   ?>
-  <tr id="view-<?= $id ?>">
+  <tr id="row-<?= $id ?>" data-editing="false">
     <td style="color:var(--muted)"><?= $id ?></td>
-    <td><?= htmlspecialchars($g['groupName']) ?></td>
-    <td><?= $g['sortOrder'] ?></td>
-    <td><span class="badge badge-group"><?= $cnt ?></span></td>
-    <td style="display:flex;gap:.4rem;justify-content:flex-end;">
-      <button type="button" onclick="startEdit(<?= $id ?>)" class="btn btn-sm btn-teal">Edit</button>
-      <form method="POST" onsubmit="return confirm('Delete group and ALL its items?')">
-        <input type="hidden" name="action" value="delete">
-        <input type="hidden" name="groupID" value="<?= $id ?>">
-        <button class="btn btn-sm btn-danger">Delete</button>
-      </form>
+    <td>
+      <div class="view"><?= htmlspecialchars($g['groupName']) ?></div>
+      <div class="edit"><input type="text" name="groupName" form="edit-form-<?= $id ?>" value="<?= htmlspecialchars($g['groupName']) ?>" required></div>
+    </td>
+    <td>
+      <div class="view"><?= $g['sortOrder'] ?></div>
+      <div class="edit"><input type="number" name="sortOrder" form="edit-form-<?= $id ?>" value="<?= (int)$g['sortOrder'] ?>" min="0"></div>
     </td>
-  </tr>
-  <tr id="edit-<?= $id ?>" style="display:none;background:rgba(79,209,197,.04);">
-    <td style="color:var(--muted)"><?= $id ?></td>
-    <td><input type="text" name="groupName" form="edit-form-<?= $id ?>" value="<?= htmlspecialchars($g['groupName']) ?>" required style="margin:0;width:100%;"></td>
-    <td><input type="number" name="sortOrder" form="edit-form-<?= $id ?>" value="<?= (int)$g['sortOrder'] ?>" min="0" style="margin:0;width:100%;max-width:80px;"></td>
     <td><span class="badge badge-group"><?= $cnt ?></span></td>
-    <td style="display:flex;gap:.4rem;justify-content:flex-end;">
-      <button type="submit" form="edit-form-<?= $id ?>" class="btn btn-sm btn-primary">💾 Save</button>
-      <button type="button" onclick="cancelEdit(<?= $id ?>)" class="btn btn-sm btn-secondary">Cancel</button>
+    <td>
+      <div class="view actions-buttons">
+        <button type="button" onclick="startEdit(<?= $id ?>)" class="btn btn-sm btn-teal">Edit</button>
+        <form method="POST" onsubmit="return confirm('Delete group and ALL its items?')">
+          <input type="hidden" name="action" value="delete">
+          <input type="hidden" name="groupID" value="<?= $id ?>">
+          <button class="btn btn-sm btn-danger">Delete</button>
+        </form>
+      </div>
+      <div class="edit actions-buttons">
+        <button type="submit" form="edit-form-<?= $id ?>" class="btn btn-sm btn-primary">💾 Save</button>
+        <button type="button" onclick="cancelEdit(<?= $id ?>)" class="btn btn-sm btn-secondary">Cancel</button>
+      </div>
     </td>
   </tr>
   <?php endforeach; ?>
@@ -105,13 +114,13 @@ show_alerts();
 
 <script>
 function startEdit(id) {
-  document.getElementById('view-' + id).style.display = 'none';
-  document.getElementById('edit-' + id).style.display = '';
-  document.querySelector('#edit-' + id + ' input[name="groupName"]').focus();
+  var row = document.getElementById('row-' + id);
+  row.dataset.editing = 'true';
+  var input = row.querySelector('.edit input[name="groupName"]');
+  if (input) input.focus();
 }
 function cancelEdit(id) {
-  document.getElementById('edit-' + id).style.display = 'none';
-  document.getElementById('view-' + id).style.display = '';
+  document.getElementById('row-' + id).dataset.editing = 'false';
 }
 </script>
 

+ 42 - 30
admin/items.php

@@ -83,40 +83,52 @@ show_alerts();
 </form>
 <?php endforeach; ?>
 
-<table class="tbl">
+<table class="tbl tbl-fixed">
+  <colgroup>
+    <col style="width:60px">
+    <col>
+    <col style="width:180px">
+    <col style="width:100px">
+    <col style="width:200px">
+  </colgroup>
   <thead><tr><th>#</th><th>Name</th><th>Group</th><th>Sort</th><th></th></tr></thead>
   <tbody>
   <?php foreach ($items as $item):
     $id = $item['itemID'];
   ?>
-  <tr id="view-<?= $id ?>">
+  <tr id="row-<?= $id ?>" data-editing="false">
     <td style="color:var(--muted)"><?= $id ?></td>
-    <td><?= htmlspecialchars($item['itemName']) ?></td>
-    <td><span class="badge badge-group"><?= htmlspecialchars($item['groupName']) ?></span></td>
-    <td><?= $item['sortOrder'] ?></td>
-    <td style="display:flex;gap:.4rem;justify-content:flex-end;">
-      <button type="button" onclick="startEdit(<?= $id ?>)" class="btn btn-sm btn-teal">Edit</button>
-      <form method="POST" onsubmit="return confirm('Delete this item?')">
-        <input type="hidden" name="action" value="delete">
-        <input type="hidden" name="itemID" value="<?= $id ?>">
-        <button class="btn btn-sm btn-danger">Delete</button>
-      </form>
+    <td>
+      <div class="view"><?= htmlspecialchars($item['itemName']) ?></div>
+      <div class="edit"><input type="text" name="itemName" form="edit-form-<?= $id ?>" value="<?= htmlspecialchars($item['itemName']) ?>" required></div>
+    </td>
+    <td>
+      <div class="view"><span class="badge badge-group"><?= htmlspecialchars($item['groupName']) ?></span></div>
+      <div class="edit">
+        <select name="groupID" form="edit-form-<?= $id ?>" required>
+          <?php foreach ($igroups as $g): ?>
+          <option value="<?= $g['groupID'] ?>" <?= $item['groupID'] == $g['groupID'] ? 'selected' : '' ?>><?= htmlspecialchars($g['groupName']) ?></option>
+          <?php endforeach; ?>
+        </select>
+      </div>
     </td>
-  </tr>
-  <tr id="edit-<?= $id ?>" style="display:none;background:rgba(79,209,197,.04);">
-    <td style="color:var(--muted)"><?= $id ?></td>
-    <td><input type="text" name="itemName" form="edit-form-<?= $id ?>" value="<?= htmlspecialchars($item['itemName']) ?>" required style="margin:0;width:100%;"></td>
     <td>
-      <select name="groupID" form="edit-form-<?= $id ?>" required style="margin:0;width:100%;">
-        <?php foreach ($igroups as $g): ?>
-        <option value="<?= $g['groupID'] ?>" <?= $item['groupID'] == $g['groupID'] ? 'selected' : '' ?>><?= htmlspecialchars($g['groupName']) ?></option>
-        <?php endforeach; ?>
-      </select>
+      <div class="view"><?= $item['sortOrder'] ?></div>
+      <div class="edit"><input type="number" name="sortOrder" form="edit-form-<?= $id ?>" value="<?= (int)$item['sortOrder'] ?>" min="0"></div>
     </td>
-    <td><input type="number" name="sortOrder" form="edit-form-<?= $id ?>" value="<?= (int)$item['sortOrder'] ?>" min="0" style="margin:0;width:100%;max-width:80px;"></td>
-    <td style="display:flex;gap:.4rem;justify-content:flex-end;">
-      <button type="submit" form="edit-form-<?= $id ?>" class="btn btn-sm btn-primary">💾 Save</button>
-      <button type="button" onclick="cancelEdit(<?= $id ?>)" class="btn btn-sm btn-secondary">Cancel</button>
+    <td>
+      <div class="view actions-buttons">
+        <button type="button" onclick="startEdit(<?= $id ?>)" class="btn btn-sm btn-teal">Edit</button>
+        <form method="POST" onsubmit="return confirm('Delete this item?')">
+          <input type="hidden" name="action" value="delete">
+          <input type="hidden" name="itemID" value="<?= $id ?>">
+          <button class="btn btn-sm btn-danger">Delete</button>
+        </form>
+      </div>
+      <div class="edit actions-buttons">
+        <button type="submit" form="edit-form-<?= $id ?>" class="btn btn-sm btn-primary">💾 Save</button>
+        <button type="button" onclick="cancelEdit(<?= $id ?>)" class="btn btn-sm btn-secondary">Cancel</button>
+      </div>
     </td>
   </tr>
   <?php endforeach; ?>
@@ -125,13 +137,13 @@ show_alerts();
 
 <script>
 function startEdit(id) {
-  document.getElementById('view-' + id).style.display = 'none';
-  document.getElementById('edit-' + id).style.display = '';
-  document.querySelector('#edit-' + id + ' input[name="itemName"]').focus();
+  var row = document.getElementById('row-' + id);
+  row.dataset.editing = 'true';
+  var input = row.querySelector('.edit input[name="itemName"]');
+  if (input) input.focus();
 }
 function cancelEdit(id) {
-  document.getElementById('edit-' + id).style.display = 'none';
-  document.getElementById('view-' + id).style.display = '';
+  document.getElementById('row-' + id).dataset.editing = 'false';
 }
 </script>
 

+ 8 - 0
admin/layout.php

@@ -47,6 +47,14 @@ h2{font-size:1rem;font-weight:600;margin-bottom:.75rem;color:var(--text);}
 .tbl th{text-align:left;font-size:.75rem;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);padding:.6rem .9rem;border-bottom:1px solid var(--border);}
 .tbl td{padding:.6rem .9rem;border-bottom:1px solid rgba(42,47,63,.6);vertical-align:middle;}
 .tbl tr:hover td{background:rgba(255,255,255,.02);}
+/* Stable-layout table for inline-edit admin pages (opt-in via .tbl-fixed). */
+.tbl-fixed{table-layout:fixed;}
+.tbl-fixed td,.tbl-fixed th{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
+.tbl-fixed tr[data-editing="false"] .edit{display:none;}
+.tbl-fixed tr[data-editing="true"] .view{display:none;}
+.tbl-fixed .edit input,.tbl-fixed .edit select{margin:0;width:100%;}
+.tbl-fixed .actions-buttons{display:flex;gap:.4rem;justify-content:flex-end;}
+.tbl-fixed tr[data-editing="true"]{background:rgba(79,209,197,.04);}
 /* form card */
 .card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:1.25rem 1.5rem;margin-bottom:1.5rem;}
 label{display:block;font-size:.8rem;font-weight:500;color:var(--muted);margin-bottom:.3rem;letter-spacing:.04em;text-transform:uppercase;}

+ 2 - 2
config.php

@@ -3,11 +3,11 @@
 // Place this file ONE directory ABOVE the web-root (e.g. /var/www/config.php)
 // so it is never served directly by the web server.
 
+// sample configuration
 $host     = 'localhost';
 $dbname   = 'packit';
 $username = 'packer';
 $password = 'DEbWX9AHkzAgaNdLC0Qj605grG';
 $charset  = 'utf8mb4';
 
-// Admin session secret – change to any random string
-define('ADMIN_SESSION_SECRET', 'fdgdffrsgjsjsrttdc4rtjuzi8edetjh');
+?>

BIN
favicon.ico


BIN
img/icon-192-maskable.png


BIN
img/icon-192.png


BIN
img/icon-512-maskable.png


BIN
img/icon-512.png


+ 5 - 0
img/icon-maskable.svg

@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
+  <rect width="512" height="512" fill="#162447"/>
+  <rect x="187" y="136" width="54" height="240" fill="#e8c547"/>
+  <path d="M 241,136 A 84,84 0 0,1 241,304 L 241,250 A 30,30 0 0,0 241,190 Z" fill="#e8c547"/>
+</svg>

+ 5 - 0
img/icon.svg

@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
+  <rect width="512" height="512" rx="96" fill="#162447"/>
+  <rect x="164" y="96" width="72" height="320" fill="#e8c547"/>
+  <path d="M 236,96 A 112,112 0 0,1 236,320 L 236,248 A 40,40 0 0,0 236,168 Z" fill="#e8c547"/>
+</svg>

+ 3 - 0
index.php

@@ -39,6 +39,9 @@ foreach ($rows as $row) {
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>PackIt – Choose Your Activities</title>
+<link rel="manifest" href="/manifest.webmanifest">
+<meta name="theme-color" content="#e8c547">
+<link rel="icon" type="image/png" sizes="192x192" href="/img/icon-192.png">
 <link rel="preconnect" href="https://fonts.googleapis.com">
 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
 <link href="https://fonts.googleapis.com/css2?family=Bebas+Neue&family=DM+Sans:wght@300;400;500;600&display=swap" rel="stylesheet">

+ 38 - 0
manifest.webmanifest

@@ -0,0 +1,38 @@
+{
+  "name": "PackIt",
+  "short_name": "PackIt",
+  "description": "Smart packing list generator for outdoor activities.",
+  "start_url": "/index.php",
+  "scope": "/",
+  "display": "standalone",
+  "orientation": "portrait",
+  "background_color": "#0f1117",
+  "theme_color": "#e8c547",
+  "lang": "en",
+  "icons": [
+    {
+      "src": "/img/icon-192.png",
+      "sizes": "192x192",
+      "type": "image/png",
+      "purpose": "any"
+    },
+    {
+      "src": "/img/icon-512.png",
+      "sizes": "512x512",
+      "type": "image/png",
+      "purpose": "any"
+    },
+    {
+      "src": "/img/icon-192-maskable.png",
+      "sizes": "192x192",
+      "type": "image/png",
+      "purpose": "maskable"
+    },
+    {
+      "src": "/img/icon-512-maskable.png",
+      "sizes": "512x512",
+      "type": "image/png",
+      "purpose": "maskable"
+    }
+  ]
+}

+ 3 - 0
packing.php

@@ -84,6 +84,9 @@ $totalItems = count($allItems);
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>PackIt – Your Packing List</title>
+<link rel="manifest" href="/manifest.webmanifest">
+<meta name="theme-color" content="#e8c547">
+<link rel="icon" type="image/png" sizes="192x192" href="/img/icon-192.png">
 <link rel="preconnect" href="https://fonts.googleapis.com">
 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
 <link href="https://fonts.googleapis.com/css2?family=Bebas+Neue&family=DM+Sans:wght@300;400;500;600&display=swap" rel="stylesheet">

+ 0 - 89
submit_activities.php

@@ -1,89 +0,0 @@
-<?php
-
-// Database configuration
-require_once '../config.php';
-
-try {
-    // Establish a database connection using PDO
-    $pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8", $username, $password, [
-        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
-        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
-    ]);
-} catch (PDOException $e) {
-    die("Database connection failed: " . $e->getMessage());
-}
-
-// Retrieve and sanitize GET parameters
-$activityIds = isset($_GET['activity_ids']) ? $_GET['activity_ids'] : '';
-$activityIds = explode(',', $activityIds);
-$sanitizedIds = [];
-
-foreach ($activityIds as $id) {
-    if (ctype_digit($id) && (int)$id >= 0 && (int)$id <= 256) {
-        $sanitizedIds[] = (int)$id;
-    }
-}
-
-if (empty($sanitizedIds)) {
-    die("No valid activity IDs provided.");
-}
-
-// Create a query to get itemIDs
-$placeholders = implode(',', array_fill(0, count($sanitizedIds), '?'));
-$sql = "SELECT itemID FROM item_activity_map WHERE activityID IN ($placeholders)";
-$stmt = $pdo->prepare($sql);
-$stmt->execute($sanitizedIds);
-$itemIDs = $stmt->fetchAll(PDO::FETCH_COLUMN);
-
-if (empty($itemIDs)) {
-    die("No matching item IDs found.");
-}
-
-// Retrieve item names based on itemIDs
-$placeholders = implode(',', array_fill(0, count($itemIDs), '?'));
-$sql = "SELECT itemID, itemName FROM item_names WHERE itemID IN ($placeholders)";
-$stmt = $pdo->prepare($sql);
-$stmt->execute($itemIDs);
-$items = $stmt->fetchAll();
-
-?>
-<!DOCTYPE html>
-<html lang="en">
-<head>
-    <meta charset="UTF-8">
-    <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>Your packing list</title>
-    <style>
-        body {
-            font-family: Arial, sans-serif;
-            padding: 20px;
-        }
-        .item-item {
-            margin: 5px 0;
-        }
-        .item-item input {
-            margin-right: 10px;
-        }
-    </style>
-</head>
-<body>
-
-<h1>You need</h1>
-<?php
-// Display results as HTML with checkboxes
-echo "<form method='post' action='index.php'>";
-echo "<ul>";
-foreach ($items as $item) {
-    echo "
-	<div class='item-item'>
-	<input type='checkbox' name='selected_items' value='" . htmlspecialchars($item['itemID']) . "'>
-	<label for=selected_items_" . htmlspecialchars($item['itemID']) . ">" 
-	. htmlspecialchars($item['itemName'])
-	. "</label></div>";
-}
-echo "</ul>";
-echo "</form>";
-?>
-
-</body>
-</html>