Skip to content

Conversation

@sacrosanctic
Copy link
Contributor

@sacrosanctic sacrosanctic commented Feb 9, 2026

In this PR

  • setup storybook
  • outline how storybook will integrate with the project

todo

  • setup chromatic @JReinhold
  • mocks for nuxt modules

considerations

  • story scope and converage
  • storybook and vitest has redundant tests
  • define component boundaries

notes

notes for me

  • LicenseDisplay - should handle the nullish case internally
  • DownloadAnalytics - should be multiple components

@vercel
Copy link

vercel bot commented Feb 9, 2026

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

Project Deployment Actions Updated (UTC)
docs.npmx.dev Ready Ready Preview, Comment Feb 12, 2026 7:34am
npmx.dev Ready Ready Preview, Comment Feb 12, 2026 7:34am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
npmx-lunaria Ignored Ignored Feb 12, 2026 7:34am

Request Review

@codecov
Copy link

codecov bot commented Feb 9, 2026

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
1664 1 1663 6
View the top 1 failed test(s) by shortest run time
test/unit/a11y-component-coverage.spec.ts > a11y component test coverage > should have accessibility tests for all components (or be explicitly skipped)
Stack Traces | 0.0138s run time
AssertionError: Missing a11y tests for 80 component(s):
  - AppFooter.vue
  - AppHeader.vue
  - AppLogo.vue
  - BaseCard.vue
  - BuildEnvironment.vue
  - Button/Base.vue
  - CallToAction.vue
  - Code/DirectoryListing.vue
  - Code/FileTree.vue
  - Code/MobileTreeDrawer.vue
  - Code/Viewer.vue
  - CollapsibleSection.vue
  - ColumnPicker.vue
  - Compare/ComparisonGrid.vue
  - Compare/FacetCard.vue
  - Compare/FacetRow.vue
  - Compare/FacetSelector.vue
  - Compare/LineChart.vue
  - Compare/PackageSelector.vue
  - Compare/ReplacementSuggestion.vue
  - DateTime.vue
  - DependencyPathPopup.vue
  - Filter/Chips.vue
  - Filter/Panel.vue
  - Header/AccountMenu.client.vue
  - Header/ConnectorModal.vue
  - Header/SearchBox.vue
  - Input/Base.vue
  - LicenseDisplay.vue
  - Link/Base.vue
  - LoadingSpinner.vue
  - Org/MembersPanel.vue
  - Org/OperationsQueue.vue
  - Org/TeamsPanel.vue
  - Package/AccessControls.vue
  - Package/Card.vue
  - Package/ChartModal.vue
  - Package/ClaimPackageModal.vue
  - Package/Compatibility.vue
  - Package/Dependencies.vue
  - Package/DeprecatedTree.vue
  - Package/InstallScripts.vue
  - Package/Keywords.vue
  - Package/List.vue
  - Package/ListControls.vue
  - Package/ListToolbar.vue
  - Package/Maintainers.vue
  - Package/ManagerSelect.vue
  - Package/MetricsBadges.vue
  - Package/Playgrounds.vue
  - Package/Replacement.vue
  - Package/Sidebar.vue
  - Package/Skeleton.vue
  - Package/SkillsCard.vue
  - Package/Table.vue
  - Package/TableRow.vue
  - Package/Versions.vue
  - Package/VulnerabilityTree.vue
  - PackageProvenanceSection.vue
  - PaginationControls.vue
  - ProvenanceBadge.vue
  - Readme.vue
  - ReadmeTocDropdown.vue
  - SearchProviderToggle.client.vue
  - SearchSuggestionCard.vue
  - Select/Base.vue
  - Select/Field.vue
  - Settings/AccentColorPicker.vue
  - Settings/BgThemePicker.vue
  - Settings/Toggle.client.vue
  - Tag/RadioButton.vue
  - Tag/Static.vue
  - Terminal/Execute.vue
  - Terminal/Install.vue
  - Tooltip/Announce.vue
  - Tooltip/App.vue
  - Tooltip/Base.vue
  - User/Avatar.vue
  - VersionSelector.vue
  - ViewModeToggle.vue

To fix: Add tests in test/nuxt/a11y.spec.ts or add to SKIPPED_COMPONENTS in test/unit/a11y-component-coverage.spec.ts with justification.: expected 80 to equal +0

