Commit Graph

245 Commits

Author SHA1 Message Date
b3c3f34e50 refactor: extract PipImage component from inline PiP markup
Deduplicates mobile PiP image code shared between the rosary page and
StickyImage. Adds fullscreen support to StickyImage and fixes hidden PiP
elements capturing pointer events via pointer-events: none default.
2026-02-10 21:16:05 +01:00
a5e119f976 rosary: add show/hide images toggle, fix PiP timing and breakpoint
- Add "Bilder anzeigen" / "Show Images" toggle persisted to localStorage
- Bump mystery image column/PiP breakpoint from 900px to 1200px so
  prayers keep full width on medium screens
- Fix PiP not appearing on page load by splitting $effect and using
  tick() to wait for DOM before measuring element dimensions
- Fix Toggle checkbox default margin causing misalignment
2026-02-09 09:12:34 +01:00
a4738134fe extract PiP drag/snap/enlarge logic into shared createPip() utility
All checks were successful
CI / update (push) Successful in 1m32s
Both StickyImage and rosary page now use the same pip.svelte.ts factory
for mobile drag-to-corner, snap, and double-tap enlarge behavior.
2026-02-09 08:48:20 +01:00
6433576b28 rosary: add mystery images with scrollable sticky column and mobile PiP
Add a third grid column for sorrowful mystery images (mocking for
mysteries 2-3, crucifixion for mystery 5). Desktop uses a scrollable
sticky sidebar synced to prayer scroll position. Mobile shows a
floating PiP thumbnail. Extract prayer page PiP logic into reusable
StickyImage component.
2026-02-09 08:47:53 +01:00
ea6d2cab5c ablassgebete: add prayer page with sticky crucifix and draggable PiP
All checks were successful
CI / update (push) Successful in 1m31s
- Add AblassGebete component and crucifix images
- Desktop: sticky crucifix on right, centered prayer with balanced spacing
- Mobile: draggable picture-in-picture thumbnail that snaps to corners
- Double-tap to enlarge/shrink with directional animation
- Monolingual sections override bilingual grey styling
- 404 for English route /faith/prayers/ablassgebete (German only)
- Reposition on window resize including desktop/mobile breakpoint crossing
2026-02-08 22:13:23 +01:00
83de5fed34 cospend: filter recent activity by chart category selection
All checks were successful
CI / update (push) Successful in 1m27s
Clicking a category on the bar chart now filters the recent activity
list to show only payments in that category. Includes a clear filter
button and empty state message. Also increases recent splits from 10
to 30 for better coverage when filtering.
2026-02-04 16:57:49 +01:00
8776ab894b fix: remove Svelte 4 object reassignment causing $effect infinite loop
The splitAmounts = { ...splitAmounts } pattern created a circular
dependency inside $effect blocks—reading and writing the same reactive
value—which Svelte 5 killed via loop protection, leaving the split
method selector non-reactive when selecting "50/50 + personal".
2026-02-04 16:52:12 +01:00
7d6a80442a faith: progressive enhancement for all faith pages without JS
All checks were successful
CI / update (push) Successful in 1m29s
- Rosary: mystery selection, luminous toggle, and latin toggle fall back
  to URL params (?mystery=, ?luminous=, ?latin=) for no-JS navigation
- Prayers/Angelus: latin toggle uses URL param fallback
- Search on prayers page hidden without JS (requires DOM queries)
- Toggle component supports href prop for link-based no-JS self-submit
- LanguageSelector uses <a> links with computed paths and :focus-within
  dropdown for no-JS; displays correct language via server-provided prop
- Recipe language links use translated slugs from $page.data
- URL params cleaned via replaceState after hydration to avoid clutter
2026-02-04 14:14:13 +01:00
b28154564f perf: pre-generate Bible verse data and reduce DOM via conditional rendering
All checks were successful
CI / update (push) Successful in 1m34s
- Extract Bible lookup logic into shared src/lib/server/bible.ts module
- Add build script to pre-generate all 20 mystery verse lookups as static data,
  eliminating runtime API calls on rosary page load
- Update Prayer.svelte to pass showLatin/urlLang as snippet parameters; all 14
  prayer components now conditionally render only visible language elements
  instead of hiding via CSS
- Extract 4 inline mystery selector SVGs into MysteryIcon.svelte component
- Remove unused CSS selectors from angelus page
2026-02-03 14:28:09 +01:00
3ff3d0dc8a fix: remove default figure margin shifting parallax hero image
All checks were successful
CI / update (push) Successful in 1m30s
2026-02-03 08:27:43 +01:00
c0eb49158c fix: apply border-radius directly on card images for older WebKit
All checks were successful
CI / update (push) Successful in 1m24s
2026-02-03 08:21:55 +01:00
43378bfec0 fix: center parallax hero image cross-browser
Replace Firefox-specific @supports hack with explicit absolute
centering (left/right/margin-inline: auto) on the image container.
2026-02-03 08:18:36 +01:00
649bd19287 streak: replace burst flame with rising particle effect
All checks were successful
CI / update (push) Successful in 1m23s
Rework the burst mode in FireEffect to use 24 data-driven particles
instead of the old scale-and-pop flame. Each particle has unique
position, size, delay, and duration for an organic rising effect.
Latch burst state in StreakAura so the animation plays its full
duration regardless of when the parent resets the prop.
2026-02-03 08:01:00 +01:00
660a1b0539 prayers: add search and individual prayer pages
All checks were successful
CI / update (push) Successful in 1m22s
- Add SearchInput component for reusable search UI
- Add search functionality to prayers list with two-tier results:
  - Primary matches (name/searchTerms) shown first
  - Secondary matches (text content) shown after with reduced opacity
- Add individual prayer pages with language-appropriate slugs
  (e.g., /glaube/gebete/ave-maria, /faith/prayers/hail-mary)
- Make prayer cards clickable to navigate to individual pages
- Fix language visibility for prayers without Latin (BruderKlaus, Joseph)
- Add Prayer wrapper to MichaelGebet for consistent styling
- Use CSS columns for masonry layout with dynamic reordering
2026-02-02 22:22:56 +01:00
95d3be8b82 prayers: bow-emphasis only for main language 2026-02-02 20:39:11 +01:00
69293c39f9 prayers: add English translations for all prayer components
Add official Catholic English translations to all prayer components
for /faith/* routes. Prayer names on /faith/prayers are now displayed
in English. Remove unused Angelus.svelte component.
2026-02-02 16:39:40 +01:00
1a5117e8d0 faith: add bilingual routes /glaube ↔ /faith
Add language toggle support for faith pages similar to recipes.
Routes now work in both German and English:
- /glaube ↔ /faith
- /glaube/gebete ↔ /faith/prayers
- /glaube/rosenkranz ↔ /faith/rosary
- /glaube/angelus ↔ /faith/angelus
2026-02-02 16:15:51 +01:00
87d5e9cbc0 rosary: clean up unused CSS, fix unclosed tag
All checks were successful
CI / update (push) Successful in 1m24s
- FireEffect now only contains fire-related styles
- StreakAura now only contains aura, number, halo, wing styles
- Fix unclosed <i> tags in JosephGebet.svelte
2026-02-01 14:12:18 +01:00
924ce386d5 rosary: server-side streak fetch, remove aggressive polling
All checks were successful
CI / update (push) Successful in 1m29s
- Fetch streak data in +page.server.ts for logged-in users via API
- Initialize store once with server data, sync only runs once
- Only poll for reconnection in PWA mode when offline with pending changes
- Extract FireEffect to separate component with burst animation
- Convert StreakAura/StreakCounter to Svelte 5 runes ($props, $state, $derived)
- Fix SSR flash by using server data for initial render
2026-02-01 13:50:33 +01:00
ee2bee6ac5 rosary: light/dark mode benedicturs medal 2026-01-31 16:09:21 +01:00
d3f0d8a24c glaube: add ⚬ to mary and jesus in prayers
All checks were successful
CI / update (push) Successful in 1m21s
2026-01-31 15:15:49 +01:00
6028373093 glaube: gone woke
All checks were successful
CI / update (push) Successful in 1m27s
2026-01-31 14:59:07 +01:00
1cce6a56ac rosary: glow animation earlier, embers before full fire
All checks were successful
CI / update (push) Successful in 1m22s
2026-01-31 12:20:35 +01:00
71dd5b6285 rosary: stylized StreakCounter dependant on length
All checks were successful
CI / update (push) Successful in 1m31s
2026-01-31 10:56:29 +01:00
17b0fb9275 remove jukit garbage 2026-01-31 10:12:45 +01:00
92963f4451 rosary: StreakCounter singular Tag for length==1 2026-01-30 15:41:20 +01:00
a58e52c891 feat: add server persistence for rosary streak
All checks were successful
CI / update (push) Successful in 1m21s
- Add RosaryStreak MongoDB model for logged-in users
- Add /api/glaube/rosary-streak GET/POST endpoints
- Sync streak to server when logged in, merge local/server data
- Auto-sync when coming back online (PWA offline support)
- Falls back to localStorage for guests
2026-01-30 12:37:01 +01:00
06477d656a feat: add streak counter to rosary page
Track daily rosary prayer streaks using localStorage. Shows consecutive
days prayed and disables button if already prayed today.
2026-01-30 12:36:55 +01:00
bff86041fd prayers: add Confiteor
All checks were successful
CI / update (push) Successful in 1m24s
2026-01-30 08:40:29 +01:00
d9e9ae049e feat: add sync progress tracking with image download status
- Service worker reports image caching progress back to main thread
- Sync progress shows current phase (recipes, pages, data, images)
- Display progress bar for image downloads in sync tooltip
- Use mediapath for thumbnail URLs (with hash for cache busting)
- Serve cached thumbnails as fallback for full/placeholder when offline
2026-01-29 10:18:02 +01:00
86f28fa1b7 feat: auto-sync recipes and show sync button only in PWA mode
- Auto-sync recipes every 30 minutes when online in PWA mode
- Only show offline sync button when running as installed PWA
- Detect standalone mode via display-mode media query and iOS check
- Trigger initial sync on PWA install (appinstalled event)
- Listen for online event to sync when coming back online
- Store last sync time in localStorage to track sync intervals
2026-01-29 09:58:03 +01:00
9ff30b28cd feat: add PWA offline support for recipe pages
- Add service worker with caching for build assets, static files, images, and pages
- Add IndexedDB storage for recipes (brief and full data)
- Add offline-db API endpoint for bulk recipe download
- Add offline sync button component in header
- Add offline-shell page for direct navigation fallback
- Pre-cache __data.json for client-side navigation
- Add +page.ts universal load functions with IndexedDB fallback
- Add PWA manifest and icons for installability
- Update recipe page to handle missing data gracefully
2026-01-28 21:38:33 +01:00
baee021869 fix latin Fatima to P. Ramm's Ordo Missæ
All checks were successful
CI / update (push) Successful in 1m22s
2026-01-26 21:40:25 +01:00
31c9f43114 refactor: replace shadow span with box-shadow on button_wrapper
All checks were successful
CI / update (push) Successful in 1m21s
Remove separate .button_wrapper_shadow element and apply box-shadow
directly to .button_wrapper in mobile view. Reduces DOM by 1 node.
2026-01-25 20:50:43 +01:00
3cc962f454 refactor: reduce DOM nesting and simplify templates
- Remove nested .wrapper div in recipe page using CSS Grid with full-bleed background
- Consolidate multiplier forms in IngredientsPage into single form
- Simplify fermentation conditionals in InstructionsPage with optional chaining
- Use conditional rendering instead of visibility wrapper in Search
- Remove unnecessary dialog wrapper in TitleImgParallax
2026-01-25 20:24:48 +01:00
5824993b18 refactor: simplify Card HTML and extract search filter composable
All checks were successful
CI / update (push) Successful in 1m23s
- Remove unnecessary wrapper divs in Card component (.card_anchor, .div_div_image)
- Flatten Card HTML from 4 levels to 2 levels of nesting
- Create reusable createSearchFilter composable in $lib/js/searchFilter.svelte.ts
- Apply search filter composable to category, tag, and favorites pages
2026-01-25 14:48:55 +01:00
940f9f14a2 fix tag styling on Cards
All checks were successful
CI / update (push) Successful in 1m19s
2026-01-23 16:14:34 +01:00
63e9b3de21 Move more CSS styling to a global css files to reduce bundle size
All checks were successful
CI / update (push) Successful in 2m53s
2026-01-23 15:37:32 +01:00
f3b92e8b1a refactor: clean up recipe routes and reduce bundle size
- Eliminate duplicate API fetch in recipe page by passing item from
  server load to universal load instead of fetching twice
- Replace cheerio with simple regex in stripHtmlTags, removing ~200KB
  dependency
- Refactor multiplier buttons in IngredientsPage to use loop instead
  of 5 repeated form elements
- Move /rezepte/untranslated to /[recipeLang]/admin/untranslated and
  delete legacy /rezepte/ layout files
2026-01-23 15:04:58 +01:00
2b3aae8087 fix: append image to FormData before submission in use:enhance
The image upload broke because formData.append() was being called in the
async callback of use:enhance, which runs AFTER the form submission.
Moved the append call to the outer function which runs BEFORE submission.

Also cleaned up debug console.log statements from CardAdd.svelte.
2026-01-20 19:37:16 +01:00
0459ef26bc fix: use simple event handler for file selection instead of $effect
All checks were successful
CI / update (push) Successful in 1m21s
Replace $effect + bind:files approach with straightforward onchange handler:
- Use event.currentTarget.files[0] to get selected file
- Avoid reactive complexity that caused infinite loops
- Add bind:this reference to file input for clearing
- Clean implementation that works reliably in Svelte 5
2026-01-20 17:29:41 +01:00
3fb0a72014 fix: rewrite CardAdd image upload using Svelte 5 best practices
All checks were successful
CI / update (push) Successful in 1m20s
Replace event handler approach with bind:files and $effect:
- Use bind:files on file input for reactive FileList binding
- Use $effect to react to file selection and handle validation
- Properly clean up blob URLs to prevent memory leaks
- Remove exported functions that aren't used externally
- Add key to each block for tags
- Fix self-assignment warning in tag handling

The previous implementation used onchange with this.files which doesn't
work in Svelte 5. The new approach uses the idiomatic bind:files pattern.
2026-01-20 17:18:25 +01:00
b5fbedd13b fix: use event parameter in CardAdd image selection handler
All checks were successful
CI / update (push) Successful in 1m21s
The show_local_image function was using `this.files[0]` which doesn't work
in Svelte 5's onchange handlers. Changed to use `event.target.files[0]`
to properly access the selected file.

This fixes recipe image uploads not working because the file was never
being captured from the input element.
2026-01-20 17:09:28 +01:00
1bf4f4cbcd debug: add client-side logging for recipe image upload
All checks were successful
CI / update (push) Successful in 1m22s
Add console logging in the browser to track image selection and form
submission:
- Log when user selects an image file in CardAdd component
- Log file validation steps (MIME type, size)
- Log form submission and FormData preparation
- Log whether image is being appended to form

This helps diagnose if the issue is client-side (image not selected/sent)
or server-side (image not received/processed).
2026-01-20 17:04:33 +01:00
a48ae3ff3c refactor: defer recipe image upload until form submission
Changed recipe image upload behavior to only process images when the
form is submitted, rather than immediately on file selection. This
prevents orphaned image files when users abandon the form.

Changes:
- CardAdd.svelte: Preview only, store File object instead of uploading
- Created imageProcessing.ts: Shared utility for image processing
- Add/edit page clients: Use selected_image_file instead of filename
- Add/edit page servers: Process and save images during form submission
- Images are validated, hashed, and saved in multiple formats on submit

Benefits:
- No orphaned files from abandoned forms
- Faster initial file selection experience
- Server-side image processing ensures security validation
- Cleaner architecture with shared processing logic
2026-01-15 14:18:52 +01:00
5fae01c06d feat: use checksummed filenames for recipe images and clean up old files
All checks were successful
CI / update (push) Successful in 1m13s
Updated recipe image handling to use checksummed filenames for proper
cache busting. When uploading a new image during recipe edit, old image
files (both hashed and unhashed versions) are now properly deleted from
all directories (full, thumb, placeholder).

Changes:
- CardAdd.svelte: Use checksummed filename from upload response
- Edit page server: Add deleteRecipeImage() helper to remove old images
- Edit page server: Delete old images when new image is uploaded
2026-01-15 13:57:06 +01:00
041d415525 fix: allow arbitrary decimal values for base multiplier 2026-01-13 19:30:35 +01:00
296201eee5 fix: improve UI elements in recipe editor
All checks were successful
CI / update (push) Successful in 1m14s
- Center isBaseRecipe toggle by changing display to inline-flex
- Fix note field editing by adding textarea with bindable value
- Clear instruction step input after submission instead of restoring placeholder
- Style note textarea with transparent background and lighter placeholder text

The instruction field now properly clears on submission, while ingredient fields retain their previous values.
2026-01-13 19:14:26 +01:00
b43b45dac2 feat: add base multiplier support for recipe references
Add optional baseMultiplier field to ingredient and instruction references, allowing base recipes to be included at scaled amounts (e.g., 0.5 for half the recipe).

- Add baseMultiplier field to Recipe schema with default value of 1
- Update TypeScript types to include baseMultiplier
- Add multiplier input field to BaseRecipeSelector modal
- Apply baseMultiplier to ingredient amounts during flattening
- Combine baseMultiplier with recipe multiplier in links
- Display and allow editing baseMultiplier in recipe editor

The multiplier cascades through nested references and works alongside the standard recipe multiplier for compound scaling.
2026-01-13 19:14:10 +01:00
0a49e20c02 refactor: migrate recipe forms to SvelteKit actions with secure image upload
Refactor recipe add/edit routes from client-side fetch to proper SvelteKit
form actions with progressive enhancement and comprehensive security improvements.

**Security Enhancements:**
- Implement 5-layer image validation (file size, MIME type, extension, magic bytes, Sharp structure)
- Replace insecure base64 JSON encoding with FormData for file uploads
- Add file-type@19 dependency for magic bytes validation
- Validate actual file type via magic bytes to prevent file type spoofing

**Progressive Enhancement:**
- Forms now work without JavaScript using native browser submission
- Add use:enhance for improved client-side UX when JS is available
- Serialize complex nested data (ingredients/instructions) via JSON in hidden fields
- Translation workflow integrated via programmatic form submission

**Bug Fixes:**
- Add type="button" to all interactive buttons in CreateIngredientList and CreateStepList
  to prevent premature form submission when clicking on ingredients/steps
- Fix SSR errors by using season_local state instead of get_season() DOM query
- Fix redirect handling in form actions (redirects were being caught as errors)
- Fix TranslationApproval to handle recipes without images using null-safe checks
- Add reactive effect to sync editableEnglish.images with germanData.images length
- Detect and hide 150x150 placeholder images in CardAdd component

**Features:**
- Make image uploads optional for recipe creation (use placeholder based on short_name)
- Handle three image scenarios in edit: keep existing, upload new, rename on short_name change
- Automatic image file renaming across full/thumb/placeholder directories when short_name changes
- Change detection for partial translation updates in edit mode

**Technical Changes:**
- Create imageValidation.ts utility with comprehensive file validation
- Create recipeFormHelpers.ts for data extraction, validation, and serialization
- Refactor /api/rezepte/img/add endpoint to use FormData instead of base64
- Update CardAdd component to upload via FormData immediately with proper error handling
- Use Image API for placeholder detection (avoids CORS issues with fetch)
2026-01-13 15:12:07 +01:00