Commit graph

57 commits

Author SHA1 Message Date
Claude
076996a470
Move wordmark to doctitle; show period instead of today's date
- Remove app-wordmark from toolbar; place it in kb-doctitle where
  the h1 "Reimbursement" was, at the same font size (--fs-h1)
- Glyph now appears to the right of "reimburse"
- Replace "Claim · today's date" with the user's selected period
  (from – to), updated live as dates are changed

https://claude.ai/code/session_01JyuActqTJG5tuRQNLmT7fZ
2026-06-08 04:53:02 +00:00
Claude
013563d13e
Polish FX direction picker and toolbar clipping
- Replace plain <select> for FX direction with the same makeCDD custom
  dropdown used for currency selection throughout the form
- Add padding-right:2px to .kb-toolbar so the theme icon button border
  is not clipped on the right edge

https://claude.ai/code/session_01JyuActqTJG5tuRQNLmT7fZ
2026-06-08 04:50:00 +00:00
Claude
e371505323
Add bidirectional FX rate entry
Users can now enter the exchange rate from either direction:
- "35 THB per USD" (foreign per base, the canonical form)
- "0.02857 USD per THB" (base per foreign, inverted display)

A compact inline select next to the rate field lets the user choose
which currency is in the numerator; the "per X" label updates to show
the denominator. Switching direction re-displays the current rate
inverted — the stored canonical (foreign/base) is unchanged, so
recalc(), fxRateMemory, and PDF output are unaffected.

Persists fxDir alongside fxRate in localStorage/IndexedDB.

https://claude.ai/code/session_01JyuActqTJG5tuRQNLmT7fZ
2026-06-08 04:40:02 +00:00
Claude
0a84ba4628
Redesign toolbar: wordmark, language select, icon theme toggle
- Remove static app-bar header element
- Add glyph + "reimburse" wordmark to toolbar left
- Add optional language <select> (shown only when CFG.languages > 1)
- Replace 3-way Auto/Light/Dark segmented with single moon/sun icon toggle
- Theme toggle persists to localStorage and respects OS preference

https://claude.ai/code/session_01JyuActqTJG5tuRQNLmT7fZ
2026-06-08 04:28:12 +00:00
Claude
3f7fcf47ed
Add subtle app bar with reimburse glyph
Thin 34px strip at the top of the page — the reimburse icon (card/
banknote outline glyph from dev/design_assets/reimburse-glyph.svg)
at 16px, 50% opacity, in var(--text-muted). One hairline border below.
aria-hidden so it is invisible to screen readers.

https://claude.ai/code/session_01JyuActqTJG5tuRQNLmT7fZ
2026-06-08 04:19:10 +00:00
Claude
345e285d30
Redesign PDF output to match kBenestad design language
Visual-only change — all logic, validation, and page-break handling
is identical. Uses Helvetica/Courier (standard PDF fonts) to avoid
file size increase.

Changes:
- kBenestad color tokens: clrText #14181E, clrMuted #5F6975,
  clrBorder #E3E7EE, clrSurface2 #F8F9FB, clrAccent from config
- Page 1 header: 44pt initials box (surface-2 fill, accent initials)
  or logo image, org name + "Expense reimbursement" subtitle left;
  "Reimbursement" title + "Claim · DD Mon YYYY" in Courier right;
  0.5pt hairline below
- Staff/period/currency: light surface-2 info block with hairline
  borders, currency value in accent color
- Continuation headers (p2+): full-width surface-2 strip with labels
  and values, bordered top + bottom
- Item sections: 3pt accent left-stripe, item name bold left,
  subtotal in Courier accent right, 0.5pt hairline below
- Eyebrow labels: uppercase, bold, szXs (sz-2), clrMuted
- Value text: clrText vs old near-black; dates/FX/amounts in Courier
- Line dividers: 0.3pt clrBorder (was 0.3pt gray)
- Grand total: 1.5pt clrBorderStrong rule; label left, szLg bold
  accent amount right (was single right-aligned string)
- Footers: clrBorder hairline, all text clrMuted at szXs

