Skip to content

feat: scatter draggable image and video frames on work pages - #421

Draft
dmnktoe wants to merge 3 commits into
mainfrom
cursor/work-page-floating-media-a902
Draft

dmnktoe wants to merge 3 commits into
mainfrom
cursor/work-page-floating-media-a902

Conversation

@dmnktoe

@dmnktoe dmnktoe commented Sep 5, 2026

Copy link
Copy Markdown
Owner

⇝pull request

*ੈ✩‧₊˚༺☆༻*ੈ✩‧₊˚

what & why

Work pages can scatter images and native videos as draggable frames, independent of in-flow image/video bloks and of the Downloads desktop icons. Frame width is a CMS dropdown (240–720px, default 400).

scope

@httpjpg/ui, @httpjpg/storyblok-ui, @httpjpg/storyblok-sync, @httpjpg/storyblok-utils, @httpjpg/storybook, @httpjpg/portfolio (search index: allowlist name)

change type

  • feat — new feature · Added · minor
  • fix — bug fix · Fixed · patch
  • refactor / style / revert · Changed · patch
  • perf — faster or leaner · Performance · patch
  • build / ci / docs / test · Tooling · patch
  • deps — dependency bump · Dependencies · patch
  • chore — hidden from the changelog · patch
  • carries a BREAKING CHANGE: footer · ⚠ BREAKING · major

screenshots / recordings

Storybook: Widgets / FloatingMedia. Image frames are Argos-tested; the mixed video story is tagged !test. The story mounts CustomCursor so hover uses the same 👋 drag animation as Now Playing (Argos runs with reduced motion, so snapshots stay cursor-free).


checklist — every pull request
  • pnpm lint, pnpm type-check, pnpm test and pnpm build pass locally
  • Follows the conventions in CLAUDE.md — I read a neighbouring file before inventing a pattern
  • Scoped: no drive-by refactors bundled with the feature
  • Server Components by default; any new "use client" boundary is as small as possible
  • Styling uses design tokens from @httpjpg/tokens via Panda (no raw hex outside genuinely off-palette decoration)
  • Dependency direction respected (tokens/env stay leaves; ui never imports back from consumers)
  • New env vars declared in packages/env/src/env.mjs, .env.example and turbo.json
  • Tests added or updated next to the source (*.test.ts(x)); E2E updated if a user-facing flow changed
  • No console.log in shipped paths; errors reported through @httpjpg/observability
  • Did not hand-edit the root package.json version, .release-please-manifest.json or CHANGELOG.md
