Skip to content

Comments

feat: copy compare table as markdown#1533

Open
mikouaji wants to merge 8 commits intonpmx-dev:mainfrom
mikouaji:feat/copy-compare-table-as-md-string
Open

feat: copy compare table as markdown#1533
mikouaji wants to merge 8 commits intonpmx-dev:mainfrom
mikouaji:feat/copy-compare-table-as-md-string

Conversation

@mikouaji
Copy link
Contributor

@mikouaji mikouaji commented Feb 16, 2026

Implements #1515

  1. Added ability to copy the comparison table as markdown. Had to parse css grid into a table.
  2. Added new util function to parse any html element to markdown.
  3. Extracted the copy button as a separate component.
  4. Moved some imports, added translations and packages.

Packages used for html to markdown util are dependencies that already were used in the project.

How it work:

Screencast_20260216_192439.mp4

@vercel
Copy link

vercel bot commented Feb 16, 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 22, 2026 7:17pm
npmx.dev Ready Ready Preview, Comment Feb 22, 2026 7:17pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
npmx-lunaria Ignored Ignored Feb 22, 2026 7:17pm

Request Review

@github-actions
Copy link

github-actions bot commented Feb 16, 2026

Lunaria Status Overview

🌕 This pull request will trigger status changes.

Learn more

By default, every PR changing files present in the Lunaria configuration's files property will be considered and trigger status changes accordingly.

You can change this by adding one of the keywords present in the ignoreKeywords property in your Lunaria configuration file in the PR's title (ignoring all files) or by including a tracker directive in the merged commit's description.

Tracked Files

File Note
lunaria/files/en-GB.json Localization changed, will be marked as complete. 🔄️
lunaria/files/en-US.json Source changed, localizations will be marked as outdated.
lunaria/files/pl-PL.json Localization changed, will be marked as complete. 🔄️
Warnings reference
Icon Description
🔄️ The source for this localization has been updated since the creation of this pull request, make sure all changes in the source have been applied.

@codecov
Copy link

codecov bot commented Feb 16, 2026

Codecov Report

❌ Patch coverage is 73.33333% with 4 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
app/components/CopyToClipboardButton.vue 84.61% 2 Missing ⚠️
app/pages/package/[[org]]/[name].vue 0.00% 0 Missing and 2 partials ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 16, 2026

📝 Walkthrough

Walkthrough

This PR introduces a new reusable CopyToClipboardButton Vue component that provides visual feedback for clipboard operations. The component is integrated into the comparison page to enable markdown table export functionality and replaces existing inline copy buttons on the package details page. Internationalisation support is added across multiple locales, and accessibility tests are included for the new component. The changes consolidate clipboard interactions into a single reusable component with consistent styling and behaviour.

Possibly related PRs

Suggested reviewers

  • danielroe
  • ghostdevv
🚥 Pre-merge checks | ✅ 1
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The pull request description is clearly related to the changeset, describing the implementation of copy-to-clipboard functionality for comparison tables and component extraction.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


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

❤️ Share

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

Copy link
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: 2

🧹 Nitpick comments (3)
server/utils/docs/text.ts (1)

121-124: Avoid the non‑null assertion on array indexing.

The guideline calls for explicit checks when indexing arrays; this avoids ! and keeps the code strictly type‑safe.