https://claude.ai/code/session_01JyuActqTJG5tuRQNLmT7fZ
2026-06-08 04:08:56 +00:00
Claude
2482cf544f
Restyle app to kBenestad design language
Replaces the ad-hoc CSS and DOM structure with the full kBenestad
forms design language from dev/mockups/kbenestad-forms.css and the
dev/mockups/reimburse.html reference mockup. Surface-only change —
all PDF engine, state, validation, and persistence logic is intact.

Key changes:
- Schibsted Grotesk + JetBrains Mono (bunny.net, system fallback)
- Semantic CSS tokens with light/dark auto + manual override
- Toolbar: font-size A−/A/A+, theme Auto/Light/Dark, about button
- Document header: logo tile + org name left, title + date right
- kb-card sections for claimant and expenses
- kb-block item containers; kb-line line rows with kb-field/kb-label
- kb-btn variants (primary, ghost, soft, dashed, danger)
- kb-note for validation errors and modal feedback
- kb-totals grand total panel (mono tabular figures)
- kb-footer with kBenestad attribution
- Favicons from dev/design_assets/favicons/

https://claude.ai/code/session_01JyuActqTJG5tuRQNLmT7fZ
2026-06-08 03:17:02 +00:00
be4b4c463e Added design assets
Some checks are pending
/ mirror (push) Waiting to run
2026-06-08 09:59:37 +07:00
696a19b142
Add design brief for kBenestad web apps
This document serves as a design brief for kBenestad web apps, outlining visual guidelines, typography, color tokens, and UI components.
2026-06-08 08:58:36 +07:00
fde406475e
Add GitHub Actions workflow for repository mirroring 2026-06-04 17:14:44 +07:00
ca81d531f7
Merge pull request #8 from kbenestad/claude/great-tesla-mlLAH
Add footer
2026-06-04 12:04:52 +07:00
Claude
f5c674aebe
Left-align app footer
https://claude.ai/code/session_01MNy1ymwx9URLgXSgHc9W3T
2026-06-04 05:01:32 +00:00
Claude
7ef4773ac0
Add app footer with About modal
Adds a footer bar at the bottom of the page with copyright, a link to
docs.benestad.net/invoice, a repo link, and an About link that opens a
modal. Modal title, Markdown content, and button label are configurable
via config.yml (about-title, about-content, about-button).

https://claude.ai/code/session_01MNy1ymwx9URLgXSgHc9W3T
2026-06-04 04:54:17 +00:00
Claude
6be776ccd2
Preserve staff name when starting a new form
https://claude.ai/code/session_01MbwfxnjLA9KdFTrfzB55HM
2026-05-24 18:11:10 +00:00
Claude
c09aca7cd3
Add New Form button that clears all saved data and resets to a fresh form
Green button next to the Staff Name field. Clicking shows a confirmation
modal; on confirm it removes all localStorage and IndexedDB data, resets
state using defaultPeriod() for the period dates, and re-renders.

Also fixes period date pickers to set .value directly (same fix applied
earlier to expense line date inputs) so they open to the right month.

https://claude.ai/code/session_01MbwfxnjLA9KdFTrfzB55HM
2026-05-24 18:09:48 +00:00
Claude
b175352df8
Persist form state and receipts across sessions
Text state (items, lines, programs, amounts, etc.) is saved to localStorage
and receipts/images are saved to IndexedDB. Data is restored automatically
on the next visit in the same browser.

Auto-save runs 1 s after the last input event. A green Save button triggers
an explicit save with a confirmation modal. Receipt validation is skipped on
save and only enforced at PDF generation time.

An entry modal on every load explains the save behaviour and (if IndexedDB
is unavailable) warns that receipts cannot be persisted.

https://claude.ai/code/session_01MbwfxnjLA9KdFTrfzB55HM
2026-05-24 18:04:48 +00:00
Claude
59fcafa135
Replace FX rate tooltip with modal popup; fix Other currency label
Selecting a non-base currency now shows a modal explaining the exchange
rate convention, using the actual currency names. Selecting Other shows
a variant asking the user to enter the ISO code first. Both messages
are configurable via fx-rate-message and fx-rate-message-other in
config.yml using {foreign} and {base} placeholders.

