Skip to content

Add a server-renderable Discover card set under ./discover - #149

Open
prakashUXtech wants to merge 12 commits into
mainfrom
feat/discover-export
Open

prakashUXtech wants to merge 12 commits into
mainfrom
feat/discover-export

Conversation

@prakashUXtech

Copy link
Copy Markdown
Contributor

Adds @ripple-ui/svelte/discover, a card set for a public Discover catalogue that renders completely on the server. It ports DiscoverTile, DiscoverRow and the item art from paw-enterprise, plus a DetailMedia block (the video, audio or image a detail view plays, without the dialog), the DiscoverItem types, and itemHref(kind, idOrSlug).

The components are pure: props in, markup out. There are no stores, no effects and no app imports. The <img>, <video> and <audio> sources are in the server HTML, so a prerendered page shows the pictures before any JavaScript loads. Tile and Row take an optional href; when set, the art and the title become links. The art link is decorative (tabindex -1, hidden from assistive tech) since the title carries the name. The click callbacks (onremix, onreport, onopen) are optional, and each action button renders only when its callback is passed, so a static page gets just the links.

What changed from the app versions: ItemArt takes imageUrl, alt, mediaKind, tint and initial directly and prints a lazy <img> or the tinted placeholder (no CardPreview, no thumbnail grant, no $effect). The item shape is flattened to id, slug?, kind, mediaKind, title, desc, imageUrl, mediaUrl?, liveUrl?, remixCount, featured; the studio flag, usage line, primary action and playable media are derived in item.ts with the same rules the app's adapter uses, including the http(s) guard on every url that becomes an href or src. The shared action cluster lives in one internal ItemActions component instead of being duplicated in Tile and Row. The placeholder palette is theme tokens (var(--ripple-*)) rather than hex, and the app's text-body / text-footnote / text-caption-1 utilities map to text-sm / text-xs, which is what ripple's sibling widgets use.

discover.ssr.test.ts runs in the ssr vitest project next to the marketing SSR test. It renders each component through svelte/server and asserts the image, media and link markup, and covers the four itemHref branches.

Verified locally: the SSR test passes (8 tests), svelte-check reports 0 errors, and svelte-package emits dist/discover. No docs list the export subpaths today, so none were updated.

@prakashUXtech

Copy link
Copy Markdown
Contributor Author

Two follow-up commits:

  • 0f4b216: tool items now route to /free-tools/ instead of /tools/. The docs site owns /tools/*. game -> /play/, site -> /templates/, everything else -> /discover/ are unchanged. Unit test updated.
  • 325ca29: the live link in ItemActions (the only place discover/ renders a listing's external liveUrl) now carries rel="nofollow ugc noopener" and target="_blank". Internal item-page links keep no rel. The SSR test asserts both.

Verified: vitest ssr project for src/lib/discover 8/8 green, bun run build emits dist/discover, svelte-check 0 errors 0 warnings.

…adge without a poster, and only takes http(s) urls

ItemArt derives its own labels from the title, so the placeholder says
Preview of and never Video poster for. imageUrl and the DetailMedia poster
route through httpUrl, making the item.ts invariant true. A failed load
drops to the placeholder after hydration; the server frame is unchanged.
Consumers whose item pages are off-site pass target="_blank" rel="noopener"
so a desktop webview does not navigate away from the app.
@prakashUXtech

Copy link
Copy Markdown
Contributor Author

Review findings addressed, one commit per row:

  • db987da ItemArt: onerror drops a dead picture to the tinted placeholder (flag keyed on the url, so a new url retries; server frame unchanged). A video with imageUrl: null keeps the play badge, and the placeholder is labelled Preview of X, never Video poster for X. imageUrl and the DetailMedia poster now route through httpUrl, so the item.ts invariant ("only http(s) urls survive into an href or a src") is true. Tests: javascript:, data:, //evil and relative previews render the placeholder; a data: poster is dropped while the video stays.
  • 8bc30d6 DiscoverTile and DiscoverRow take optional target and rel, passed to the art and title links (for paw-enterprise #1145 row 1: pass target="_blank" rel="noopener" for off-site item pages). SSR test covers both components.
  • 3dc1eaa ItemActions live link is rel="nofollow ugc noopener noreferrer", as the app had.
  • 09470b0 art.ts: --ripple-muted-foreground replaced by --ripple-info-text; no id gets the grey wash.
  • d4f4af9 Tests: primaryFor with javascript: and //evil liveUrl, labels at 0 and 1, a Tile rendering music, tintFor stability.
  • 6d8e88a discover-contract.test.ts: exact export list via toEqual, exports['./discover'] defined.
  • c3c05c2 docs/discover.md lists the exports and the purity rule, linked from docs/README.md.

One prop change: ItemArt takes title instead of alt and derives the alt text and placeholder label itself. The app imports only Tile, Row and DetailMedia, so no consumer is affected.

Follow-ups, not in this PR: the typography drift (text-sm/text-xs vs the app's canon scale, rounded-xl vs 10px, font-display) and playsinline plus eager loading for the first shelf.

Verified from packages/svelte: bunx vitest run --project ssr src/lib/discover 20 passed; bunx vitest run src/lib/discover (ssr + client, incl. the contract test and the onerror client test) 3 files, 38 passed; bun run build emits dist/discover/{index.js,index.d.ts,*.svelte}; svelte-check --tsconfig ./tsconfig.json 5907 files, 0 errors, 0 warnings (a negative control with an injected type error reported 1 error, so the 0 is real). The manifest bump from the build was reverted, not committed.

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.

1 participant