Skip to content

Conversation

@Shriya-Chauhan
Copy link
Contributor

@Shriya-Chauhan Shriya-Chauhan commented Nov 6, 2025

This PR introduces several new pages and updates across the site to enhance navigation and improve overall user experience.

🔧 Changes Included

Added new pages:

  • Case Studies
  • Blogs
  • Technical Steering Committee (TSC)
  • Roadmap
  • Events
  • Ambassadors
  • tools page
  • community

Fixes and updates:

  • Fixed mobile and desktop layout issues

  • Updated heading sizes for better hierarchy and consistency

  • Redesigned Roadmaps page

  • Updated Ambassadors page content and layout

  • Improved Blog desktop design

  • Added new graphics and assets where needed

related issues : #3669

Summary by CodeRabbit

  • New Features

    • Added comprehensive dark mode support across the entire platform
    • Launched new community events and updates hub with integrated calendar
    • Redesigned case studies page with interactive carousel showcase
    • Added blog post filtering and pagination with category tabs
    • Introduced community tooling showcase section
  • Bug Fixes & Improvements

    • Enhanced community pages with improved search and filtering capabilities
  • Documentation

    • Updated Code of Conduct to version 3.0 with refined enforcement guidelines

@netlify
Copy link

netlify bot commented Nov 6, 2025

Deploy Preview for asyncapi-website ready!

Built without sensitive environment variables

Name Link
🔨 Latest commit 4b25bcc
🔍 Latest deploy log https://app.netlify.com/projects/asyncapi-website/deploys/6919e26cd90119000899a2bf
😎 Deploy Preview https://deploy-preview-4553--asyncapi-website.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 6, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This PR implements extensive website modernization including a Code of Conduct 3.0 update, dark mode support across UI components, new community-focused components (FeatureCard, TSCMemberCard, ToolingCard, UpcomingEventsSection), major page refactors with pagination/filtering (blog, case studies, community, TSC, ambassadors), new icon components, and configuration updates for community meetings and events.

Changes

Cohort / File(s) Summary
Code of Conduct & Documentation
CODE_OF_CONDUCT.md
Comprehensive rewrite from Contributor Covenant v2 to v3.0: updated title, pledge/intro sections, renamed "Our Standards" to "Encouraged Behaviors", reorganized unacceptable behaviors into 7 principles, replaced "Our Responsibilities" with "Restricted Behaviors", added detailed enforcement ladder (warning through permanent ban), expanded scope and reporting sections, updated attribution and links.
New Icon Components
components/icons/{Book,Clipboard,CodeBrackets,Document,Gear,LightBulb,Lightning,Microphone,Play,Plus,Star,Terminal,UsersGroup,Video}.tsx
Added 13 new icon components with className prop support and SVG rendering. LightBulb renamed from IconLightBulb to IconLightbulb. Newsroom icon signature refactored from positional to destructured props.
Community Components (New)
components/community/{FeatureCard,TSCMemberCard,ToolingCard,ToolingsShowcase,UpcomingEventsSection}.tsx
Five new community-focused components: FeatureCard (icon/title/description card), TSCMemberCard (TSC member profile with social links), ToolingCard (animated tool showcase), ToolingsShowcase (interactive tool selection), UpcomingEventsSection (paginated events grid with navigation).
Community Components (Updated)
components/community/{Card,Header,HomeCard}.tsx
Added comprehensive dark mode styling (dark:bg-dark-card, dark:border-, dark:text-) and improved heading/paragraph component usage across small/large card variants and headers.
Layout & Dark Mode
components/layout/{BlogLayout,GenericLayout}.tsx, components/form/Select.tsx, components/tools/{CategoryDropdown,Toggle,Checkbox}.tsx
Extensive dark mode support added via dark: Tailwind variants for backgrounds, text, borders, shadows. BlogLayout restructured with outer wrapper for background styling. Select component expanded with dark-mode option styling.
Navigation Components (Updated)
components/navigation/{BlogPostItem,EventPostItem,Filter,DocsNav,communityItems}.tsx
BlogPostItem redesigned with new author layout and reading time display; EventPostItem refactored with gradient header and action button; Filter dependency arrays updated; DocsNav effect dependency extended; communityItems updated to replace Events with Events & Updates.
Newsroom & Blog Components
components/newsroom/{NewsroomBlogPosts,NewsroomSection,NewsroomYoutube}.tsx, components/newsroom/YouTubeCard.tsx
Removed Swiper carousel logic, replaced with static grid layouts (3 posts/videos); NewsroomSection button target changed to /community/events-and-updates; YouTubeCard converted to anchor-based clickable structure.
Tools Components
components/tools/{Filters,FiltersDisplay,ToolsCard,ToolsDashboard,ToolsList}.tsx
Added dark mode variants throughout; Filters updated with CardData extended API (visible/setVisible props); ToolsCard enhanced with descriptions, tags, and dark mode styling; ToolsDashboard scroll behavior dependency updated; comprehensive className refinements for interactions/transitions.
CaseStudyCard & Roadmap
components/CaseStudyCard.tsx, components/roadmap/{GoalCardRoadmapPage,RoadmapColumn,RoadmapItem,RoadmapPill}.tsx
CaseStudyCard refactored to Next.js Link with responsive grid layout, logo, description, and Button CTA; Roadmap components updated with dark mode support and improved styling (connectors, pills, columns with className support).
Dependency Updates
components/AlgoliaSearch.tsx, components/dashboard/table/Filters.tsx, components/navigation/Filter.tsx
Minor effect hook dependency array expansions (actionKey/children in SearchButton; setOpen in Filters; route/checks/data in Filter) to ensure re-runs on prop/state changes.
Styling & Globals
styles/globals.css
Added dark-mode hooks (.dark overrides), line-clamp utilities (line-clamp-{3,4,6}), smooth gradient animation (.animate-gradient), and custom Swiper carousel styling for featured and case-studies sections with dark-mode pagination variants.
Page Refactors
pages/blog/index.tsx
Added tab-based filtering (All Posts, Community, Conference, etc.), client-side pagination (postsPerPage responsive to screen size), filter/clear controls, page selector, and empty-state messaging; currentPage/activeTab state management.
Page Refactors
pages/casestudies/index.tsx
Major refactor: renamed component Casestudies → CaseStudies; replaced static layout with Swiper carousel (case studies section), paginated adopters table, pagination controls, and modern hero/CTA sections.
Page Refactors
pages/community/{index,tsc,ambassadors}.tsx, pages/community/events-and-updates.tsx
Community index simplified with CTA sections, ToolingsShowcase, and removed legacy Card components; TSC page complete overhaul with hero, stats, filterable/paginated member directory, search, and enriched member data; Ambassadors page restructured with feature cards, video section, contribution icons grid, token cards, and CTA; new events-and-updates page with multi-section layout (hero, features, events, blog, videos, newsletter).
Page Styling
pages/tools/index.tsx, pages/roadmap.tsx
Tools page: expanded decorative hero with gradient orbs, badges (Open Source, Community Driven, Production Ready), and dark-mode page wrapper. Roadmap: rewrote hero section, added Our Goals grid (GoalCardRoadmapPage items), Outcomes section with Get Involved CTA, Roadmap Graph legend and styling updates.
Configuration & Types
config/meetings.json
Updated/added meetings: "AsyncAPI Community WG Meeting" (replaced first entry), new "AsyncAPI Design WG Meeting" and "Governance Board Meeting", updated "Marketing WG Meeting" with new calendar/URL links; added banner and date fields.
Environment & Types
next-env.d.ts, types/components/navigation/BlogPostType.ts, types/pages/community/Community.ts
Added next-env.d.ts with Next.js type references; extended BlogPostType enum with Conference, Engineering, Community members; extended Tsc interface with optional githubUrl, twitterUrl, linkedinUrl, reposList properties.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Page as Blog/Case Studies Page
    participant Filter as Filter Component
    participant State as Page State
    participant Render as Render

    User->>Page: Visit page / click filter
    Page->>Filter: Pass onFilter callback
    User->>Filter: Select filter option
    Filter->>Page: onFilter(selected)
    Page->>State: Update filters, reset pagination
    State->>Page: Re-compute filtered/paginated posts
    Page->>Render: Re-render with currentPosts
    Render->>User: Display filtered page 1
    
    User->>Page: Click next page / select tab
    Page->>State: Update currentPage/activeTab
    State->>Page: Compute page slice
    Page->>Render: Render new slice
    Render->>User: Display new page content
Loading
sequenceDiagram
    participant ToolingsShowcase
    participant ToolData as Tool Selection State
    participant ToolingCard
    participant UI as Rendered Card

    ToolingsShowcase->>ToolData: Mount with first tool selected
    User->>ToolingsShowcase: Click tool tag
    ToolingsShowcase->>ToolData: Set isShuffling = true
    ToolData->>ToolingCard: Pass isShuffling prop
    ToolingCard->>UI: Apply rotation/translation animation
    ToolingsShowcase->>ToolingsShowcase: After 300ms timeout
    ToolingsShowcase->>ToolData: Update selected tool + isShuffling = false
    ToolData->>ToolingCard: Pass new tool data
    ToolingCard->>UI: Render new tool, clear animation
    UI->>User: Display selected tool
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas requiring extra attention:

  • Page refactors (blog, case studies, community, TSC, ambassadors): Major structural changes with new filtering, pagination, and component composition; verify state management correctness and edge cases (empty states, boundary page navigation).
  • Configuration changes (config/meetings.json): Verify meeting entries are correctly structured and don't conflict with existing integrations; ensure calendar links and URLs are valid.
  • New community components (ToolingsShowcase, UpcomingEventsSection, TSCMemberCard): Review data flow, prop passing, and interaction logic; verify list rendering and pagination logic (off-by-one errors, ellipses handling).
  • Dark mode consistency: Verify dark: Tailwind classes are applied consistently across all updated components; check contrast ratios and readability in dark mode.
  • Type extensions (Tsc interface, BlogPostType enum): Ensure new fields (githubUrl, twitterUrl, linkedinUrl, reposList) are populated in data sources and used correctly across components.
  • Icon components standardization: Verify all new icon components follow consistent signature patterns (className prop, default empty string, SVG rendering).
  • Effect dependency arrays: Review updated dependencies in SearchButton, Filters, Filter, and DocsNav to ensure effects re-run at appropriate times and avoid stale closures.

Possibly related PRs

Suggested labels

do-not-merge

Suggested reviewers

  • derberg
  • akshatnema
  • sambhavgupta0705
  • anshgoyalevil
  • Mayaleeeee
  • vishvamsinh28
  • TRohit20

Poem

🐰 Hops and twitches with glee

Dark nights now shimmer with care,
A thousand icons in the air,
Communities gather, events aligned,
Pages reborn with filtering refined—
The AsyncAPI warren shines anew, hoorah!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main changes—adding multiple new pages (case studies, blogs, TSC, roadmap, events, ambassadors, tools, community) across the entire site.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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.

@Shriya-Chauhan Shriya-Chauhan marked this pull request as draft November 6, 2025 16:43
@Shriya-Chauhan Shriya-Chauhan marked this pull request as ready for review November 7, 2025 14:23
@codecov
Copy link

codecov bot commented Nov 7, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (website-ui@702e050). Learn more about missing BASE report.

Additional details and impacted files
@@              Coverage Diff               @@
##             website-ui     #4553   +/-   ##
==============================================
  Coverage              ?   100.00%           
==============================================
  Files                 ?        22           
  Lines                 ?       778           
  Branches              ?       144           
==============================================
  Hits                  ?       778           
  Misses                ?         0           
  Partials              ?         0           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@Shriya-Chauhan Shriya-Chauhan changed the title feat: adding casestudies, blogs, tsc, roadmap, events, ambassadors page feat: adding casestudies, blogs, tsc, roadmap, events, ambassadors page, tools page and community page Nov 10, 2025
@devilkiller-ag
Copy link
Member

@Shriya-Chauhan Starting to review this, will complete the review by tomorrow.

@devilkiller-ag
Copy link
Member

image

The scrollbar should not appear at the bottom of the navmenu dropdown.

@devilkiller-ag
Copy link
Member

On load, the dark mode should appear instantly instead of showing a transition from light mode:

Screen.Recording.2025-11-13.224339.mp4

@devilkiller-ag
Copy link
Member

devilkiller-ag commented Nov 13, 2025

The font colour of the author's name in the case study and the title of the TOC should be changed to something lighter in the dark mode.

Also, the colour of the left border of the TOC is very sharp as compared to background in the dark mode, please change it.

image

ref: https://deploy-preview-4553--asyncapi-website.netlify.app/casestudies/adeogroup

@devilkiller-ag
Copy link
Member

The go-to page dropdown on the case studies page is not working:

Screen.Recording.2025-11-13.225426.mp4

@devilkiller-ag
Copy link
Member

The pagination "go to page" dropdown should not go out of the screen, keep the height restricted to 3-4 options. Also, increase the width of the box and the dropdown to make the content fit correctly.

image

ref: https://deploy-preview-4553--asyncapi-website.netlify.app/blog

@devilkiller-ag
Copy link
Member

devilkiller-ag commented Nov 13, 2025

The hover background colour and the search icon color are too similar in dark mode, making it hard to recognise.

image

@devilkiller-ag
Copy link
Member

The pagination number text and background colors are too similar in dark mode, making them hard to read.

Also, the "Go to page" dropdown box width is too small, the text and the dropdown icon are overlapping.

image

@devilkiller-ag
Copy link
Member

devilkiller-ag commented Nov 13, 2025

On the roadmap page, the collapsible arrow and background colors are too similar in dark mode, making them hard to see.

image

ref: https://deploy-preview-4553--asyncapi-website.netlify.app/roadmap

@devilkiller-ag
Copy link
Member

In the Events & Update Page, the event title text and background colors are too similar in dark mode, making them hard to read.

image

ref: https://deploy-preview-4553--asyncapi-website.netlify.app/community/events-and-updates

@devilkiller-ag
Copy link
Member

The Subscribe to Newsletter section is incomplete on the "Ambassadors" page. Ideally, you should use a single "Subscribe to Newsletter" component on all pages to avoid inconsistencies.

image

ref: https://deploy-preview-4553--asyncapi-website.netlify.app/community/ambassadors

@devilkiller-ag
Copy link
Member

The community Dashboard page is incomplete for dark mode (headings, Hot Topics, Good First Issues) topics.

image

ref: https://deploy-preview-4553--asyncapi-website.netlify.app/community/dashboard

@devilkiller-ag
Copy link
Member

@CodeRabbit fullreview

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 16, 2025

@devilkiller-ag: I'll conduct a full review of the PR. The review will cover all the changes including the newly added pages (Case Studies, Blogs, TSC, Roadmap, Events, Ambassadors, Tools, and Community) and will take into account the various styling and functionality issues you've already identified in your comments, particularly around dark mode compatibility, pagination, and incomplete sections.


🧠 Learnings used
Learnt from: akshatnema
Repo: asyncapi/website PR: 3265
File: tests/fixtures/toolsObjectData.js:51-52
Timestamp: 2024-10-09T17:35:36.557Z
Learning: When reviewing code in the 'asyncapi/website' repository, akshatnema prefers that I do not provide committable code suggestions.

Learnt from: akshatnema
Repo: asyncapi/website PR: 3298
File: .coderrabbit.yml:2-2
Timestamp: 2024-10-23T09:13:57.844Z
Learning: When a user prefers detailed reviews including nitpicks, set `reviews.profile` to `"assertive"` in the `.coderrabbit.yml` configuration file.
✅ Actions performed

Full review triggered.

@devilkiller-ag
Copy link
Member

Hi @devilkiller-ag,

Since there were lots of code changes in this one. Can we start with one page review at a time whichever are mentioned in the description?

That will take a lot of time. I have shared the per-page visual earlier. For the code part, I have triggered a full review by Coderabbit. In addition to that, I will go through all the files one by one.

Also, can we get the other pr merged first? Otherwise rebase would be difficult for me.

The other PR was merged. Have you taken the latest pull from the base and master branches?

@Shriya-Chauhan
Copy link
Contributor Author

Hi @devilkiller-ag,
Since there were lots of code changes in this one. Can we start with one page review at a time whichever are mentioned in the description?

That will take a lot of time. I have shared the per-page visual earlier. For the code part, I have triggered a full review by Coderabbit. In addition to that, I will go through all the files one by one.

Also, can we get the other pr merged first? Otherwise rebase would be difficult for me.

The other PR was merged. Have you taken the latest pull from the base and master branches?

yes

@Shriya-Chauhan
Copy link
Contributor Author

i have started making changes

Hi @devilkiller-ag,
Since there were lots of code changes in this one. Can we start with one page review at a time whichever are mentioned in the description?

That will take a lot of time. I have shared the per-page visual earlier. For the code part, I have triggered a full review by Coderabbit. In addition to that, I will go through all the files one by one.

Also, can we get the other pr merged first? Otherwise rebase would be difficult for me.

The other PR was merged. Have you taken the latest pull from the base and master branches?

yes

I have started working on the changes.

Copy link
Contributor

@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: 20

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (7)
components/AlgoliaSearch.tsx (1)

288-318: Memoize actionKey to prevent unnecessary effect re-runs.

Adding actionKey to the dependency array at Line 318 is correct in principle, but actionKey is computed from getActionKey() on every render (Line 288), creating a new object reference each time. This causes the effect to run on every render, even though the underlying platform information never changes.

Apply this diff to memoize actionKey:

+import React, { ..., useMemo, ... } from 'react';

 export function SearchButton({ children, indexName = INDEX_NAME, ...props }: ISearchButtonProps) {
   const { onOpen, onInput } = useContext(SearchContext);
   const [Children, setChildren] = useState<string | React.ReactNode>('');
   const searchButtonRef = useRef<HTMLButtonElement>(null);
-  const actionKey = getActionKey();
+  const actionKey = useMemo(() => getActionKey(), []);
components/Calendar.tsx (2)

56-61: Add dark mode text colors for event items.

The event title and date text lack dark mode styling, which can cause poor contrast in dark mode. This aligns with the reported issue about event title text/background contrast being too similar in dark mode.

Apply this diff to add dark mode text colors:

               <div className='grow text-left sm:mt-0 sm:pl-6'>
-                <h2 className='title-font font-medium text-gray-900 hover:text-gray-500'>{event.title}</h2>
-                <p className='text-gray-600'>
+                <h2 className='title-font font-medium text-gray-900 dark:text-gray-100 hover:text-gray-500 dark:hover:text-gray-400'>{event.title}</h2>
+                <p className='text-gray-600 dark:text-gray-400'>
                   {moment(event.date).local().format('LLLL')} UTC
                   {moment(event.date).local().format('Z')}
                 </p>

67-67: Add dark mode text color for "no meetings" message.

The message text lacks dark mode styling, which can cause poor contrast in dark mode.

Apply this diff:

-        {!eventsExist && <div className='font-bold text-gray-700 lg:pb-8'>{t('calendar.noMeetingsMessage')}</div>}
+        {!eventsExist && <div className='font-bold text-gray-700 dark:text-gray-300 lg:pb-8'>{t('calendar.noMeetingsMessage')}</div>}
components/tools/ToolsDashboard.tsx (1)

153-167: Guard against missing hash targets in tools hash‑scroll effect

With the dependency array updated to [toolsList], this effect will rerun on filter changes, which is good. However, const element = toolsList[elementID]?.elementRef!; can still be undefined for an unknown hash, and the subsequent if (element.current) will then throw. Suggest a small guard:

-    if (hash) {
-      const elementID = decodeURIComponent(hash.slice(1));
-      const element = toolsList[elementID]?.elementRef!;
-
-      if (element.current) {
+    if (hash) {
+      const elementID = decodeURIComponent(hash.slice(1));
+      const element = toolsList[elementID]?.elementRef;
+
+      if (element?.current) {
         document.documentElement.style.scrollPaddingTop = '6rem';
         element.current.scrollIntoView({ behavior: 'smooth' });
         document.documentElement.style.scrollPaddingTop = '0';
       }

This keeps behavior the same when the hash is valid, while avoiding crashes on unexpected hashes.

components/navigation/EventPostItem.tsx (1)

23-44: Avoid brittle date comparison and hard‑coded event metadata

  • Lines [23–44]: Comparing currentDate and postDate.format() as strings mixes local time with a hard‑coded UTC suffix and relies on lexicographic ordering. This can misclassify events as past/future around time‑zone boundaries. Prefer moment’s date comparison directly on moment instances, e.g.:
-  const localTime = moment().format('YYYY-MM-DD'); // store localTime
-  const currentDate = `${localTime}T00:00:00.000Z`;
+  const now = moment();

   let active = true;
   const postDate = moment(post.date);
@@
-  } else if (currentDate > postDate.format()) {
-    active = false;
-  }
+  } else if (postDate.isBefore(now, 'day')) {
+    active = false;
+  }
  • Lines [28–34]: title.includes('community' | 'conference' | 'workshop') is case‑sensitive, so titles like “Community Meetup” won’t match. Normalizing once helps:
const normalizedTitle = title.toLowerCase();
if (normalizedTitle.includes('community')) {  }
  • Lines [50–60]: The "150 attending" copy is hard‑coded; if IEvent exposes attendance or similar metadata, it should come from post or be removed to avoid misleading users.

  • Lines [66–75]: For dark mode, consider adding dark:text-white / dark:text-gray-300 to the heading and date/time text, to avoid low contrast against dark backgrounds.

Also applies to: 48-87

components/tools/ToolsCard.tsx (1)

31-49: Avoid stale visible state inside delayed tooltip handlers (and confirm truncation assumptions).

In the Open Source/Commercial pill, onMouseEnter/onMouseLeave use setTimeout with setVisible({ ...visible, desc: true/false }). Because visible is captured when the handler runs, any changes to visible made in the meantime (e.g., from CardData using the same state) can be overwritten when the timeout fires.

To avoid stale state, use functional updates:

-            <div
-              className='...'
-              onMouseEnter={() =>
-                setTimeout(() => {
-                  if (!visible.desc) setVisible({ ...visible, desc: true });
-                }, 400)
-              }
-            >
+            <div
+              className='...'
+              onMouseEnter={() =>
+                setTimeout(() => {
+                  setVisible((prev) =>
+                    prev.desc ? prev : { ...prev, desc: true }
+                  );
+                }, 400)
+              }
+            >
@@
-                onMouseLeave={() =>
-                  setTimeout(() => {
-                    if (visible.desc) setVisible({ ...visible, desc: false });
-                  }, 300)
-                }
+                onMouseLeave={() =>
+                  setTimeout(() => {
+                    setVisible((prev) =>
+                      prev.desc ? { ...prev, desc: false } : prev
+                    );
+                  }, 300)
+                }

Also, isTruncated is currently computed only once on mount (useEffect(..., [])). If toolData.description can change for a mounted card or the layout size changes significantly, consider adding dependencies or recalculating when needed. If the card is strictly static, the mount-only check is fine.

Also applies to: 60-73

components/tools/Filters.tsx (1)

69-105: Remove duplicate techs filter and fix router.push query parameter format.

In handleApplyFilters (lines 84–91), the checkedTechnology filter is set twice. Remove one of these duplicate blocks.

Additionally, at lines 97–100, router.push is called with query: searchParams.toString(). The object form of router.push expects query to be an object map of keys to values, not a string. Pass an object instead:

  • query: { pricing: checkPaid !== 'all' ? checkPaid : undefined, ... } (include only defined filters), or
  • Use the string form: router.push('/tools?' + searchParams.toString(), undefined, { shallow: true }).
♻️ Duplicate comments (2)
components/icons/Lightning.tsx (1)

4-4: Add TypeScript type annotation for props.

Same issue as in components/icons/Terminal.tsx: the className parameter lacks an explicit type annotation.

Apply this diff:

+interface IconLightningProps {
+  className?: string;
+}
+
 /**
  * @description Icon component for Lightning
  */
-export default function IconLightning({ className = '' }) {
+export default function IconLightning({ className = '' }: IconLightningProps) {
   return (
config/meetings.json (1)

9-22: Replace placeholder calendar links with real event data.

The AsyncAPI Design WG Meeting and Governance Board Meeting entries also contain placeholder calLink values (eid=sample2 and eid=sample3 respectively) and generic issue URLs.

These placeholder values must be replaced with actual Google Calendar event IDs and specific GitHub issue URLs before deployment.

🧹 Nitpick comments (33)
components/icons/Clipboard.tsx (2)

4-4: Add TypeScript prop types.

The file has a .tsx extension but the function lacks TypeScript type annotations. Consider adding proper types for the props to improve type safety and developer experience.

Apply this diff to add TypeScript types:

-export default function IconClipboard({ className = '' }) {
+export default function IconClipboard({ className = '' }: { className?: string }) {

6-13: Add accessibility attributes to the SVG icon.

The SVG element lacks accessibility attributes, which can make it difficult for screen reader users to understand its purpose. Consider adding an aria-label or a <title> element to provide an accessible name for the icon.

Apply this diff to add an aria-label:

-    <svg className={className} fill='currentColor' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'>
+    <svg className={className} fill='currentColor' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' aria-label='Clipboard icon'>
       <path d='M9 2a1 1 0 000 2h2a1 1 0 100-2H9z' />

Alternatively, add a <title> element inside the SVG:

export default function IconClipboard({ className = '' }: { className?: string }) {
  return (
    <svg className={className} fill='currentColor' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' role='img'>
      <title>Clipboard icon</title>
      <path d='M9 2a1 1 0 000 2h2a1 1 0 100-2H9z' />
      <path
        fillRule='evenodd'
        d='M4 5a2 2 0 012-2 3 3 0 003 3h2a3 3 0 003-3 2 2 0 012 2v11a2 2 0 01-2 2H6a2 2 0 01-2-2V5zm3 4a1 1 0 000 2h.01a1 1 0 100-2H7zm3 0a1 1 0 000 2h3a1 1 0 100-2h-3zm-3 4a1 1 0 100 2h.01a1 1 0 100-2H7zm3 0a1 1 0 100 2h3a1 1 0 100-2h-3z'
        clipRule='evenodd'
      />
    </svg>
  );
}
components/icons/UsersGroup.tsx (1)

4-10: Add TypeScript type annotation for the className parameter.

The className parameter lacks an explicit type annotation. For consistency and type safety, specify the type as string.

Apply this diff:

-export default function IconUsersGroup({ className = '' }) {
+export default function IconUsersGroup({ className = '' }: { className?: string }) {
components/icons/Book.tsx (1)

4-15: Add TypeScript type annotation for the className parameter.

For type safety and consistency with TypeScript best practices, add an explicit type annotation for the className parameter.

Apply this diff:

-export default function IconBook({ className = '' }) {
+export default function IconBook({ className = '' }: { className?: string }) {
components/icons/Video.tsx (1)

4-10: Add TypeScript type annotation for the className parameter.

For type safety and consistency with TypeScript best practices, add an explicit type annotation for the className parameter.

Apply this diff:

-export default function IconVideo({ className = '' }) {
+export default function IconVideo({ className = '' }: { className?: string }) {
components/icons/Document.tsx (1)

4-4: Add TypeScript interface for props to improve type safety.

The component accepts a className prop but lacks a TypeScript interface definition. This is a common pattern across the new icon components in this PR (Document, CodeBrackets, Gear).

Apply this diff to add type safety:

+interface IconDocumentProps {
+  className?: string;
+}
+
 /**
  * @description Icon component for Document
  */
-export default function IconDocument({ className = '' }) {
+export default function IconDocument({ className = '' }: IconDocumentProps) {
   return (

Consider creating a shared IconProps interface in a types file if this pattern repeats across all icon components.

components/icons/CodeBrackets.tsx (1)

4-4: Add TypeScript interface for props to improve type safety.

Similar to the IconDocument component, this icon lacks a TypeScript interface for its props.

Apply this diff:

+interface IconCodeBracketsProps {
+  className?: string;
+}
+
 /**
  * @description Icon component for Code Brackets
  */
-export default function IconCodeBrackets({ className = '' }) {
+export default function IconCodeBrackets({ className = '' }: IconCodeBracketsProps) {
   return (
components/form/Select.tsx (1)

34-34: Consider extracting long className string for maintainability.

The dark mode classes are correctly implemented, but the className string is becoming quite long (200+ characters), making it harder to read and maintain.

Consider extracting the classes into a constant or using a utility like clsx for better readability:

+const selectClasses = [
+  'form-select h-full pl-2 pr-8 inline-flex justify-center rounded-md',
+  'border border-gray-300 dark:border-gray-700 shadow-sm px-4 py-2',
+  'bg-white dark:bg-dark-card text-sm font-medium',
+  'text-gray-700 dark:text-gray-300',
+  'hover:bg-gray-50 dark:hover:bg-dark-background',
+  'focus:outline-none focus:ring-2 focus:ring-offset-2',
+  'focus:ring-offset-gray-100 dark:focus:ring-offset-dark-background',
+  'focus:ring-primary-500'
+].join(' ');
+
 export default function Select({ className = '', onChange = () => {}, options, selected }: SelectProps) {
   // ...
   return (
     <select
       // ...
-      className={twMerge(
-        `form-select h-full pl-2 pr-8 inline-flex justify-center rounded-md border border-gray-300 dark:border-gray-700 shadow-sm px-4 py-2 bg-white dark:bg-dark-card text-sm font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-dark-background focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-100 dark:focus:ring-offset-dark-background focus:ring-primary-500 ${className}`
-      )}
+      className={twMerge(`${selectClasses} ${className}`)}
components/icons/Gear.tsx (1)

4-4: Add TypeScript interface for props to improve type safety.

Consistent with the other icon components in this PR, this component would benefit from a TypeScript interface for its props.

Apply this diff:

+interface IconGearProps {
+  className?: string;
+}
+
 /**
  * @description Icon component for Gear
  */
-export default function IconGear({ className = '' }) {
+export default function IconGear({ className = '' }: IconGearProps) {
   return (

Alternatively, if you apply the suggestion to create a shared IconProps interface mentioned in the IconDocument review, you can reuse it here.

components/tools/Checkbox.tsx (1)

27-27: Consider extracting the className logic for improved readability.

The className string is quite long and complex with multiple conditionals and dark mode variants, making it harder to read and maintain.

Consider extracting the className logic:

+  const baseClasses = `border ${borderColor} dark:border-secondary-500 ${bgColor} dark:bg-gray-800 ${textColor} dark:text-secondary-400 p-1 pb-0 rounded-2xl flex gap-1 cursor-pointer items-start transition-all duration-200 hover:shadow-md`;
+  const checkedClasses = checked ? `${checkedStateBgColor} dark:bg-secondary-700 ${checkedStateTextColor} dark:text-white` : '';
+
   return (
     <div
-      className={twMerge(
-        `border ${borderColor} dark:border-secondary-500 ${bgColor} dark:bg-gray-800 ${textColor} dark:text-secondary-400 p-1 pb-0 rounded-2xl flex gap-1 cursor-pointer items-start transition-all duration-200 hover:shadow-md ${checked ? `${checkedStateBgColor} dark:bg-secondary-700 ${checkedStateTextColor} dark:text-white` : ''}`
-      )}
+      className={twMerge(`${baseClasses} ${checkedClasses}`)}
components/roadmap/GoalCardRoadmapPage.tsx (1)

18-18: Improve icon contrast in dark mode.

The icon uses text-gray-900 for both light and dark modes. In dark mode, dark text on a dark background (even with the corrected dark:bg-secondary-700) may have insufficient contrast.

Apply this diff to ensure proper contrast:

-          <Icon className='w-8 h-8 text-gray-900 dark:text-gray-900' />
+          <Icon className='w-8 h-8 text-gray-900 dark:text-white' />
components/tools/CategoryDropdown.tsx (1)

21-21: LGTM with optional readability suggestion.

The dark mode styling is comprehensive with proper contrast for background, borders, and shadows. The long className could be split into logical groups for better readability, but this is a minor nitpick.

Optionally, consider grouping related classes:

+      const containerClasses = [
+        'absolute z-10 h-60 w-52 origin-top-right overflow-y-auto',
+        'rounded-lg shadow-xl dark:shadow-2xl',
+        'bg-white dark:bg-dark-card',
+        'ring-1 ring-black/5 dark:ring-gray-700',
+        'border border-gray-200 dark:border-gray-700',
+        'focus:outline-none lg:w-56'
+      ].join(' ');
+
       <div
-        className='absolute z-10 h-60 w-52 origin-top-right overflow-y-auto rounded-lg bg-white dark:bg-dark-card shadow-xl dark:shadow-2xl ring-1 ring-black/5 dark:ring-gray-700 focus:outline-none lg:w-56 border border-gray-200 dark:border-gray-700'
+        className={containerClasses}
components/icons/Terminal.tsx (1)

4-4: Add TypeScript type annotation for props.

The className parameter lacks an explicit type annotation, relying on TypeScript's implicit typing. For better type safety and maintainability, define an interface for the component props.

Apply this diff:

+interface IconTerminalProps {
+  className?: string;
+}
+
 /**
  * @description Icon component for Terminal
  */
-export default function IconTerminal({ className = '' }) {
+export default function IconTerminal({ className = '' }: IconTerminalProps) {
   return (
components/newsroom/NewsroomYoutube.tsx (1)

16-17: Consider making the video count configurable.

The component hard-codes the number of videos to display at 3. While this aligns with the grid layout (lg:grid-cols-3), making this configurable through props would improve reusability.

Example refactor:

 interface NewsroomYoutubeProps {
   className?: string;
+  maxVideos?: number;
 }

-export default function NewsroomYoutube({ className = '' }: NewsroomYoutubeProps) {
+export default function NewsroomYoutube({ className = '', maxVideos = 3 }: NewsroomYoutubeProps) {
   // Only show the first 3 videos
-  const videos = videoData.slice(0, 3);
+  const videos = videoData.slice(0, maxVideos);
components/community/ToolingCard.tsx (2)

19-34: Extract magic numbers to constants for maintainability.

The stacked card backgrounds use multiple hard-coded positioning and rotation values that make the component difficult to maintain and adjust. Consider extracting these values to named constants or configuration objects.

Example refactor:

+const CARD_STACK_CONFIG = {
+  back: { rotate: -12, rotateShuffling: -18, top: -15, left: -45, zIndex: 1 },
+  middle: { rotate: -7, rotateShuffling: -13, top: -10, left: -25, zIndex: 2 }
+};
+
 export default function ToolingCard({ name, description, badge, language, link, isShuffling }: ToolingCardProps) {
   const CardContent = (
     <div className='relative max-w-xl w-full'>
-      {/* Stacked Cards Behind - Positioned on LEFT side */}
       <div
-        className={`absolute w-full h-full bg-gradient-to-br from-purple-200 to-purple-300 
-          dark:from-purple-800/60 dark:to-purple-700/50 rounded-3xl shadow-xl border-4 
-          border-purple-400 dark:border-purple-600 transition-all duration-300 ${
-            isShuffling ? 'transform -rotate-[18deg] translate-x-[-10px]' : 'transform -rotate-[12deg]'
-          }`}
-        style={{ top: '-15px', left: '-45px', zIndex: 1 }}
+        className={`absolute w-full h-full bg-gradient-to-br from-purple-200 to-purple-300 
+          dark:from-purple-800/60 dark:to-purple-700/50 rounded-3xl shadow-xl border-4 
+          border-purple-400 dark:border-purple-600 transition-all duration-300`}
+        style={{ 
+          transform: `rotate(${isShuffling ? CARD_STACK_CONFIG.back.rotateShuffling : CARD_STACK_CONFIG.back.rotate}deg)`,
+          top: `${CARD_STACK_CONFIG.back.top}px`, 
+          left: `${CARD_STACK_CONFIG.back.left}px`, 
+          zIndex: CARD_STACK_CONFIG.back.zIndex 
+        }}
       />

37-37: Consider overflow handling for long content.

The card has a fixed height (h-[520px]) and the description uses flex-grow. If the description text is very long, it could overflow the fixed-height container without any indication or scroll behavior.

Consider adding overflow handling:

-        <div className='relative bg-white dark:bg-dark-card rounded-3xl p-10 shadow-2xl dark:shadow-primary-500/20 overflow-hidden border-4 border-primary-500 dark:border-primary-400 h-[520px] transition-all hover:translate-y-[-4px] hover:shadow-3xl cursor-pointer z-10'>
+        <div className='relative bg-white dark:bg-dark-card rounded-3xl p-10 shadow-2xl dark:shadow-primary-500/20 overflow-hidden border-4 border-primary-500 dark:border-primary-400 h-[520px] transition-all hover:translate-y-[-4px] hover:shadow-3xl cursor-pointer z-10 flex flex-col'>

And on the description:

-          <p className='text-gray-700 dark:text-gray-300 mb-6 leading-relaxed text-base flex-grow'>{description}</p>
+          <p className='text-gray-700 dark:text-gray-300 mb-6 leading-relaxed text-base flex-grow overflow-y-auto'>{description}</p>

Also applies to: 97-97

components/community/TSCMemberCard.tsx (1)

62-94: Consider extracting social icons to separate components.

The inline SVG icons for GitHub, Twitter, and LinkedIn could be extracted into reusable icon components (similar to other icons in the codebase like IconPlus, IconPlay). This would improve maintainability and consistency.

For example, create components/icons/GitHub.tsx, components/icons/Twitter.tsx, and components/icons/LinkedIn.tsx, then import and use them:

import IconGitHub from '../icons/GitHub';
import IconTwitter from '../icons/Twitter';
import IconLinkedIn from '../icons/LinkedIn';

// Then in the JSX:
<IconGitHub className='h-5 w-5' />
<IconTwitter className='h-5 w-5' />
<IconLinkedIn className='h-5 w-5' />
components/community/ToolingsShowcase.tsx (1)

23-32: Consider minor robustness and accessibility tweaks for the tooling selector

Overall component looks solid and the shuffle effect is a nice touch. A few small improvements you might consider:

  • currentTool = toolsData[selectedTool] assumes selectedTool will always exist in toolsData. Today it’s true because state is only set from known tools, but a future refactor or data-driven config could break this. A simple fallback keeps this safe:
-  const currentTool = toolsData[selectedTool];
+  const currentTool = toolsData[selectedTool] ?? toolsData['java-asyncapi'];
+  if (!currentTool) return null;
  • setTimeout in handleToolChange is never cleared. It’s short-lived (300ms), so this is low-risk, but if you want to be defensive you could store the timeout id in a useRef and clear it on unmount / before scheduling a new one.
  • For the tool buttons, exposing selection to assistive tech would help accessibility. Adding aria-pressed={selectedTool === tool.name} (or aria-current="true" on the active one) would make the “currently selected tool” state clearer.

Also applies to: 97-115, 147-161, 164-181

components/community/UpcomingEventsSection.tsx (2)

16-25: Optimize events initialization and guard window.scrollTo

Two small improvements here:

  • useState(getEvents(meetings)) calls getEvents on every render even though React only uses the first result. Switching to a lazy initializer avoids redundant work:
-  const [events] = useState(getEvents(meetings));
+  const [events] = useState(() => getEvents(meetings));
  • window.scrollTo is fine in the browser, but defending against non-DOM environments (tests, Storybook, SSR edge cases) is cheap:
-  const goToPage = (pageNumber: number) => {
-    setCurrentPage(pageNumber);
-    // Scroll to top of events section
-    window.scrollTo({ top: 0, behavior: 'smooth' });
-  };
+  const goToPage = (pageNumber: number) => {
+    setCurrentPage(pageNumber);
+    // Scroll to top of events section
+    if (typeof window !== 'undefined') {
+      window.scrollTo({ top: 0, behavior: 'smooth' });
+    }
+  };

Also applies to: 26-30


32-37: Improve pagination accessibility and use stable keys for events

A couple of small tweaks would make this pagination more robust and accessible:

  • The Prev/Next buttons currently render only < and > text. Screen readers will announce “less than”/“greater than”, which is not ideal. Adding ARIA labels keeps the visuals while improving semantics:
-      <button
+      <button
         key='prev'
         onClick={() => goToPage(currentPage - 1)}
         disabled={currentPage === 1}
         className='...'
         data-testid='Pagination-Prev'
+        aria-label='Previous page'
       >
         &lt;
       </button>
...
-      <button
+      <button
         key='next'
         onClick={() => goToPage(currentPage + 1)}
         disabled={currentPage === totalPages}
         className='...'
         data-testid='Pagination-Next'
+        aria-label='Next page'
       >
         &gt;
       </button>
  • For the events grid, using index as the React key is fragile if the events array ever reorders or changes length. If Event exposes something stable (e.g. id or slug), prefer that:
-            {currentEvents.map((event: Event, index: number) => {
-              return <EventPostItem key={index} id={event.title} post={event} />;
-            })}
+            {currentEvents.map((event: Event) => {
+              const key = event.id ?? event.title;
+              return <EventPostItem key={key} id={event.title} post={event} />;
+            })}

Also applies to: 42-53, 76-92, 94-113, 115-127, 159-162, 166-187

pages/tools/index.tsx (1)

19-21: Tools hero/layout looks good; add rel for the external TextLink

The new hero and page wrapper integrate nicely with dark mode and keep the ToolsDashboard wiring intact. One small hardening point:

  • The TextLink to the GitHub “Tool Documentation” opens in a new tab via target='_blank'. Unless TextLink internally adds rel="noopener noreferrer", it’s safer to include it explicitly to avoid window.opener issues:
-                <TextLink
-                  href='https://github.com/asyncapi/community/blob/master/new-tool-documentation.md'
-                  target='_blank'
+                <TextLink
+                  href='https://github.com/asyncapi/community/blob/master/new-tool-documentation.md'
+                  target='_blank'
+                  rel='noopener noreferrer'
                   className='...'
                 >

Also applies to: 22-33, 55-78

pages/community/index.tsx (1)

117-141: Align heading levels with page semantics for better accessibility

You now have several prominent headings on this page:

  • “AsyncAPI Slack” (HeadingLevel.h1)
  • “AsyncAPI Community Meetings & Events” (HeadingLevel.h2)
  • “Ambassador Programs” (HeadingLevel.h2)
  • “Our Goals, Financials, and Merchandising” (HeadingLevel.h1)

Depending on what the Hero component renders, this may result in multiple h1 elements on a single page. HTML5 allows this, but for accessibility and SEO it’s often clearer to keep a single logical H1 and use H2/H3 for subsequent sections.

Consider:

  • Keeping the main page title/hero as h1.
  • Demoting section titles like “AsyncAPI Slack” and “Our Goals, Financials, and Merchandising” to HeadingLevel.h2 (or h3 where appropriate), while keeping visual size via typeStyle.

Example:

-            <Heading
-              level={HeadingLevel.h1}
+            <Heading
+              level={HeadingLevel.h2}
               typeStyle={HeadingTypeStyle.xl}
               className='text-gray-900 dark:text-dark-heading font-bold'
             >
               AsyncAPI Slack
             </Heading>
...
-          <Heading
-            level={HeadingLevel.h1}
+          <Heading
+            level={HeadingLevel.h2}
             typeStyle={HeadingTypeStyle.lg}
             className='text-gray-900 dark:text-dark-heading font-bold mb-12 text-center lg:text-left'
           >
             Our Goals, Financials, and Merchandising
           </Heading>

This preserves the visual hierarchy while clarifying the semantic structure.

Also applies to: 156-181, 196-239

components/community/Card.tsx (1)

84-107: Large card dark‑mode styling is solid; consider minor class cleanup

The large card’s conditional dark border and background plus dark text on heading/description align well with the rest of the palette, especially the bg === 'bg-code-editor-dark' exception. One small nit: ${!bg && 'border-[#ad20e2] dark:border-primary-400'} will stringify false into the class list when bg is truthy; consider using a helper or bg ? '' : '...' for cleaner output.

components/layout/BlogLayout.tsx (1)

63-77: Check author link color consistency with previous hydration constraints

The author list now conditionally renders <a> elements with className='dark:text-gray-100' inside a parent <p> that already sets text-gray-900 dark:text-gray-100. Functionally this is fine and avoids nested Links, but you might want to explicitly mirror the light-mode color on the anchors (e.g., also set text-gray-900) for consistent styling and to keep behavior uniform with other author renderers that previously ran into hydration issues. Based on learnings.

components/tools/ToolsDashboard.tsx (1)

184-205: Filter/category/search bar dark‑mode and interaction polish look good

The updated classes on the filter button, category dropdown trigger, and search bar (dark borders/backgrounds, font-medium, hover/scale/transition states, and improved focus styles) address the previously noted dark-mode issues, including search icon visibility (dark:opacity-80) and “Clear Filters” readability (dark:text-gray-400 + hover variants). Behavior stays the same, just more usable in dark mode.

Also applies to: 217-221, 227-243

pages/blog/index.tsx (2)

38-49: Filtering, tabs, and pagination state management looks consistent

The combination of activeTab, currentPage, and postsPerPage, plus the two effects that reset currentPage and activeTab on filter changes, is coherent and avoids stale page indices across viewport changes and filter toggles. The hasDropdownFilters guard to give dropdown filters precedence over tabs is also clear and easy to reason about.

If you want to simplify a bit, you can likely drop the setActiveTab('All Posts') inside onFilter (Lines [42–47]) and rely solely on the useEffect watching router.query (Lines [117–121]) to keep tab state in sync with dropdown filters.

Also applies to: 72-92, 94-123


217-241: Refine desktop pagination “Go to page” UX / a11y

  • Lines [299–310]: The <select> is functional but on long lists the native dropdown can feel cramped and may overflow horizontally on smaller viewports. Consider:

    • Adding a minimum width (e.g. min-w-[80px]) so the value and chevron never overlap.
    • If you need to limit visible options (3–4) as per earlier UX feedback, you may want to follow the custom dropdown pattern you implemented on the Case Studies page instead of a native <select>.
  • For accessibility, wiring the “Go to page” label to the select via id/htmlFor or adding aria-label directly on the <select> will make the control clearer to screen readers.

Also applies to: 251-311

pages/roadmap.tsx (1)

515-521: Avoid placeholder href='#' on hero TextLink

The “Any kind of APIs” TextLink (Lines [515–521]) currently points to href='#', which just jumps to the top and doesn’t give users more context.

Consider either:

  • Pointing it to a relevant internal section (e.g., a specs/vision section anchor), or
  • Rendering it as non‑link styled text if there is no target yet.
pages/community/ambassadors/index.tsx (2)

180-195: Add a descriptive title to the YouTube iframe for accessibility

The embedded video iframe (Lines [183–189]) lacks a title attribute, which screen readers rely on to describe the content.

Consider adding a concise title, e.g.:

-              <iframe
-                src='https://www.youtube.com/embed/3rg_7hIb9PQ'
+              <iframe
+                title='AsyncAPI Ambassador Program overview'
+                src='https://www.youtube.com/embed/3rg_7hIb9PQ'

262-281: Double‑check ambassador profile link path

Lines [269–280]: Link uses href={ambassadors/${ambassador.github}} with as set to the same relative string. Depending on your routing setup, this may resolve to /ambassadors/[github] rather than /community/ambassadors/[github], or vice versa.

If the detail page lives under /community/ambassadors/[github].tsx, it’s safer to use an absolute path like:

<Link href={`/community/ambassadors/${ambassador.github}`}>

Please verify the generated URLs in the deploy preview to ensure they match the actual ambassador profile route.

pages/casestudies/index.tsx (1)

222-257: Polish adopters table row clickability and pagination dropdown UX

  • Lines [225–257]: Each adopter row uses cursor-pointer, but only the “Learn More” button inside the Link is actually interactive. Either:

    • Make the whole row clickable by wrapping the row in Link, or
    • Drop cursor-pointer so the pointer cursor doesn’t imply a larger hit area than exists.
  • Lines [248–253]: href={adopter.resources[0]?.link || '#'} means adopters without resources will still render a CTA that navigates to #. Consider conditionally hiding or disabling the button when no resources are available.

  • Lines [315–357]: The custom “Go to page” dropdown nicely addresses the previous overflow issue (max-h-48, scrollable list). For a11y, you might also add:

    • aria-haspopup='listbox' and aria-expanded={isDropdownOpen} on the trigger button.
    • role='listbox'/role='option' on the menu and items, if you want full screen‑reader semantics.

Also applies to: 260-359

pages/community/tsc.tsx (1)

288-390: Pagination logic is overly complex and can render redundant ellipses.

The current set of conditionals for page numbers/ellipses (currentPage > 2 && currentPage < totalPages - 1, currentPage < totalPages && currentPage > 1, plus separate ... blocks) can lead to multiple ellipses and omit intermediate pages in some states, making the control harder to reason about and test.

Given TSC member counts are relatively small, a simpler approach would be to:

  • Render all page numbers in a loop and highlight the active one, or
  • Reuse the same pagination component/logic you use on blog/case-studies to keep behavior consistent.

Example of a simpler pattern:

-              {/* Page Numbers */}
-              {currentPage > 1 && (
-                <button ...>1</button>
-              )}
-              ...
-              {currentPage === totalPages && (
-                <button ...>{totalPages}</button>
-              )}
+              {/* Page Numbers */}
+              {Array.from({ length: totalPages }, (_, i) => i + 1).map((page) => (
+                <button
+                  key={page}
+                  onClick={() => setCurrentPage(page)}
+                  className={
+                    page === currentPage
+                      ? 'w-10 h-10 flex items-center justify-center rounded-md bg-primary-500 text-white font-medium'
+                      : 'w-10 h-10 flex items-center justify-center rounded-md border border-gray-300 dark:border-gray-700 bg-white dark:bg-dark-card hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors'
+                  }
+                  aria-current={page === currentPage ? 'page' : undefined}
+                >
+                  {page}
+                </button>
+              ))}

You can then decide whether ellipses are even necessary here. Also, to address earlier feedback about “Go to page” dropdown overflow, you may want to add a max-h and overflow-y-auto on the <select> to constrain visible options.

components/tools/Filters.tsx (1)

207-207: Use vertical scrolling for dropdown content instead of overflow-x-auto.

The language, technology, and category dropdown panels are declared with overflow-x-auto, but their content lists grow vertically. For long lists, vertical scrolling is what you want; horizontal scrolling is unlikely to ever be needed and may have no effect.

You can make the dropdowns more robust by switching to vertical overflow with a max height, e.g.:

-              <div className='w-auto overflow-x-auto rounded-b-lg border border-gray-400 dark:border-gray-600 bg-gray-200 dark:bg-gray-700 duration-150'>
+              <div className='w-auto max-h-60 overflow-y-auto rounded-b-lg border border-gray-400 dark:border-gray-600 bg-gray-200 dark:bg-gray-700 duration-150'>

(and similarly for the technology and category dropdown containers).

Also applies to: 248-248, 287-287

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 702e050 and d323f1e.

⛔ Files ignored due to path filters (1)
  • public/img/social/woman.jpg is excluded by !**/*.jpg
📒 Files selected for processing (65)
  • CODE_OF_CONDUCT.md (1 hunks)
  • components/AlgoliaSearch.tsx (1 hunks)
  • components/Calendar.tsx (1 hunks)
  • components/CaseStudyCard.tsx (2 hunks)
  • components/community/Card.tsx (2 hunks)
  • components/community/FeatureCard.tsx (1 hunks)
  • components/community/Header.tsx (2 hunks)
  • components/community/HomeCard.tsx (1 hunks)
  • components/community/TSCMemberCard.tsx (1 hunks)
  • components/community/ToolingCard.tsx (1 hunks)
  • components/community/ToolingsShowcase.tsx (1 hunks)
  • components/community/UpcomingEventsSection.tsx (1 hunks)
  • components/dashboard/table/Filters.tsx (1 hunks)
  • components/form/Select.tsx (1 hunks)
  • components/icons/Book.tsx (1 hunks)
  • components/icons/Clipboard.tsx (1 hunks)
  • components/icons/CodeBrackets.tsx (1 hunks)
  • components/icons/Document.tsx (1 hunks)
  • components/icons/Gear.tsx (1 hunks)
  • components/icons/LightBulb.tsx (1 hunks)
  • components/icons/Lightning.tsx (1 hunks)
  • components/icons/Microphone.tsx (1 hunks)
  • components/icons/Newsroom.tsx (1 hunks)
  • components/icons/Play.tsx (1 hunks)
  • components/icons/Plus.tsx (1 hunks)
  • components/icons/Star.tsx (1 hunks)
  • components/icons/Terminal.tsx (1 hunks)
  • components/icons/UsersGroup.tsx (1 hunks)
  • components/icons/Video.tsx (1 hunks)
  • components/layout/BlogLayout.tsx (2 hunks)
  • components/layout/GenericLayout.tsx (1 hunks)
  • components/navigation/BlogPostItem.tsx (2 hunks)
  • components/navigation/DocsNav.tsx (1 hunks)
  • components/navigation/EventPostItem.tsx (1 hunks)
  • components/navigation/Filter.tsx (1 hunks)
  • components/navigation/communityItems.tsx (1 hunks)
  • components/newsroom/NewsroomBlogPosts.tsx (2 hunks)
  • components/newsroom/NewsroomSection.tsx (1 hunks)
  • components/newsroom/NewsroomYoutube.tsx (1 hunks)
  • components/newsroom/YouTubeCard.tsx (1 hunks)
  • components/roadmap/GoalCardRoadmapPage.tsx (1 hunks)
  • components/roadmap/RoadmapColumn.tsx (2 hunks)
  • components/roadmap/RoadmapItem.tsx (2 hunks)
  • components/roadmap/RoadmapPill.tsx (2 hunks)
  • components/tools/CategoryDropdown.tsx (2 hunks)
  • components/tools/Checkbox.tsx (1 hunks)
  • components/tools/Filters.tsx (9 hunks)
  • components/tools/FiltersDisplay.tsx (1 hunks)
  • components/tools/Toggle.tsx (1 hunks)
  • components/tools/ToolsCard.tsx (8 hunks)
  • components/tools/ToolsDashboard.tsx (4 hunks)
  • components/tools/ToolsList.tsx (1 hunks)
  • config/meetings.json (1 hunks)
  • next-env.d.ts (1 hunks)
  • pages/blog/index.tsx (3 hunks)
  • pages/casestudies/index.tsx (2 hunks)
  • pages/community/ambassadors/index.tsx (3 hunks)
  • pages/community/events-and-updates.tsx (1 hunks)
  • pages/community/index.tsx (2 hunks)
  • pages/community/tsc.tsx (1 hunks)
  • pages/roadmap.tsx (4 hunks)
  • pages/tools/index.tsx (1 hunks)
  • styles/globals.css (4 hunks)
  • types/components/navigation/BlogPostType.ts (1 hunks)
  • types/pages/community/Community.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (13)
📓 Common learnings
Learnt from: asyncapi-bot
Repo: asyncapi/website PR: 0
File: :0-0
Timestamp: 2025-02-18T12:07:42.211Z
Learning: The following PR commands are supported in the asyncapi/website repository:
- `/please-take-a-look` or `/ptal`: Requests attention from reviewers who haven't reviewed the PR
- `/ready-to-merge` or `/rtm`: Triggers automerge when all conditions are met
- `/do-not-merge` or `/dnm`: Blocks automerge even if all conditions are met
- `/autoupdate` or `/au`: Adds autoupdate label to keep PR in sync with target branch
- `/update` or `/u`: One-time update of PR with latest changes from target branch
📚 Learning: 2024-10-11T11:17:32.246Z
Learnt from: akshatnema
Repo: asyncapi/website PR: 3262
File: components/navigation/BlogPostItem.tsx:80-87
Timestamp: 2024-10-11T11:17:32.246Z
Learning: In the `BlogPostItem` component, the parent `Link` wraps the entire content, so inner `Link` components around the title and excerpt are unnecessary.

Applied to files:

  • components/newsroom/NewsroomBlogPosts.tsx
  • components/navigation/EventPostItem.tsx
  • components/layout/BlogLayout.tsx
  • components/newsroom/YouTubeCard.tsx
  • components/navigation/BlogPostItem.tsx
📚 Learning: 2024-10-11T11:32:30.226Z
Learnt from: akshatnema
Repo: asyncapi/website PR: 3262
File: components/navigation/BlogPostItem.tsx:95-119
Timestamp: 2024-10-11T11:32:30.226Z
Learning: In the `BlogPostItem` component (`components/navigation/BlogPostItem.tsx`), nesting `<a>` tags inside the parent `Link` component leads to hydration issues; therefore, we should avoid nesting `<a>` tags inside `Link` components in this component.

Applied to files:

  • components/newsroom/NewsroomBlogPosts.tsx
  • components/community/Card.tsx
  • pages/blog/index.tsx
  • components/navigation/EventPostItem.tsx
  • components/CaseStudyCard.tsx
  • pages/casestudies/index.tsx
  • components/layout/BlogLayout.tsx
  • components/newsroom/YouTubeCard.tsx
  • components/navigation/BlogPostItem.tsx
📚 Learning: 2024-10-11T10:46:58.882Z
Learnt from: akshatnema
Repo: asyncapi/website PR: 3262
File: components/Avatar.tsx:35-44
Timestamp: 2024-10-11T10:46:58.882Z
Learning: In Next.js, when avoiding nested `<a>` tags due to hydration issues, use accessible non-link elements like `<button>` or `<span>` with appropriate roles, `tabIndex`, and event handlers to maintain accessibility and SEO.

Applied to files:

  • components/community/Card.tsx
  • components/newsroom/NewsroomSection.tsx
  • pages/community/ambassadors/index.tsx
  • components/CaseStudyCard.tsx
  • pages/casestudies/index.tsx
  • components/navigation/BlogPostItem.tsx
📚 Learning: 2024-10-11T07:38:35.745Z
Learnt from: akshatnema
Repo: asyncapi/website PR: 3262
File: components/newsroom/FeaturedBlogPost.tsx:90-92
Timestamp: 2024-10-11T07:38:35.745Z
Learning: In Next.js, nested `<a>` tags cause hydration issues due to invalid HTML. To fix this, avoid nesting `<a>` tags by replacing inner `<a>` tags with non-interactive elements like `<span>`, and use click handlers to maintain interactivity if needed.

Applied to files:

  • components/community/Card.tsx
  • pages/community/ambassadors/index.tsx
  • components/CaseStudyCard.tsx
  • pages/casestudies/index.tsx
  • components/roadmap/RoadmapPill.tsx
  • components/navigation/BlogPostItem.tsx
📚 Learning: 2025-05-09T17:35:57.171Z
Learnt from: TRohit20
Repo: asyncapi/website PR: 4107
File: markdown/docs/tools/studio/architecture.md:23-23
Timestamp: 2025-05-09T17:35:57.171Z
Learning: In the AsyncAPI Studio architecture documentation, "Layer Breakdown" is intentionally structured as an H3 heading (subsection) because it provides additional detail about the layered architecture pattern introduced earlier, rather than being a standalone main section.

Applied to files:

  • components/community/Header.tsx
📚 Learning: 2024-11-11T21:30:32.478Z
Learnt from: amanbhoria
Repo: asyncapi/website PR: 3373
File: components/AlgoliaSearch.tsx:313-313
Timestamp: 2024-11-11T21:30:32.478Z
Learning: In the `SearchButton` component within `components/AlgoliaSearch.tsx`, if the component re-renders on every button click and the `useEffect` runs accordingly, adding dependencies to the dependency array might not be necessary.

Applied to files:

  • components/navigation/DocsNav.tsx
  • components/dashboard/table/Filters.tsx
  • components/AlgoliaSearch.tsx
  • components/navigation/Filter.tsx
📚 Learning: 2025-01-18T08:44:43.614Z
Learnt from: akshatnema
Repo: asyncapi/website PR: 3423
File: tests/index.test.js:2-7
Timestamp: 2025-01-18T08:44:43.614Z
Learning: In the AsyncAPI website project, JavaScript test files must include the .ts extension when importing TypeScript files (e.g., `require('../scripts/build-rss.ts')`). This is enforced by the project's configuration which uses `moduleResolution: "bundler"` in tsconfig.json and TypeScript-aware ESLint plugins. The .ts extensions are required even though the files are imported using CommonJS require statements.

Applied to files:

  • next-env.d.ts
📚 Learning: 2025-04-20T16:05:16.482Z
Learnt from: anshgoyalevil
Repo: asyncapi/website PR: 3950
File: scripts/utils/check-locales.ts:122-129
Timestamp: 2025-04-20T16:05:16.482Z
Learning: In the AsyncAPI website project, Next.js throws errors at runtime when locale files are missing, making additional validation for missing files unnecessary in the check-locales script.

Applied to files:

  • next-env.d.ts
📚 Learning: 2025-01-18T08:44:43.614Z
Learnt from: akshatnema
Repo: asyncapi/website PR: 3423
File: tests/index.test.js:2-7
Timestamp: 2025-01-18T08:44:43.614Z
Learning: In the AsyncAPI website project, JavaScript test files must include the .ts extension when importing TypeScript files (e.g., `require('../scripts/build-rss.ts')`). This is a project-specific requirement enforced by the linting rules and build setup, even though it differs from typical Node.js behavior.

Applied to files:

  • next-env.d.ts
📚 Learning: 2025-06-03T06:48:09.304Z
Learnt from: iambami
Repo: asyncapi/website PR: 4111
File: markdown/blog/community-spotlight-aayush.md:3-3
Timestamp: 2025-06-03T06:48:09.304Z
Learning: For AsyncAPI community spotlight blog posts, the frontmatter date should reflect the actual publication date, not the month being highlighted in the spotlight. For example, a "May Community Spotlight" can be published in June with a June date in the frontmatter.

Applied to files:

  • components/navigation/EventPostItem.tsx
📚 Learning: 2025-06-10T06:27:25.419Z
Learnt from: aminoxix
Repo: asyncapi/website PR: 4127
File: components/layout/CommunityLayout.tsx:179-179
Timestamp: 2025-06-10T06:27:25.419Z
Learning: In AsyncAPI's community data structure, ambassadors and TSC members are guaranteed to have GitHub accounts. The `github` field is required in both `Ambassador` and `Tsc` interfaces, and the data processing in `addAdditionalUserInfo()` converts GitHub usernames to full URLs, ensuring safe string operations when extracting usernames from URLs.

Applied to files:

  • types/pages/community/Community.ts
📚 Learning: 2024-10-11T07:27:53.362Z
Learnt from: akshatnema
Repo: asyncapi/website PR: 3262
File: components/newsroom/FeaturedBlogPost.tsx:90-92
Timestamp: 2024-10-11T07:27:53.362Z
Learning: Using anchor tags for author names in 'FeaturedBlogPost' component leads to hydration issues on the website.

Applied to files:

  • components/layout/BlogLayout.tsx
  • components/navigation/BlogPostItem.tsx
🪛 LanguageTool
CODE_OF_CONDUCT.md

[style] ~31-~31: ‘on the basis of’ might be wordy. Consider a shorter alternative.
Context: ...rizing anyone’s personality or behavior on the basis of immutable identities or traits. 4. **Se...

(EN_WORDINESS_PREMIUM_ON_THE_BASIS_OF)


[style] ~53-~53: In some texts, you can shorten this phrase. Consider using “email us”.
Context: ...f_conduct). - Or, if you’d prefer, just send us an email at [email protected]. Community...

(SEND_PRP_AN_EMAIL)


[style] ~55-~55: Consider a more concise word here.
Context: ...rioritizing safety and confidentiality. In order to honor these values, enforcement actions...

(IN_ORDER_TO_PREMIUM)


[style] ~81-~81: ‘in keeping with’ might be wordy. Consider a shorter alternative.
Context: ...s to use their discretion and judgment, in keeping with the best interests of our community. ...

(EN_WORDINESS_PREMIUM_IN_KEEPING_WITH)

🪛 markdownlint-cli2 (0.18.1)
CODE_OF_CONDUCT.md

53-53: Bare URL used

(MD034, no-bare-urls)


- Join our [AsyncAPI Slack](https://asyncapi.com/slack-invite) and share your report in the `#coc` channel.
- Reach out directly to any member of the [Code of Conduct Committee](https://github.com/orgs/asyncapi/teams/code_of_conduct).
- Or, if you’d prefer, just send us an email at **[email protected]**.
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Format email address as a proper markdown link.

The email address should be formatted as a link to comply with markdown best practices and improve user experience.

Apply this diff:

-- Or, if you'd prefer, just send us an email at **[email protected]**.
+- Or, if you'd prefer, just send us an email at [[email protected]](mailto:[email protected]).
📝 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
- Or, if youd prefer, just send us an email at **[email protected]**.
- Or, if you'd prefer, just send us an email at [[email protected]](mailto:[email protected]).
🧰 Tools
🪛 LanguageTool

[style] ~53-~53: In some texts, you can shorten this phrase. Consider using “email us”.
Context: ...f_conduct). - Or, if you’d prefer, just send us an email at [email protected]. Community...

(SEND_PRP_AN_EMAIL)

🪛 markdownlint-cli2 (0.18.1)

53-53: Bare URL used

(MD034, no-bare-urls)

🤖 Prompt for AI Agents
In CODE_OF_CONDUCT.md around line 53, the email address is plain text; change it
to a proper Markdown mailto link by replacing the text with
[[email protected]](mailto:[email protected]) so it renders as a clickable
email link in Markdown.

Comment on lines +46 to +81
<div className='absolute -bottom-40 -left-32 w-[700px] h-[500px]'>
<svg viewBox='0 0 500 500' xmlns='http://www.w3.org/2000/svg' className='w-full h-full'>
<defs>
<linearGradient id='blueGradient' x1='20%' y1='80%' x2='80%' y2='20%'>
<stop
offset='0%'
className='text-primary-500 dark:text-primary-600'
stopColor='currentColor'
stopOpacity='0.9'
/>
<stop
offset='40%'
className='text-blue-400 dark:text-blue-500'
stopColor='currentColor'
stopOpacity='0.85'
/>
<stop
offset='100%'
className='text-cyan-400 dark:text-cyan-600'
stopColor='currentColor'
stopOpacity='0.8'
/>
</linearGradient>
</defs>
{/* Fan/Petal shape spreading from bottom left */}
<path
fill='url(#blueGradient)'
d='M 50 450 Q 150 350 280 320 Q 400 300 480 340 Q 500 380 470 420
Q 440 460 380 480 Q 280 500 180 490 Q 100 480 50 450 Z
M 60 440 Q 140 380 240 360 Q 320 350 380 380
L 320 420 Q 240 400 160 430 Z
M 80 430 Q 150 390 220 380 Q 280 375 320 395
L 280 420 Q 220 410 160 425 Z'
/>
</svg>
</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add accessibility attributes to decorative SVG.

The large decorative SVG element (fan/petal shape) should be marked as presentational to prevent screen readers from attempting to parse it.

Apply this diff:

         <div className='absolute -bottom-40 -left-32 w-[700px] h-[500px]'>
-          <svg viewBox='0 0 500 500' xmlns='http://www.w3.org/2000/svg' className='w-full h-full'>
+          <svg viewBox='0 0 500 500' xmlns='http://www.w3.org/2000/svg' className='w-full h-full' aria-hidden='true' role='presentation'>
             <defs>
📝 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 className='absolute -bottom-40 -left-32 w-[700px] h-[500px]'>
<svg viewBox='0 0 500 500' xmlns='http://www.w3.org/2000/svg' className='w-full h-full'>
<defs>
<linearGradient id='blueGradient' x1='20%' y1='80%' x2='80%' y2='20%'>
<stop
offset='0%'
className='text-primary-500 dark:text-primary-600'
stopColor='currentColor'
stopOpacity='0.9'
/>
<stop
offset='40%'
className='text-blue-400 dark:text-blue-500'
stopColor='currentColor'
stopOpacity='0.85'
/>
<stop
offset='100%'
className='text-cyan-400 dark:text-cyan-600'
stopColor='currentColor'
stopOpacity='0.8'
/>
</linearGradient>
</defs>
{/* Fan/Petal shape spreading from bottom left */}
<path
fill='url(#blueGradient)'
d='M 50 450 Q 150 350 280 320 Q 400 300 480 340 Q 500 380 470 420
Q 440 460 380 480 Q 280 500 180 490 Q 100 480 50 450 Z
M 60 440 Q 140 380 240 360 Q 320 350 380 380
L 320 420 Q 240 400 160 430 Z
M 80 430 Q 150 390 220 380 Q 280 375 320 395
L 280 420 Q 220 410 160 425 Z'
/>
</svg>
</div>
<div className='absolute -bottom-40 -left-32 w-[700px] h-[500px]'>
<svg viewBox='0 0 500 500' xmlns='http://www.w3.org/2000/svg' className='w-full h-full' aria-hidden='true' role='presentation'>
<defs>
<linearGradient id='blueGradient' x1='20%' y1='80%' x2='80%' y2='20%'>
<stop
offset='0%'
className='text-primary-500 dark:text-primary-600'
stopColor='currentColor'
stopOpacity='0.9'
/>
<stop
offset='40%'
className='text-blue-400 dark:text-blue-500'
stopColor='currentColor'
stopOpacity='0.85'
/>
<stop
offset='100%'
className='text-cyan-400 dark:text-cyan-600'
stopColor='currentColor'
stopOpacity='0.8'
/>
</linearGradient>
</defs>
{/* Fan/Petal shape spreading from bottom left */}
<path
fill='url(#blueGradient)'
d='M 50 450 Q 150 350 280 320 Q 400 300 480 340 Q 500 380 470 420
Q 440 460 380 480 Q 280 500 180 490 Q 100 480 50 450 Z
M 60 440 Q 140 380 240 360 Q 320 350 380 380
L 320 420 Q 240 400 160 430 Z
M 80 430 Q 150 390 220 380 Q 280 375 320 395
L 280 420 Q 220 410 160 425 Z'
/>
</svg>
</div>
🤖 Prompt for AI Agents
In components/community/ToolingCard.tsx around lines 46 to 81, the decorative
SVG should be marked presentational so screen readers ignore it; update the
<svg> element to include accessibility attributes (e.g., role="presentation",
aria-hidden="true", and focusable="false") so it is excluded from the
accessibility tree and not keyboard-focusable while leaving visual output
unchanged.

Comment on lines +14 to +17
<div
key={member.github}
className='bg-white dark:bg-dark-card rounded-xl border border-gray-200 dark:border-gray-700 p-6 hover:shadow-lg transition-shadow'
>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Remove key prop from component root.

The key prop on line 15 should be applied by the parent component when rendering a list of TSCMemberCard components, not within the component itself. React keys are used by the parent to identify elements in a collection.

Apply this diff:

   return (
     <div
-      key={member.github}
       className='bg-white dark:bg-dark-card rounded-xl border border-gray-200 dark:border-gray-700 p-6 hover:shadow-lg transition-shadow'
     >
📝 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
key={member.github}
className='bg-white dark:bg-dark-card rounded-xl border border-gray-200 dark:border-gray-700 p-6 hover:shadow-lg transition-shadow'
>
<div
className='bg-white dark:bg-dark-card rounded-xl border border-gray-200 dark:border-gray-700 p-6 hover:shadow-lg transition-shadow'
>
🤖 Prompt for AI Agents
In components/community/TSCMemberCard.tsx around lines 14 to 17, the root div
currently includes a key={member.github} which should be removed because keys
must be set by the parent when rendering lists; delete the key prop from the
component's root element and ensure any list rendering of TSCMemberCard in the
parent passes key={member.github} (or another stable identifier) instead.


{member.reposList && member.reposList.length > 0 && (
<div className='mb-4'>
<p className='text-xs text-gray-500 dark:text-gray-500 mb-2'>Maintainer of:</p>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Verify contrast for "Maintainer of:" label in dark mode.

The label uses text-gray-500 in both light and dark modes. In dark mode, gray-500 may not provide sufficient contrast against the dark background. Consider using a lighter shade for dark mode.

Apply this diff to improve dark mode contrast:

-          <p className='text-xs text-gray-500 dark:text-gray-500 mb-2'>Maintainer of:</p>
+          <p className='text-xs text-gray-500 dark:text-gray-400 mb-2'>Maintainer of:</p>
📝 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
<p className='text-xs text-gray-500 dark:text-gray-500 mb-2'>Maintainer of:</p>
<p className='text-xs text-gray-500 dark:text-gray-400 mb-2'>Maintainer of:</p>
🤖 Prompt for AI Agents
In components/community/TSCMemberCard.tsx around line 35, the label uses the
same text-gray-500 for both light and dark modes which may fail contrast in dark
mode; update the className to keep text-gray-500 for light but add a lighter
dark variant (for example dark:text-gray-300 or dark:text-gray-400) so the label
is readable on dark backgrounds, then verify the change with the app in dark
mode and ensure it meets contrast requirements.

Comment on lines +54 to +95
<div className='flex gap-3 pt-4 border-t border-gray-200 dark:border-gray-700'>
{member.githubUrl && (
<a
href={member.githubUrl}
target='_blank'
rel='noreferrer'
className='text-gray-600 dark:text-gray-400 hover:!text-primary-500 dark:hover:!text-primary-500 transition-colors'
>
<svg className='h-5 w-5' fill='currentColor' viewBox='0 0 20 20'>
<path
fillRule='evenodd'
d='M10 0C4.477 0 0 4.484 0 10.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0110 4.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.203 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.942.359.31.678.921.678 1.856 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0020 10.017C20 4.484 15.522 0 10 0z'
clipRule='evenodd'
/>
</svg>
</a>
)}
{member.twitterUrl && (
<a
href={member.twitterUrl}
target='_blank'
rel='noreferrer'
className='text-gray-600 dark:text-gray-400 hover:!text-primary-500 dark:hover:!text-primary-500 transition-colors'
>
<svg className='h-5 w-5' fill='currentColor' viewBox='0 0 20 20'>
<path d='M6.29 18.251c7.547 0 11.675-6.253 11.675-11.675 0-.178 0-.355-.012-.53A8.348 8.348 0 0020 3.92a8.19 8.19 0 01-2.357.646 4.118 4.118 0 001.804-2.27 8.224 8.224 0 01-2.605.996 4.107 4.107 0 00-6.993 3.743 11.65 11.65 0 01-8.457-4.287 4.106 4.106 0 001.27 5.477A4.073 4.073 0 01.8 7.713v.052a4.105 4.105 0 003.292 4.022 4.095 4.095 0 01-1.853.07 4.108 4.108 0 003.834 2.85A8.233 8.233 0 010 16.407a11.616 11.616 0 006.29 1.84' />
</svg>
</a>
)}
{member.linkedinUrl && (
<a
href={member.linkedinUrl}
target='_blank'
rel='noreferrer'
className='text-gray-600 dark:text-gray-400 hover:!text-primary-500 dark:hover:!text-primary-500 transition-colors'
>
<svg className='h-5 w-5' fill='currentColor' viewBox='0 0 20 20'>
<path d='M16.338 16.338H13.67V12.16c0-.995-.017-2.277-1.387-2.277-1.39 0-1.601 1.086-1.601 2.207v4.248H8.014v-8.59h2.559v1.174h.037c.356-.675 1.227-1.387 2.526-1.387 2.703 0 3.203 1.778 3.203 4.092v4.711zM5.005 6.575a1.548 1.548 0 11-.003-3.096 1.548 1.548 0 01.003 3.096zm-1.337 9.763H6.34v-8.59H3.667v8.59zM17.668 1H2.328C1.595 1 1 1.581 1 2.298v15.403C1 18.418 1.595 19 2.328 19h15.34c.734 0 1.332-.582 1.332-1.299V2.298C19 1.581 18.402 1 17.668 1z' />
</svg>
</a>
)}
</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add accessibility labels to social links.

The social links lack aria-label attributes, which would improve screen reader accessibility by providing clear labels for each link type.

Apply this diff to add aria-labels:

         {member.githubUrl && (
           <a
             href={member.githubUrl}
             target='_blank'
             rel='noreferrer'
+            aria-label='GitHub profile'
             className='text-gray-600 dark:text-gray-400 hover:!text-primary-500 dark:hover:!text-primary-500 transition-colors'
           >
             <svg className='h-5 w-5' fill='currentColor' viewBox='0 0 20 20'>
         {member.twitterUrl && (
           <a
             href={member.twitterUrl}
             target='_blank'
             rel='noreferrer'
+            aria-label='Twitter profile'
             className='text-gray-600 dark:text-gray-400 hover:!text-primary-500 dark:hover:!text-primary-500 transition-colors'
           >
             <svg className='h-5 w-5' fill='currentColor' viewBox='0 0 20 20'>
         {member.linkedinUrl && (
           <a
             href={member.linkedinUrl}
             target='_blank'
             rel='noreferrer'
+            aria-label='LinkedIn profile'
             className='text-gray-600 dark:text-gray-400 hover:!text-primary-500 dark:hover:!text-primary-500 transition-colors'
           >
             <svg className='h-5 w-5' fill='currentColor' viewBox='0 0 20 20'>
🤖 Prompt for AI Agents
In components/community/TSCMemberCard.tsx around lines 54 to 95, the social
anchor links are missing aria-labels; add descriptive aria-label attributes to
each <a> so screen readers can announce them (e.g. aria-label={`${member.name ||
'Member'} on GitHub`}, aria-label={`${member.name || 'Member'} on Twitter`},
aria-label={`${member.name || 'Member'} on LinkedIn`}); keep existing
target/rel/className intact and ensure the fallback when member.name is
undefined is used to avoid runtime errors.

Comment on lines +119 to +166
{/* Upcoming Events Section */}
<div className='bg-secondary-200 rounded-3xl dark:bg-dark-card'>
<Container wide className='py-20'>
<div className='text-center'>
<Heading level={HeadingLevel.h2} typeStyle={HeadingTypeStyle.lg} className='mb-4 text-gray-900'>
Upcoming Events
</Heading>
<Paragraph
typeStyle={ParagraphTypeStyle.md}
className='mx-auto mb-12 max-w-2xl dark:text-gray-400 text-gray-600'
>
Don&apos;t miss out on these amazing community gatherings
</Paragraph>
</div>

<div className='mt-12 lg:flex lg:flex-row-reverse lg:items-center lg:gap-12'>
<section className='mt-10 lg:mt-0 lg:flex-1'>
<Calendar size={2} />
</section>
<section className='mt-10 lg:mt-0 lg:max-w-xl lg:text-left'>
<div>
<Heading level={HeadingLevel.h3} typeStyle={HeadingTypeStyle.mdSemibold} className='text-gray-900'>
Join AsyncAPI meetings
</Heading>
<Paragraph typeStyle={ParagraphTypeStyle.md} className='mt-4 dark:text-gray-400 text-gray-600'>
We meet every week to discuss the future of AsyncAPI and event-driven architectures. Join us to share
your ideas, ask questions, and connect with the community.{' '}
<TextLink href='/community/meetings' className='text-indigo-600 hover:text-indigo-700'>
Learn more about our meetings
</TextLink>
</Paragraph>
<ul className='mt-8 flex flex-wrap justify-center gap-3 lg:justify-start'>
<li>
<GoogleCalendarButton href='https://calendar.google.com/calendar/u/3?cid=Y19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bncm91cC5jYWxlbmRhci5nb29nbGUuY29t' />
</li>
<li>
<SubscribeButton href='/community/meetings' />
</li>
<li>
<ICSFileButton href='https://calendar.google.com/calendar/ical/c_q9tseiglomdsj6njuhvbpts11c%40group.calendar.google.com/public/basic.ics' />
</li>
</ul>
</div>
</section>
</div>
</Container>
</div>

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix dark‑mode contrast in “Upcoming Events” section

This block uses bg-secondary-200 rounded-3xl dark:bg-dark-card, but key text still forces light-mode colors only:

  • Heading “Upcoming Events” (Line 123) uses text-gray-900 with no dark: override on a dark card.
  • Subheading “Join AsyncAPI meetings” (Line 140) likewise uses text-gray-900.
  • The inline TextLink (Line 146) keeps text-indigo-600 hover:text-indigo-700 only.

In dark mode those colors will be low-contrast against dark:bg-dark-card, especially the heading and link. Consider adding dark variants, e.g.:

- <Heading ... className='mb-4 text-gray-900'>
+ <Heading ... className='mb-4 text-gray-900 dark:text-dark-heading'>

- <Heading ... className='text-gray-900'>
+ <Heading ... className='text-gray-900 dark:text-dark-heading'>

- <TextLink ... className='text-indigo-600 hover:text-indigo-700'>
+ <TextLink ... className='text-indigo-400 hover:text-indigo-300 dark:text-indigo-300 dark:hover:text-indigo-200'>

This should address the previously reported dark-mode readability issues for events titles/links.

📝 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
{/* Upcoming Events Section */}
<div className='bg-secondary-200 rounded-3xl dark:bg-dark-card'>
<Container wide className='py-20'>
<div className='text-center'>
<Heading level={HeadingLevel.h2} typeStyle={HeadingTypeStyle.lg} className='mb-4 text-gray-900'>
Upcoming Events
</Heading>
<Paragraph
typeStyle={ParagraphTypeStyle.md}
className='mx-auto mb-12 max-w-2xl dark:text-gray-400 text-gray-600'
>
Don&apos;t miss out on these amazing community gatherings
</Paragraph>
</div>
<div className='mt-12 lg:flex lg:flex-row-reverse lg:items-center lg:gap-12'>
<section className='mt-10 lg:mt-0 lg:flex-1'>
<Calendar size={2} />
</section>
<section className='mt-10 lg:mt-0 lg:max-w-xl lg:text-left'>
<div>
<Heading level={HeadingLevel.h3} typeStyle={HeadingTypeStyle.mdSemibold} className='text-gray-900'>
Join AsyncAPI meetings
</Heading>
<Paragraph typeStyle={ParagraphTypeStyle.md} className='mt-4 dark:text-gray-400 text-gray-600'>
We meet every week to discuss the future of AsyncAPI and event-driven architectures. Join us to share
your ideas, ask questions, and connect with the community.{' '}
<TextLink href='/community/meetings' className='text-indigo-600 hover:text-indigo-700'>
Learn more about our meetings
</TextLink>
</Paragraph>
<ul className='mt-8 flex flex-wrap justify-center gap-3 lg:justify-start'>
<li>
<GoogleCalendarButton href='https://calendar.google.com/calendar/u/3?cid=Y19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bncm91cC5jYWxlbmRhci5nb29nbGUuY29t' />
</li>
<li>
<SubscribeButton href='/community/meetings' />
</li>
<li>
<ICSFileButton href='https://calendar.google.com/calendar/ical/c_q9tseiglomdsj6njuhvbpts11c%40group.calendar.google.com/public/basic.ics' />
</li>
</ul>
</div>
</section>
</div>
</Container>
</div>
{/* Upcoming Events Section */}
<div className='bg-secondary-200 rounded-3xl dark:bg-dark-card'>
<Container wide className='py-20'>
<div className='text-center'>
<Heading level={HeadingLevel.h2} typeStyle={HeadingTypeStyle.lg} className='mb-4 text-gray-900 dark:text-dark-heading'>
Upcoming Events
</Heading>
<Paragraph
typeStyle={ParagraphTypeStyle.md}
className='mx-auto mb-12 max-w-2xl dark:text-gray-400 text-gray-600'
>
Don&apos;t miss out on these amazing community gatherings
</Paragraph>
</div>
<div className='mt-12 lg:flex lg:flex-row-reverse lg:items-center lg:gap-12'>
<section className='mt-10 lg:mt-0 lg:flex-1'>
<Calendar size={2} />
</section>
<section className='mt-10 lg:mt-0 lg:max-w-xl lg:text-left'>
<div>
<Heading level={HeadingLevel.h3} typeStyle={HeadingTypeStyle.mdSemibold} className='text-gray-900 dark:text-dark-heading'>
Join AsyncAPI meetings
</Heading>
<Paragraph typeStyle={ParagraphTypeStyle.md} className='mt-4 dark:text-gray-400 text-gray-600'>
We meet every week to discuss the future of AsyncAPI and event-driven architectures. Join us to share
your ideas, ask questions, and connect with the community.{' '}
<TextLink href='/community/meetings' className='text-indigo-600 hover:text-indigo-700 dark:text-indigo-300 dark:hover:text-indigo-200'>
Learn more about our meetings
</TextLink>
</Paragraph>
<ul className='mt-8 flex flex-wrap justify-center gap-3 lg:justify-start'>
<li>
<GoogleCalendarButton href='https://calendar.google.com/calendar/u/3?cid=Y19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bncm91cC5jYWxlbmRhci5nb29nbGUuY29t' />
</li>
<li>
<SubscribeButton href='/community/meetings' />
</li>
<li>
<ICSFileButton href='https://calendar.google.com/calendar/ical/c_q9tseiglomdsj6njuhvbpts11c%40group.calendar.google.com/public/basic.ics' />
</li>
</ul>
</div>
</section>
</div>
</Container>
</div>
🤖 Prompt for AI Agents
pages/community/events-and-updates.tsx lines 119-166: headings and link lack
dark-mode color variants causing poor contrast on dark:bg-dark-card; update the
Heading at line 123 and the Heading at line 140 to include dark: text classes
(e.g., replace or augment text-gray-900 with text-gray-900 dark:text-gray-100 or
dark:text-gray-50), and update the inline TextLink at line 146 to include dark
variants for normal and hover states (e.g., text-indigo-600
hover:text-indigo-700 dark:text-indigo-400 hover:dark:text-indigo-300); ensure
any other hardcoded light colors in this block are given appropriate dark:
counterparts to restore sufficient contrast.

Comment on lines +167 to +190
{/* From the Blogs Section */}
<div className='bg-white dark:bg-dark-background'>
<Container wide className='py-20' data-testid='EventsAndUpdates-Blogs'>
<div className='mb-12 flex flex-col items-start justify-between gap-4 sm:flex-row sm:items-center'>
<div>
<Heading level={HeadingLevel.h2} typeStyle={HeadingTypeStyle.lg} className='mb-2 text-gray-900'>
From the Blogs
</Heading>
<Paragraph typeStyle={ParagraphTypeStyle.md} className='text-gray-600'>
Stay connected with the pulse of our community
</Paragraph>
</div>
<Button
text='Read All Posts'
href='/blog'
className='rounded-lg bg-indigo-600 px-8 py-3 font-semibold text-white shadow-lg hover:bg-indigo-700'
bgClassName='bg-indigo-600 hover:bg-indigo-700'
/>
</div>
<div className='mt-12'>
<NewsroomBlogPosts />
</div>
</Container>
</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Also adjust dark‑mode text for “From the Blogs” section

This section uses bg-white dark:bg-dark-background, but:

  • The H2 (Line 172) is text-gray-900 only.
  • The paragraph (Line 175) is text-gray-600 only.

In dark mode that will be muted against the dark background. Suggest adding dark variants similar to other sections:

- className='mb-2 text-gray-900'
+ className='mb-2 text-gray-900 dark:text-dark-heading'

- <Paragraph ... className='text-gray-600'>
+ <Paragraph ... className='text-gray-600 dark:text-gray-400'>

This keeps blog titles/summary readable in dark mode.

📝 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
{/* From the Blogs Section */}
<div className='bg-white dark:bg-dark-background'>
<Container wide className='py-20' data-testid='EventsAndUpdates-Blogs'>
<div className='mb-12 flex flex-col items-start justify-between gap-4 sm:flex-row sm:items-center'>
<div>
<Heading level={HeadingLevel.h2} typeStyle={HeadingTypeStyle.lg} className='mb-2 text-gray-900'>
From the Blogs
</Heading>
<Paragraph typeStyle={ParagraphTypeStyle.md} className='text-gray-600'>
Stay connected with the pulse of our community
</Paragraph>
</div>
<Button
text='Read All Posts'
href='/blog'
className='rounded-lg bg-indigo-600 px-8 py-3 font-semibold text-white shadow-lg hover:bg-indigo-700'
bgClassName='bg-indigo-600 hover:bg-indigo-700'
/>
</div>
<div className='mt-12'>
<NewsroomBlogPosts />
</div>
</Container>
</div>
{/* From the Blogs Section */}
<div className='bg-white dark:bg-dark-background'>
<Container wide className='py-20' data-testid='EventsAndUpdates-Blogs'>
<div className='mb-12 flex flex-col items-start justify-between gap-4 sm:flex-row sm:items-center'>
<div>
<Heading level={HeadingLevel.h2} typeStyle={HeadingTypeStyle.lg} className='mb-2 text-gray-900 dark:text-dark-heading'>
From the Blogs
</Heading>
<Paragraph typeStyle={ParagraphTypeStyle.md} className='text-gray-600 dark:text-gray-400'>
Stay connected with the pulse of our community
</Paragraph>
</div>
<Button
text='Read All Posts'
href='/blog'
className='rounded-lg bg-indigo-600 px-8 py-3 font-semibold text-white shadow-lg hover:bg-indigo-700'
bgClassName='bg-indigo-600 hover:bg-indigo-700'
/>
</div>
<div className='mt-12'>
<NewsroomBlogPosts />
</div>
</Container>
</div>
🤖 Prompt for AI Agents
pages/community/events-and-updates.tsx around lines 167 to 190: the "From the
Blogs" H2 and Paragraph only specify light-mode text colors (text-gray-900 and
text-gray-600) which will be hard to read against the dark background; update
the Heading to include a dark-mode class (e.g., add dark:text-white or
dark:text-gray-100) and update the Paragraph to include a darker-mode variant
(e.g., dark:text-gray-300 or similar) to match other sections so both title and
summary remain readable in dark mode.

Comment on lines +64 to +88
const [currentPage, setCurrentPage] = useState(1);
const [searchTerm, setSearchTerm] = useState('');
const [filterType, setFilterType] = useState<'all' | 'maintainer' | 'available' | 'company'>('all');
const membersPerPage = 9;

// Filter members
const filteredMembers = tscMembers.filter((member) => {
const matchesSearch =
member.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
(member.github && member.github.toLowerCase().includes(searchTerm.toLowerCase()));

const matchesFilter =
filterType === 'all' ||
(filterType === 'maintainer' && member.repos && member.repos.length > 0) ||
(filterType === 'available' && member.availableForHire) ||
(filterType === 'company' && member.company);

return matchesSearch && matchesFilter;
});

const totalPages = Math.ceil(filteredMembers.length / membersPerPage);
const indexOfLastMember = currentPage * membersPerPage;
const indexOfFirstMember = indexOfLastMember - membersPerPage;
const currentMembers = filteredMembers.slice(indexOfFirstMember, indexOfLastMember);

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Reset pagination when filters/search change and align search placeholder.

If a user is on a higher page and then changes the search term or filter, filteredMembers.length can drop so that currentPage > totalPages. In that case the grid renders no members while the “Showing X of Y” text still updates, which is confusing.

Also, the placeholder says “Search members by role or name...”, but the filter only checks name and github, not a role field.

Consider:

  • Resetting or clamping currentPage whenever filters/search change, e.g. by setting page to 1 inside the search onChange and each filter button handler.
  • Or, adding a useEffect after filteredMembers:
+  useEffect(() => {
+    setCurrentPage(1);
+  }, [searchTerm, filterType, filteredMembers.length]);
  • Updating the placeholder to match behavior, e.g. “Search members by name or GitHub handle...”.
  • Optionally, show a small “No members found for this filter” message when filteredMembers.length === 0.

Also applies to: 222-231, 277-279

🤖 Prompt for AI Agents
In pages/community/tsc.tsx around lines 64 to 88 (also apply similar changes at
222-231 and 277-279), currentPage can become greater than totalPages after
search/filter changes causing an empty grid; update the code to clamp or reset
pagination whenever searchTerm or filterType (or filteredMembers) change—add a
useEffect that sets currentPage to 1 if totalPages === 0 or currentPage >
totalPages (or setCurrentPage(1) on search/filter handlers), update the search
input placeholder to “Search members by name or GitHub handle...” to match the
actual fields searched, and optionally render a “No members found for this
filter” message when filteredMembers.length === 0.

Comment on lines +549 to +553
icon={IconGear}
title='400% Community Growth'
description="AsyncAPI thrives on community. Expanding contributions, sponsorships, and
engagement ensures continued success. Let's grow together."
/>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix invalid multi‑line description string in GoalCardRoadmapPage

Lines [549–553]: description is passed as a double‑quoted string spanning multiple lines, which is invalid TSX/JS syntax and will fail to compile. It also contains "Let's" which requires either double quotes or escaping if you switch to single quotes.

You can fix it by keeping it on a single line or by using a JSX fragment:

-              <GoalCardRoadmapPage
-                icon={IconGear}
-                title='400% Community Growth'
-                description="AsyncAPI thrives on community. Expanding contributions, sponsorships, and
-                  engagement ensures continued success. Let's grow together."
-              />
+              <GoalCardRoadmapPage
+                icon={IconGear}
+                title='400% Community Growth'
+                description="AsyncAPI thrives on community. Expanding contributions, sponsorships, and engagement ensures continued success. Let's grow together."
+              />

(or wrap the text in <>{'...'}</> if you prefer JSX content).

📝 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
icon={IconGear}
title='400% Community Growth'
description="AsyncAPI thrives on community. Expanding contributions, sponsorships, and
engagement ensures continued success. Let's grow together."
/>
icon={IconGear}
title='400% Community Growth'
description="AsyncAPI thrives on community. Expanding contributions, sponsorships, and engagement ensures continued success. Let's grow together."
/>
🤖 Prompt for AI Agents
In pages/roadmap.tsx around lines 549 to 553, the description prop is written as
a multi-line double-quoted string which is invalid TSX and will fail to compile
(and contains "Let's" which needs proper quoting/escaping); replace the
multi-line quoted string with either a single-line string literal, a JSX
fragment containing the text, or a JS string expression with proper
quoting/escaping (e.g., use a single-line description="..." or
description={<>{'...'} </>} or description={'...'} with the apostrophe escaped)
so the prop is valid TSX and compiles.

Comment on lines +53 to +56
githubUrl?: string;
twitterUrl?: string;
linkedinUrl?: string;
reposList?: { name: string; url: string }[];
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify the relationship between github and githubUrl fields.

The Tsc interface now contains both github (line 44, required) and githubUrl (line 53, optional). Based on learnings, the github field contains usernames that are converted to URLs by addAdditionalUserInfo(). Please clarify:

  1. Is githubUrl the processed version of github?
  2. Are both fields needed, or is there potential duplication?
  3. Should consumers use githubUrl when available and fall back to constructing from github?

Run the following script to check how these fields are used:

Based on learnings


🏁 Script executed:

#!/bin/bash
# Description: Check usage of github and githubUrl fields in Tsc interface

# Search for Tsc interface usage patterns
echo "=== Searching for Tsc type usage ==="
rg -n "Tsc" --type=ts --type=tsx -C3

echo -e "\n=== Searching for githubUrl field access ==="
rg -n "\.githubUrl" --type=ts --type=tsx -C3

echo -e "\n=== Searching for github field access in TSC context ==="
rg -n "tsc.*\.github|member\.github" --type=ts --type=tsx -C3

echo -e "\n=== Check addAdditionalUserInfo implementation ==="
rg -n "addAdditionalUserInfo" --type=ts --type=tsx -C5

Length of output: 304



---

🏁 Script executed:

```shell
#!/bin/bash
# Description: Check usage of github and githubUrl fields in Tsc interface

# Search for Tsc interface usage patterns
echo "=== Searching for Tsc type usage ==="
rg -n "Tsc" --type=ts -C3

echo -e "\n=== Searching for githubUrl field access ==="
rg -n "\.githubUrl" -g "*.ts" -g "*.tsx" -C3

echo -e "\n=== Searching for github field access in context ==="
rg -n "\.github\b" -g "*.ts" -g "*.tsx" -C2

echo -e "\n=== Check addAdditionalUserInfo implementation ==="
rg -n "addAdditionalUserInfo" -g "*.ts" -g "*.tsx" -C5

echo -e "\n=== Search for Tsc interface definition ==="
rg -n "interface Tsc" -g "*.ts" -g "*.tsx" -A15

Length of output: 28653


Fix CommunityLayout.tsx to create githubUrl instead of mutating github field.

A critical type safety issue was found: CommunityLayout.tsx (line 48) mutates the github field to become a full URL (userData.github = https://www.github.com/${userData.github}`), which violates the type contract. The Tsc interface defines github as a required string intended to be a username.

The other implementations—pages/community/tsc.tsx (line 31) and pages/community/ambassadors/index.tsx (line 37)—correctly handle this by creating a separate githubUrl field while keeping github as the username.

Changes needed in components/layout/CommunityLayout.tsx:

  • Line 48: Replace mutation of github with creation of githubUrl field
  • Line 59: Update avatar URL to use githubUrl instead of github
  • Line 187: Extract username from github directly (since it's kept as username)
  • Line 208: Update to use githubUrl for the href

Alternatively, if CommunityLayout.tsx intentionally converts github to URL for display purposes, the Tsc interface and component contracts need updating to reflect this consistently.

🤖 Prompt for AI Agents
In types/pages/community/Community.ts around lines 53-56, CommunityLayout.tsx is
mutating the required github username field into a full URL which breaks the Tsc
type contract; update components/layout/CommunityLayout.tsx so that at line 48
it does not overwrite userData.github but instead creates userData.githubUrl =
`https://www.github.com/${userData.github}`, change the avatar construction at
line 59 to use githubUrl, ensure any username extraction at line 187 reads
userData.github (the username), and update the link href at line 208 to use
githubUrl; alternatively, if the intent is to store a URL, update the Tsc type
to reflect github?: string | url and adjust all usages consistently.

Signed-off-by: Shriya-Chauhan <[email protected]>
@Shriya-Chauhan
Copy link
Contributor Author

On load, the dark mode should appear instantly instead of showing a transition from light mode:

Screen.Recording.2025-11-13.224339.mp4

fixed

Signed-off-by: Shriya-Chauhan <[email protected]>
@Shriya-Chauhan
Copy link
Contributor Author

The font colour of the author's name in the case study and the title of the TOC should be changed to something lighter in the dark mode.

Also, the colour of the left border of the TOC is very sharp as compared to background in the dark mode, please change it.

image ref: https://deploy-preview-4553--asyncapi-website.netlify.app/casestudies/adeogroup

fixed

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.

3 participants