The Other option in the currency dropdown no longer shows __OTHER__.

https://claude.ai/code/session_01MbwfxnjLA9KdFTrfzB55HM
2026-05-24 17:45:17 +00:00
Claude
0853fae199
Add descriptive FX rate tooltip and Other currency option
Tooltip now appears below the FX rate field, wraps across multiple lines,
and explains the rate convention using the actual currency names from config.

Currency dropdown gains an Other option: selecting it swaps to a three-letter
ISO input with its own tooltip. A × button cancels back to the dropdown.
The FX rate field responds to the custom code once three letters are entered.

https://claude.ai/code/session_01MbwfxnjLA9KdFTrfzB55HM
2026-05-24 17:10:28 +00:00
Claude
ab7a17c971
Set date input .value property directly so picker opens to the correct month
setAttribute only sets the defaultValue attribute; the browser date picker
uses the .value property to determine which month to show on open.

https://claude.ai/code/session_01MbwfxnjLA9KdFTrfzB55HM
2026-05-24 16:58:15 +00:00
Claude
0c7bb8ac91
Fix period initialisation order so first expense line date defaults correctly
state.periodFrom was set inside render(), after newItem() was called,
so the first line always got an empty date. Setting the period before
pushing the first item ensures the default date is the period start.

https://claude.ai/code/session_01MbwfxnjLA9KdFTrfzB55HM
2026-05-24 16:54:38 +00:00
Claude
f1be8fde1b
Default new expense line date to period start so picker opens to correct month
https://claude.ai/code/session_01MbwfxnjLA9KdFTrfzB55HM
2026-05-24 16:47:40 +00:00
Claude
e08ffbf333
Right-align FX rate and Amount labels in PDF to sit above their values
Labels were left-aligned at c4 while values were flush-right, causing
them to not line up. Labels now share the same right edge as their values.

https://claude.ai/code/session_01MbwfxnjLA9KdFTrfzB55HM
2026-05-24 16:42:53 +00:00
Claude
eeed56ca89
Warn when expense date falls outside the report period
When a user enters a date outside the selected period, a modal warning
appears explaining they can continue but the date will be flagged. The
date input gets an amber border/background as a persistent visual cue.
The PDF marks out-of-period dates in orange with a trailing (!) marker.

https://claude.ai/code/session_01MbwfxnjLA9KdFTrfzB55HM
2026-05-24 16:37:44 +00:00
Claude
4cad8ed292
Right-align text in FX Rate input to match Amount field
https://claude.ai/code/session_01MbwfxnjLA9KdFTrfzB55HM
2026-05-24 16:21:00 +00:00
Claude
1e01329d18
Show calculated base-currency amount alongside each programme percentage
When multiple programmes are allocated on a line, each row now displays
the pro-rated amount in the base currency next to the percentage
(e.g. "10.00% – USD 12.34"). The figure updates live as the line amount,
FX rate, or currency changes, as well as when the percentage is edited.
The PDF receipt renders the same information as a right-aligned suffix
on each programme row.

https://claude.ai/code/session_01MbwfxnjLA9KdFTrfzB55HM
2026-05-24 16:10:26 +00:00
Claude
66260fec1b
Support multiple program allocations with percentage split per expense line
Replaces single program field with a dynamic multi-program UI. A single
program shows the select inline with an "+ Add program" button and no
percentages. Adding a second program switches the layout to show a percent
input per row, a colour-coded total (yellow <100%, green =100%, red >100%),
and a × button to remove individual rows. Returning to one program reverts
to the simple layout. PDF renders programmes stacked with (XX.XX%) suffix
when multiple are present. Validation requires each selection, all percents
positive, and total = 100% when multiple programmes are allocated.