- Expected
+ Received

- 0
+ 80

 ❯ test/unit/a11y-component-coverage.spec.ts:166:12
 ❯ node_modules/.pnpm/@voidzero-dev+vite-plus-test@0.0.0-833c515fa25cef20905a7f9affb156dfa6f151ab_@types+node_310e5dad6395fccdf5f424a1dccab9b9/node_modules/@voidzero-dev/vite-plus-test/dist/@vitest/runner/index.js:145:14
 ❯ node_modules/.pnpm/@voidzero-dev+vite-plus-test@0.0.0-833c515fa25cef20905a7f9affb156dfa6f151ab_@types+node_310e5dad6395fccdf5f424a1dccab9b9/node_modules/@voidzero-dev/vite-plus-test/dist/@vitest/runner/index.js:915:28
 ❯ node_modules/.pnpm/@voidzero-dev+vite-plus-test@0.0.0-833c515fa25cef20905a7f9affb156dfa6f151ab_@types+node_310e5dad6395fccdf5f424a1dccab9b9/node_modules/@voidzero-dev/vite-plus-test/dist/@vitest/runner/index.js:1243:24
 ❯ runWithTimeout node_modules/.pnpm/@voidzero-dev+vite-plus-test@0.0.0-833c515fa25cef20905a7f9affb156dfa6f151ab_@types+node_310e5dad6395fccdf5f424a1dccab9b9/node_modules/@voidzero-dev/vite-plus-test/dist/@vitest/runner/index.js:1209:12
 ❯ node_modules/.pnpm/@voidzero-dev+vite-plus-test@0.0.0-833c515fa25cef20905a7f9affb156dfa6f151ab_@types+node_310e5dad6395fccdf5f424a1dccab9b9/node_modules/@voidzero-dev/vite-plus-test/dist/@vitest/runner/index.js:1653:42
 ❯ Traces.$ node_modules/.pnpm/@voidzero-dev+vite-plus-test@0.0.0-833c515fa25cef20905a7f9affb156dfa6f151ab_@types+node_310e5dad6395fccdf5f424a1dccab9b9/node_modules/@.../dist/chunks/traces.CCmnQaNT.js:142:29
 ❯ trace node_modules/.pnpm/@voidzero-dev+vite-plus-test@0.0.0-833c515fa25cef20905a7f9affb156dfa6f151ab_@types+node_310e5dad6395fccdf5f424a1dccab9b9/node_modules/@.../dist/chunks/test.B8ej_ZHS.js:239:23
 ❯ runTest node_modules/.pnpm/@voidzero-dev+vite-plus-test@0.0.0-833c515fa25cef20905a7f9affb156dfa6f151ab_@types+node_310e5dad6395fccdf5f424a1dccab9b9/node_modules/@voidzero-dev/vite-plus-test/dist/@vitest/runner/index.js:1653:17

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

Copy link
Collaborator

@JReinhold JReinhold left a comment

Choose a reason for hiding this comment

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

my suggestions here could potentially be a longer-term solution to the unsupported parts of nuxt.

Copy link
Collaborator

@JReinhold JReinhold left a comment

Choose a reason for hiding this comment

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

great job! I didn't look too much into the stories themselves, but it looked good.

@sacrosanctic
Copy link
Contributor Author

great job! I didn't look too much into the stories themselves, but it looked good.

No worries, the stories will be iterative. I will be removing them so they can be discussed in their own PR.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

📝 Walkthrough

Walkthrough

Adds Storybook to the Nuxt/Vue project: new Storybook config (.storybook/main.ts) and preview (.storybook/preview.ts) with theme, locale and accent controls; documentation (.storybook/README.md and docs/content/2.guide/3.storybook.md). Introduces component stories for Button and Input (app/components/.../*.stories.ts) and exposes new props on app/components/Button/Base.vue (disabled, type, variant, size, ariaKeyshortcuts, block, classicon). Updates nuxt.config.ts to toggle settings when Storybook/Vitest are active, adds Storybook scripts and dependencies to package.json, and adjusts .gitignore and VS Code settings.

🚥 Pre-merge checks | ✅ 1
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The pull request description accurately relates to the changeset, outlining Storybook setup and integration plans with specific TODOs and considerations.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

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: 3

🧹 Nitpick comments (4)
.storybook/README.md (1)

47-51: Add language specifier to fenced code block.

The static analysis tool flagged this code block for missing a language identifier. Adding text or plaintext will satisfy the linter and improve rendering consistency.

📝 Proposed fix
-```
+```text
 components/
 ├── Button.vue
 └── Button.stories.ts
</details>

</blockquote></details>
<details>
<summary>nuxt.config.ts (1)</summary><blockquote>

`19-19`: **Consider using `.filter(Boolean)` for cleaner module array.**

While Nuxt handles `undefined` values in the modules array, using `.filter(Boolean)` makes the intent more explicit and avoids potential confusion.



<details>
<summary>♻️ Alternative approach</summary>

```diff
   modules: [
     '@unocss/nuxt',
     '@nuxtjs/html-validator',
     '@nuxt/scripts',
     '@nuxt/a11y',
     '@nuxt/fonts',
     'nuxt-og-image',
     '@nuxt/test-utils',
     '@vite-pwa/nuxt',
     '@vueuse/nuxt',
     '@nuxtjs/i18n',
-    isStorybook ? undefined : '@nuxtjs/color-mode',
-  ],
+    !isStorybook && '@nuxtjs/color-mode',
+  ].filter(Boolean),
app/components/Button/Base.vue (1)

25-26: Update icon class example to use colon syntax.

The JSDoc example uses dash-separated form (i-carbon-add), but the project convention is to use colon syntax (i-carbon:add) for UnoCSS icons. This aids UnoCSS in resolving the correct collection directly.

📝 Suggested documentation fix
-    /** Icon class (e.g., i-carbon-add) */
+    /** Icon class (e.g., i-carbon:add) */
     classicon?: string

Based on learnings: "In Vue components that use UnoCSS with the preset-icons collection, prefer colon-syntax for icons (e.g., i-carbon:checkmark) over the dash-separated form (i-carbon-checkmark)."

app/components/Button/Base.stories.ts (1)

12-112: Consider extracting a reusable render helper to reduce duplication.

Each story repeats the same render function pattern. While this is a common Storybook approach, you could reduce boilerplate by extracting a helper.

♻️ Optional refactor to reduce duplication
+const createRender = (label: string) => (args: Story['args']) => ({
+  components: { Component },
+  setup() {
+    return { args }
+  },
+  template: `<Component v-bind="args">${label}</Component>`,
+})
+
 export const Primary: Story = {
   args: {
     variant: 'primary',
     size: 'medium',
   },
-  render: args => ({
-    components: { Component },
-    setup() {
-      return { args }
-    },
-    template: '<Component v-bind="args">Primary Button</Component>',
-  }),
+  render: createRender('Primary Button'),
 }

Apply the same pattern to other stories.

Comment on lines +1 to +11
import type { StorybookConfig } from '@nuxtjs/storybook'

const config = {
stories: ['../app/**/*.stories.@(js|ts|mdx)'],
addons: ['@storybook/addon-a11y', '@storybook/addon-docs'],
framework: '@storybook-vue/nuxt',
features: {
backgrounds: false,
},
} satisfies StorybookConfig
export default config
Copy link
Contributor

@coderabbitai coderabbitai bot Feb 12, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

# Check package.json for the dependency
echo "=== Checking package.json for `@storybook-vue/nuxt` ==="
if [ -f "package.json" ]; then
  jq '.devDependencies["@storybook-vue/nuxt"] // .dependencies["@storybook-vue/nuxt"] // "NOT FOUND"' package.json
else
  echo "package.json not found"
fi

echo ""
echo "=== Checking `@nuxtjs/storybook` dependency ==="
if [ -f "package.json" ]; then
  jq '.devDependencies["@nuxtjs/storybook"] // .dependencies["@nuxtjs/storybook"] // "NOT FOUND"' package.json
fi

echo ""
echo "=== Searching for knip configuration ==="
find . -type f \( -name "knip.json" -o -name "knip.ts" -o -name "knip.js" \) 2>/dev/null | head -10
if [ $? -eq 0 ]; then
  fd -t f -e json -e ts -e js -path "*knip*" --exec cat {} \; 2>/dev/null | head -100
fi

echo ""
echo "=== Checking package.json for knip config ==="
if [ -f "package.json" ]; then
  jq '.knip // "NOT FOUND"' package.json
fi

Repository: npmx-dev/npmx.dev

Length of output: 293


🏁 Script executed:

#!/bin/bash

echo "=== Contents of knip.ts ==="
if [ -f "knip.ts" ]; then
  cat -n knip.ts
fi

echo ""
echo "=== Checking if `@storybook-vue/nuxt` appears in knip ignoreDependencies ==="
if [ -f "knip.ts" ]; then
  grep -i "storybook-vue\|ignoreDependencies\|ignoreWorkspaces" knip.ts
fi

echo ""
echo "=== Checking node_modules for `@storybook-vue/nuxt` ==="
if [ -d "node_modules/@storybook-vue" ]; then
  ls -la node_modules/@storybook-vue/
else
  echo "@storybook-vue directory not found in node_modules (expected in sandbox)"
fi

echo ""
echo "=== Checking `@nuxtjs/storybook` package.json for peer dependencies ==="
if [ -f "node_modules/@nuxtjs/storybook/package.json" ]; then
  jq '.peerDependencies["@storybook-vue/nuxt"] // .dependencies["@storybook-vue/nuxt"] // "NOT FOUND in peer or direct dependencies"' node_modules/@nuxtjs/storybook/package.json
else
  echo "@nuxtjs/storybook package.json not found in node_modules"
fi

Repository: npmx-dev/npmx.dev

Length of output: 2964


🏁 Script executed:

#!/bin/bash

echo "=== Checking for lock files ==="
ls -la package-lock.json pnpm-lock.yaml yarn.lock 2>/dev/null || echo "No standard lock files found in root"

echo ""
echo "=== Checking .storybook directory structure ==="
find .storybook -type f -name "*.ts" -o -name "*.js" -o -name "*.json" 2>/dev/null | head -20

echo ""
echo "=== Checking if there's a .storybook/package.json or similar ==="
if [ -f ".storybook/package.json" ]; then
  cat .storybook/package.json
fi

echo ""
echo "=== Checking if `@storybook-vue/nuxt` appears anywhere in config files ==="
rg "@storybook-vue/nuxt" --type ts --type js --type json -l

Repository: npmx-dev/npmx.dev

Length of output: 425


🏁 Script executed:

#!/bin/bash

echo "=== Searching pnpm-lock.yaml for `@storybook-vue/nuxt` ==="
grep -c "@storybook-vue/nuxt" pnpm-lock.yaml 2>/dev/null && echo "Found in lock file" || echo "Not found in lock file"

echo ""
echo "=== Checking if `@storybook-vue` is mentioned at all in lock file ==="
grep "@storybook-vue" pnpm-lock.yaml | head -5

echo ""
echo "=== Checking `@nuxtjs/storybook` in lock file for dependencies on `@storybook-vue/nuxt` ==="
rg "/@nuxtjs/storybook" -A 10 pnpm-lock.yaml | head -30

Repository: npmx-dev/npmx.dev

Length of output: 2355


Add @storybook-vue/nuxt to knip's ignoreDependencies or explicitly to devDependencies.

The dependency @storybook-vue/nuxt is installed transitively (present in pnpm-lock.yaml), but knip reports it as unlisted because it's not declared in package.json and is not ignored in the knip configuration. Add it to the ignoreDependencies array in knip.ts at line 37, or add it explicitly to devDependencies in package.json.

🧰 Tools
🪛 GitHub Actions: ci

[error] 1-1: Unlisted dependencies: @storybook-vue/nuxt. knip step failed with exit code 1 (ELIFECYCLE).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@yannbf Is this relevant?

Copy link
Contributor

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

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: 1

Comment on lines +47 to +51
```
components/
├── Button.vue
└── Button.stories.ts
```
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

Add a language tag to the fenced block.
The tree example fence is missing a language identifier, which trips MD040.

🔧 Proposed fix
-```
+```text
 components/
 ├── Button.vue
 └── Button.stories.ts
🧰 Tools
🪛 markdownlint-cli2 (0.20.0)

[warning] 47-47: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

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