feat: add packer

This commit is contained in:
2026-10-03 23:11:51 +02:00
parent e82561862a
commit 5452f72087
14 changed files with 976 additions and 25 deletions
+68 -1
View File
@@ -12,7 +12,8 @@ picked up automatically. The root only holds what apps share:
401 for the API prefixes in `PROTECTED_PREFIXES` until `/api/auth/login` has set the session cookie
(signed with `NUXT_SESSION_SECRET`, http-only, 30 days), and a page wraps itself in `<PasswordGate>` to show the
password prompt. To protect a new app, add its API prefix and use the gate.
- `readValidBody(event, zodSchema)` and the client util `errorMessage(error)`
- `readValidBody(event, zodSchema)`, the client util `errorMessage(error)` and `usePdfExport(fileName)` ("Save as PDF"
through the browser's print dialog: names the PDF and prints light also in dark mode; used by CV and Packer, with the `<SavePdfButton>` under the content)
| Path | App |
|---|---|
@@ -20,6 +21,7 @@ picked up automatically. The root only holds what apps share:
| `/wishlist` | [Wishlist](#wishlist) — `layers/wishlist/` |
| `/notes` | [Notes](#notes) — `layers/notes/` (password protected) |
| `/cv` | [CV](#cv) — `layers/cv/` |
| `/packer` | [Packer](#packer) — `layers/packer/` |
```bash
pnpm install
@@ -36,6 +38,70 @@ pnpm dev
names that won't clash with another app's (e.g. `DiaryEntry`, not `Entry`).
3. Don't use `~/` inside a layer — it points to the root `app/`. Use relative imports.
# Packer
A public packing list built from the Baserow packing table (`NUXT_BASEROW_PACKER_TABLE_ID`). At the top you set the
trip: number of days and people, where you sleep, weather, season and activities. The list below is grouped by category in table order, items sorted alphabetically.
The settings are kept in the URL, so a list can be bookmarked or sent.
- **Activities** are the options of the table's `activity` field that some item uses, sorted alphabetically. Items with activities are
only listed when one of them is picked; items without are always listed. Their icons are set in
`layers/packer/app/app.config.ts` under `packer.activityIcons` (a tag icon otherwise).
- **Sleeping:** the activities in `packer.stays` (Übernachtung, Camping) aren't picked with the others. On a trip of
more than one day a switch picks exactly one of them (the first by default); a day trip has neither.
- **Counts:** an item with `every_n_days` is packed once every n days (rounded up), the rest once. With the
`packer.laundry` activity (Wäsche waschen) picked, items of the laundry categories (Kleidung) are counted for at
most 4 days.
- **Automatic activities** (`packer.autoActivities`): Wäsche waschen from 5 days, Duschen from 2 days, Kochen when
sleeping is Camping. Each turns on when its condition starts to hold and off when it stops; in between it can be
switched by hand.
- **Weather:** a switch between the options of the `weather` field that some item uses (Sonnig, Bewölkt, Regnerisch;
`packer.defaultWeather` on a fresh list), and next to it toggles for the weathers in `packer.weatherExtras` (Windig),
which come on top of the picked one. Items with weathers are listed when one of them applies, empty means any
weather. `weather` may be a single or a multiple select. Icons and the switch's order in `packer.weatherIcons`.
- **Alternatives:** rows with the same `item` name are listed once, when any of them fits the trip. That is how an item
gets "or" conditions, e.g. `Schal/Buff` once with season Winter and once with weather Windig. Ticks, deletions and
weight changes belong to the name's first row, so they stick whichever row fits.
- **Season:** items with `season` set are only listed in those seasons, empty means always. The season defaults to
today's in Germany, by meteorological seasons (spring from 1 March, summer from 1 June, autumn from
1 September, winter from 1 December).
- **People:** everything that isn't `sharable` is multiplied by the number of people; `sharable` items are packed
once for the group.
- **Weight:** once `weight_g` is filled in, each item shows its weight (times its count), and under the progress bar
the weight already packed next to the list's total; "≥" means some listed items have no weight yet (hover for how
many).
- **Session only:** you can tick items off, delete items (✕, on hover with a mouse), add items to a category (fields at
the bottom of each category: name and optional weight; added items count once) and change any item's weight (click
it; it's the weight of one piece, an empty field goes back to the table's weight, changed weights are shown in the
primary color). None of this touches the table: it is kept in the browser
tab's `sessionStorage`, survives reloads and is gone when the tab is closed.
- **Als PDF speichern** (under the list, as on the CV) prints the list as a checklist (with the browser's "Save as PDF"): the trip in one line under the title
(days, people, season, stay, activities, total weight), the categories in two columns, ticked items ticked. The
settings and the buttons are left out; the file is named `packer_<days>_tage`.
- **Zurücksetzen** (shown once anything differs from a fresh list) clears all of that and puts the settings back to
their defaults (weights changed on the page go back to the table's too): 1 day, 1 person, today's season, Übernachtung and the automatic activities.
**Table:** `item` (text), `category` (single select), `sharable` (boolean), `every_n_days` (number), `weight_g`
(number), `season` (multiple select: `Frühling`, `Sommer`, `Herbst`, `Winter`), `activity` (multiple select),
`weather` (single or multiple select). Rows
without `item` are skipped. The token needs read (rows and fields).
```
layers/packer/
nuxt.config.ts baserowPackerTableId
app/
app.config.ts packer: activityIcons, weatherIcons, defaultWeather, weatherExtras, stays, laundry,
autoActivities
pages/packer.vue settings, progress, reset, the list, PDF button
components/PackerSettingsBar.vue days, people, sleeping, weather, season, activities
components/PackerCategory.vue one category: tick, delete, add
composables/usePacker.ts settings in the URL, session changes, filtering and counts
server/
api/packer/index.get.ts GET all items, the activities and the weathers
utils/packer.ts Baserow row -> PackerItem
shared/types/packer.ts
```
# CV
A public CV built from the Baserow CV table (`NUXT_BASEROW_CV_TABLE_ID`). Only rows with `relevant` checked are shown,
@@ -160,6 +226,7 @@ self-hosted Baserow tables.
| `NUXT_BASEROW_NOTES_TABLE_ID` | Notes table |
| `NUXT_BASEROW_WISHLIST_TABLE_ID` | Wishlist table (see [Wishlist](#wishlist)) |
| `NUXT_BASEROW_CV_TABLE_ID` | CV table (see [CV](#cv)) |
| `NUXT_BASEROW_PACKER_TABLE_ID` | Packing table (see [Packer](#packer)) |
| `NUXT_BASEROW_NOTES_APP_TABLE_ID` | Table of the notes app (see [Notes](#notes)), not the diary's notes |
| `NUXT_DIARY_PASSWORD` | Password that unlocks the diary and notes |
| `NUXT_SESSION_SECRET` | Signs the login cookie, at least 32 characters (`openssl rand -hex 32`) |