https://claude.ai/code/session_01MbwfxnjLA9KdFTrfzB55HM
2026-05-24 15:50:07 +00:00
Claude
7d49759c75
Add user, admin, and developer documentation; expand CLAUDE.md
Creates docs/ with three audience-specific guides:
- docs/user-guide.md: step-by-step form-filling instructions, field
  descriptions, FX rate explanation, receipt handling, troubleshooting
- docs/admin-guide.md: deployment instructions and exhaustive config.yml
  key/value reference with types, defaults, and constraints
- docs/developer-guide.md: architecture overview, full state model, all
  CFG key mappings, PDF engine internals, column positions, four-pass build
  process, common modification checklists, known limitations

Rewrites CLAUDE.md as a dense agent reference covering the same ground
in a compact format: code section line ranges, full config key table with
JS access patterns, validation rules, PDF coordinate system, design
decisions, and modification checklists.

https://claude.ai/code/session_01Dad69NPna53u4hucCYnVNs
2026-05-19 09:50:11 +00:00
Claude
f13b2cef6d
Rename PDF label from "Explanation:" to "Explanation for no receipt:"
https://claude.ai/code/session_016aNBqHpiQciTr1DvNvE7nk
2026-05-19 09:33:47 +00:00
Claude
66396219af
Place PDF logo at absolute 10mm from top-left, above all content
Logo is now pinned to an absolute position (10mm from top, 10mm from
left) independent of the content cursor, so it can never overlap any
form elements. The cursor y is pushed below the logo bottom before
the title and remaining header elements are drawn.

https://claude.ai/code/session_016aNBqHpiQciTr1DvNvE7nk
2026-05-19 09:26:47 +00:00
Claude
9749b70fe2
Fix PDF logo overlapping form fields
The logo was placed with a fixed +10pt offset that didn't account for
actual logo height. Content below always advanced by a fixed 28pt, so
any logo taller than ~18pt bled into the intro text and form fields.

Now the logo is anchored with its top at the cursor position (bottom at
y - lhh), the title baseline aligns to the same top edge, and y advances
by max(logoHeight, titleSize) + 8pt gap before the next element.

https://claude.ai/code/session_016aNBqHpiQciTr1DvNvE7nk
2026-05-19 09:20:52 +00:00
f72607fa9e New structure 2026-05-19 15:54:14 +07:00
c3dc28ac46
Merge pull request #7 from kbenestad/claude/fix-form-layout-P8uHa
Fix crash, form layout, PDF formatting, and date handling
2026-05-13 17:20:26 +07:00
Claude
e4f54c16bf
Currency in row 1 above Receipt; FX rate above Amount
Row 1: Date | Vendor (grow) | Currency | FX rate
Row 2: Description (grow) | Receipt | Amount
Currency and Receipt share the same x position; FX rate and Amount share the same x position.

https://claude.ai/code/session_014uUwDBtG5y5FuWcy5zqVD1
2026-05-13 10:19:18 +00:00
66927fd2cd
Merge pull request #6 from kbenestad/claude/fix-form-layout-P8uHa
Reorganise line fields: Currency moves to row 2, FX rate narrows
2026-05-13 17:16:52 +07:00
Claude
12b2bb9720
Reorganise line fields: Currency moves to row 2, FX rate narrows
Form: Row 1 = Date | Vendor (grow) | FX rate (120px)
      Row 2 = Description (grow) | Currency | Receipt | Amount (120px)
      Base currency header: fixed width (no grow)
PDF:  Same two-row layout with matching column positions

https://claude.ai/code/session_014uUwDBtG5y5FuWcy5zqVD1
2026-05-13 10:15:54 +00:00
9dd09c8ad5
Merge pull request #5 from kbenestad/claude/fix-form-layout-P8uHa
Claude/fix form layout p8u ha
2026-05-13 17:11:43 +07:00
Claude
7bca92bc0b
Stretch base currency dropdown to fill form width
Add grow class to base currency fgrp; add CSS rules so .cdd and its
trigger button fill 100% width when inside a grow container.

https://claude.ai/code/session_014uUwDBtG5y5FuWcy5zqVD1
2026-05-13 10:09:34 +00:00
Claude
ee2ee6df40
PDF dates always YYYY-MM-DD; remove formatDate and date-format config
https://claude.ai/code/session_014uUwDBtG5y5FuWcy5zqVD1
2026-05-13 10:08:41 +00:00
Claude
4a0b755f37
Restore native date pickers; keep formatDate for PDF output only
https://claude.ai/code/session_014uUwDBtG5y5FuWcy5zqVD1
2026-05-13 10:07:54 +00:00
67e1a2a7f1
Merge pull request #4 from kbenestad/claude/fix-form-layout-P8uHa
Claude/fix form layout p8u ha
2026-05-13 17:05:27 +07:00
Claude
67786317d7
Standardise all field labels to szSm-1 in PDF output
Staff/Period/Currency header labels and Explanation were using szSm
while all line field labels used szSm-1, causing inconsistent sizing.

https://claude.ai/code/session_014uUwDBtG5y5FuWcy5zqVD1
2026-05-13 10:01:52 +00:00
Claude
31b5b2e255
Footer left: show 'Reimbursement form' and staff name on second line
https://claude.ai/code/session_014uUwDBtG5y5FuWcy5zqVD1
2026-05-13 10:00:43 +00:00
Claude
0dd4506ed5
PDF: right-align FX rate, use standard font for FX rate and amount
https://claude.ai/code/session_014uUwDBtG5y5FuWcy5zqVD1
2026-05-13 09:59:54 +00:00
Claude
971c1f2fc9
Replace three blue separators before grand total with one double-weight line
The last item divider plus two double-rule lines produced three blue lines.
Removed the item divider and the double-rule pair; replaced with a single
line at thickness 3 (double the standard 1.5).

https://claude.ai/code/session_014uUwDBtG5y5FuWcy5zqVD1
2026-05-13 09:58:17 +00:00
Claude
8f64694115
Fix PDF line separator position and footer bleed-through
- Move inter-line separator from bottom to top of each expense line;
  skip on first line and on page breaks (justBroke flag) so the
  continuation header is never followed immediately by a divider
- Increase needSpace from lh*5 (70pt) to lh*7 (98pt) to match the
  actual line block height (~6lh + 16pt), preventing content from
  overrunning M.bottom and bleeding into the footer area

https://claude.ai/code/session_014uUwDBtG5y5FuWcy5zqVD1
2026-05-13 09:53:46 +00:00
eaff681ab9
Merge pull request #3 from kbenestad/claude/fix-form-layout-P8uHa
Add configurable date-format; replace browser date pickers with text …
2026-05-13 16:47:35 +07:00
Claude
8be37f29fe
Add configurable date-format; replace browser date pickers with text inputs
- New config key date-format (default DD/MM/YYYY) controls date display
  throughout the form and PDF output
- formatDate(iso) converts stored YYYY-MM-DD to the configured display format
- parseDate(str) converts user input back to YYYY-MM-DD for state storage
- All three date inputs (line date, period from/to) switched from type=date
  to type=text with format placeholder, removing browser locale dependency
- PDF line dates, period header, and continuation header all use formatDate()
- Filename stays in YYYY-MM-DD for safe file naming

https://claude.ai/code/session_014uUwDBtG5y5FuWcy5zqVD1
2026-05-13 09:38:27 +00:00
cae6416ffd
Merge pull request #2 from kbenestad/claude/fix-form-layout-P8uHa
Fix crash: state initialized before CFG is loaded
2026-05-13 16:33:40 +07:00
Claude
156c76baae
Fix crash: state initialized before CFG is loaded
state.baseCurrency was set to CFG['currency-base'] at declaration time,
but CFG is only populated after await loadConfig(). Reading a property of
undefined throws synchronously, crashing the script before init() runs.
Move the assignment to after loadConfig() resolves in init().

https://claude.ai/code/session_014uUwDBtG5y5FuWcy5zqVD1
2026-05-13 09:30:22 +00:00
edc9d915e0
Merge pull request #1 from kbenestad/claude/fix-form-layout-P8uHa
Make base currency dynamic and reorganize line item layout
2026-05-13 16:27:32 +07:00