Skip to content

Conversation

@JeanneGrenet
Copy link
Collaborator

@JeanneGrenet JeanneGrenet commented Nov 18, 2025

Closes #428
Examples of result
image
image
image

Summary by CodeRabbit

  • New Features
    • Added a schedule image asset for events that generates a composite 1920×1080 image showing event details (city, type, date, optional location) and a right-side list of up to three talks with speaker names and avatars, plus city/country and footer link.
  • Chores
    • Added a new route entry to expose the schedule asset on event pages.

@JeanneGrenet JeanneGrenet self-assigned this Nov 18, 2025
@vercel
Copy link

vercel bot commented Nov 18, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
forkit-community Ready Ready Preview Comment Nov 19, 2025 9:13am

@coderabbitai
Copy link

coderabbitai bot commented Nov 18, 2025

Walkthrough

A new 1920×1080 React asset generator was added at src/pages/events/[id]/assets/_schedule-short.tsx that fetches event, cover image, co-organizer logos and up to three talks (with speaker avatars) and renders a composite schedule image. The route key _schedule-short was added to src/routes.gen.ts.

Changes

Cohort / File(s) Summary
Schedule Short Image Asset
src/pages/events/[id]/assets/_schedule-short.tsx
New React asset component exporting config: AssetImageConfig = { width: 1920, height: 1080 }, a scheduleShort(options) factory that returns an async renderer. Renderer fetches event data, post cover (base64), co-organizer logos, and up to 3 talks with speaker avatars (fallbacks used), then composes and returns a Frame containing background image, left info column, right talks list, and footer.
Route Configuration Update
src/routes.gen.ts
Adds "_schedule-short" asset key under events/:id/assets in the generated ROUTES_CONFIG.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Renderer as ScheduleShort Renderer
    participant Fetchers as Data Fetchers
    participant Composer as Composer/Frame

    Client->>Renderer: call renderer({ params: { id } })
    Renderer->>Fetchers: getEventData(id)
    Renderer->>Fetchers: getAstroImageBase64(post.cover)
    Renderer->>Fetchers: fetch co-organizers logos
    Renderer->>Fetchers: getTalkData (up to 3) + speaker avatars
    Fetchers-->>Renderer: event, images, talks, avatars

    Renderer->>Composer: assemble Frame (1920×1080)
    Composer->>Composer: render BgImage, left info column
    Composer->>Composer: render talks list, avatars, footer
    Composer-->>Renderer: JSX image
    Renderer-->>Client: return rendered asset
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Pay attention to async data fetching and fallback/error handling
  • Verify correctness of exported config and default export usage
  • Check image base64 embedding, size/encoding and performance implications
  • Inspect layout/styling constants and accessibility of text contrast

Suggested reviewers

  • yoannfleurydev
  • houssembaltii

Poem

🐰 I stitched a frame with light and shade,
Cities, talks, and avatars parade,
Logos hum and dates align,
Three small hops — the schedule's fine,
A rabbit grins: the image's made.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: adding visual save-the-date assets for meetups featuring speakers and topics, which matches the new component introduced in the changeset.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/meetup-schedule-asset

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/pages/events/[id]/assets/_schedule-short.tsx (1)

176-255: Consider handling for empty talks array.

When talks is empty (fewer than 3 talks or none at all), the right panel will render nothing. This might create an unbalanced layout.

Consider adding a conditional message or adjusting the layout when no talks are available:

            >
+             {talks.length === 0 ? (
+               <div style={{ 
+                 fontSize: 36, 
+                 opacity: 0.7,
+                 fontStyle: 'italic' 
+               }}>
+                 Schedule coming soon
+               </div>
+             ) : (
              {await Promise.all(
                talks.map(async (talk) => (
                  // ... existing talk rendering
                )),
              )}
+             )}
            </div>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8baa0a6 and 5b929ba.

📒 Files selected for processing (2)
  • src/pages/events/[id]/assets/_schedule-short.tsx (1 hunks)
  • src/routes.gen.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/pages/events/[id]/assets/_schedule-short.tsx (7)
src/generated-assets/image.ts (2)
  • AssetImageConfig (11-15)
  • getAstroImageBase64 (171-174)
src/pages/events/[id]/talks/[talkId]/assets/_utils.ts (1)
  • getTalkData (4-30)
src/generated-assets/components/Frame.tsx (1)
  • Frame (4-35)
src/generated-assets/components/BgImage.tsx (1)
  • BgImage (1-63)
src/generated-assets/components/LogoWithFriends.tsx (1)
  • LogoWithFriends (6-63)
src/generated-assets/theme.ts (1)
  • COLORS (1-6)
src/lib/events.ts (2)
  • getEventDisplayType (329-336)
  • getEventDisplayDate (315-328)
🔇 Additional comments (8)
src/routes.gen.ts (1)

36-36: LGTM! Auto-generated route entry is correctly added.

The new _schedule-short route is properly integrated into the assets configuration and follows the existing pattern for similar asset routes.

src/pages/events/[id]/assets/_schedule-short.tsx (7)

1-12: LGTM! Imports are well-organized.

All necessary components, utilities, and assets are properly imported with clear naming.


14-17: LGTM! Standard Full HD configuration.

The 1920×1080 resolution is appropriate for social media and digital display assets.


196-215: Nice touch with overlapping speaker avatars!

The overlapping avatar effect (line 209: marginLeft: index === 0 ? 0 : -25) creates a visually appealing presentation for multi-speaker talks, and the fallback to peoplePlaceholder ensures the layout doesn't break.


276-278: Verify data consistency for footer location.

The footer displays city and country names, but there's no guarantee these values exist if they were conditionally rendered above (e.g., line 83).

Please confirm that event.data._computed.city and event.data._computed.country are always populated for events, or add optional chaining here as well:

-              {event.data._computed.city?.data.name},{" "}
-              {event.data._computed.country?.data.name}
+              {event.data._computed.city?.data.name ?? 'TBD'},{" "}
+              {event.data._computed.country?.data.name ?? 'TBD'}

298-298: LGTM! Standard default export pattern.

The default export correctly applies the configuration to the component function.


83-84: Now let me check the specific context around lines 83-84 to understand if rendering nothing is the intended behavior:


The code correctly uses optional chaining (?.) which short-circuits and evaluates to undefined instead of throwing an error when city is undefined. When returning undefined in React, these are all valid React nodes and are ignored when rendering the DOM. This means if city data is unavailable, the element simply renders empty text, which is the intended behavior. The same pattern is consistently applied across 25+ asset generation files in the codebase, confirming this is an established, correct approach for handling potentially undefined nested properties.

Likely an incorrect or invalid review comment.


19-32: The original review comment is incorrect and should be ignored.

After verification:

  1. Error handling exists: Both getEventData and getTalkData explicitly throw NotFoundAssetError when data is not found (lines 13-14 in getEventData and lines 7-8 in getTalkData). This is proper error handling for build-time asset generation, where errors should propagate to fail the build.

  2. Empty talks is safe: Calling slice(0, 3) on an empty array returns an empty array, and Promise.all([]) resolves safely. No edge case handling needed here.

  3. Try-catch wrapping is inappropriate: In an asset generation context (as this code is in the /assets folder), throwing errors is the intended pattern. Wrapping in try-catch would suppress legitimate build failures when required data is missing.

The utilities are correctly designed to let errors propagate in the build pipeline rather than silently failing.

Likely an incorrect or invalid review comment.

@houssembaltii
Copy link
Contributor

houssembaltii commented Nov 18, 2025

1- in my opinion the new section is not coherent with the left side text because style is different .
can you please test with no background and we make it simpler and see how it looks . if it's not good, then we can keep the current style .
2- i think we can add a title to the new section, explaining that those are the talks featured in the meetup .
3- i think maybe we can reduce the spacing between talk title and speaker .

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
src/pages/events/[id]/assets/_schedule-short.tsx (1)

176-212: Consider extracting nested Promise.all logic for better readability.

The nested await Promise.all calls (lines 176 and 193) work correctly but could be refactored for improved readability. Consider extracting the speaker avatar fetching logic into a separate function.

Example refactor:

// Before the return statement
const talksWithAvatars = await Promise.all(
  talks.map(async (talk) => ({
    ...talk,
    speakerAvatars: await Promise.all(
      talk.__speakers.map(async (speaker) => ({
        speaker,
        image: await getAstroImageBase64(
          speaker.data.avatar ?? peoplePlaceholder
        ),
      }))
    ),
  }))
);

Then use talksWithAvatars in the JSX without the nested async operations.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5b929ba and 8da84e3.

📒 Files selected for processing (1)
  • src/pages/events/[id]/assets/_schedule-short.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/pages/events/[id]/assets/_schedule-short.tsx (7)
src/generated-assets/image.ts (2)
  • AssetImageConfig (11-15)
  • getAstroImageBase64 (171-174)
src/pages/events/[id]/talks/[talkId]/assets/_utils.ts (1)
  • getTalkData (4-30)
src/generated-assets/components/Frame.tsx (1)
  • Frame (4-35)
src/generated-assets/components/BgImage.tsx (1)
  • BgImage (1-63)
src/generated-assets/components/LogoWithFriends.tsx (1)
  • LogoWithFriends (6-63)
src/generated-assets/theme.ts (1)
  • COLORS (1-6)
src/lib/events.ts (2)
  • getEventDisplayType (329-336)
  • getEventDisplayDate (315-328)
🔇 Additional comments (1)
src/pages/events/[id]/assets/_schedule-short.tsx (1)

145-145: No issues found—textWrap: "balance" is fully supported.

The project uses Satori 0.18.3, which explicitly supports textWrap with the "balance" option. The asset generation environment has no compatibility issues with this CSS property.

Comment on lines +169 to +175
<div
style={{
display: "flex",
flexDirection: "column",
gap: 24,
}}
>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add a title for the talks section as suggested in PR feedback.

PR comment from houssembaltii recommends adding a title to explain that these are the talks featured in the meetup. This would improve clarity for viewers.

Consider adding a header above the talks list:

 <div
   style={{
     display: "flex",
     flexDirection: "column",
     gap: 24,
   }}
 >
+  <div
+    style={{
+      fontSize: 48,
+      fontWeight: 500,
+      textTransform: "uppercase",
+      color: COLORS.primary,
+      marginBottom: 12,
+    }}
+  >
+    Featured Talks
+  </div>
   {await Promise.all(
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div
style={{
display: "flex",
flexDirection: "column",
gap: 24,
}}
>
<div
style={{
display: "flex",
flexDirection: "column",
gap: 24,
}}
>
<div
style={{
fontSize: 48,
fontWeight: 500,
textTransform: "uppercase",
color: COLORS.primary,
marginBottom: 12,
}}
>
Featured Talks
</div>
🤖 Prompt for AI Agents
In src/pages/events/[id]/assets/_schedule-short.tsx around lines 169 to 175,
there's a talks list container rendered without a section title; add a clear
header above this div (e.g., an accessible <h3> or <h2> with text like "Featured
Talks" or "Talks") to indicate these are the talks featured in the meetup, style
it consistently with existing page headings, and ensure semantic/accessible
markup (appropriate heading level and aria attributes if needed).

Comment on lines +214 to +221
<div
style={{
display: "flex",
flexDirection: "column",
gap: 8,
minWidth: 0,
}}
>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Reduce spacing between talk title and speaker name as suggested in PR feedback.

PR comment from houssembaltii recommends reducing the gap between the talk title and speaker name. The current gap of 8px (line 218) could be decreased for a tighter visual grouping.

Apply this diff to reduce the spacing:

 <div
   style={{
     display: "flex",
     flexDirection: "column",
-    gap: 8,
+    gap: 4,
     minWidth: 0,
   }}
 >
🤖 Prompt for AI Agents
In src/pages/events/[id]/assets/_schedule-short.tsx around lines 214 to 221 the
vertical gap between the talk title and speaker name is set to 8px; reduce that
gap to 4px to tighten the visual grouping by updating the style.gap value from 8
to 4 on the containing div.

@yoannfleurydev
Copy link
Member

No background here? As we are on a "lighter" side of the image, it can be hard to read.

image

@yoannfleurydev
Copy link
Member

No background here? As we are on a "lighter" side of the image, it can be hard to read.
image

Try with the "yellow" for the title maybe?

image

And do opacity: 0.7 or use a light gray for the person's name

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (3)
src/pages/events/[id]/assets/_schedule-short.tsx (3)

30-32: The existing comment on empty talks handling remains valid.

The past review comment correctly identifies that when event.__talks is empty, the right column renders without content, creating layout imbalance. This issue should be addressed as previously suggested.


169-175: The existing comments on this section remain valid.

Past review comments correctly identify:

  1. Style coherence issue between left and right sections (per PR feedback)
  2. Missing section title to explain these are featured talks

These concerns should be addressed as previously suggested.


214-221: The existing comment on spacing remains valid.

The past review comment correctly suggests reducing the gap from 8px to 4px for tighter visual grouping between talk title and speaker name, per PR feedback.

🧹 Nitpick comments (1)
src/pages/events/[id]/assets/_schedule-short.tsx (1)

237-250: Consider adjusting opacity per PR feedback.

PR feedback from yoannfleurydev suggests using opacity: 0.7 for the speaker names to improve contrast. The current value is 0.9, which may not provide sufficient distinction from the talk title above.

Apply this diff to match the PR suggestion:

                      <div
                        style={{
                          display: "flex",
                          fontSize: 32,
                          fontWeight: 500,
                          lineHeight: 1.2,
-                         opacity: 0.9,
+                         opacity: 0.7,
                          color: "lightgray",
                        }}
                      >
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8da84e3 and cc4cda4.

📒 Files selected for processing (1)
  • src/pages/events/[id]/assets/_schedule-short.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/pages/events/[id]/assets/_schedule-short.tsx (7)
src/generated-assets/image.ts (2)
  • AssetImageConfig (11-15)
  • getAstroImageBase64 (171-174)
src/pages/events/[id]/talks/[talkId]/assets/_utils.ts (1)
  • getTalkData (4-30)
src/generated-assets/components/Frame.tsx (1)
  • Frame (4-35)
src/generated-assets/components/BgImage.tsx (1)
  • BgImage (1-63)
src/generated-assets/components/LogoWithFriends.tsx (1)
  • LogoWithFriends (6-63)
src/generated-assets/theme.ts (1)
  • COLORS (1-6)
src/lib/events.ts (2)
  • getEventDisplayType (329-336)
  • getEventDisplayDate (315-328)
🔇 Additional comments (5)
src/pages/events/[id]/assets/_schedule-short.tsx (5)

1-17: LGTM: Imports and configuration are well-structured.

The imports are properly organized and the asset configuration follows the standard pattern for generating 1920×1080 images.


34-53: LGTM: Frame and container structure is solid.

The layout correctly positions the background image and ensures content appears above it with appropriate z-indexing.


62-167: LGTM: Left column event information is well-implemented.

The code properly handles optional fields (city, location) with safe navigation and conditional rendering. The bold styling with shadows and primary color creates strong visual hierarchy.


258-290: LGTM: Footer layout and content are appropriate.

The footer provides essential location and website information with proper styling hierarchy via opacity.


297-297: LGTM: Default export follows standard pattern.

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.

Meetup Visual

4 participants