Skip to content

Conversation

grahamc
Copy link
Member

@grahamc grahamc commented Aug 15, 2025

Summary by CodeRabbit

  • New Features

    • Code blocks support “snippet” or “file” with optional download; new example stories.
    • Install CTA adds AWS & GitHub tabs, version-aware flows, AWS AMI finder, GitHub Actions, and NixOS guidance.
    • New Navigation component and stories.
  • Improvements

    • Updated styling (code blocks, Install CTA, links, mac installer) with theme-aware colors and new mixins/tokens.
    • Added Nix syntax highlighting; Mac installer supports versioned downloads.
  • Reliability

    • Safer SSR handling for theming and color-scheme detection.
  • Chores

    • Broadened React 19 peer dependency; removed legacy CodeFile and WSL tab.

Copy link

netlify bot commented Aug 15, 2025

Deploy Preview for determinate-ui ready!

Name Link
🔨 Latest commit f0f28a1
🔍 Latest deploy log https://app.netlify.com/projects/determinate-ui/deploys/68c38e5bea79b5000883bf3f
😎 Deploy Preview https://deploy-preview-48--determinate-ui.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.

@grahamc grahamc force-pushed the push-ynlmnrwpxkql branch from 161fa56 to 32bbd3f Compare August 15, 2025 12:33
@grahamc grahamc force-pushed the push-ynlmnrwpxkql branch 5 times, most recently from 0be93a7 to 96c7434 Compare August 27, 2025 14:16
Copy link

coderabbitai bot commented Sep 12, 2025

Walkthrough

Adds CodeBlock file-mode and download support, removes the CodeFile component and stories, overhauls InstallCTA into tab-driven, version-aware flows (adds AWS/GitHub/NixOS content), introduces a Navigation component and stories, adds Sass mixins/tokens, makes SSR-safe color handling, adds Nix highlighting, and adjusts various styles and exports.

Changes

Cohort / File(s) Summary of changes
Package and public API
package.json, src/index.ts
Broaden React peerDependency to ^19; remove CodeFile export and add Navigation export.
CodeBlock (file mode & download)
src/CodeBlock/index.tsx, src/CodeBlock/index.scss, src/CodeBlock/CodeBlock.stories.tsx
Add props `kind: "snippet"
CodeFile removal
src/CodeFile/index.tsx, src/CodeFile/index.scss, src/CodeFile/CodeFile.stories.tsx
Delete component, its styles, and stories (removes CodeFile and CodeFileProps).
InstallCTA: tabs, versioning, new tab content
src/InstallCTA/index.tsx, src/InstallCTA/types.ts, src/InstallCTA/TabSelector.tsx, src/InstallCTA/InstallFromCurl.tsx, src/InstallCTA/InstallCTA.stories.tsx, src/InstallCTA/FindAwsAMIs.tsx, src/InstallCTA/InstallForNixOS.tsx, src/InstallCTA/UseWithGitHubActions.tsx, src/InstallCTA/index.scss, src/InstallCTA/NavTab.tsx
Replace WSL with AWS/GitHub targets; add version plumbing via TabProps; map targets to components; introduce new per-target components (AWS AMIs, GitHub Actions, NixOS); make curl/install scripts version-aware; refactor styles and story controls; remove legacy NavTab.
Navigation component & stories
src/Navigation/index.tsx, src/Navigation/index.scss, src/Navigation/Navigation.stories.tsx
Add new collapsible Navigation component (props: initialState?, children), responsive styles, and four story variants demonstrating embedded/header usage.
Theming, SSR safety, highlighting
src/ColorProvider/index.tsx, src/hooks/useSystemColorScheme.ts, src/Highlight/index.scss, src/hooks/useHighlight.ts
Make theme application SSR-safe (guard root/classList), adjust React imports, remove CSS var fallbacks for highlight backgrounds, add nix language support and reorder highlightLanguages.
Sass tokens & mixins
src/sass/_mixins.scss, src/sass/_tokens.scss
Add mixins border, border-top, border-bottom, shadow, margin-y; update $code bg-dark value; add spacing tokens lg and xl.
UI tweaks (links, Mac installer, header, PageLayout, Header, Highlight styles)
src/Link/index.scss, src/MacInstaller/index.scss, src/MacInstaller/index.tsx, src/Header/index.tsx, src/PageLayout/index.tsx, src/PageLayout/PageLayout.stories.tsx, src/Highlight/index.scss
Underline link text with offset; make MacInstaller version-aware (props + URL/text) and style tweaks; Header now accepts ReactElement[] and wraps elements; PageLayout maps panes into keyed wrappers; remove Shiki CSS var fallbacks.
Misc (stories, hooks)
src/CodeBlock/CodeBlock.stories.tsx, src/InstallCTA/InstallCTA.stories.tsx, src/PageLayout/PageLayout.stories.tsx, src/hooks/useHighlight.ts, src/hooks/useSystemColorScheme.ts
Add/adjust Storybook controls and new stories; ordering and language support updates for highlighter; SSR-safe media-query guard.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant U as User
  participant CTA as InstallCTA
  participant TS as TabSelector
  participant Map as ctaComponents
  participant TB as TabBody
  participant CB as CodeBlock

  U->>CTA: Load (initialTab, version?)
  CTA->>TS: render tabs from ctaTabs
  U->>TS: select tab
  TS-->>CTA: activeTab
  CTA->>Map: resolve active component
  Map-->>CTA: TabBody component
  CTA->>TB: render <TabBody version={version}/>
  TB->>CB: render code (kind, allowCopy, allowDownload)
  alt kind == "file" and allowDownload
    CB->>CB: show DownloadButton (filename from downloadAs/title)
  end
  alt allowCopy
    CB->>CB: show CopyButton (data = trimmedCode)
  end
Loading
sequenceDiagram
  autonumber
  participant P as Props
  participant CB as CodeBlock
  participant HL as Highlight
  P-->>CB: {code, language, title, kind, allowCopy, allowDownload, downloadAs?}
  CB->>CB: trimmedCode = code.trim()
  CB->>HL: Highlight(language, trimmedCode)
  CB->>CB: Conditionally render Copy/Download icons based on props
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • gustavderdrache

Pre-merge checks (1 passed, 2 warnings)

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Title Check ⚠️ Warning The current title "Push ynlmnrwpxkql" is opaque and does not describe the contents of this changeset; it gives reviewers no hint about the purpose or scope. This PR introduces several notable changes (e.g., CodeBlock file-kind and download support, removal of CodeFile, a refactored/versioned InstallCTA with new tabs and components, plus a new Navigation component and style/token updates), so the title is misleading and unhelpful for history or review. Please rename the pull request to a short, specific sentence summarizing the primary change(s), for example: "Add CodeBlock file-kind and download support; refactor InstallCTA and add Navigation". Make sure the final title clearly reflects the main functional change so reviewers can understand the PR at a glance.
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

Poem

I thump with glee on meadow bytes,
New tabs to hop, new code delights—
Files to fetch and snippets bright,
Nix and YAML snug at night.
I nibble carrots, push the change—hooray! 🐇✨

✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch push-ynlmnrwpxkql

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

@grahamc grahamc marked this pull request as ready for review September 12, 2025 01:10
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (26)
package.json (1)

51-53: Peer dep set to React 19 only—confirm intent; consider allowing React 18 too.

If you don’t use React 19–specific APIs, widening helps consumers still on 18.

Apply this diff if you want to support 18 and 19:

-    "react": "^19"
+    "react": ">=18 <20"
src/InstallCTA/TabSelector.tsx (2)

4-8: Type the icon as ComponentType rather than FC for better compatibility with react-icons.

react-icons exports IconType = ComponentType<IconBaseProps>; FC is unnecessarily restrictive.

-  icon: FC<IconBaseProps>;
+  icon: ComponentType<IconBaseProps>;

Add the type import (outside this range):

import { useCallback, type FC, type MouseEvent, type ComponentType } from "react";

38-38: Avoid duplicate accessible names; make the icon decorative.

The link already contains text ({name}), so the icon should be aria-hidden instead of getting a title.

-        <Icon title={name} /> {name}
+        <Icon aria-hidden="true" focusable="false" /> {name}
src/hooks/useSystemColorScheme.ts (1)

35-52: Add Safari <14 fallback for media query change events.

Older Safari only supports addListener/removeListener.

-    media.addEventListener("change", handleChange);
-    return function cleanup() {
-      media.removeEventListener("change", handleChange);
-    };
+    if ("addEventListener" in media) {
+      media.addEventListener("change", handleChange);
+      return () => media.removeEventListener("change", handleChange);
+    } else {
+      // Safari <14
+      // @ts-expect-error legacy API
+      media.addListener(handleChange);
+      return () => {
+        // @ts-expect-error legacy API
+        media.removeListener(handleChange);
+      };
+    }
src/ColorProvider/index.tsx (4)

97-105: Don’t reassign the destructured prop; compute a resolvedRoot instead.

Improves clarity and avoids param shadowing.

-  root,
+  root,
   children,
 }) => {
-  if (!root) {
-    if (typeof document !== "undefined") {
-      root = document.body;
-    }
-  }
+  const resolvedRoot =
+    root ?? (typeof document !== "undefined" ? document.body : undefined);

118-121: Avoid DOM side effects during render; use a layout effect for initial apply.

This prevents render-time mutations and still avoids FOUC.

-  if (root) {
-    applyTheme(root, scheme);
-  }
+  // Apply ASAP before paint to reduce FOUC
+  // (import useLayoutEffect at top)
+  useLayoutEffect(() => {
+    if (resolvedRoot) {
+      applyTheme(resolvedRoot, scheme);
+    }
+  }, []);

Add import (outside this range):

import React, { useEffect, useLayoutEffect, useMemo, useState, type PropsWithChildren } from "react";

138-141: Use the resolved root variable consistently.

Keeps semantics consistent with the earlier resolution.

-    if (root) {
-      applyTheme(root, scheme);
+    if (resolvedRoot) {
+      applyTheme(resolvedRoot, scheme);
     }

150-154: Avoid console noise in libraries.

Drop or gate the log in production.

-  if (classes === undefined) {
-    console.log("classList on the root is null... probably SSR?");
-    return;
-  }
+  if (classes === undefined) {
+    return;
+  }
src/sass/_tokens.scss (1)

104-106: Spacing scale: lg duplicates base.

base and lg are both 0.75rem, which defeats the scale. Recommend monotonic increase.

Example adjustment:

 $spacing: (
   xs: 0.25rem,
   sm: 0.5rem,
   base: 0.75rem,
-  lg: 0.75rem,
-  xl: 1rem,
+  lg: 1rem,
+  xl: 1.25rem,
 );
src/sass/_mixins.scss (2)

49-51: Guard radius math against edge cases.

If a future radius token drops below 1px, calc(... - 1px) can go negative. Cheap guard with max().

-  border-top-left-radius: calc(map.get(tokens.$border-radius, $size) - 1px);
-  border-top-right-radius: calc(map.get(tokens.$border-radius, $size) - 1px);
+  border-top-left-radius: max(calc(map.get(tokens.$border-radius, $size) - 1px), 0px);
+  border-top-right-radius: max(calc(map.get(tokens.$border-radius, $size) - 1px), 0px);
@@
-  border-bottom-left-radius: calc(map.get(tokens.$border-radius, $size) - 1px);
-  border-bottom-right-radius: calc(map.get(tokens.$border-radius, $size) - 1px);
+  border-bottom-left-radius: max(calc(map.get(tokens.$border-radius, $size) - 1px), 0px);
+  border-bottom-right-radius: max(calc(map.get(tokens.$border-radius, $size) - 1px), 0px);

Also applies to: 69-71


82-95: DRY nit: duplicate box-shadow in light mode.

Same shadow in both modes—drop the override unless you plan to diverge later.

 @mixin shadow {
   box-shadow:
     0 0 #0000,
     0 0 #0000,
     0 1px 3px 0 rgba(0, 0, 0, 0.1),
     0 1px 2px -1px rgba(0, 0, 0, 0.1);
-  @include light-mode {
-    box-shadow:
-      0 0 #0000,
-      0 0 #0000,
-      0 1px 3px 0 rgba(0, 0, 0, 0.1),
-      0 1px 2px -1px rgba(0, 0, 0, 0.1);
-  }
 }
src/CodeBlock/CodeBlock.stories.tsx (1)

14-17: Stories read well; consider adding a Nix example and a filename for downloads.

  • Add a small Nix snippet to showcase the new language.
  • Provide downloadAs (e.g., ".github/workflows/nix-ci.yaml") so downloads have a friendly filename.

Example:

 export const GithubCI: Story = {
   args: {
@@
-    allowDownload: true,
+    allowDownload: true,
+    downloadAs: ".github/workflows/nix-ci.yaml",
   },
 };
@@
+export const NixSample: Story = {
+  args: {
+    language: "nix",
+    code: 'pkgs: pkgs.mkShell { buildInputs = [ pkgs.hello ]; }',
+    title: "shell.nix",
+    kind: "file",
+    allowCopy: true,
+  },
+};

Also applies to: 21-23, 65-93, 95-115

src/InstallCTA/FindAwsAMIs.tsx (2)

12-14: Type the component as FC and drop the unused param

Prevents mismatched prop typing and removes the placeholder arg.

-const FindAwsAMIs: FC = (_: TabProps) => {
+const FindAwsAMIs: FC<TabProps> = () => {

6-10: Tighten the AMI search to only available images

Adds a safe state filter; keeps output deterministic.

 const code = `aws ec2 describe-images \
   --owners 535002876703 \
   --filters "Name=name,Values=determinate/nixos/epoch-1/*" \
-            "Name=architecture,Values=x86_64,arm64" \
+            "Name=architecture,Values=x86_64,arm64" \
+            "Name=state,Values=available" \
   --query "Images | sort_by(@, &CreationDate) | [-1]"`;
src/InstallCTA/InstallForNixOS.tsx (1)

16-19: Type the component as FC

Avoids accepting {} props at the type level.

-const InstallForNixOS: FC = ({ version }: TabProps) => {
+const InstallForNixOS: FC<TabProps> = ({ version }) => {
src/InstallCTA/index.tsx (1)

71-89: A11y: ensure proper tab semantics in TabSelector

Tab lists should expose role="tablist"/"tab" and aria-selected; verify TabSelector does this.

src/CodeBlock/index.tsx (1)

47-58: Prevent rendering an empty icon wrapper

Only show the icons container when at least one control will render.

-        {(allowCopy || allowDownload) && (
+        {(allowCopy || (allowDownload && isFile)) && (
           <span className="code-block__icons">
             {allowCopy && <CopyButton data={trimmedCode} />}
             {allowDownload && isFile && (
               <DownloadButton
                 data={trimmedCode}
                 filename={downloadAs.split("/").reverse()[0]}
               />
             )}
           </span>
         )}
src/InstallCTA/UseWithGitHubActions.tsx (2)

6-7: Type the component as FC

Tightens prop typing.

-const UseWithGitHubActions: FC = ({ version }: TabProps) => {
+const UseWithGitHubActions: FC<TabProps> = ({ version }) => {

7-18: Option: set minimal permissions in the workflow

Sensible default for least privilege.

   const code = `
 on:
   push:
+permissions:
+  contents: read
 jobs:
   tests:
     runs-on: ubuntu-24.04
     steps:
       - uses: actions/checkout@v5
       - uses: DeterminateSystems/determinate-nix-action@v${version || "3"}
       - run: nix build .#
 
 `;
src/CodeBlock/index.scss (1)

11-15: Naming consistency: prefer a BEM-scoped class over .highlight

Minor: consider .code-block__highlight to avoid coupling to global .highlight naming.

src/InstallCTA/InstallCTA.stories.tsx (6)

9-23: Use Storybook controls instead of raw type in argTypes

type: "string" isn’t a control and may be ignored by Storybook. Recommend proper controls and (optionally) deriving options from the enum for future-proofing.

   argTypes: {
     initialTab: {
-      type: "string",
-      options: [
+      control: { type: "select" },
+      options: [
         InstallTarget.AWS,
         InstallTarget.GitHub,
         InstallTarget.Linux,
         InstallTarget.MacOS,
         InstallTarget.NixOS,
       ],
     },
     version: {
-      type: "string",
+      control: { type: "text" },
     },
   },

33-35: Fix inconsistent story name

MacOSLatest is labeled “macOS Tagged”. Rename to “macOS Latest” to match intent and avoid confusion with MacOSTagged.

 export const MacOSLatest: Story = {
-  name: "macOS Tagged",
+  name: "macOS Latest",

40-44: Add name for consistency

Other “Latest” stories have readable names; add one here for uniformity.

 export const LinuxLatest: Story = {
+  name: "Linux Latest",
   args: {
     initialTab: InstallTarget.Linux,
   },
 };

46-50: Add name for consistency

Match labeling with GitHub/NixOS Latest.

 export const AWSLatest: Story = {
+  name: "AWS Latest",
   args: {
     initialTab: InstallTarget.AWS,
   },
 };

74-79: Add name for consistency

Provide a friendly label like other Tagged stories.

 export const LinuxTagged: Story = {
+  name: "Linux Tagged",
   args: {
     initialTab: InstallTarget.Linux,
     version: "3.8.6",
   },
 };

81-86: Add name for consistency

Align with GitHubTagged/NixOSTagged.

 export const AWSTagged: Story = {
+  name: "AWS Tagged",
   args: {
     initialTab: InstallTarget.AWS,
     version: "3.8.6",
   },
 };
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 594a614 and c07e350.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (27)
  • package.json (1 hunks)
  • src/CodeBlock/CodeBlock.stories.tsx (2 hunks)
  • src/CodeBlock/index.scss (1 hunks)
  • src/CodeBlock/index.tsx (2 hunks)
  • src/CodeFile/CodeFile.stories.tsx (0 hunks)
  • src/CodeFile/index.scss (0 hunks)
  • src/CodeFile/index.tsx (0 hunks)
  • src/ColorProvider/index.tsx (4 hunks)
  • src/Highlight/index.scss (1 hunks)
  • src/InstallCTA/FindAwsAMIs.tsx (1 hunks)
  • src/InstallCTA/InstallCTA.stories.tsx (2 hunks)
  • src/InstallCTA/InstallForNixOS.tsx (1 hunks)
  • src/InstallCTA/InstallFromCurl.tsx (1 hunks)
  • src/InstallCTA/NavTab.tsx (0 hunks)
  • src/InstallCTA/TabSelector.tsx (2 hunks)
  • src/InstallCTA/UseWithGitHubActions.tsx (1 hunks)
  • src/InstallCTA/index.scss (2 hunks)
  • src/InstallCTA/index.tsx (3 hunks)
  • src/InstallCTA/types.ts (2 hunks)
  • src/Link/index.scss (1 hunks)
  • src/MacInstaller/index.scss (2 hunks)
  • src/MacInstaller/index.tsx (1 hunks)
  • src/hooks/useHighlight.ts (3 hunks)
  • src/hooks/useSystemColorScheme.ts (2 hunks)
  • src/index.ts (0 hunks)
  • src/sass/_mixins.scss (1 hunks)
  • src/sass/_tokens.scss (2 hunks)
💤 Files with no reviewable changes (5)
  • src/CodeFile/index.scss
  • src/CodeFile/index.tsx
  • src/CodeFile/CodeFile.stories.tsx
  • src/InstallCTA/NavTab.tsx
  • src/index.ts
🧰 Additional context used
🧬 Code graph analysis (7)
src/InstallCTA/InstallForNixOS.tsx (1)
src/InstallCTA/index.tsx (1)
  • TabProps (32-37)
src/InstallCTA/types.ts (1)
src/InstallCTA/index.tsx (1)
  • InstallTarget (17-17)
src/CodeBlock/index.tsx (2)
src/index.ts (2)
  • CodeBlockProps (15-15)
  • HighlightLanguage (7-7)
src/hooks/useHighlight.ts (1)
  • HighlightLanguage (21-21)
src/InstallCTA/FindAwsAMIs.tsx (1)
src/InstallCTA/index.tsx (1)
  • TabProps (32-37)
src/InstallCTA/InstallFromCurl.tsx (1)
src/InstallCTA/index.tsx (1)
  • TabProps (32-37)
src/InstallCTA/UseWithGitHubActions.tsx (1)
src/InstallCTA/index.tsx (1)
  • TabProps (32-37)
src/InstallCTA/InstallCTA.stories.tsx (1)
src/InstallCTA/index.tsx (1)
  • InstallTarget (17-17)
🪛 Biome (2.1.2)
src/InstallCTA/index.tsx

[error] 78-83: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)

🔇 Additional comments (14)
src/InstallCTA/types.ts (2)

8-10: LGTM: targets expanded (AWS, GitHub).

Enum additions look consistent with the rest of the PR. Ensure stories and the tab/component map cover these targets.


17-22: SSR safety: avoid defaulting to navigator in the parameter; confirm Windows→Linux mapping.

Defaulting userAgent to navigator.userAgent will throw during SSR — make the param optional and read navigator at runtime if available. Also confirm the product decision to map Windows → InstallTarget.Linux.

File: src/InstallCTA/types.ts Lines: 17-22 (also applies to 24-28)

-export function detectInstallTarget(
-  userAgent = navigator.userAgent,
-): InstallTarget {
-  if (userAgent.includes("Windows")) {
+export function detectInstallTarget(userAgent?: string): InstallTarget {
+  const ua =
+    userAgent ?? (typeof navigator !== "undefined" ? navigator.userAgent : "");
+  if (ua.includes("Windows")) {
     return InstallTarget.Linux;
   }
 
-  if (userAgent.includes("Linux")) {
+  if (ua.includes("Linux")) {
     return InstallTarget.Linux;
   }
 
   return InstallTarget.MacOS;
 }
src/hooks/useSystemColorScheme.ts (1)

5-10: Nice SSR guard on window access.

Prevents crashes during SSR while preserving client behavior.

src/Link/index.scss (1)

8-9: Good a11y improvement.

Underline + offset improves discoverability beyond color alone.

src/sass/_tokens.scss (1)

44-46: Code bg color change acknowledged.

Switching bg-dark to #231f20 aligns with brand black; verify contrast with Shiki dark token colors in real code samples.

src/Highlight/index.scss (1)

11-11: Removing CSS var fallbacks is fine with our Shiki config.

Given defaultColor: false, relying solely on token-driven backgrounds is consistent.

Also applies to: 14-15

src/sass/_mixins.scss (1)

31-40: Solid base border mixin.

Consistent radius and color with light-mode override reads well.

src/InstallCTA/InstallForNixOS.tsx (1)

7-14: Use inputs.determinate for module reference to match the input declaration

The snippet declares inputs.determinate; reference it consistently.

-    # Load the Determinate module
-    determinate.nixosModules.default
+    # Load the Determinate module
+    inputs.determinate.nixosModules.default

If your docs intentionally show the parameter-style binding (outputs = { self, nixpkgs, determinate, ... }:), ignore this change. Otherwise, this keeps the two snippets consistent.

src/MacInstaller/index.scss (1)

15-26: LGTM

Nice light-mode theming and spacing tweaks.

Also applies to: 29-32, 38-50, 56-57

src/InstallCTA/InstallCTA.stories.tsx (5)

52-57: LGTM

Story name and args look good.


59-64: LGTM

Consistent with other “Latest” stories.


66-72: LGTM

Tagged story and version wiring look good.


88-94: LGTM

Naming and args are consistent.


96-102: LGTM

Looks consistent with the rest.

Comment on lines +18 to 19
kind: "snippet" | "file";
}
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Make kind optional for backward compatibility

You already default kind to "snippet"; let callers omit it.

-  kind: "snippet" | "file";
+  kind?: "snippet" | "file";

Also ensure the exported type mirrors this change.

Also applies to: 24-33


🏁 Script executed:

#!/bin/bash
# Verify external exports and callsites for kind
rg -nP 'export\s+(type|interface)\s+CodeBlockProps' src/index.ts
rg -nP --type=tsx '<CodeBlock(?![^>]*\bkind=)' -C1

Length of output: 83


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "PWD: $(pwd)"
echo "=== List src/CodeBlock ==="
ls -la src/CodeBlock 2>/dev/null || echo "src/CodeBlock does not exist"

echo
echo "=== Show src/CodeBlock/index.tsx (first 240 lines) ==="
if [[ -f src/CodeBlock/index.tsx ]]; then
  sed -n '1,240p' src/CodeBlock/index.tsx | nl -ba -v1
else
  echo "MISSING: src/CodeBlock/index.tsx"
fi

echo
echo "=== Search for CodeBlockProps occurrences ==="
rg -n --hidden -S "CodeBlockProps" src || true

echo
echo "=== Search for 'export type|interface CodeBlockProps' ==="
rg -n --hidden -S "export\s+(type|interface)\s+CodeBlockProps" src || true

echo
echo "=== Search for 'kind:' definitions ==="
rg -n --hidden -S "kind\s*:" src || true

echo
echo "=== Find files with <CodeBlock and show context (3 lines) ==="
rg -n --hidden -S "<CodeBlock" -g 'src/**' -C3 || true

echo
echo "=== For each file containing <CodeBlock, check if file contains 'kind=' anywhere ==="
files=$(rg -n --hidden -S "<CodeBlock" -g 'src/**' --files || true)
if [[ -z "${files// /}" ]]; then
  echo "No files with <CodeBlock found under src/"
else
  for f in $files; do
    echo "---- File: $f ----"
    rg -n --hidden -S "<CodeBlock" -n -C3 "$f" || true
    echo "---- 'kind=' occurrences in $f ----"
    rg -n --hidden -S "kind\s*=" -n -C3 "$f" || echo "no kind= in $f"
  done
fi

Length of output: 455


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "PWD: $(pwd)"
echo

echo "=== Show src/CodeBlock/index.tsx ==="
if [[ -f src/CodeBlock/index.tsx ]]; then
  sed -n '1,400p' src/CodeBlock/index.tsx || true
else
  echo "MISSING: src/CodeBlock/index.tsx"
fi

echo
echo "=== Search for CodeBlockProps occurrences ==="
rg -n --hidden --no-ignore "CodeBlockProps" src || true

echo
echo "=== Search for explicit exports of CodeBlockProps ==="
rg -n --hidden --no-ignore "export type CodeBlockProps" src || true
rg -n --hidden --no-ignore "export interface CodeBlockProps" src || true

echo
echo "=== Search for 'kind' property definitions/usages ==="
rg -n --hidden --no-ignore "kind\s*:" src || true
rg -n --hidden --no-ignore "\"snippet\"\s*\|\s*\"file\"" src || true

echo
echo "=== Find <CodeBlock components and whether they pass kind= ==="
rg -n --hidden --no-ignore "<CodeBlock" -g 'src/**' -C2 || true
files=$(rg --hidden --no-ignore "<CodeBlock" -g 'src/**' --files || true)
if [[ -z "${files// /}" ]]; then
  echo "No files with <CodeBlock found under src/"
else
  for f in $files; do
    echo
    echo "---- File: $f ----"
    sed -n '1,200p' "$f" || true
    echo "---- 'kind=' occurrences in $f ----"
    rg -n --hidden --no-ignore "kind\s*=" -n -C2 "$f" || echo "no kind= in $f"
  done
fi

Length of output: 5026


Make CodeBlockProps.kind optional

Align the exported type with the component default and existing call sites.

-  kind: "snippet" | "file";
+  kind?: "snippet" | "file";

Edit: src/CodeBlock/index.tsx (interface CodeBlockProps — kind at ~line 18). src/index.ts re-exports the type — no change needed.

📝 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
kind: "snippet" | "file";
}
kind?: "snippet" | "file";
}
🤖 Prompt for AI Agents
In src/CodeBlock/index.tsx around lines 18-19, the CodeBlockProps.interface
marks kind as required but the component and existing callers treat it as
optional; change the interface to make kind optional (kind?: "snippet" |
"file"), leaving any re-exports unchanged, and run typecheck to ensure no other
call sites need updates.

import langShell from "@shikijs/langs/shellscript";
import langTerraform from "@shikijs/langs/terraform";
import langYaml from "@shikijs/langs/yaml";
import langNix from "@shikijs/langs/nix";
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Nix support looks good; add a safe no-highlight path for "text".

If "text" isn’t a registered Shiki language, codeToHtml can throw. Short-circuit when language === "text" to return escaped HTML without invoking Shiki. Also consider catching unknown langs to avoid runtime crashes.

Apply inside useHighlight:

 function useHighlight(language: HighlightLanguage, code: string): string {
   return useMemo(() => {
+    if (language === "text") {
+      const escape = (s: string) =>
+        s.replace(/[&<>"']/g, (ch) => ({ "&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;" }[ch]!));
+      return `<pre class="highlight"><code>${escape(code)}</code></pre>`;
+    }
     const html = getShiki().codeToHtml(code, {
       lang: language,
       themes: {
         light: "github-light",
         dark: "github-dark",
       },
       defaultColor: false,
       structure: "inline",
     });
 
     return html;
   }, [language, code]);
 }

Also applies to: 15-20, 28-29

🤖 Prompt for AI Agents
In src/hooks/useHighlight.ts around lines 6, 15-20 and 28-29, add a safe
no-highlight path for language === "text" and guard against unknown Shiki
languages: short-circuit before calling shiki.codeToHtml to return HTML-escaped
code for plain text, and wrap the shiki highlighting call in a try/catch (or
check shiki.getLanguage) to fall back to escaped HTML when the requested
language isn't registered or an error occurs; ensure you import or use an
existing HTML-escape utility and return the same shape as the successful
codeToHtml result.

Comment on lines +59 to 63
display: flex;
text-align: center;
align-items: center;
text-wrap-mode: nowrap;

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Use white-space: nowrap (text-wrap-mode is nonstandard/unsupported)

Fixes a CSS correctness issue.

-  text-wrap-mode: nowrap;
+  white-space: nowrap;
📝 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
display: flex;
text-align: center;
align-items: center;
text-wrap-mode: nowrap;
display: flex;
text-align: center;
align-items: center;
white-space: nowrap;
🤖 Prompt for AI Agents
In src/InstallCTA/index.scss around lines 59 to 63, the stylesheet uses the
nonstandard property text-wrap-mode: nowrap; — replace that line with the
standard property white-space: nowrap; so the text will not wrap across
browsers; keep the surrounding declarations (display, text-align, align-items)
as-is.

Comment on lines +77 to +84
{ctaTabs.map(([target, icon]) => (
<TabSelector
name={target}
icon={icon}
active={activeTab == target}
onClick={() => setActiveTab(target)}
/>
))}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add a key to mapped elements; fix strict equality

Resolves the Biome error and avoids accidental coercion.

-        {ctaTabs.map(([target, icon]) => (
-          <TabSelector
+        {ctaTabs.map(([target, icon]) => (
+          <TabSelector
+            key={target}
             name={target}
             icon={icon}
-            active={activeTab == target}
+            active={activeTab === target}
             onClick={() => setActiveTab(target)}
           />
         ))}
📝 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
{ctaTabs.map(([target, icon]) => (
<TabSelector
name={target}
icon={icon}
active={activeTab == target}
onClick={() => setActiveTab(target)}
/>
))}
{ctaTabs.map(([target, icon]) => (
<TabSelector
key={target}
name={target}
icon={icon}
active={activeTab === target}
onClick={() => setActiveTab(target)}
/>
))}
🧰 Tools
🪛 Biome (2.1.2)

[error] 78-83: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)

🤖 Prompt for AI Agents
In src/InstallCTA/index.tsx around lines 77 to 84, the mapped TabSelector
elements are missing a key prop and use loose equality; add a unique key (e.g.,
key={target}) to the TabSelector returned by the map and change the active
comparison from == to strict === (activeTab === target) to satisfy React/Biome
rules and avoid accidental coercion.

Comment on lines +6 to +12
const installScript = (version: string | undefined) => {
if (typeof version === "undefined") {
return "curl -fsSL https://install.determinate.systems/nix | sh -s -- install --determinate";
} else {
return `curl -fsSL https://install.determinate.systems/nix/tag/v${version} | sh -s -- install --determinate`;
}
};
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Sanitize version before embedding in a shell command URL.

Unencoded versions can break the URL users copy-paste; encode for safety.

-const installScript = (version: string | undefined) => {
-  if (typeof version === "undefined") {
+const installScript = (version: string | undefined) => {
+  if (typeof version === "undefined" || version === "") {
     return "curl -fsSL https://install.determinate.systems/nix | sh -s -- install --determinate";
   } else {
-    return `curl -fsSL https://install.determinate.systems/nix/tag/v${version} | sh -s -- install --determinate`;
+    const v = encodeURIComponent(version);
+    return `curl -fsSL https://install.determinate.systems/nix/tag/v${v} | sh -s -- install --determinate`;
   }
 };
📝 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
const installScript = (version: string | undefined) => {
if (typeof version === "undefined") {
return "curl -fsSL https://install.determinate.systems/nix | sh -s -- install --determinate";
} else {
return `curl -fsSL https://install.determinate.systems/nix/tag/v${version} | sh -s -- install --determinate`;
}
};
const installScript = (version: string | undefined) => {
if (typeof version === "undefined" || version === "") {
return "curl -fsSL https://install.determinate.systems/nix | sh -s -- install --determinate";
} else {
const v = encodeURIComponent(version);
return `curl -fsSL https://install.determinate.systems/nix/tag/v${v} | sh -s -- install --determinate`;
}
};
🤖 Prompt for AI Agents
In src/InstallCTA/InstallFromCurl.tsx around lines 6 to 12, the version string
is interpolated directly into the install URL which can break or introduce
unsafe characters; sanitize the version by URL-encoding it (e.g., use
encodeURIComponent) before embedding into the backtick string, ensure the
undefined branch remains unchanged, and use the encodedVersion variable in the
tag path so the generated curl URL is safe for copy-paste.

Comment on lines +14 to 15
const InstallFromCurl: FC = ({ version }: TabProps) => (
<>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Props typing bug: component exported as FC<{}> (loses version).

Typing the variable as FC without generics erases the version prop from the public type, causing TS errors for consumers.

Apply:

-const InstallFromCurl: FC = ({ version }: TabProps) => (
+const InstallFromCurl: FC<TabProps> = ({ version }) => (
📝 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
const InstallFromCurl: FC = ({ version }: TabProps) => (
<>
const InstallFromCurl: FC<TabProps> = ({ version }) => (
<>
🤖 Prompt for AI Agents
In src/InstallCTA/InstallFromCurl.tsx around lines 14 to 15, the component is
typed as FC without generics which erases the version prop; change the component
type to FC<TabProps> and adjust the parameter typing by removing the inline cast
(e.g. keep destructuring { version } without : TabProps) so the exported
component retains the correct public prop type; ensure TabProps is
imported/available and update the signature to use the generic FC<TabProps>.

Comment on lines +17 to +21
const urlPath = version ? `tag/v${version}` : `stable`;
return (
<a
href={`https://install.determinate.systems/determinate-pkg/${urlPath}/Universal`}
className="mac-installer"
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Encode version in URLs to avoid malformed links.

Protect the path segment when version contains spaces or special chars.

-  const urlPath = version ? `tag/v${version}` : `stable`;
+  const urlPath = version ? `tag/v${encodeURIComponent(version)}` : `stable`;
📝 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
const urlPath = version ? `tag/v${version}` : `stable`;
return (
<a
href={`https://install.determinate.systems/determinate-pkg/${urlPath}/Universal`}
className="mac-installer"
const urlPath = version ? `tag/v${encodeURIComponent(version)}` : `stable`;
return (
<a
href={`https://install.determinate.systems/determinate-pkg/${urlPath}/Universal`}
className="mac-installer"
🤖 Prompt for AI Agents
In src/MacInstaller/index.tsx around lines 17 to 21, the URL uses the raw
version string which can produce malformed links if version contains spaces or
special characters; update the code to URL-encode the version segment (e.g., use
encodeURIComponent on the version value when building urlPath or the href) so
the href becomes safe, preserving the "v" prefix only once and leaving the
stable branch unchanged.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
src/InstallCTA/types.ts (1)

17-19: Make detectInstallTarget SSR-safe (navigator may be undefined).

Calling this during SSR will throw. Guard access to navigator and work off a local ua string.

-export function detectInstallTarget(
-  userAgent = navigator.userAgent,
-): InstallTarget {
-  if (userAgent.includes("Windows")) {
+export function detectInstallTarget(userAgent?: string): InstallTarget {
+  const ua =
+    userAgent ??
+    (typeof navigator !== "undefined" ? navigator.userAgent : "");
+  if (ua.includes("Windows")) {
     return InstallTarget.Linux;
   }
 
-  if (userAgent.includes("Linux")) {
+  if (ua.includes("Linux")) {
     return InstallTarget.Linux;
   }
 
   return InstallTarget.MacOS;
 }

Also applies to: 20-29

♻️ Duplicate comments (1)
src/InstallCTA/index.tsx (1)

77-83: Add a key to mapped elements; use strict equality.

Avoid React warnings and accidental coercion.

-        {ctaTabs.map(([target, icon]) => (
+        {ctaTabs.map(([target, icon]) => (
           <TabSelector
+            key={target}
             name={target}
             icon={icon}
-            active={activeTab == target}
+            active={activeTab === target}
             onClick={() => setActiveTab(target)}
           />
         ))}
🧹 Nitpick comments (14)
src/InstallCTA/types.ts (1)

24-26: Optionally recognize Android/ChromeOS as Linux.

Many Android/CrOS UAs won’t match "Linux" literally.

-  if (ua.includes("Linux")) {
+  if (ua.includes("Linux") || ua.includes("Android") || ua.includes("CrOS")) {
     return InstallTarget.Linux;
   }
src/InstallCTA/index.tsx (2)

15-15: Prefer IconType over React.FC for react-icons.

IconType is the canonical type for these icons. Validate TabSelector’s prop type before changing.

-import type { IconBaseProps } from "react-icons";
+import type { IconType } from "react-icons";
 
-const ctaTabs: [InstallTarget, React.FC<IconBaseProps>][] = [
+const ctaTabs: [InstallTarget, IconType][] = [

Also applies to: 39-45


1-1: Client-only detection to avoid SSR mismatches.

Initialize with a stable default and detect on mount. This also sidesteps any future SSR access pitfalls.

-import { useState, type FC } from "react";
+import { useState, useEffect, type FC } from "react";
@@
-const InstallCTA: FC<InstallCTAProps> = ({ initialTab, version }) => {
-  const [activeTab, setActiveTab] = useState<InstallTarget>(() => {
-    if (initialTab) {
-      return initialTab;
-    }
-
-    return detectInstallTarget();
-  });
+const InstallCTA: FC<InstallCTAProps> = ({ initialTab, version }) => {
+  const [activeTab, setActiveTab] = useState<InstallTarget>(
+    initialTab ?? InstallTarget.MacOS,
+  );
+  useEffect(() => {
+    if (!initialTab) {
+      setActiveTab(detectInstallTarget());
+    }
+  }, [initialTab]);

Also applies to: 60-67

src/InstallCTA/InstallCTA.stories.tsx (2)

33-35: Fix mislabeled story name (Latest vs Tagged).

MacOSLatest should display “macOS Latest”.

-export const MacOSLatest: Story = {
-  name: "macOS Tagged",
+export const MacOSLatest: Story = {
+  name: "macOS Latest",

9-23: Enable proper Storybook controls for args.

Use control types instead of argTypes.type to get a select/text UI.

   argTypes: {
     initialTab: {
-      type: "string",
+      control: { type: "select" },
       options: [
         InstallTarget.AWS,
         InstallTarget.GitHub,
         InstallTarget.Linux,
         InstallTarget.MacOS,
         InstallTarget.NixOS,
       ],
     },
     version: {
-      type: "string",
+      control: { type: "text" },
     },
   },
src/PageLayout/index.tsx (1)

26-32: Per-pane wrapper: add a class and avoid index fallback keys.

Wrapping each pane is good. Add a specific class for styling hooks and prefer explicit keys over index to avoid reconciliation glitches when panes reorder.

Apply:

-            {panes.map((pane, idx) => (
-              <div key={pane.key ?? idx}>{pane}</div>
-            ))}
+            {panes.map((pane, idx) => (
+              <div key={pane.key ?? idx} className="page-layout__pane">
+                {pane}
+              </div>
+            ))}

Please double-check any CSS that assumed panes were direct children of .page-layout__panes.

src/PageLayout/PageLayout.stories.tsx (1)

64-64: Add a key to the single pane element.

Eliminates the “key” lint error and avoids index fallback keys.

-    panes: [<Placeholder height="3em" label="Pane 1" />],
+    panes: [<Placeholder key="pane-1" height="3em" label="Pane 1" />],
src/Navigation/index.scss (1)

55-61: Avoid fixed widths that can overflow on very narrow viewports.

Use a responsive width to prevent horizontal scrolling.

-    .navigation__element {
-      width: 320px;
-
-      @media screen and (width < 650px) {
-        width: 268px;
-      }
-    }
+    .navigation__element {
+      /* Fit within viewport while capping at desktop size */
+      width: min(320px, 100vw);
+    }
src/Navigation/index.tsx (1)

8-11: Broaden children type and preserve child keys.

Support single-child usage and avoid index keys by normalizing via React.Children.toArray and using element keys when present.

 export interface NavigationProps {
   initialState?: "open" | "closed";
-  children: React.ReactNode[];
+  children: React.ReactNode;
 }
@@
-        {children.map((child, idx) => (
-          <div key={idx} className="navigation__element">
-            {child}
-          </div>
-        ))}
+        {React.Children.toArray(children).map((child, idx) => {
+          const key =
+            React.isValidElement(child) && child.key != null
+              ? String(child.key)
+              : String(idx);
+          return (
+            <div key={key} className="navigation__element">
+              {child}
+            </div>
+          );
+        })}

Also applies to: 47-51

src/Navigation/Navigation.stories.tsx (5)

27-29: Add keys to children array elements to satisfy React and lint.

-    children: [
-      <Placeholder height="100%" label="Primary Element" />,
-      <Placeholder height="100%" label="Navigation Link" />,
-    ],
+    children: [
+      <Placeholder key="primary" height="100%" label="Primary Element" />,
+      <Placeholder key="link" height="100%" label="Navigation Link" />,
+    ],

50-52: Add keys in InHeader story.

-    children: [
-      <Placeholder height="100%" label="Lorem" />,
-      <Placeholder height="100%" label="Ipsum" />,
-    ],
+    children: [
+      <Placeholder key="lorem" height="100%" label="Lorem" />,
+      <Placeholder key="ipsum" height="100%" label="Ipsum" />,
+    ],

69-71: Add keys in DefaultOpen story.

-    children: [
-      <Placeholder height="100%" label="Lorem" />,
-      <Placeholder height="100%" label="Ipsum" />,
-    ],
+    children: [
+      <Placeholder key="lorem" height="100%" label="Lorem" />,
+      <Placeholder key="ipsum" height="100%" label="Ipsum" />,
+    ],

94-96: Add keys in InHeaderOpen story.

-    children: [
-      <Placeholder height="100%" label="Lorem" />,
-      <Placeholder height="100%" label="Ipsum" />,
-    ],
+    children: [
+      <Placeholder key="lorem" height="100%" label="Lorem" />,
+      <Placeholder key="ipsum" height="100%" label="Ipsum" />,
+    ],

23-31: Optional: switch stories to JSX children instead of a children prop.

This aligns with React conventions and eliminates the no-children-prop lint across stories.

Example for Default:

-export const Default: Story = {
-  args: {
-    initialState: undefined,
-    children: [
-      <Placeholder key="primary" height="100%" label="Primary Element" />,
-      <Placeholder key="link" height="100%" label="Navigation Link" />,
-    ],
-  },
-  render: (props) => (
+export const Default: Story = {
+  args: { initialState: undefined },
+  render: (props) => (
     <div style={{ height: "300px", width: "500px", border: "1px solid black", display: "flex", justifyContent: "end" }}>
-      <Navigation {...props} />
+      <Navigation {...props}>
+        <Placeholder key="primary" height="100%" label="Primary Element" />
+        <Placeholder key="link" height="100%" label="Navigation Link" />
+      </Navigation>
     </div>
   ),
 };

Apply similarly to the other stories.

Also applies to: 46-63, 65-88, 90-107

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c07e350 and f0f28a1.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (33)
  • package.json (1 hunks)
  • src/CodeBlock/CodeBlock.stories.tsx (2 hunks)
  • src/CodeBlock/index.scss (1 hunks)
  • src/CodeBlock/index.tsx (2 hunks)
  • src/CodeFile/CodeFile.stories.tsx (0 hunks)
  • src/CodeFile/index.scss (0 hunks)
  • src/CodeFile/index.tsx (0 hunks)
  • src/ColorProvider/index.tsx (4 hunks)
  • src/Header/index.tsx (1 hunks)
  • src/Highlight/index.scss (1 hunks)
  • src/InstallCTA/FindAwsAMIs.tsx (1 hunks)
  • src/InstallCTA/InstallCTA.stories.tsx (2 hunks)
  • src/InstallCTA/InstallForNixOS.tsx (1 hunks)
  • src/InstallCTA/InstallFromCurl.tsx (1 hunks)
  • src/InstallCTA/NavTab.tsx (0 hunks)
  • src/InstallCTA/TabSelector.tsx (2 hunks)
  • src/InstallCTA/UseWithGitHubActions.tsx (1 hunks)
  • src/InstallCTA/index.scss (2 hunks)
  • src/InstallCTA/index.tsx (3 hunks)
  • src/InstallCTA/types.ts (2 hunks)
  • src/Link/index.scss (1 hunks)
  • src/MacInstaller/index.scss (2 hunks)
  • src/MacInstaller/index.tsx (1 hunks)
  • src/Navigation/Navigation.stories.tsx (1 hunks)
  • src/Navigation/index.scss (1 hunks)
  • src/Navigation/index.tsx (1 hunks)
  • src/PageLayout/PageLayout.stories.tsx (2 hunks)
  • src/PageLayout/index.tsx (1 hunks)
  • src/hooks/useHighlight.ts (3 hunks)
  • src/hooks/useSystemColorScheme.ts (2 hunks)
  • src/index.ts (1 hunks)
  • src/sass/_mixins.scss (1 hunks)
  • src/sass/_tokens.scss (2 hunks)
💤 Files with no reviewable changes (4)
  • src/InstallCTA/NavTab.tsx
  • src/CodeFile/index.scss
  • src/CodeFile/index.tsx
  • src/CodeFile/CodeFile.stories.tsx
🚧 Files skipped from review as they are similar to previous changes (20)
  • src/MacInstaller/index.tsx
  • src/sass/_tokens.scss
  • src/CodeBlock/index.tsx
  • src/InstallCTA/TabSelector.tsx
  • src/InstallCTA/InstallForNixOS.tsx
  • src/Link/index.scss
  • src/index.ts
  • src/InstallCTA/UseWithGitHubActions.tsx
  • src/CodeBlock/CodeBlock.stories.tsx
  • package.json
  • src/CodeBlock/index.scss
  • src/hooks/useHighlight.ts
  • src/InstallCTA/FindAwsAMIs.tsx
  • src/Highlight/index.scss
  • src/sass/_mixins.scss
  • src/hooks/useSystemColorScheme.ts
  • src/MacInstaller/index.scss
  • src/InstallCTA/InstallFromCurl.tsx
  • src/ColorProvider/index.tsx
  • src/InstallCTA/index.scss
🧰 Additional context used
🧬 Code graph analysis (6)
src/Navigation/Navigation.stories.tsx (1)
src/Placeholder/index.tsx (1)
  • Placeholder (9-29)
src/PageLayout/PageLayout.stories.tsx (1)
src/Placeholder/index.tsx (1)
  • Placeholder (9-29)
src/Header/index.tsx (1)
src/index.ts (1)
  • HeaderProps (58-58)
src/Navigation/index.tsx (1)
src/index.ts (1)
  • NavigationProps (78-78)
src/InstallCTA/types.ts (1)
src/InstallCTA/index.tsx (1)
  • InstallTarget (17-17)
src/InstallCTA/InstallCTA.stories.tsx (1)
src/InstallCTA/index.tsx (1)
  • InstallTarget (17-17)
🪛 Biome (2.1.2)
src/Navigation/Navigation.stories.tsx

[error] 27-27: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)


[error] 28-28: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)


[error] 50-50: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)


[error] 51-51: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)


[error] 69-69: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)


[error] 70-70: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)


[error] 94-94: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)


[error] 95-95: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)

src/PageLayout/PageLayout.stories.tsx

[error] 55-55: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 64-64: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)

src/InstallCTA/index.tsx

[error] 78-83: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)

🔇 Additional comments (6)
src/InstallCTA/types.ts (1)

20-22: Confirm product intent: map Windows → Linux.

If Windows users shouldn’t be funneled to Linux instructions, consider a neutral landing or explicit Windows guidance.

src/InstallCTA/index.tsx (1)

47-53: All mapped components accept an optional version prop.
MacInstaller declares MacInstallerProps { version?: string }; InstallFromCurl, FindAwsAMIs, UseWithGitHubActions and InstallForNixOS use TabProps { version?: string }. No changes required.

src/PageLayout/index.tsx (1)

26-32: LGTM: conditional rendering and per-item wrapping improves reconciliation.

No functional concerns with the conditional panes rendering; this should reduce unnecessary DOM churn.

src/Header/index.tsx (1)

8-9: Public API tightening — verify downstream call sites & re-exports

elements changed to React.ReactElement[] (src/Header/index.tsx); src/index.ts re-exports HeaderProps. Repo search found no in-repo usages of elements — verify stories and external consumers accept an array of React elements and update call-sites or types if they previously relied on ReactNode/other types.

src/Navigation/index.scss (1)

28-31: Confirm focus-visible styles on the toggle.

Ensure @include mixins.svg-button; provides a clear :focus-visible outline for keyboard users. If not, add an explicit focus style.

src/Navigation/index.tsx (1)

32-41: A11y details look solid.

Good use of useId, aria-controls/expanded, and hiding decorative SVG via aria-hidden and focusable="false".

const Header: FC<HeaderProps> = ({ logo, elements = [] }) => {
return (
<header className="header" role="banner">
<div className="header">
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Restore semantic landmark: use

(banner).

Switching the root to a div loses the banner landmark. Use the semantic element (role optional).

-    <div className="header">
+    <header className="header" role="banner">
...
-    </div>
+    </header>

Also applies to: 25-25

🤖 Prompt for AI Agents
In src/Header/index.tsx around lines 13 and 25 the root element was changed from
a semantic <header> (banner) to a <div>, removing the landmark; replace the <div
className="header"> (and the corresponding closing tag) with a semantic <header
className="header"> to restore the banner landmark, optionally add role="banner"
if you need explicit role support for older assistive tech, and ensure any
props/attributes and CSS selectors continue to work with the header element.

Comment on lines +55 to +60
children={[
<Placeholder key="lorem" height="100%" label="Lorem" />,
<Placeholder key="ipsum" height="100%" label="Ipsum" />,
]}
/>,
]}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Don’t pass children prop explicitly; use JSX children.

Fixes the lint error and matches React conventions.

-          <Navigation
-            key="nav"
-            children={[
-              <Placeholder key="lorem" height="100%" label="Lorem" />,
-              <Placeholder key="ipsum" height="100%" label="Ipsum" />,
-            ]}
-          />,
+          <Navigation key="nav">
+            <Placeholder key="lorem" height="100%" label="Lorem" />
+            <Placeholder key="ipsum" height="100%" label="Ipsum" />
+          </Navigation>,
📝 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
children={[
<Placeholder key="lorem" height="100%" label="Lorem" />,
<Placeholder key="ipsum" height="100%" label="Ipsum" />,
]}
/>,
]}
<Navigation key="nav">
<Placeholder key="lorem" height="100%" label="Lorem" />
<Placeholder key="ipsum" height="100%" label="Ipsum" />
</Navigation>,
]}
🧰 Tools
🪛 Biome (2.1.2)

[error] 55-55: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

🤖 Prompt for AI Agents
In src/PageLayout/PageLayout.stories.tsx around lines 55 to 60, the story is
passing children via an explicit children prop which triggers a lint error and
goes against React conventions; remove the children={...} prop and instead place
the Placeholder elements as normal JSX children inside the component tag
(keeping their key and props intact), e.g. collapse the children array and nest
the two <Placeholder ... /> elements between the component's opening and closing
tags so the story uses standard JSX children.

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.

1 participant