storyblok / cms — only if a blok or schema moved
  • Schema added or updated in packages/storyblok-sync/scripts/blocks/*
  • sync:components (and sync:datasources for new CMS_OPTIONS) run against Storyblok
  • Sb* component added under packages/storyblok-ui/src/components/<kebab>/ and exported explicitly from src/index.ts
  • Registered in apps/portfolio/lib/storyblok.ts under its blok name
  • editableAttrs(blok) spread on the root element, spacing handled via BlokSpacing / spacingCss()
  • Cache tags / revalidation adjusted if the content shape changed

notes for reviewers

This is not the Downloads overlay (#420). Work stories get a new floating_media field (nestable floating_item: name, Storyblok file and/or pasted url, width).

Width is not CMS_OPTIONS.imageWidth (those are 10–100% of the grid). It is a new pixel scale CMS_OPTIONS.floatingMediaWidth: 240 / 320 / 400 / 480 / 560 / 720. Default 400px.

Images and mp4s share one portal; YouTube/Vimeo stay on the regular Video blok.

floating_item is not registered in the Storyblok component registry — same pattern as other nestables that only live on the work story.

Drag the title bar (images also drag from the picture). Video controls are no-drag so seeking still works. Frames already set data-draggable="true", which is what Now Playing uses for the 👋 cursor. Positions are seeded, not Math.random().

Someone with Management API access still needs:

pnpm --filter @httpjpg/storyblok-sync sync:components

May conflict with #420 on pages.ts / SbPageWork if that lands first — both add a work-page field, they do not share one.

Open in Web Open in Cursor 

Add a Floating media field on work stories, independent of in-flow
image/video bloks. Native videos and images render as 400px frames
with a seeded scatter and a title-bar drag handle.
@codecov

codecov Bot commented Sep 5, 2026

Copy link
Copy Markdown

Bundle Report

Changes will increase total bundle size by 31.22kB (0.18%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
portfolio-server-cjs 11.06MB 11.02kB (0.1%) ⬆️
portfolio-client-array-push 3.42MB 20.2kB (0.59%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: portfolio-client-array-push

Assets Changed:

Asset Name Size Change Total Size Change (%)
static/chunks/3458-*.js (New) 187.76kB 187.76kB 100.0% 🚀
static/css/*.css 381 bytes 123.73kB 0.31%
server/app/_global-*.js 809 bytes 97.36kB 0.84%
server/app/_not-*.js 809 bytes 97.36kB 0.84%
server/app/(portfolio)/[...slug]/page_client-*.js 809 bytes 97.29kB 0.84%
server/app/page_client-*.js 809 bytes 97.27kB 0.84%
server/app/(portfolio)/cookie-*.js 665 bytes 88.66kB 0.76%
server/app/api/psn-*.js 798 bytes 63.93kB 1.26%
server/app/api/cloudflare/route_client-*.js 796 bytes 63.77kB 1.26%
server/app/api/letterboxd/route_client-*.js 796 bytes 63.77kB 1.26%
server/app/work/feed.xml/route_client-*.js 795 bytes 63.68kB 1.26%
server/app/api/discogs/route_client-*.js 793 bytes 63.52kB 1.26%
server/app/api/discord/route_client-*.js 793 bytes 63.52kB 1.26%
server/app/api/weather/route_client-*.js 793 bytes 63.52kB 1.26%
server/app/api/status/route_client-*.js 791 bytes 63.36kB 1.26%
server/app/api/x/route_client-*.js 787 bytes 63.03kB 1.26%
static/chunks/app/layout-*.js 955 bytes 48.18kB 2.02%
server/app/api/og/[...slug]/route_client-*.js 610 bytes 43.74kB 1.41%
static/chunks/4680-*.js -1 bytes 28.11kB -0.0%
static/chunks/6996-*.js 1.04kB 19.25kB 5.72% ⚠️
static/chunks/app/(portfolio)/[...slug]/page-*.js 40 bytes 11.42kB 0.35%
static/chunks/app/api/cloudflare/route-*.js 40 bytes 3.48kB 1.16%
static/chunks/app/api/discogs/route-*.js 40 bytes 3.48kB 1.16%
static/chunks/app/api/discord/route-*.js 40 bytes 3.48kB 1.16%
static/chunks/app/api/letterboxd/route-*.js 40 bytes 3.48kB 1.16%
static/chunks/app/api/psn-*.js 40 bytes 3.48kB 1.16%
static/chunks/app/api/weather/route-*.js 40 bytes 3.48kB 1.16%
static/chunks/app/api/x/route-*.js 40 bytes 3.48kB 1.16%
static/chunks/app/api/status/route-*.js 40 bytes 3.48kB 1.16%
static/chunks/app/work/feed.xml/route-*.js 40 bytes 3.48kB 1.16%
static/chunks/app/(portfolio)/cookie-*.js 42 bytes 3.3kB 1.29%
static/chunks/app/(portfolio)/[...slug]/not-*.js 42 bytes 3.12kB 1.36%
static/chunks/app/not-*.js 42 bytes 3.12kB 1.36%
static/chunks/app/(portfolio)/loading-*.js 42 bytes 3.12kB 1.36%
static/chunks/app/loading-*.js 42 bytes 3.12kB 1.36%
static/chunks/app/api/og/[...slug]/route-*.js 42 bytes 3.12kB 1.36%
static/7KphuSBRl67U5IQwghYF4/_buildManifest.js (New) 1.5kB 1.5kB 100.0% 🚀
react-*.json -1 bytes 901 bytes -0.11%
server/middleware-*.js -347 bytes 495 bytes -41.21%
server/middleware-*.js 346 bytes 841 bytes 69.9% ⚠️
static/chunks/3047.*.js (New) 681 bytes 681 bytes 100.0% 🚀
static/chunks/1930.*.js (New) 680 bytes 680 bytes 100.0% 🚀
static/7KphuSBRl67U5IQwghYF4/_ssgManifest.js (New) 77 bytes 77 bytes 100.0% 🚀
static/chunks/9378-*.js (Deleted) -182.24kB 0 bytes -100.0% 🗑️
static/sFSdLuN4TFQ8DKJwNDPqs/_buildManifest.js (Deleted) -1.5kB 0 bytes -100.0% 🗑️
static/chunks/3218.*.js (Deleted) -681 bytes 0 bytes -100.0% 🗑️
static/chunks/8586.*.js (Deleted) -681 bytes 0 bytes -100.0% 🗑️
static/sFSdLuN4TFQ8DKJwNDPqs/_ssgManifest.js (Deleted) -77 bytes 0 bytes -100.0% 🗑️

App Routes Affected:

App Route Size Change Total Size Change (%)
/ 954 bytes 79.09kB 1.22%
view changes for bundle: portfolio-server-cjs

Assets Changed:

Asset Name Size Change Total Size Change (%)
8957.js (New) 238.62kB 238.62kB 100.0% 🚀
../app/(portfolio)/[...slug]/page.js 88 bytes 160.42kB 0.05%
5188.js (New) 75.23kB 75.23kB 100.0% 🚀
6040.js 1.95kB 68.61kB 2.93%
2728.js 2 bytes 52.37kB 0.0%
../app/(portfolio)/cookie-policy/page.js 80 bytes 22.03kB 0.36%
../app/api/ask/route.js 7 bytes 20.56kB 0.03%
../app/api/search/route.js 7 bytes 16.41kB 0.04%
1581.js 1.0kB 13.46kB 8.05% ⚠️
9615.js (New) 6.64kB 6.64kB 100.0% 🚀
5267.js (New) 6.28kB 6.28kB 100.0% 🚀
../app/(portfolio)/[...slug]/page.js.nft.json 2 bytes 1.26kB 0.16%
../app/api/cloudflare/route.js.nft.json 2 bytes 1.24kB 0.16%
../app/api/discogs/route.js.nft.json 2 bytes 1.24kB 0.16%
../app/api/psn-trophies/route.js.nft.json 2 bytes 1.24kB 0.16%
../app/api/discord/route.js.nft.json 2 bytes 1.24kB 0.16%
../app/api/status/route.js.nft.json 2 bytes 1.24kB 0.16%
../app/api/letterboxd/route.js.nft.json 2 bytes 1.24kB 0.16%
../app/api/weather/route.js.nft.json 2 bytes 1.24kB 0.16%
../app/api/x/route.js.nft.json 2 bytes 1.24kB 0.16%
../app/work/feed.xml/route.js.nft.json 2 bytes 1.16kB 0.17%
../app/page.js.nft.json 2 bytes 853 bytes 0.24%
../app/(portfolio)/cookie-policy/page.js.nft.json 2 bytes 775 bytes 0.26%
1526.js (New) 616 bytes 616 bytes 100.0% 🚀
9880.js (New) 616 bytes 616 bytes 100.0% 🚀
../app/_not-found/page.js.nft.json 2 bytes 545 bytes 0.37%
6524.js (Deleted) -231.92kB 0 bytes -100.0% 🗑️
4493.js (Deleted) -74.24kB 0 bytes -100.0% 🗑️
5696.js (Deleted) -6.56kB 0 bytes -100.0% 🗑️
1775.js (Deleted) -6.2kB 0 bytes -100.0% 🗑️
718.js (Deleted) -614 bytes 0 bytes -100.0% 🗑️
853.js (Deleted) -614 bytes 0 bytes -100.0% 🗑️

App Routes Affected:

App Route Size Change Total Size Change (%)
/api/search 7 bytes 16.41kB 0.04%
/api/weather 4 bytes 262.27kB 0.0%
/api/discogs 4 bytes 261.24kB 0.0%
/work/feed.xml 4 bytes 264.19kB 0.0%
/api/cloudflare 4 bytes 263.34kB 0.0%
/api/psn-trophies 4 bytes 261.48kB 0.0%
/(portfolio)/[...slug] 92 bytes 412.15kB 0.02%
/api/x 4 bytes 261.28kB 0.0%
/api/ask 7 bytes 20.56kB 0.03%
/(portfolio) 172 bytes 434.18kB 0.04%
/api/letterboxd 4 bytes 261.27kB 0.0%
/ 997 bytes 356.9kB 0.28%
/api/status 4 bytes 260.97kB 0.0%
/(portfolio)/cookie-policy 84 bytes 273.76kB 0.03%
/api/discord 4 bytes 262.76kB 0.0%

@codecov

codecov Bot commented Sep 5, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.12207% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 97.31%. Comparing base (5fad6f3) to head (5d8dec6).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...ui/src/components/page-work/work-floating-media.ts 90.90% 3 Missing ⚠️
...omponents/floating-media/floating-media-window.tsx 96.15% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #421      +/-   ##
==========================================
+ Coverage   97.29%   97.31%   +0.01%     
==========================================
  Files         356      361       +5     
  Lines        9109     9322     +213     
  Branches     3091     3067      -24     
==========================================
+ Hits         8863     9072     +209     
- Misses        238      242       +4     
  Partials        8        8              
Components Coverage Δ
ui 97.55% <99.43%> (+0.11%) ⬆️
storyblok 96.65% <91.89%> (-0.16%) ⬇️
integrations 93.73% <ø> (ø)
foundations 92.10% <ø> (ø)
portfolio 98.15% <ø> (ø)
Files with missing lines Coverage Δ
apps/portfolio/lib/search/story-text.ts 100.00% <ø> (ø)
packages/storyblok-sync/scripts/blocks/pages.ts 100.00% <ø> (ø)
packages/storyblok-sync/scripts/lib/options.ts 100.00% <100.00%> (ø)
...oryblok-ui/src/components/page-work/SbPageWork.tsx 100.00% <100.00%> (ø)
packages/storyblok-utils/src/cms-options.ts 100.00% <100.00%> (ø)
...i/src/components/floating-media/floating-media.tsx 100.00% <100.00%> (ø)
packages/ui/src/components/floating-media/lib.ts 100.00% <100.00%> (ø)
...mponents/floating-media/use-floating-media-drag.ts 100.00% <100.00%> (ø)
...omponents/floating-media/floating-media-window.tsx 96.15% <96.15%> (ø)
...ui/src/components/page-work/work-floating-media.ts 90.90% <90.90%> (ø)

Reuse a dedicated CMS dropdown (240–720px, default 400) rather than the
in-flow image width percentages. Frames still use the Now Playing drag
cursor via data-draggable.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants