Wonders of Work Review hub

Open changes waiting for a look, and what shipped recently. Anyone can open a preview below and leave feedback on GitLab.

Open for review

MR !99 by Iftakhar Hasnayen Abir ·

Fix

markdown support for footer menu items text

What this changes, and why

Add markdown support in the footer text item

What this affects

src/components/Footer.astro

How to try it

update any footer item text with markdown text

Updates · newest first

  • preview ↗ fix: markdown support for footer menu items text by ih-abir ·

MR !97 by Iftakhar Hasnayen Abir ·

Other

Fix/event content editing

What this changes, and why

creat/edit event markdown editor line break and event type detector fixed

What this affects
  • public/scripts/render-markdown.js & src/components/MarkdownEditor2.astro markdown editor rendering
  • src/pages/[...locale]/create-event.astro event type detector
  • src/pages/[...locale]/event-preview.astro preview menus after title
How to try it

1. create or edit an event description or event type 2. after update and redirect to preview page check the menus right after the title

Updates · newest first

  • preview ↗ fix: markdown editor css style by ih-abir ·
  • preview ↗ Merge remote-tracking branch 'origin/fix/event-content-editing' into fix/event-content-editing by ih-abir ·
  • preview ↗ fix: show preview menu after redirect from edit page by ih-abir ·
  • no preview fix: remove redundant log by ih-abir ·
  • no preview fix: event type detector by ih-abir ·

MR !98 by Iftakhar Hasnayen Abir ·

Other

Fix/status bar layout

What this changes, and why

Statusbar UI flexible for both desktop and mobile, text show without turncate, navbar overflow fixed, reduce motion, dynamic color detector error and fallback. disable notifiaction aria label is now from strapi

What this affects

src/utils/getGlobals.ts, src/layouts/Layout.astro, src/components/StatusBar.astro, src/components/NavBar.astro

How to try it

take a new window and load the page, check with both mobile and desktop version

Updates · newest first

  • preview ↗ fix: reduce motion, dynamic color fallback, center both text & cross by ih-abir ·
  • preview ↗ fix: status bar position by ih-abir ·
  • no preview fix: status bar enable button, aria label getting from strapi by ih-abir ·

Recently shipped to production (main) wondersofwork.nl 🎉

  • MR !100 by Jurjen de Vries ·
    Fix
    Cloudflare Pages cache headers (assets/images/scripts)
    What this changes, and why

    Adds public/_headers so Cloudflare Pages sends an explicit Cache-Control per asset class. Goal: returning visitors stay fast and pick up new deploys quickly, without ever needing a manual Cloudflare cache purge.

    Context: the root cause of the recurring "site messed up until purge-everything" was Cloudflare APO (a WordPress-era leftover) edge-caching HTML on an Astro/Pages origin — that has been disabled in the Cloudflare dashboard. This MR is the browser-side hardening so stale caching cannot bite returning visitors either.

    Per class:

    • /assets/* — content-hashed by Astro (CSS, JS, fonts under /assets/fonts/) → max-age=31536000, immutable. Filename changes on content change, so no revalidation is ever needed.
    • /images/* — clean stable filenames; by editor convention a replaced photo gets a NEW filename → max-age=31536000 without immutable, so a hard reload can still revalidate and recover if a filename is ever reused.
    • /scripts/* — hand-written modules keep the same filename (external references depend on it) but their content changes on deploy → max-age=60, stale-while-revalidate=86400: served instantly from cache, refreshed in the background, at most one navigation behind after a deploy.

    Freshness relies on the ETags Pages already sends, so a revalidation is a cheap bodyless 304. HTML is intentionally untouched (already max-age=0, must-revalidate, served fresh from origin).

    What this affects

    Only HTTP response headers for static assets served by Cloudflare Pages. No application code, no build logic, no filenames change. Nothing security-sensitive (no profile / key export / OpenBunker paths touched). _headers has no effect in local dev — it only applies on Pages (preview + production).

    How to try it

    On the preview deploy link, check the three classes:

    `` curl -sSI <preview-url>/assets/<any-hashed>.css | grep -i cache-control # max-age=31536000, immutable curl -sSI <preview-url>/images/og-default.jpg | grep -i cache-control # max-age=31536000 (no immutable) curl -sSI <preview-url>/scripts/global.js | grep -i cache-control # max-age=60, stale-while-revalidate=86400 ``

    Expect each header to match the class above. Also confirm the site still loads and Nostr scripts run (the /scripts/* change is the only one that alters behaviour for returning visitors).

  • Feature
    add status bar
    What this changes, and why

    Status bar added

    What this affects

    dynamic component src/components/StatusBar.astro added, gets active, color and text update via strapi

    How to try it

    take a new new window and visit site

  • Fix
    wrong url after deleting event from /nl page
    What this changes, and why

    preview-menu.js hardcoded "calendar" as the post-delete redirect, so Dutch users always landed on /nl/calendar/ (404) instead of /nl/agenda/. Now uses window.eventCollectionPrefix which is baked in at build time per locale.

    What this affects
    • public/scripts/preview-menu.js — delete redirect for both events and stories
    • src/pages/[...locale]/event-preview.astro — inline onclick replaced with a wired handler; eventCollectionPrefix exposed via define:vars
    How to try it

    Sign in as the event owner on the NL preview link

    Open an event, click the kebab menu → Delete → confirm

    Should redirect to /nl/agenda/ — not /nl/calendar/

    Repeat on the EN preview link and confirm it still lands on /en/calendar/

  • Other
    Fix/openbunker login blank page
    What this changes, and why

    Fixes a white-page blocker for new OpenBunker users: the post-login redirect pointed at the removed /profile route. Also fixes the export-key page sending signed-out users to the same dead route, adds an OpenBunker welcome prompt on the edit-profile page, improves the offline-at-load relay error message, and disables the Send Code button while the OTP request is in flight to prevent double-submits.

    What this affects
    • public/scripts/login/check-user-metadata.js — redirect target for new OpenBunker users
    • src/pages/[...locale]/edit-profile.astro — reads source=openbunker-new and shows the completion prompt
    • src/pages/[...locale]/export-key.astro — dead /profile fallback replaced with /login
    • src/pages/[...locale]/login.astro — Send Code button disabled state + back-button reset
    • public/scripts/login/login-page.js — button loading state logic; offline relay error message says "Reload the page"
    How to try it

    Create a new OpenBunker account with no name set → should land on /edit-profile?source=openbunker-new with the "Please complete your profile details" prompt visible

    On the login page, enter an email and click Send Code → button should gray out immediately; click Back → button should be clickable again

    While on the export-key page, sign out → should redirect to /login, not a blank page

  • Fix
    navbar edit button redirect to correct page with functionality
    What this changes, and why

    Nav edit button dispatched a profileEditMode custom event the page never listened to — fixed to dispatch popstate instead. Edit href now includes key=npub built from userInfo at click time. Entering from another page appends returnUrl and redirects back on save/cancel. returnUrl was followed raw without origin check — added safeReturnUrl() matching the guard from the old profile.astro.

    What this affects
    • NavBar.astro — key=npub in edit href, popstate dispatch, returnUrl on cross-page nav
    • profile-preview.astro — leaveEditMode redirects to returnUrl when present
    • edit-profile.astro — safeReturnUrl() validates same-origin before navigating, falls back to /profile-preview
    How to try it

    Click edit profile from navbar on any page — profile-preview opens in edit mode, save/cancel returns to the originating page. Craft a link to /edit-profile?returnUrl=.... — save or cancel stays on-site instead of redirecting away.

  • Other
    Keep newest across relays
    What this changes, and why

    __fetchNewest helper__: Single shared helper replaces duplicated "keep newest across relays" logic in story/event-preview and adds it to profile-preview, which was missing it — causing stale profile data for returning visitors.

    __NIP-09 e-tag deletions fix__: deletion-cache.js only tracked a-tag (coordinate) deletions and completely ignored e-tag (event id) deletions. A kind:5 deletion referencing an event by ["e", "<id>"] was invisible, so deleted events kept showing. prefetchDeletionsForEvent also used a #a filter that excluded e-tag deletions from relay queries. Fixed by:

    • recordDeletion: now processes both a-tag and e-tag deletion references, with a comment that author-trust relies on callers using an authors filter
    • isEventDeleted: checks event.id against deleted IDs alongside the existing a-coordinate check
    • prefetchDeletionsForEvent: dropped the #a filter to retrieve all kind:5 from the author
    • removeDeletedCard: now looks up the bare d-tag from the matched event's own tags instead of using the coordinate key (kind:pubkey:dtag) as a DOM selector
    • — fixing the race where a card rendered before its deletion arrived was never removed

    • Dead code removed: kind:5 was bundled into fetchStories/fetchCalendarEvents REQs, but relays apply the #t filter to all kinds in a REQ and real deletions carry no #t tag, so those subs returned zero deletions. The overview already gets its deletions from prefetchDeletions(authors). The bundling is removed; each fetch is back to a single clean filter.
    What this affects
    • nostr-fetch.js — new fetchNewest export; kind:5 bundled into fetchStories / fetchCalendarEvents
    • deletion-cache.js — e-tag support, proactive card removal with correct d-tag lookup, author-check comment, #a filter removed from prefetchDeletionsForEvent
    • event-handlers.jshandleStory and handleCalendarEvent route kind:5 → recordDeletion
    • story-preview, event-preview, profile-preview — all use fetchNewest; profile now bypasses fetchProfiles cache short-circuit
    How to try it
    • __Profile freshness__: Update a profile from another client, reload the detail page — fresh data appears without waiting for cache expiry.
    • __Deleted events__: Publish an event/story, delete it via a kind:5 with an e-tag, reload the overview or detail page — the event is hidden.
  • Other
    Fix/relay connection delay
    What this changes, and why

    Detail pages were first-relay-wins: story-preview resolved on the first event received, event-preview gated re-renders with a one-shot found flag. A stale relay answering first meant the old version was shown even when a newer one arrived moments later. nostr-fetch was also writing cache entries under pubkey:kind:dtag while every reader uses generateUId (kind:pubkey:dtag) — dead writes under a key nobody looks up.

    Previously: late-connecting relays received a raw ws.send() without attachMux, so their EVENT/EOSE frames were silently dropped. handleCalendarEvent also had no created_at guard, so a stale relay answering last could overwrite a newer cached version.

    What this affects

    Detail pages were first-relay-wins: story-preview resolved on the first event received, event-preview gated re-renders with a one-shot found flag. A stale relay answering first meant the old version was shown even when a newer one arrived moments later. nostr-fetch was also writing cache entries under pubkey:kind:dtag while every reader uses generateUId (kind:pubkey:dtag) — dead writes under a key nobody looks up.

    Previously: late-connecting relays received a raw ws.send() without attachMux, so their EVENT/EOSE frames were silently dropped. handleCalendarEvent also had no created_at guard, so a stale relay answering last could overwrite a newer cached version.

    How to try it

    Load any page that fetches Nostr content. Edit a story or calendar event from a Nostr client, reload the detail page while one relay is slow — the updated version should always win. For the cache key fix: confirm stories and events still load correctly on overview pages after navigation.

  • MR !90 by Jurjen de Vries ·
    Other
    Revert MR 88: relay fetch change breaks calendar overview (only 1 event shows)
    What this changes

    Reverts MR 88 (fix/relay-connection-delay, merge commit 2e123fb) in full. That change introduced a regression: the calendar overview now shows only a single event instead of the full list. Reverting restores the previous, working version so it goes live again while the relay-update fix is reworked.

    How to try it

    Open any page with the calendar events overview after this merges and deploys. All events should render again, not just one.

    What this affects

    Nostr fetch/queue layer and the story/event detail pages: public/scripts/nostr-queue.js, public/scripts/nostr-fetch.js, public/scripts/event-handlers.js, public/scripts/send-message.js, src/pages/[...locale]/story-preview.astro, src/pages/[...locale]/event-preview.astro, plus the prettier bump and formatting changes bundled in MR 88. No content or auth changes.

    Note: this reverts a merge commit, so fix/relay-connection-delay will count as already-merged. The relay-update fix must be reworked on a fresh branch (or by reverting this revert) before it can land again.

  • Fix
    relay connection delay & fetch queue based on relays gets connected
    What this changes, and why

    Detail pages were first-relay-wins: story-preview resolved on the first event received, event-preview gated re-renders with a one-shot found flag. A stale relay answering first meant the old version was shown even when a newer one arrived moments later. nostr-fetch was also writing cache entries under pubkey:kind:dtag while every reader uses generateUId (kind:pubkey:dtag) — dead writes under a key nobody looks up.

    Previously: late-connecting relays received a raw ws.send() without attachMux, so their EVENT/EOSE frames were silently dropped. handleCalendarEvent also had no created_at guard, so a stale relay answering last could overwrite a newer cached version.

    What this affects

    Detail pages were first-relay-wins: story-preview resolved on the first event received, event-preview gated re-renders with a one-shot found flag. A stale relay answering first meant the old version was shown even when a newer one arrived moments later. nostr-fetch was also writing cache entries under pubkey:kind:dtag while every reader uses generateUId (kind:pubkey:dtag) — dead writes under a key nobody looks up.

    Previously: late-connecting relays received a raw ws.send() without attachMux, so their EVENT/EOSE frames were silently dropped. handleCalendarEvent also had no created_at guard, so a stale relay answering last could overwrite a newer cached version.

    How to try it

    Load any page that fetches Nostr content. Edit a story or calendar event from a Nostr client, reload the detail page while one relay is slow — the updated version should always win. For the cache key fix: confirm stories and events still load correctly on overview pages after navigation.

  • Fix
    center hero text content on multiple images
    What this changes, and why

    Center hero text content when pages have multiple images

    What this affects

    src/components/blocks/Hero.astro and src/utils/getHeroAlign.ts

    How to try it

    go to /nl/zomer-focusdagen-ondernemers/

See all merged changes on GitLab →