Skip to content

refactor: videos page revamp#17870

Open
wackerow wants to merge 64 commits intodevfrom
videos-refactor
Open

refactor: videos page revamp#17870
wackerow wants to merge 64 commits intodevfrom
videos-refactor

Conversation

@wackerow
Copy link
Copy Markdown
Member

@wackerow wackerow commented Mar 27, 2026

Note: This is a draft preview PR with intent to extend PR:

Summary

Refactors the video data architecture and page structure to align with site conventions.

Data layer

  • Moved all video metadata from videos.json into markdown frontmatter (index.md)
  • Renamed transcript.md to index.md for each video
  • Rewrote data layer to read from filesystem instead of JSON
  • Added VideoFrontmatter type, replaced old Video/VideoMeta/VideoWithMeta types
  • Deleted videos.json and videoTranscripts.ts (merged into videos.ts)
  • Added breadcrumb frontmatter to all 42 videos
  • Used shared stripMarkdown instead of duplicate stripMdx

Components and organization

  • Moved page-scoped components out of src/components/ into app/[locale]/videos/_components/
  • Inlined transcript accordion and markdown rendering directly into page.tsx
  • Moved VIDEO_CATEGORIES to colocated constants.ts, getVideosByCategory to utils.ts
  • Updated VideoWatch shared component for new data layer
  • Cleaned up unused i18n keys
  • Removed PR-added unit and e2e tests

SEO preserved

  • JSON-LD VideoObject schema on every video detail page
  • Transcript text stays in DOM when accordion is closed via forceMount
  • generateStaticParams pre-renders all video pages at build time
  • Per-video generateMetadata for title and description meta tags
  • Breadcrumbs with translatable labels
  • Sitemap inclusion for video pages
  • Semantic HTML structure

Preview links

Schema Markup Validator

mnelsonBT and others added 30 commits March 26, 2026 15:37
Add VideoFrontmatter interface extending SharedFrontmatter with video-specific fields (youtubeId, uploadDate, duration, topic as string[], etc). Replace Video/VideoMeta/VideoWithMeta with VideoData and VideoCardData types.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rename transcript.md to index.md for all 42 videos. Merge metadata from videos.json into YAML frontmatter (youtubeId, uploadDate, duration, educationLevel, topic as array, format, author, lang, breadcrumb). This consolidates the split data model into a single source of truth per video.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rewrite videos.ts to read video data from index.md frontmatter via readdir + gray-matter instead of videos.json. Delete videos.json and videoTranscripts.ts (logic merged into videos.ts).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add optional boolean parameter to preserve paragraph structure instead of collapsing all whitespace. Used by video JSON-LD transcript output.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update VideoWatch to use getVideoData and conditionally hide transcript link. Delete Transcript, TranscriptContent (inlined into page.tsx), VideoGalleryFilter (moved to _components/), and barrel export from src/components/Videos/.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add VideoGalleryFilter, constants.ts (VIDEO_CATEGORIES), and utils.ts (getVideosByCategory) under the /videos route. Update listing page to use filesystem-based getVideos() and colocated imports.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rewrite video detail page to use getVideoData with frontmatter, SimpleHero, Breadcrumbs, formatDate, renderSimpleMarkdown for transcript, and forceMount accordion for SEO. Update JSON-LD to accept VideoFrontmatter and use shared stripMarkdown. Update translation keys.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove PR-added Playwright test files for video utilities. These tested the old JSON-based data layer and are not needed for production.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove unused CSS classes from VideoWatch, delete e2e video tests from PR, and remove 5 unused i18n keys from page-videos.json.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@myelinated-wackerow
Copy link
Copy Markdown
Collaborator

Review cleanup

Performance

  • Static generation for all 25 locales (was English-only; non-English was SSR on-demand)
  • Sitemap updated with all locale variants and hreflang alternates
  • String comparison for date sorting (YYYY-MM-DD is lexicographic; avoids Date object churn)
  • JSON-LD ItemList sorted by newest before slice, matching default page display

Dead code removed

  • getTranscript(), getVideoMeta() -- exported but never called
  • minVideos on every category -- defined, typed, never read
  • 4 unused fields trimmed from VideoCardData client serialization (youtubeId, educationLevel, format, author) -- full data still available server-side via VideoFrontmatter

DRY / cleanup

  • Shared cached getVideoSlugs() eliminates duplicate readdir calls
  • Removed unnecessary cn() wrapping static class strings
  • Fixed SimpleHero import to use barrel export
  • Renamed view-transcript key to page-videos-view-transcript for prefix consistency
  • Removed redundant .trim() check on transcript

Reviewed by Claude Opus 4.6

@wackerow wackerow marked this pull request as ready for review April 2, 2026 01:25
@wackerow
Copy link
Copy Markdown
Member Author

wackerow commented Apr 2, 2026

@pettinarip Wouldn't merge this without checking with @mnelsonBT but marking it for code review

@github-actions github-actions bot added the documentation 📖 Change or add documentation label Apr 6, 2026
wackerow and others added 20 commits April 6, 2026 17:37
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
Extract escapeHeadingIds to shared module and add remark-heading-id plugin to renderSimpleMarkdown so video transcripts can use {#custom-header-ids}.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
Replaces `sddefault` (640x480) which is not guaranteed to exist

Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
@@ -1,8 +1,10 @@
import { compileMDX, type MDXRemoteProps } from "next-mdx-remote/rsc"
import remarkGfm from "remark-gfm"
import remarkHeadingId from "remark-heading-id"
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

markdownlint enforcing header ID's on all content -- This enables proper parsing when using renderSimple approach. Compatible for even simpler markdown where these ID's won't be present (e.g., externally fetched data)

Comment on lines +113 to +114
label: t("nav-videos-label"),
description: t("nav-videos-description"),
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reminder note: These need translations

Comment on lines +31 to +37
/**
* Default YouTube thumbnail URL derived from a video ID.
* Returns hqdefault (480x360) which is guaranteed to exist.
*/
export function getDefaultThumbnailUrl(youtubeId: string): string {
return `https://img.youtube.com/vi/${youtubeId}/hqdefault.jpg`
}
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • sddefault.jpg not always available (higher resolution)
  • Using hq version for now which is guaranteed to be available from YT
  • Conditionally rendering sd if available requires several sequential fetches during build -- avoided
  • Future Trigger.dev task could load highest-quality image to s3 bucket so we can point to that instead

{
variants: {
variant: {
semibold: "text-lg font-semibold",
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small addition here in lieu of hard-coding this styling into where the card is consumed

Comment on lines -19 to -25
// Preprocess the markdown content
function preprocessMarkdown(content: string) {
// Replace heading IDs without escaping to escaped version
// TODO: move to a separate file and test it more
return content.replace(/^(#{1,6}.*?)\{(#[\w-]+)\}/gm, "$1\\{$2\\}")
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shared -- abstracted to @/lib/md/escapeHeadingIds and renamed

youtubeId: string
uploadDate: string
duration: string
educationLevel: "beginner" | "intermediate" | "advanced"
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Some of these are used for JSONLD and not rendered)

{ protocol: "https", hostname: "cdn.charmverse.io" },
{ protocol: "https", hostname: "ethwingman.com" },
{ protocol: "https", hostname: "eth-mcp.dev" },
{ protocol: "https", hostname: "img.youtube.com", pathname: "/vi/**" },
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If/when we implement Trigger.dev/s3 bucket handling for these, we could remove this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

config ⚙️ Changes to configuration files content 🖋️ This involves copy additions or edits documentation 📖 Change or add documentation tooling 🔧 Changes related to tooling of the project translation 🌍 This is related to our Translation Program

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants