Add talk thumbnail rendering for slides and download#75
Add talk thumbnail rendering for slides and download#75
Conversation
23b3822 to
5272248
Compare
5272248 to
7bf53ab
Compare
| img.src = svgBlobUrl | ||
| }, | ||
| [talkTitle] | ||
| ) |
There was a problem hiding this comment.
SVG percentage dimensions cause blurry rasterized downloads
High Severity
The TalkThumbnail SVG uses width="100%" and height="100%", and buildEmbeddedSvgString clones this SVG as-is. When the serialized SVG is loaded as a standalone image via blob URL for canvas rasterization, percentage dimensions have no parent to resolve against. Per the CSS spec, the browser falls back to a default object size (typically 300×150), so the SVG is rasterized at very low resolution and then upscaled to 1280×720 on the canvas, producing a blurry downloaded image. The cloned SVG needs explicit pixel width and height attributes before serialization.
Additional Locations (1)
| {profilePhotoUrl ? ( | ||
| <clipPath id="thumbPhotoClip"> | ||
| <circle cx={photoCx} cy={photoCy} r={photoRadius} /> | ||
| </clipPath> |
There was a problem hiding this comment.
Hardcoded SVG clipPath ID causes multi-instance collision
Medium Severity
The clipPath uses a hardcoded id="thumbPhotoClip". Since TalkThumbnail is an exported reusable component, rendering multiple instances on the same page (e.g., a talk listing) would create duplicate DOM IDs. The clipPath="url(#thumbPhotoClip)" reference would resolve to the first instance's clip circle, causing all other thumbnails' photos to be clipped incorrectly. A unique ID per instance (e.g., using useId) would fix this.
tomatrow
left a comment
There was a problem hiding this comment.
Only issue might be lack of speaker name on the talk card.
Looks good to me otherwise.
Rename the TalkThumbnail `talkTitle` prop to `hook` to better reflect its purpose as short, punchy thumbnail text. Add a dedicated Hook field to the talk submission form (defaults to talk title via placeholder) and persist it as `talk_hook` in the database with a 50-char limit.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 5 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
| ) | ||
| } | ||
|
|
||
| img.src = svgBlobUrl |
| .replace(/[^a-z0-9]+/g, "-") | ||
| .replace(/^-|-$/g, "") | ||
| .slice(0, 50) | ||
| return `${slug}-thumbnail.${ext}` |
There was a problem hiding this comment.
|
|
||
| const blobUrl = URL.createObjectURL(file) | ||
| setPhotoUrl(blobUrl) | ||
| setPhotoSource("upload") |
There was a problem hiding this comment.
Upload blob URL lacks unmount cleanup
Low Severity
handleFileUpload creates a blob URL with URL.createObjectURL, but there is no component-unmount cleanup path. If users navigate away without calling clearPhoto, the blob URL stays allocated in the SPA session and can accumulate memory over repeated visits.
| } | ||
| setPhotoUrl(profile.profile_photo) | ||
| setPhotoSource("handle") | ||
| } else { |
There was a problem hiding this comment.
Lookup path leaves stale file input value
Low Severity
When handleLookup switches photo source to a handle image, it does not clear fileInputRef.current.value. The file input can still hold the old upload, so re-selecting that same file may not trigger onChange, leaving photo replacement seemingly broken.


Note
Medium Risk
Touches talk submission persistence (
talk_hook) and adds client-side image fetching/rasterization for downloads, which may surface runtime/CORS issues or require matching DB schema changes.Overview
Adds a new
TalkThumbnailclient component that renders a DEVx-styled 16:9 SVG thumbnail (background + hook text + optional circular speaker photo + branding) with basic text wrapping.Updates
submit-talkto collect an optional "Hook" string, fetchprofile_photofor the logged-in user, preview the generated thumbnail in-form, and persist the hook via the newtalk_hookfield ontalk_submissions.Introduces a new
talk-thumbnail-genpage that can load a photo via file upload or Supabase handle lookup and export the rendered SVG as downloadable PNG/JPG by embedding image assets as data URLs before rasterizing to canvas. Also bumps the Supabase CLI version and adds adev:supabasescript; includes a small JSON formatting change in a slides metadata file.Written by Cursor Bugbot for commit 399b3a6. This will update automatically on new commits. Configure here.