Skip to content

feat: advanced label designer for spool print page#14

Open
akira69 wants to merge 19 commits into
mainfrom
feat/advanced-label-designer
Open

feat: advanced label designer for spool print page#14
akira69 wants to merge 19 commits into
mainfrom
feat/advanced-label-designer

Conversation

@akira69
Copy link
Copy Markdown
Owner

@akira69 akira69 commented Apr 18, 2026

Advanced Label Designer

Replaces the existing simple print page with a full label designer accessible per-spool at /spools/{id}/print.

What's New

Two-tab interface:

  • Print Settings — Classic label controls (width, height, QR size, font size, display toggles for logo/QR/spool-ID/manufacturer/material/color/color-swatch, plus zoom slider)
  • Label Designer — Advanced template-based designer with section-by-section control

Label Designer features:

  • Presets — Save/load named label configurations (stored in localStorage)
  • Label — Width/height (mm), print border toggle, margin control
  • Logo — Space height, scale-to-fit, left/center/right justification
  • Title — Template format string with {filament.name} token, max font size, fit-to-width, line above/below, justification, margin
  • Lines — Up to 4 configurable lines, each with template string, font size, style (bold/italic/optional), justification
  • QR Code — Size, position (right/bottom), justification
  • Available Tokens — clickable token badges auto-inserted into focused template fields
    • Filament: color_swatch[1], id, name, type, subtype, color, color_hex, manufacturer, extruder_temp, bed_temp, weight, diameter, finish, density, price
    • Spool: id, remaining_weight, tag, location, purchased_at
    • Extra Fields: auto-populated from configured system extra fields

New files:

  • frontend/src/lib/label-template.ts (227 lines) — token substitution engine, preset serialization, render helpers
  • frontend/src/pages/spools/[id]/print.astro (3800+ lines) — complete label designer page

i18n: +54 translation strings in en.json and de.json

No backend changes — pure frontend addition; no new migrations.

Screenshots

Label preview with manufacturer logo, material, color and print temps:

Label Designer — full preview with logo and rich data

Zoomed-in label preview:

Label Designer — zoomed preview

Print Settings tab:

Print Settings tab

Label Designer — template config with token chips:

Template tokens and config

@akira69 akira69 force-pushed the feat/advanced-label-designer branch 5 times, most recently from b035b11 to 585c9f7 Compare April 18, 2026 22:43
@akira69 akira69 marked this pull request as ready for review April 19, 2026 04:14
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 585c9f74fe

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread version.txt Outdated
Comment thread frontend/src/pages/spools/[id]/print.astro Outdated
@akira69 akira69 force-pushed the feat/advanced-label-designer branch 3 times, most recently from a9eaf00 to 53d9961 Compare April 19, 2026 05:04
@akira69 akira69 force-pushed the feat/advanced-label-designer branch 7 times, most recently from bb182b2 to 79ab91a Compare May 6, 2026 03:48
@akira69
Copy link
Copy Markdown
Owner Author

akira69 commented May 6, 2026

@codex review

@akira69 akira69 force-pushed the feat/advanced-label-designer branch from 79ab91a to 03b8bc4 Compare May 6, 2026 04:22
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 79ab91a767

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread frontend/src/pages/spools/[id]/print.astro
Comment thread frontend/src/pages/spools/[id]/print.astro
@akira69 akira69 force-pushed the feat/advanced-label-designer branch from 03b8bc4 to a34a9c5 Compare May 6, 2026 04:34
@akira69
Copy link
Copy Markdown
Owner Author

akira69 commented May 6, 2026

@ManuelW77 I am curious what you think about this
for me a good label is a very important feature of a Filamant/Spool management database -
this is a nearly fully fleshed out concept that allows maximum flexibility of a label design export - but maintains the simple one for causual users. I'd love to see something like this in Filaman.

@Tschipel
Copy link
Copy Markdown

Hi @akira69 ,
i'm not sure how can i test your feature.

  1. I created a docker lxc on my proxmox environment
  2. git clone your (my fork of your) repository
  3. created the .env as described
  4. Build the docker container (docker build -t filaman-system:latest .)
  5. run the docker container
# Start container
docker run -d \
  --name filaman-system-app \
  --restart unless-stopped \
  -p 8083:8000 \
  -v filaman_data:/app/data \
  -e DEBUG=false \
  -e SECRET_KEY=your-secret-key \
  -e CSRF_SECRET_KEY=your-csrf-secret \
  -e ADMIN_EMAIL=admin@example.com \
  -e ADMIN_PASSWORD=your-admin-password \
  filaman-system:latest

But i can't see you advanced label designer - as i'm also don't know how to do it (obviously) correct, can you please provide me how to do this right? Thanks in advance.

@akira69
Copy link
Copy Markdown
Owner Author

akira69 commented May 14, 2026

I can do a build for for you. Let me figure that out and I'll send you a link or something. It's because in my fork it is just a PR and it's not actually merged.

@akira69
Copy link
Copy Markdown
Owner Author

akira69 commented May 14, 2026

@Tschipel

Actually if you grab my specific branch you can build it: Here are minimal instructions for building my filaman-system repository (including changes from PR #14) in Docker:


Instructions to Build and Run in Docker

  1. Clone the Repository

    git clone https://github.com/akira69/filaman-system.git
    cd filaman-system
  2. Checkout the Feature Branch

    git checkout feat/advanced-label-designer
  3. Build the Docker Image
    Run this command to build the image:

    docker build -t filaman-system:latest .
  4. Run the Docker Container
    Start a container from the Docker image:

    docker run -p 8080:8080 filaman-system:latest
  • or whatever port
  1. Access the Application
    Open your browser and go to:
    http://localhost:8080
    

@Tschipel
Copy link
Copy Markdown

Thanks, seems my missing step was the 'git checkout' - had to use the 'main' run command, but now i can test a few things. Looks very promising to me.

@Tschipel
Copy link
Copy Markdown

Just a question - it seems the behavior is a little bit different (or is it just me?)
When i was on the tap 'label designer' and switch to 'print settings' i get the following picture/label
grafik
when returning to spool and print label again i get the following
grafik
seems to be there are two different labels for the same function?!
grafik
Is the label designer variant, which is correct but the filaman logo in the qr is missing.

Nevertheless the roll id/number bug from the official release - all numbers with three digits are cutted to the first two digits.

@akira69
Copy link
Copy Markdown
Owner Author

akira69 commented May 14, 2026

@Tschipel Full disclaimer ahead, certainly there are issues and errors that need to be improved in the label designer tab implementation. This is part of the reason I didn't do a PR upstream. However, let me try to address your points:

Just a question - it seems the behavior is a little bit different (or is it just me?) When i was on the tap 'label designer' and switch to 'print settings' i get the following picture/label

I thought I had squashed this bug, the regular print tab should not change if the label designer is adjusted (in fact I even added a screenshot proving this in my PR...) could be that I didn't commit that fix from my local workspace or there's a further bug I missed.

when returning to spool and print label again i get the following... seems to be there are two different labels for the same function?!

The intent here is to have the print label function un-affected by the new label designer tab. and therefore 2 separate label printing areas. I felt this was easier to get implemented, as the label designer is quite complex in comparison. However as mentioned above these should be completely separated - if there's cross-talk that's a bug. or if it's not saving - that's a bug. Please try to exercise the preset saving function - perhaps there's a bug or a missing feature that doesn't retain the label designer changes without saving a preset.

Is the label designer variant, which is correct but the filaman logo in the qr is missing.

perhaps that logo element is not getting pulled successfully - To fix this, it should be a asset in the build and not pulled from a webpage. I will try to fix it.

Nevertheless the roll id/number bug from the official release - all numbers with three digits are cutted to the first two digits.

do you see that bug in the label designer? I can't test it right now myself.

akira69 added a commit that referenced this pull request May 17, 2026
- backend: add ruff>=0.4 and mypy>=1.10 to dev optional-dependencies
  with ruff config (E/W/F/I/UP/B rules, py311 target, 120 char line)
  and mypy config (ignore_missing_imports, check_untyped_defs)
- frontend: add eslint, typescript-eslint, eslint-plugin-astro as
  devDependencies; add 'check' (astro check) and 'lint' scripts
  scoped to PR #14 files only ([id]/index.astro, [id]/print.astro,
  src/lib/label-template.ts)
- frontend: create eslint.config.mjs with flat config for TS + Astro
- fix: replace @ts-ignore with @ts-expect-error in [id]/index.astro
  (QRCode UMD global) as required by @typescript-eslint/ban-ts-comment
akira69 added a commit that referenced this pull request May 17, 2026
- backend: add ruff>=0.4 and mypy>=1.10 to dev optional-dependencies
  with ruff config (E/W/F/I/UP/B rules, py311 target, 120 char line)
  and mypy config (ignore_missing_imports, check_untyped_defs)
- frontend: add eslint, typescript-eslint, eslint-plugin-astro as
  devDependencies; add 'check' (astro check) and 'lint' scripts
  scoped to PR #14 files only ([id]/index.astro, [id]/print.astro,
  src/lib/label-template.ts)
- frontend: create eslint.config.mjs with flat config for TS + Astro
- fix: replace @ts-ignore with @ts-expect-error in [id]/index.astro
  (QRCode UMD global) as required by @typescript-eslint/ban-ts-comment
akira69 added a commit that referenced this pull request May 17, 2026
- backend: add ruff>=0.4 and mypy>=1.10 to dev optional-dependencies
  with ruff config (E/W/F/I/UP/B rules, py311 target, 120 char line)
  and mypy config (ignore_missing_imports, check_untyped_defs)
- frontend: add eslint, typescript-eslint, eslint-plugin-astro as
  devDependencies; add 'check' (astro check) and 'lint' scripts
  scoped to PR #14 files only ([id]/index.astro, [id]/print.astro,
  src/lib/label-template.ts)
- frontend: create eslint.config.mjs with flat config for TS + Astro
- fix: replace @ts-ignore with @ts-expect-error in [id]/index.astro
  (QRCode UMD global) as required by @typescript-eslint/ban-ts-comment
@akira69
Copy link
Copy Markdown
Owner Author

akira69 commented May 17, 2026

@Tschipel : I did fix a bunch of bugs - maybe you'd find it resolving all the issues you noted, I hope :D

@Tschipel
Copy link
Copy Markdown

Tschipel commented May 18, 2026

Wonderful - a lot of bugs are fixed - but the behavior for not touched 'print settings' tab is still different
https://github.com/user-attachments/assets/5a7b6ae3-3986-44f8-8ebf-0209ff844c00

@akira69
Copy link
Copy Markdown
Owner Author

akira69 commented May 18, 2026

Wonderful - a lot of bugs are fixed - but the behavior for not touched 'print settings' tab is still different https://github.com/user-attachments/assets/5a7b6ae3-3986-44f8-8ebf-0209ff844c00

ooof, embarrassing - bad testing on my part
let me dig...

@akira69
Copy link
Copy Markdown
Owner Author

akira69 commented May 18, 2026

@Tschipel I need to build this and test myself in detail but I think it's fixed:

Commit cda0350 added labelPreview.innerHTML = '' in activateTab() for both tab directions, which was the right instinct — it cleared the designer's Document Object Model (DOM) before rebuilding the classic layout. But it introduced a new regression: a module-level const qrContainer = document.getElementById('label-qr-container') captured the static HTML element at page-init time. Once innerHTML = '' destroyed that element, ensureClassicPreviewLayout() rebuilt the browser's DOM with a fresh #label-qr-container— but qrContainer still pointed to the detached original. Every QR render in updatePreview silently wrote to a dead node, so the QR code never appeared in Print Settings after any tab activation (including the very first page load).

The fix moves qrContainer from module scope into updatePreview(), declared immediately after ensureClassicPreviewLayout() runs, so it always resolves against the live DOM. Additionally, activePreviewTab guards were added at the entry of both render functions and at each async yield point (isStale() || activePreviewTab !== '...'), so in-flight renders triggered by input listeners are correctly abandoned if the user switches tabs mid-render rather than completing on the wrong DOM.

@akira69 akira69 force-pushed the feat/advanced-label-designer branch from 791f71a to cc1425b Compare May 19, 2026 01:37
@akira69
Copy link
Copy Markdown
Owner Author

akira69 commented May 19, 2026

Two additional fixes landed in cc1425b from an exhaustive cross-contamination audit run after the main fix:

  • @media print transform reset — both updatePreview and updateDesignerPreview now inject transform: none !important; transform-origin: unset !important into their print stylesheets. Without this, previewing at zoom ≠ 100% and then printing would scale the physical label by the zoom factor, producing labels with incorrect dimensions on paper.

  • activateTab print branch cleanup — the print branch now explicitly clears the designer's inline border and padding before the async updatePreview call (matching the symmetrical cleanup already in the designer branch). This eliminates a brief flash of the designer's dashed border during the QR library await on tab switch.

