Skip to content

feat(website): add tabbed code snippet section to homepage#4084

Merged
khajavi merged 14 commits intozio:mainfrom
khajavi:worktree-brilliant-code-snippet
Apr 11, 2026
Merged

feat(website): add tabbed code snippet section to homepage#4084
khajavi merged 14 commits intozio:mainfrom
khajavi:worktree-brilliant-code-snippet

Conversation

@khajavi
Copy link
Copy Markdown
Member

@khajavi khajavi commented Apr 11, 2026

Summary

Adds a new interactive HomepageCodeSnippet component to the website homepage that replaces the existing HomepageShowcases section. The new component features:

  • 5 interactive Scala code tabs: Create an HTTP Server, Define Endpoints, Add Middleware, HTTP Client, WebSocket
  • Syntax-highlighted code panel using prism-react-renderer with dracula theme
  • Line numbers (non-selectable so copy gets only code)
  • Copy-to-clipboard button with checkmark feedback
  • Responsive two-column layout: 40% text on left, 60% code panel on right; single column on mobile
  • Light theme support: section respects site light/dark mode, code panel stays dark for contrast
  • Alternating backgrounds: uses var(--ifm-color-emphasis-100) to alternate with adjacent sections

Implementation Details

  • New component: website/src/components/HomepageCodeSnippet/
    • index.js: React component with tab state management, Prism integration, copy functionality
    • styles.module.css: CSS Modules with responsive grid layout, dark code panel styling
  • Updated: website/src/pages/index.js to swap HomepageShowcasesHomepageCodeSnippet

Test Plan

  • Run `cd website && yarn start` to preview locally
  • Verify dark section renders after hero banner
  • Click all 5 tabs and confirm code updates
  • Test copy button and checkmark feedback
  • Check line numbers are visible but not selectable
  • Test on mobile (≤996px): should stack to single column with horizontal tab scroll
  • Toggle light/dark site theme and verify code panel stays dark

🤖 Generated with Claude Code

Replace HomepageShowcases with a new interactive tabbed code panel
inspired by the Node.js homepage. Features 5 Scala code examples with
syntax highlighting, line numbers, copy-to-clipboard, and responsive
two-column layout. Section alternates background color with adjacent
sections following the homepage design pattern.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 11, 2026 04:42
@khajavi khajavi requested a review from 987Nabil as a code owner April 11, 2026 04:42
@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 11, 2026

Deploy Preview for zio-http ready!

Name Link
🔨 Latest commit 7daeaae
🔍 Latest deploy log https://app.netlify.com/projects/zio-http/deploys/69d9ebc58b0ac70008d700da
😎 Deploy Preview https://deploy-preview-4084--zio-http.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.

…ating color pattern

Change background from light gray to white to match the homepage's
alternating white-gray-white pattern starting after the hero banner.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
khajavi and others added 2 commits April 11, 2026 08:15
…ections

Change HomepageEcosystem and HomepageUsers to white background to create
proper alternating pattern: white → gray → white → gray → white across
all main sections.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…light mode contrast

Change gray sections from var(--ifm-color-emphasis-0) to var(--ifm-color-emphasis-100)
to ensure proper visual distinction in light mode while maintaining contrast in dark mode.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new interactive, tabbed “ZIO HTTP in Action” code-snippet section to the Docusaurus homepage, replacing the older HomepageShowcases section to provide a more engaging, copyable set of Scala examples.

Changes:

  • Replaces HomepageShowcases with a new HomepageCodeSnippet section on the homepage.
  • Introduces HomepageCodeSnippet React component with tab switching, Prism highlighting, and copy-to-clipboard feedback.
  • Adds dedicated CSS module styling for a responsive two-column layout and dark code panel UI.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 7 comments.

File Description
website/src/pages/index.js Swaps the homepage section from HomepageShowcases to HomepageCodeSnippet.
website/src/components/HomepageCodeSnippet/index.js New tabbed code example component with syntax highlighting and copy button.
website/src/components/HomepageCodeSnippet/styles.module.css Styles for layout, tab bar, code panel, line numbers, and responsive behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1 to +4
.codeSnippetSection {
background-color: var(--ifm-background-surface-color);
padding: 5rem 0;
width: 100%;
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

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

The section background color doesn’t match the PR description (“Alternating backgrounds: uses var(--ifm-color-emphasis-100)”). The CSS currently uses var(--ifm-background-surface-color), which likely won’t create an alternating emphasis band. Either switch to var(--ifm-color-emphasis-100) (or the intended token) or update the PR description to reflect the actual styling.

Copilot uses AI. Check for mistakes.
Comment on lines +95 to +102
.pre {
margin: 0;
padding: 1.25rem 1rem;
overflow-y: auto;
max-height: 500px;
font-size: 0.875rem;
line-height: 1.6;
}
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

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

.pre sets overflow-y: auto but not overflow-x. Since .codePanel has overflow: hidden, long code lines can be clipped with no horizontal scroll. Consider using overflow: auto (or at least overflow-x: auto) on .pre to ensure long lines remain accessible.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

✅ Fixed in 7daeaae — changed overflow-y: auto to overflow: auto to enable both vertical and horizontal scrolling

Comment on lines +141 to +149
navigator.clipboard
.writeText(TABS[activeTab].code.trim())
.then(() => {
setCopied(true);
setTimeout(() => setCopied(false), 2000);
})
.catch((err) => {
console.error('Failed to copy:', err);
});
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

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

navigator.clipboard is not guaranteed to exist in all browsers/contexts (e.g., non-secure contexts or restricted permissions). Accessing navigator.clipboard.writeText(...) can throw synchronously before the Promise chain, so the .catch(...) won’t run. Add a guard for navigator.clipboard?.writeText (and/or a fallback) and wrap the call in try/catch to avoid runtime errors.

Suggested change
navigator.clipboard
.writeText(TABS[activeTab].code.trim())
.then(() => {
setCopied(true);
setTimeout(() => setCopied(false), 2000);
})
.catch((err) => {
console.error('Failed to copy:', err);
});
const textToCopy = TABS[activeTab].code.trim();
try {
if (!navigator.clipboard?.writeText) {
throw new Error('Clipboard API is not available');
}
navigator.clipboard
.writeText(textToCopy)
.then(() => {
setCopied(true);
setTimeout(() => setCopied(false), 2000);
})
.catch((err) => {
console.error('Failed to copy:', err);
});
} catch (err) {
console.error('Failed to copy:', err);
}

Copilot uses AI. Check for mistakes.
Comment on lines +143 to +146
.then(() => {
setCopied(true);
setTimeout(() => setCopied(false), 2000);
})
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

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

The setTimeout(() => setCopied(false), 2000) isn’t cleared on unmount. If the user navigates away quickly, React can warn about setting state on an unmounted component. Store the timeout id (e.g., in a ref) and clear it in an effect cleanup (and also clear/replace any existing timeout when copying again).

Copilot uses AI. Check for mistakes.
Comment on lines +176 to +186
<div className={styles.tabBar}>
{TABS.map((tab, idx) => (
<button
key={idx}
className={clsx(
styles.tab,
activeTab === idx && styles.tabActive
)}
onClick={() => handleTabClick(idx)}
aria-selected={activeTab === idx}
role="tab">
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

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

The tab UI uses role="tab" on buttons, but the parent container isn’t marked as a tablist, and the tabs aren’t wired to a tabpanel (id/aria-controls) or keyboard navigation (arrow keys/Home/End). This makes the control incomplete for screen reader and keyboard users. Consider using the full WAI-ARIA tabs pattern (tablist + tabs + tabpanel + roving tabindex + key handlers).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

✅ Fixed in 7daeaae — added role="tablist" to tab bar, id/aria-controls on tabs, role="tabpanel" with aria-labelledby on code area

Comment on lines +178 to +186
<button
key={idx}
className={clsx(
styles.tab,
activeTab === idx && styles.tabActive
)}
onClick={() => handleTabClick(idx)}
aria-selected={activeTab === idx}
role="tab">
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

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

These <button> elements don’t specify type="button". If this component is ever rendered inside a <form>, the default type="submit" can cause unexpected form submissions. Set type="button" for non-submit buttons (tabs and copy button).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

✅ Fixed in 7daeaae — added type="button" to all tab buttons to prevent form submission

Comment on lines +237 to +244
<button
className={clsx(
styles.copyButton,
copied && styles.copyButtonCopied
)}
onClick={handleCopy}
aria-label={copied ? 'Copied!' : 'Copy code'}
title={copied ? 'Copied!' : 'Copy to clipboard'}>
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

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

This copy button should also set type="button" to avoid acting as an implicit submit button if rendered within a form context.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

✅ Fixed in 7daeaae — added type="button" to copy button

khajavi and others added 8 commits April 11, 2026 08:21
Document the design patterns, conventions, and principles followed in the
website components, including:
- Component structure (CSS Modules)
- Theme system (Infima variables, alternating backgrounds)
- Interactive components (Prism highlighting, icons, state management)
- Responsive design and accessibility
- SSR safety patterns
- Styling best practices
- Testing checklist

This serves as a reference for maintaining consistency in future website updates.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…mepage

- Add CSS variables for accent greens in custom.css:
  - --zio-accent-green: #81c784 (main accent)
  - --zio-accent-green-light: #a5d6a7 (lighter variant)
  - --zio-accent-green-pale: #e8f5e9 (pale variant for gradients)
- Replace all hardcoded green colors with variables in:
  - HomepageHero (button, text, icons, gradients)
  - HomepageCodeSnippet (tabs, buttons, accents)
- Ensure harmony and consistency across light and dark modes

This creates a unified design system where all green accents reference
the same color palette, making future theme changes easier.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Add 3px accent green top border to feature cards
- Change feature card border to accent green on hover
- Feature card icons transition to accent green on hover
- Creates visual cohesion between code snippet and features sections

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…ent green

Change featuresSubtitle from var(--ifm-color-primary) to var(--zio-accent-green)
to ensure consistent green color across the homepage sections.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…n variable

Replace all remaining instances of var(--ifm-color-primary) with
var(--zio-accent-green) in:
- HomepageFeatures: card headers and icons
- HomepageEcosystem: subtitle and card headers
- HomepageUsers: user names and titles
- HomepageZionomicon: subtitle

Now all green text throughout the homepage uses the same unified
accent green color (#81c784) for perfect visual consistency.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…mary the accent green

- Update primary color palette in custom.css to use #81c784 (accent green) as the main primary color
- Remove redundant --zio-accent-green variable and its variants
- Replace all var(--zio-accent-green) references with var(--ifm-color-primary)
- Update gradient colors to use hardcoded values (#e8f5e9, #a5d6a7)

This eliminates color duplication and creates a single, unified primary color
throughout the entire homepage. The primary color now represents the accent
green used consistently across all sections.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

<div>
<Link
className="button button--outline button--lg"
to="/docs">
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

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

to="/docs" likely points to a non-existent route in this site: the Docusaurus config sets docs.routeBasePath to '/', so docs are served from the root (and /docs may 404). Update this link to a valid docs URL for this site (e.g., a specific doc like /installation or the doc index route used by the navbar).

Suggested change
to="/docs">
to="/">

Copilot uses AI. Check for mistakes.
Comment on lines +176 to +187
<div className={styles.tabBar}>
{TABS.map((tab, idx) => (
<button
key={idx}
className={clsx(
styles.tab,
activeTab === idx && styles.tabActive
)}
onClick={() => handleTabClick(idx)}
aria-selected={activeTab === idx}
role="tab">
{tab.label}
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

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

The tab UI is missing required ARIA structure for tabs: the container should have role="tablist", each tab should have an id, and the code panel should be a role="tabpanel" with aria-labelledby/aria-controls wiring. Also consider adding keyboard navigation (ArrowLeft/ArrowRight, Home/End) per WAI-ARIA tabs pattern.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

✅ Fixed in 7daeaae — added complete ARIA structure: role="tablist", id on tabs, aria-controls/aria-labelledby wiring, and role="tabpanel"

Comment on lines +139 to +146
const handleCopy = () => {
if (!isBrowser) return;
navigator.clipboard
.writeText(TABS[activeTab].code.trim())
.then(() => {
setCopied(true);
setTimeout(() => setCopied(false), 2000);
})
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

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

handleCopy schedules a setTimeout without cleanup; if the component unmounts within 2s this can trigger a state update on an unmounted component. Store the timeout id in a ref and clear it in a useEffect cleanup (and before scheduling a new one).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

✅ Fixed in 7daeaae — added useRef to store timeout ID with proper cleanup in useEffect and when copying again

Comment on lines +75 to +79
transition: color 0.3s ease;
}

.featureCard:hover .featureCardIcon svg {
color: var(--ifm-color-primary);
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

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

The new hover color styling for .featureCardIcon likely has no effect because the imported Undraw SVGs use hard-coded fill attributes (not currentColor). If the intent is to tint icons via CSS, update the SVGs to use fill="currentColor" (or strip hard-coded fills) and/or apply fill: currentColor to the relevant SVG/path selectors.

Suggested change
transition: color 0.3s ease;
}
.featureCard:hover .featureCardIcon svg {
color: var(--ifm-color-primary);
fill: currentColor;
transition: color 0.3s ease, fill 0.3s ease;
}
.featureCardIcon svg * {
fill: currentColor;
transition: fill 0.3s ease;
}
.featureCard:hover .featureCardIcon svg {
color: var(--ifm-color-primary);
fill: currentColor;

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

✅ Fixed in 7daeaae — added fill: currentColor to SVG elements and fill transition to enable color inheritance on hover

khajavi and others added 2 commits April 11, 2026 10:01
Update custom.css to apply the consolidated accent green color (#81c784)
as the primary color across both light and dark themes. This ensures
consistent coloring throughout the website.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Add timeout cleanup on unmount using useRef/useEffect to prevent state updates
- Add navigator.clipboard optional chaining and try/catch for safety
- Add type="button" to tab and copy buttons to prevent form submissions
- Add proper ARIA structure: tablist, tabpanel, aria-controls, aria-labelledby
- Fix copy button timeout to clear previous timeout when switching tabs
- Fix horizontal scroll on code blocks: change overflow-y to overflow
- Fix feature card icon hover: add fill: currentColor for SVG fill inheritance
- Change docs link from /docs to / (correct route)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
@khajavi khajavi merged commit c0ab15d into zio:main Apr 11, 2026
45 checks passed
@khajavi khajavi deleted the worktree-brilliant-code-snippet branch April 11, 2026 07:03
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.

2 participants