| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
| |
Root.svelte already gated the fly transition on
\$settings.displayDisableAnimations, but the View Transition path
added in 7e2495bd ran unconditionally. The setting appeared broken
because the slide kept firing via the browser API.
Adds the same check to onNavigate via get(settings) (the callback is
not in reactive context, so a synchronous store read is the right
shape). When the setting is on, both transition paths bypass and
navigation snaps as expected.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Wires SvelteKit's onNavigate hook into document.startViewTransition,
with a callback that bypasses cleanly when the API is unavailable or
the user prefers reduced motion.
Direction is computed from navigation.from/to.pathname using the same
navigationOrder logic as the existing fly slide (forward through the
ordered routes, backward otherwise; entering /user is +1, leaving
-1). Sign is written to --vt-direction on :root before the transition
fires.
::view-transition-old(root) and -new(root) get explicit slide
keyframes that read --vt-direction as a sign multiplier on
translateX(200px), replacing the browser default crossfade with a
direction-aware page-flip that matches the prior feel.
.header carries view-transition-name: app-header so it is pulled out
of the root snapshot and treated as a shared element. Since the
header lives outside the {#key data.url} block and is the same DOM
element on both sides, its morph is a visual no-op: only the body
slides past it instead of the whole viewport.
Svelte's existing fly transition in Root.svelte still runs hidden
beneath the snapshot for browsers without View Transitions support,
acting as a graceful fallback.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A document-level click delegate intercepts <summary> clicks and
animates the parent <details> height instead of relying on the
browser's instant snap.
Initial attempt used the CSS pseudo-element approach
(::details-content + interpolate-size: allow-keywords). Both features
have shipped at different times across browsers (Safari < 18.2 has
neither, Safari 18.2 to 25 only has the pseudo) and degrade in
distinct broken ways. JS via WAAPI works in every browser that has
shipped Web Animations.
Closed height is computed from the summary's offsetHeight plus the
details element's vertical padding and border (read from
getComputedStyle), so the animation end-state matches the natural
collapsed height regardless of per-element padding tweaks
(details-unstyled, card variants, etc). Earlier draft animated to
summary.offsetHeight only, which undershot by 2 * padding and caused
the element to clip text before snapping back to its resting height.
Respects prefers-reduced-motion (bypass to native toggle). Uses a
WeakMap so rapid toggles cancel the in-flight animation cleanly.
Duration 240ms / cubic-bezier(0.22,1,0.36,1) matches the panel-class
motion token used elsewhere.
|
| |
|
|
|
|
|
| |
When the menu is open and the user scrolls, they have signalled they
want to interact with content rather than the menu. Closes
isMenuOpen on any scroll event alongside the existing
isHeaderVisible recalculation in the same handler.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Commit 485f1b11 narrowed :global(a) transition to color/opacity/
text-decoration-color, intentionally excluding background. That
swallowed background-color animation across every anchor, including
the dropdown items (Schedule, Profile) whose :hover toggles
background-color from base01.
Adds background-color to the narrowed list. The original intent of
excluding background-image / shorthand background transitions still
holds; only background-color was a real loss.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Adds src/styles/_breakpoints.scss with five canonical tokens
(\$bp-sm 600, \$bp-md 800, \$bp-lg 1024, \$bp-xl 1280, \$bp-2xl 1600)
and migrates all 15 @media (max-width: ...) occurrences across 9 files.
Configures vite.config.ts with scss loadPaths so any file can
@use "breakpoints" without relative paths.
Conservative rounding-up where existing values were near-duplicates:
500 and 512 collapse to 600, 768 collapses to 800, 1000 collapses to
1024. Slightly more viewports get the smaller-layout treatment in
those bands, which is usually beneficial on cramped widths.
Converts 7 Svelte files from <style> to <style lang="scss"> to access
the SCSS tokens. SCSS is a CSS superset, so existing rules stay valid.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The existing --base0011 glass tint is #ffffff80 / #0c0c0c80 (50%
alpha), which is unusually transparent for floating UI. The desktop
header and the mobile hamburger sit over scrolling content, so the
content bleeds through and reads as distracting.
Introduces --base0011-strong at #ffffffcc / #0c0c0ccc (80% alpha) for
floating chrome. The backdrop blur still has enough content to soften,
but the surface now reads as grounded rather than barely-present.
Applied to: desktop .header background, mobile toggle background and
hover, mobile open panel background. Other glass cards (CommandPalette
dropdown, Dropdown component content, tooltips, hover covers) keep the
softer --base0011 since they sit over relatively static surfaces and
the see-through effect there is not distracting.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Adds 0.24s between --duration-fast (0.15s) and --duration-slow (0.4s)
for animations that live in the touch-UI floor: panels, sheets,
drawers, modals. 150ms reads as crisp on desktop but undershoots the
200-300ms range touch UI conventions prescribe (finger occludes the
target during the tap, deliberation pace is slower, and high-DPI
displays compress small translateY into less perceptible motion).
Applies the new token to the mobile hamburger panel open/close
transition and to the bar-morph that fires on the same tap, so the
bars and the panel finish arriving together.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Three changes to the mobile floating header:
- Restore the desktop scroll-driven hide/show on the corner button by
dropping the transform:none override. Override the translate distance
under 800px so the toggle (44px tall at top:1.25rem) and its 5px
outline ring fully clear the viewport: translateY(calc(-100% - 2rem))
instead of -150%, which had been leaving 3px of ring poking through.
- Replace display:none / display:flex on the open panel (uneanimatable)
with always-rendered panel that flips opacity, transform, visibility,
and pointer-events. Uses --duration-fast / --ease-out-quart so the
motion vocabulary matches the rest of the project. transform-origin
is top right so the scale grows from the toggle position.
- Move per-item styling out of the .menu-open qualifier so items keep
their block layout even while the panel is faded out, avoiding a
layout reflow at the moment menu-open flips.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
Two related touch fixes:
- Dropdown :hover rule was sticky on touch devices after a tap, keeping
the menu visible even when the click toggle set open to false. Gate
the hover rule behind @media (hover: hover) so only true pointer
devices use the hover path; touch uses the click-driven open class.
- Hamburger menu had no outside-click close. Added a window click
handler that closes isMenuOpen when the target is outside .header.
Clicks on the toggle and on nav items stay inside .header, so opening
and item navigation are unaffected.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Below 800px the inline header overflows the viewport. Strips card chrome
from .header itself and floats it position:fixed at top:1.25rem/right
:1.25rem so it does not consume a horizontal band. The 44x44 toggle
button carries the desktop banner's exact card recipe (--base0011 glass,
shadow-card-emphasized + 5px --base02 ring, blur, 8px radius), and the
open panel mirrors it as a separately-positioned card below.
Menu closes on route navigation and Escape. Header stays visible while
the menu is open so a scroll-driven hide does not chop the open sheet
mid-interaction. Profile-avatar anchor and the bullet separator are
hidden in the mobile menu (avatar is redundant alongside the Profile
dropdown; separator reads as line noise vertically).
|
| |
|
|
|
|
|
|
| |
Add explicit .header-item:focus { outline: none } and
.header-item:focus-visible rules in +layout.svelte so the navbar
matches the dropdown menu's teal rounded ring on keyboard focus and
stops leaking the browser default blue square ring on mouse click.
Same pattern as the Dropdown component's scoped focus-visible rule.
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
| |
Introduce --shadow-card, --shadow-card-emphasized, --shadow-cta,
--scrim, --scrim-soft, and --scrim-banner. Migrate 14 inline
literals (card.css, input.css, Notification, MediaRoulette, the
two Landing CTA buttons, the popup overlay, the palette and
roulette scrims, three identity banners, the user profile cover
art shadow) onto the tokens, with light/dark adaptation handled
by the existing prefers-color-scheme blocks instead of duplicated
inline. Two single-use Landing demo-focus values stay inline.
|
| |
|
|
|
|
|
|
|
|
|
| |
Strip backdrop-filter: blur(4px) from the base .card so the ~50
in-flow surfaces (landing panels, schedule rows, tool cards, user
profile cards, badge wall, etc.) stop paying for a blur they don't
need. Introduce .card-glass for the surfaces that actually float over
other content: the sticky page header, header nav dropdowns, command
palette, title-attribute tooltips, LinkedTooltip, and HoverCover.
Popup, MediaRoulette, and Notification keep their existing
parent-overlay or solid-background treatments.
|
| |
|
|
|
|
|
| |
Add a global reduced-motion media query that collapses animation and
transition durations and disables smooth scroll. Skip Lenis init when
the same preference is set so the JS-driven smooth scroll falls back to
the browser default, which the spec already honours.
|
| |
|
|
| |
Add --ease-out-quart, --ease-in-out-quart, --duration-fast, --duration-slow in motion.css and migrate the global anchor, header, and theme-switch transitions to use them. Establishes a shared motion vocabulary for future polish.
|
| |
|
|
| |
Replace transform 0.3s ease with 0.4s cubic-bezier(0.22, 1, 0.36, 1) so the header settles instead of snapping, pairing with Lenis-smoothed scroll.
|
| |
|
|
| |
Replace transition: all with explicit color, opacity, and text-decoration-color so unrelated property changes (transform, background) do not get incidentally tweened.
|
| |
|
|
| |
Lenis disables native CSS smooth scroll, so window.scrollTo({behavior:"smooth"}) jumps instantly. Expose the Lenis instance via a store and scroll through it, falling back to native when unavailable.
|
| | |
|
| |
|
|
|
|
|
|
| |
Adds 13 reactive quick toggles (24h time, animations, blur adult, cover
modes, hover cover, schedule list, reverse sort, data saver, notifications,
language, title format cycle, outbound link target cycle), three sync
actions (push/pull/disable), and login/logout entries gated on auth state.
Names reflect current state so the palette doubles as a status surface.
|
| |
|
|
| |
This reverts commit 13226aaeb7c4dc1ce01074ef1ba1eeb87b53d5f5.
|
| |
|
|
|
|
|
| |
setShadowHidden is async and hits Supabase. The PUT handler called it
without await, so the handler could respond before the database write
landed (and any error was silently lost). Add the missing await so the
response only goes out after the update settles.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
The refresh endpoint accepted a ?redirect query param and, when
present, called redirect(303, "/") instead of returning the refreshed
token as JSON. The target was hardcoded to "/" regardless of the
param's value, so the feature was dead — and the pattern of reading
a "redirect" param invited future open-redirect bugs if someone wired
the value through to redirect() directly.
The sole in-tree caller (feeds/activity-notifications) reads the JSON
response, so always return JSON and drop the redirect import.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
The PUT ?incrementClickCount path ran before any auth guard, letting
unauthenticated callers spam-increment arbitrary badges. Require the
request Origin to match appOrigin() so legitimate in-browser clicks
(authenticated or not) still count while direct scripted calls are
rejected.
Also convert the shared `unauthorised` Response singleton into a
factory. The singleton's body was consumed on first use, so subsequent
401 paths returned a `Response body is locked` error instead of the
intended "Unauthorised" body.
|
| |
|
|
|
|
|
| |
The `tz` query value was interpolated raw into the upstream URL, letting
callers append arbitrary query segments (e.g. `tz=foo&f=hax`). Wrap the
value in encodeURIComponent and rename the local variable away from the
banned `tz` abbreviation.
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|