feat: Instagram-shaped URLs, Instagram-shaped gestures, iOS-feel animations
Docker Build and Publish / build-and-push (push) Failing after 10s
Docker Build and Publish / build-and-push (push) Failing after 10s
Navigation gestures Horizontal swipe used to advance the carousel and then, on the last slide, fling you into the next post — one gesture meaning two things. Horizontal is now carousel-only. On touch, vertical swipe moves between posts (down on the first post still dismisses, keeping drag-to-close where it can't mean "previous"). Desktop keeps the arrows outside the modal. URLs Permalinks now mirror Instagram: /<archive>/ profile /<archive>/reels/ tab /<archive>/p/<shortcode>/ post A post URL carries no tab, as on Instagram; the tab is re-derived from the post's source, so opening a reel link lands on the Reels tab with next/prev paging through reels. Sidecar posts keep directory-scoped ids internally but expose only the shortcode. The old ?a=&t=&p= form is still parsed so existing links keep working, and reserved prefixes (api, archives, assets…) can never be mistaken for a profile name. Animations Adds a shared motion vocabulary tuned to feel native: critically damped springs rather than fixed-duration easing, and gestures hand their exit velocity to the animation so a flick continues instead of restarting. Post transitions animate along the axis the input implies — vertical for a swipe, horizontal for the arrows. Modal and story viewer present/dismiss with a scale, tiles and highlight circles get touch-down feedback, and prefers-reduced-motion is honoured throughout. Adds 22 routing tests (58 total). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011uBWhwV3wFQ5MBCcMHHem7
This commit is contained in:
co-authored by
Claude Opus 5
parent
0cff91edae
commit
877d21ff1f
@@ -0,0 +1,44 @@
|
||||
import type { Transition } from 'motion/react';
|
||||
|
||||
/**
|
||||
* Shared motion vocabulary, tuned to feel like a native iOS app.
|
||||
*
|
||||
* Two rules do most of the work:
|
||||
* - UIKit animates with springs, not fixed-duration easing, so gestures hand
|
||||
* their exit velocity to the animation and motion continues rather than
|
||||
* restarting.
|
||||
* - iOS springs are critically damped. They settle firmly with no visible
|
||||
* bounce; overshoot reads as "web animation", not "native".
|
||||
*/
|
||||
|
||||
/** The curve UIKit uses for sheet presentation. */
|
||||
export const IOS_EASE = [0.32, 0.72, 0, 1] as const;
|
||||
|
||||
/** Moving between peers: carousel slides, next/previous post. */
|
||||
export const NAVIGATE: Transition = { type: 'spring', stiffness: 420, damping: 40, mass: 1 };
|
||||
|
||||
/** Presenting or dismissing a surface. Slightly softer than navigation. */
|
||||
export const PRESENT: Transition = { type: 'spring', stiffness: 320, damping: 34, mass: 1 };
|
||||
|
||||
/** Backdrops and cross-fades, where a spring would feel fussy. */
|
||||
export const FADE: Transition = { duration: 0.28, ease: IOS_EASE };
|
||||
|
||||
/** Touch-down feedback. Fast enough to feel like a direct response. */
|
||||
export const PRESS: Transition = { type: 'spring', stiffness: 600, damping: 30 };
|
||||
|
||||
/**
|
||||
* Continue a drag into its animation.
|
||||
*
|
||||
* Handing the gesture's exit velocity to the spring is what separates "the
|
||||
* sheet kept moving because I flicked it" from "the sheet started a new
|
||||
* animation once I let go".
|
||||
*/
|
||||
export const withVelocity = (velocity: number, base: Transition = NAVIGATE): Transition => ({
|
||||
...base,
|
||||
velocity,
|
||||
});
|
||||
|
||||
/** True when the viewer has asked the OS to reduce motion. */
|
||||
export const prefersReducedMotion = () =>
|
||||
typeof window !== 'undefined' &&
|
||||
window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
Reference in New Issue
Block a user