The audit found no other cross-contamination pathways. Zoom state is intentionally shared between tabs as a UI preference. localStorage keys are separate per tab. buildSpoolData() is pure and reads only immutable data. style#page-style is always replaced (not appended) by both render functions.

akira69 added 17 commits May 19, 2026 07:46
Adds a per-spool label designer at /spools/[id]/print with:
- Interactive label preview (print to scale)
- Logo, title, QR code, information, side column sections
- Preset save/load/delete with dirty tracking
- Template parser with token substitution
- 2nd title row and 2nd information column support
- PDF/PNG export
Updates spool detail page to link to /spools/[id]/print with
pre-populated query params and extra fields via sessionStorage
- make title ==...== render full-row inverse consistently
- allow [size=..] tags case-insensitively in template markup
- move QR custom URL field under link mode context and relabel as base URL
- append spool ID automatically for QR custom URL mode
- remove QR URL token chips to avoid template confusion
- add i18n keys for QR custom URL base label/hint
- add {color-swatch[N]} token support (N in ch units, default 8)
- render swatch from filament.color_hex with safe normalization
- support swatch token in optional token blocks
- expose swatch token in designer token chips and syntax help
- make title and subtitle format controls auto-growing wrapped textareas
- move QR custom URL base above position and vertical align controls
- clarify syntax help that size works with field values and swatches
- simplify color swatch helper text
- add @@text@@ markup for filament-color inverse styling
- choose black or white text automatically from color brightness
- support full-row title/subtitle color inverse when template is wrapped in @@...@@
- document the new syntax in template help
…nt preview

The previous fix (cda0350) added labelPreview.innerHTML = '' in activateTab
for both tab directions, which correctly cleared cross-tab DOM pollution but
introduced a new regression: the module-level qrContainer reference captured
the original static HTML element at init time. After innerHTML clear, that
element was detached from the DOM. ensureClassicPreviewLayout() rebuilt the
HTML with a new label-qr-container element, but qrContainer still pointed to
the dead original -- so all QR rendering in updatePreview wrote to a detached
node and QR code never appeared in Print Settings on any render.

Fixes:
- Remove module-level qrContainer capture; declare it as a local variable
  inside updatePreview() after ensureClassicPreviewLayout() runs, so it
  always references the current DOM element
- Add activePreviewTab guard at the start of updatePre- Add activePreviewTab guard at the start of updatePre- Add activePreviewTab guard at the start of updatePre- Add activePreviewTab guard at the start oasync
  renders that yield across a tab switch are correctly abandoned rather than
  completing   completing   completing   completing   completing   completing   completis:  completing   completing   completing   completing   completing   completi:
  completing   completing   completing   completing   completing   completa  completing   completing   completing   completing   completing   completer  completing   completing   completing   completing   completing   completasigner tab
- npm run lint: 0 errors; npm run check: passed; npm run build: passed
…cleanup

Two follow-up fixes from exhaustive cross-contamination audit:

- Add `transform: none` and `transform-origin: unset` to the @media print
  rules in both updatePreview and updateDesignerPreview. Without this,
  printing with preview zoom != 100% would scale the printed label by the
  zoom factor, producing incorrect label dimensions on physical paper.

- In activateTab()'s print branch, explicitly clear the designer's inline
  border and padding before the async updatePreview call, matching the
  symmetrical cleanup already present in the designer branch. Eliminates
  the brief flash of the designer's dashed border during the QR library
  await on tab switch.

Audit result: no other cross-contamination pathways found between tabs.
Zoom state is intentionally shared (UI preference). localStorage keys are
separate. buildSpoolData() is pure. style#page-style is always replaced.

Also fixed in this patch set (companion commit 3db8eb5):
- Move qrContainer capture inside updatePreview() after
  ensureClassicPreviewLayout() so it always references the live DOM node
  rather than the detached original after innerHTML clear
- Add activePreviewTab guards to both updatePreview() and
  updateDesignerPreview() so async renders that straddle a tab switch are
  correctly abandoned instead of writing into the wrong tab's DOM
- Strengthen isStale() checks to also bail when the render's target tab is
  no longer active
- Replace @ts-ignore with @ts-expect-error; fix let -> const lint warnings
@akira69 akira69 force-pushed the feat/advanced-label-designer branch from cc1425b to 75e5533 Compare May 19, 2026 12:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants