Commit Graph
11 Commits
Author SHA1 Message Date
Bendik Aagaard Lynghaug f0a571916d Quicksand: font-display optional, not swap, to stop the text-jump on scroll
Deploy / deploy (push) Successful in 34s
Confirmed via user testing that the jump was in DOM text below the
hero (headings using Quicksand), not the YES canvas (which draws in
plain Arial, unaffected). swap always paints the fallback font first
then reflows once Quicksand loads - a real layout shift if that swap
lands after the user has already scrolled past that heading, which
is exactly what was happening. optional skips the swap entirely
unless the font is already cached/ready almost immediately.
2026-08-06 16:48:11 +02:00
Bendik Aagaard Lynghaug adaaf7f3e3 Add plain-unit fallbacks for svmin/svh in case of unsupported engines
Deploy / deploy (push) Successful in 33s
Couldn't reproduce the reported "hero-yes doesn't show" in a live
WebKitGTK check (svmin/svh both resolved correctly there), but an
engine that doesn't support these newer viewport units would treat
the whole declaration as invalid and drop it - for .hero-yes's height
that means falling through to auto, which collapses the section to
its in-flow content height and clips the canvas via overflow:hidden.
Declaring a plain px/vh value first means an unsupported engine keeps
that instead of falling through further.
2026-08-06 15:37:49 +02:00
Bendik Aagaard Lynghaug a6dfa30f71 Responsive base font size via svmin, not fixed 17px
Deploy / deploy (push) Successful in 34s
Scales with viewport instead of capping at a fixed px value.
svmin (small-viewport min) rather than plain vmin - plain viewport
units recalculate as mobile Safari's address bar hides/shows on
scroll, which would reflow every text size mid-scroll; svmin stays
pinned to the smallest viewport state, matching the stability
.hero-yes already gets from 100svh.
2026-08-06 15:28:32 +02:00
Bendik Aagaard LynghaugandClaude Sonnet 5 bdab23d0f6 Use the real institutional logo for the header wordmark, not plain text
Deploy / deploy (push) Successful in 35s
The header link was just styled "UHHM" text, unrelated to the actual
brand mark - swapped in the institutional logo (the three-arch
"building" mark, matching infrastructure/assets/brand/institutional-*.svg
and Gitea's own homepage logo) instead. Dark-stroke variant only -
portal is a single permanent dark theme, no light mode to switch for.
Same explicit-route treatment the favicon files needed (the /*any
wildcard route would otherwise swallow the request before the static
file handler gets a chance).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-06 13:59:03 +02:00
Bendik Aagaard LynghaugandClaude Sonnet 5 400316f622 Inline encouragements with the submit button, vertically centered
Deploy / deploy (push) Successful in 33s
Was stacked vertically; now a row (encouragements left, button right,
center-aligned), falling back to the stacked layout under 640px where
a row would get cramped.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-06 13:03:43 +02:00
Bendik Aagaard LynghaugandClaude Sonnet 5 a200161334 Fix bucket-404 on empty resources, redesign review actions as select-then-confirm, CSS polish
Deploy / deploy (push) Successful in 35s
get_resource's Kv path treated a not-yet-created bucket (nothing
submitted there yet) as a hard error instead of an empty list -
projects bucket never got created since the backfill found nothing to
migrate, so /review's Projects alternative 404'd outright. Now matches
store_answer's own "doesn't exist yet is normal" posture; a specific
key request still errors, only listing degrades gracefully.

AnswerRow's Invite/Decline buttons fired transition_answer immediately
on click, with no staging step and no visible confirmation once it
landed (the resource list never refetched, so a click barely looked
like it did anything). Redesigned as toggle-select (reusing the
.select-option pattern from the resource-backed select requirement)
plus one explicit Confirm button; a successful transition now refetches
the parent Resource so the row actually reflects the change.

CSS: soften the hard cut where the hero canvas meets the page
background below it (gradient fade over the last few ems, matching
--paper); center the "Asked by X" responsible note with the em-dash
starting its own line; give it and the report button real styling
(previously unstyled default text).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-06 12:42:54 +02:00
Bendik Aagaard LynghaugandClaude Sonnet 5 11c6f3e8f7 Fix favicon (real icon, not an unrelated orange circle) + stack encouragements with the submit button
Deploy / deploy (push) Successful in 35s
favicon.svg was a plain solid circle, unrelated to the actual brand
mark - replaced with the real single-arch icon (matching
infrastructure/assets/icon-{light,dark}.svg), split into two
prefers-color-scheme-scoped files rather than one SVG with an embedded
@media query - the latter doesn't reliably re-evaluate via <link> on
Safari/iOS (confirmed by prior real-device testing on the Gitea side,
see gitea-head.tmpl).

Encouragements used to render right after the description, separated
from the actual submit button by the whole features/requirements
block - moved them into the same wrapper as the form, directly above
the button, so reassurance text and the call to action read together.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-06 12:11:17 +02:00
Bendik Aagaard LynghaugandClaude Sonnet 5 755b796ad1 Resource-backed multi/single-select requirement
Deploy / deploy (push) Successful in 34s
Requirement gains an optional `resource` (reuses ResourceSpec/
ResourceSource/jq wholesale - a resource is a resource whether it's
displayed read-only or offered as choices to pick from) and `id_field`
(which field in each item is its stable id, defaults to _id then id).
`type: select` + `multiple` (already-existing field, previously file
-only) picks single vs multi. New get_requirement_options server fn
shares its auth/fetch/jq logic with get_resource via two extracted
helpers rather than duplicating it.

Submitted value is the selected id (single) or a JSON array of ids
(multi) - a new select_field_map (RwSignal<Vec<String>>, alongside the
existing field_map/file_refs maps, since a multi-select's value is a
set, not a string) threaded through the same nested <For> structure
the other requirement kinds already use.

Content validation extended: a `type: select` requirement declaring no
resource now fails at load time instead of rendering a dead field.
Caught a real bug in my own first version of that check while testing
it - it was nested inside a feature-level resource guard, so it never
ran unless the *feature* also happened to have its own resource.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-06 11:57:15 +02:00
Bendik Aagaard LynghaugandClaude Sonnet 5 bd702bfbae Render generic resource lists as cards, not raw JSON dump
Deploy / deploy (push) Failing after 32s
A jq-shaped resource (e.g. the GiteaStarred showcase) previously fell
through to the raw <pre> JSON dump - same fallback path meant for
truly unstructured data. Added a card renderer for the common case
(array of plain objects): name/title as a linked heading, description
as body text, everything else as small key/value chips - same visual
language as AnswerRow's answer-fields, just for non-Answer data.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-06 11:31:42 +02:00
Bendik Aagaard Lynghaug 00d2a95625 Fix hero-canvas navigation race; style the prosekit editor and add a toolbar
Deploy / deploy (push) Successful in 28s
- Hero: gate RasterizedYES construction on a NodeRef resolving, not
  just "the Effect ran". Root cause of the reported "loading..." stall
  + "RefCell already borrowed" panic - navigating back to / client-side
  could run the Effect before the new <canvas> was actually in the
  DOM, yes.js did an unchecked getElementById(...).getContext() on
  null and threw mid-reactive-update, corrupting wasm_bindgen_futures'
  executor badly enough to panic on the next tick. Same NodeRef-gating
  pattern the prosekit editor's own mount already used.
- style/main.css: .prosekit-wrap/.prosekit-toolbar/.prosekit-editor to
  match the existing input/textarea look (border, background, focus
  ring).
- prosekit-editor.js: a real toolbar (Bold, Italic, H1, H2, Link, and
  a dedicated Gitea-repo-embed button reusing the paste rule's own
  insert logic) with active-state highlighting via the standard
  ProseMirror markActive/nodeActive idiom.
2026-08-05 14:52:08 +02:00
Bendik Aagaard Lynghaug aa1a7fa572 Initial commit: content-driven onboarding portal
Leptos/Axum app that renders a Question/Alternative/Feature schema
loaded from a sibling content repo (portal-content). Kanidm OIDC login,
content-driven authorization (Question.qualifies), a generic NATS
KV-backed resource + state-transition mechanism (no bespoke "applicant"
concept baked into the runtime - it's all content), a SHA-256 DAG chain
tying submissions and decisions together, and the "YES - Rasterized
Lines" piece (ported from the live uhhm.no site) as the landing hero.
2026-07-29 19:38:40 +02:00