♻️ Suggested fix
-  for (let i = 0; i < codeBlockData.length; i++) {
-    const { lang, code } = codeBlockData[i]!
+  for (let i = 0; i < codeBlockData.length; i++) {
+    const entry = codeBlockData[i]
+    if (!entry) continue
+    const { lang, code } = entry
     const highlighted = await highlightCodeBlock(code, lang)
     result = result.replace(`__CODE_BLOCK_${i}__`, highlighted)
   }

As per coding guidelines, "Ensure you write strictly type-safe code, for example by ensuring you always check when accessing an array value by index".

app/pages/compare.vue (1)

95-100: Consider adding a type guard for safer array access.

Accessing children[0] at line 97 could return undefined if the grid has no children. While line 100 handles the falsy case, TypeScript may not narrow the type correctly. The current logic works but could be made more explicit.

Proposed defensive check
 function gridToMarkdown(gridEl: HTMLElement): string {
   const children = Array.from(gridEl.children)
-  const headerRow = children[0]
+  const headerRow = children[0] as Element | undefined
   const dataRows = children.slice(1)
 
   if (!headerRow || dataRows.length === 0) return ''
app/components/CopyToClipboardButton.vue (1)

51-83: Consider adding graceful degradation for older browsers without allow-discrete support.

The allow-discrete transitions are well-supported across modern browsers (Chrome 117+, Safari 17.4+, Firefox 129+), but this is a feature projected to reach "Baseline widely available" by February 2027. For enhanced compatibility with older browser versions, consider either removing allow-discrete from production builds or implementing a progressive enhancement strategy. Without it, transitions become discrete jumps rather than smooth animations—the component remains functional, but the visual refinement is lost.

Copy link
Member

@danielroe danielroe left a comment

Choose a reason for hiding this comment

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

although these were already dependencies, I don't think any of them were used in the client.

I think there must be a better way to render the table to markdown without converting from html - as we have the source for that html, the most complex piece here would only be padding to ensure the columns are the same width

@mikouaji
Copy link
Contributor Author

although these were already dependencies, I don't think any of them were used in the client.

I think there must be a better way to render the table to markdown without converting from html - as we have the source for that html, the most complex piece here would only be padding to ensure the columns are the same width

I see no issue with changing this and can update the code to just generate markdown from the client side data without doing the entire html(grid -> table) -> markdown conversion. It will be simpler.

My idea was here to create a function we could re-use in the future while allowing this functionality as the first one using it.

@danielroe
Copy link
Member

thank you ❤️

My idea was here to create a function we could re-use in the future while allowing this functionality as the first one using it.

let's wait until we see if we need it in other cases - we can refer back to this PR for implementation if so. 🙏

@mikouaji
Copy link
Contributor Author

100%, will update once I have a moment :)

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.

🧹 Nitpick comments (1)
lunaria/files/en-US.json (1)

915-915: Optional: consider aligning the label with the existing copy_as_markdown pattern.

The sibling key package.readme.copy_as_markdown (line 249) uses the value "Copy README as Markdown", which tells the user about the output format. The new compare.packages.copy_as_markdown value "Copy table" omits any mention of Markdown, so users pasting into a plain-text editor may be surprised by the raw Markdown syntax.

"Copy table as Markdown" (or simply "Copy as Markdown") would be consistent with the existing pattern and make the output format explicit. This should be addressed in the base i18n/locales/en.json as well, since lunaria/files/en-US.json mirrors it.

@mikouaji
Copy link
Contributor Author

@danielroe updated

Since you mentioned padding, do you think the link in the package headers should be removed? I padded only to names.

|                 | [vue@3.5.28](https://npmx.dev/package/vue/v/3.5.28) | [solid-js@1.9.11](https://npmx.dev/package/solid-js/v/1.9.11) | [svelte@5.53.2](https://npmx.dev/package/svelte/v/5.53.2) | [nuxt@4.3.1](https://npmx.dev/package/nuxt/v/4.3.1) |
| --------------- | --------------- | ------------- | ------------ | ----------------------------- |
| Package Size    | 2.5 MB          | 1.1 MB        | 2.8 MB       | 716.2 kB                      |
| Install Size    | 16.7 MB         | 3.6 MB        | 4.9 MB       | 123.6 MB                      |
| Direct Deps     | 5               | 3             | 16           | 57                            |
| Total Deps      | 22              | 3             | 19           | 500                           |
| Downloads/wk    | 8.5M            | 1.5M          | 2.7M         | 1.2M                          |
| Likes           | 68              | 15            | 163          | 86                            |
| Published       | Feb 9, 2026     | Jan 23, 2026  | Feb 21, 2026 | Feb 7, 2026                   |
| Deprecated?     | No              | No            | No           | No                            |
| Engines         | Any             | Any           | Node.js >=18 | Node.js ^20.19.0 ǀǀ >=22.12.0 |
| Types           | Included        | Included      | Included     | Included                      |
| Module Format   | ESM + CJS       | ESM + CJS     | ESM + CJS    | ESM + CJS                     |
| License         | MIT             | MIT           | MIT          | MIT                           |
| Vulnerabilities | None            | None          | None         | None                          |

vue@3.5.28 solid-js@1.9.11 svelte@5.53.2 nuxt@4.3.1
Package Size 2.5 MB 1.1 MB 2.8 MB 716.2 kB
Install Size 16.7 MB 3.6 MB 4.9 MB 123.6 MB
Direct Deps 5 3 16 57
Total Deps 22 3 19 500
Downloads/wk 8.5M 1.5M 2.7M 1.2M
Likes 68 15 163 86
Published Feb 9, 2026 Jan 23, 2026 Feb 21, 2026 Feb 7, 2026
Deprecated? No No No No
Engines Any Any Node.js >=18 Node.js ^20.19.0 ǀǀ >=22.12.0
Types Included Included Included Included
Module Format ESM + CJS ESM + CJS ESM + CJS ESM + CJS
License MIT MIT MIT MIT
Vulnerabilities None None None None

@mikouaji mikouaji requested a review from danielroe February 22, 2026 19:22
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