Skip to content

refactor: move fund link#1995

Closed
parion wants to merge 3 commits intonpmx-dev:mainfrom
parion:fix-fund-link
Closed

refactor: move fund link#1995
parion wants to merge 3 commits intonpmx-dev:mainfrom
parion:fix-fund-link

Conversation

@parion
Copy link
Contributor

@parion parion commented Mar 8, 2026

resolves #1835

🧭 Context

For the reasons given in the attached issue, the fund button needed more visibility on package pages. I moved the fund link from the external link list to the top button group. This also enables the f key to activate the fund link.

Please provide any feedback on this design change! I'm noticing this button bar is getting pretty wide, I was considering scaling it down.

Desktop View

image

Mobile View

image

@vercel
Copy link

vercel bot commented Mar 8, 2026

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

Project Deployment Actions Updated (UTC)
npmx.dev Ready Ready Preview, Comment Mar 8, 2026 7:41pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs.npmx.dev Ignored Ignored Preview Mar 8, 2026 7:41pm
npmx-lunaria Ignored Ignored Mar 8, 2026 7:41pm

Request Review

@parion parion changed the title Fix fund link Move fund link Mar 8, 2026
@codecov
Copy link

codecov bot commented Mar 8, 2026

Codecov Report

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

Files with missing lines Patch % Lines
app/pages/package/[[org]]/[name].vue 0.00% 7 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 8, 2026

📝 Walkthrough

Walkthrough

The package page navigation was changed to surface funding more prominently. The inline funding link was removed from the main links list (desktop and mobile). When a funding URL exists, a dedicated LinkBase button with a heart icon appears in the desktop top navigation; it includes the keyboard shortcut f, accessible title and screen‑reader text. A global f key handler (when not focused on an editable element) opens the funding URL in a new external tab. Funding is now reachable only via this top navigation element.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The PR description clearly relates to the changeset, explaining the rationale for moving the fund link from the external link list to the top button group and enabling the 'f' keyboard shortcut.
Linked Issues check ✅ Passed The PR moves the fund link to a more prominent location in the top button group (#1835), enabling keyboard shortcut activation, which aligns with the issue's objective to make the fund button more visible.
Out of Scope Changes check ✅ Passed All changes are scoped to improving fund link visibility on the package page as specified in issue #1835; no unrelated modifications detected.

✏️ 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

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
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: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f0166c68-4f3f-48d6-a2df-02c77ff5df2d

📥 Commits

Reviewing files that changed from the base of the PR and between d26e250 and e0b89f6.

📒 Files selected for processing (1)
  • app/pages/package/[[org]]/[name].vue

@parion parion changed the title Move fund link refactor: Move fund link Mar 8, 2026
@parion parion changed the title refactor: Move fund link refactor: move fund link Mar 8, 2026
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


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cb1eaf14-5ea0-49d8-a65b-5c0441547d9c

📥 Commits

Reviewing files that changed from the base of the PR and between e0b89f6 and 38f87e2.

📒 Files selected for processing (1)
  • app/pages/package/[[org]]/[name].vue

Comment on lines +732 to +740
onKeyStroke(
e => keyboardShortcuts.value && isKeyWithoutModifiers(e, 'f') && !isEditableElement(e.target),
e => {
if (!fundingUrl.value) return
e.preventDefault()
navigateTo(fundingUrl.value, { external: true, open: { target: '_blank' } })
},
{ dedupe: true },
)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Possible LinkBase implementation =="
fd 'LinkBase*' . app components

echo
echo "== Existing URL sanitisation / external navigation helpers =="
rg -n -C3 --glob '**/*.{ts,vue}' \
  'javascript:|data:|sanitize|safe.*url|allowed.*protocol|new URL\(|navigateTo\('

Repository: npmx-dev/npmx.dev

Length of output: 50448


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Searching for LinkBase in app directory ==="
find app -name '*LinkBase*' -o -name '*link*' -type f | head -20

echo
echo "=== Looking for the actual file and funding shortcut code ==="
sed -n '730,745p' app/pages/package/[[org]]/[name].vue

echo
echo "=== Searching for URL validation utilities in app ==="
rg -n 'export.*function.*url|export.*const.*url' app --glob '**/*.ts' | grep -i 'valid\|safe\|allow'

echo
echo "=== Checking for any protocol validation utilities in app ==="
rg -n 'protocol.*http|https.*protocol' app --glob '**/*.{ts,vue}' -A 2 -B 2

Repository: npmx-dev/npmx.dev

Length of output: 607


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Searching for LinkBase as a component (case-insensitive) ==="
rg -i 'linkbase|link-base' app --glob '**/*.{vue,ts}' -l

echo
echo "=== Looking for Link components in app/components ==="
fd -e vue app/components | grep -i link

echo
echo "=== Reading usePermalink.ts ==="
head -80 app/composables/usePermalink.ts

echo
echo "=== Searching for any external link or safe URL patterns in app ==="
rg -n 'external.*true|open.*target|target.*blank' app --glob '**/*.vue' -B 2 -A 2 | head -40

Repository: npmx-dev/npmx.dev

Length of output: 1694


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Looking for Link component files ==="
find app/components/Link -type f 2>/dev/null | head -20

echo
echo "=== Reading Link component files ==="
cat app/components/Link/*.vue 2>/dev/null | head -150

echo
echo "=== Checking for LinkBase usage in the funding section ==="
sed -n '850,900p' app/pages/package/[[org]]/[name].vue

echo
echo "=== Looking for fundingUrl computation ==="
sed -n '520,550p' app/pages/package/[[org]]/[name].vue

Repository: npmx-dev/npmx.dev

Length of output: 8066


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Verify LinkBase component name (check if it's exported as LinkBase or something else) ==="
grep -n "export\|name:" app/components/Link/Base.vue | head -10

echo
echo "=== Check how LinkBase is imported/used in the page ==="
grep -n "import.*LinkBase\|LinkBase" app/pages/package/[[org]]/[name].vue | head -5

echo
echo "=== Verify navigateTo is being used and understand its behavior ==="
grep -n "navigateTo" app/pages/package/[[org]]/[name].vue

Repository: npmx-dev/npmx.dev

Length of output: 154


🏁 Script executed:

#!/bin/bash
set -eulo pipefail

echo "=== Check component registration in nuxt.config ==="
grep -n "LinkBase\|Link/Base" nuxt.config.ts app.vue 2>/dev/null || echo "Not found in those files"

echo
echo "=== Verify the page uses LinkBase and check surrounding context ==="
sed -n '1,50p' app/pages/package/[[org]]/[name].vue | grep -E "import|script"

echo
echo "=== Confirm navigateTo usage in shortcut handler ==="
sed -n '730,745p' app/pages/package/[[org]]/[name].vue

echo
echo "=== Check if there are any tests for the funding shortcut ==="
find test -name "*.spec.ts" -o -name "*.spec.vue" | xargs grep -l "fundingUrl\|funding.*shortcut" 2>/dev/null || echo "No tests found"

Repository: npmx-dev/npmx.dev

Length of output: 1592


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Verify that LinkBase is used for the funding button ==="
sed -n '865,885p' app/pages/package/[[org]]/[name].vue

echo
echo "=== Check what keyboardShortcutsEnabled is in LinkBase ==="
grep -n "keyboardShortcutsEnabled" app/components/Link/Base.vue

echo
echo "=== Verify aria-keyshortcuts handling in LinkBase ==="
grep -n "aria-keyshortcuts" app/components/Link/Base.vue

Repository: npmx-dev/npmx.dev

Length of output: 1507


Add protocol validation to the funding keyboard shortcut.

The keyboard shortcut at lines 732–740 calls navigateTo(fundingUrl.value, { external: true, ... }) without protocol validation. Unlike the LinkBase button which restricts external links to http:, https:, and //, the shortcut bypasses this check. An unsafe protocol such as javascript: or data: in the package metadata would be reachable only via the global shortcut path. Validate the protocol before navigating, or explicitly allow only HTTP(S) schemes.

Suggested fix
 onKeyStroke(
   e => keyboardShortcuts.value && isKeyWithoutModifiers(e, 'f') && !isEditableElement(e.target),
   e => {
-    if (!fundingUrl.value) return
+    if (!fundingUrl.value) return
+
+    let safeFundingUrl: string | null = null
+    try {
+      const parsed = new URL(fundingUrl.value, window.location.origin)
+      if (parsed.protocol === 'http:' || parsed.protocol === 'https:') {
+        safeFundingUrl = parsed.toString()
+      }
+    } catch {
+      return
+    }
+
+    if (!safeFundingUrl) return
     e.preventDefault()
-    navigateTo(fundingUrl.value, { external: true, open: { target: '_blank' } })
+    navigateTo(safeFundingUrl, { external: true, open: { target: '_blank' } })
   },
   { dedupe: true },
 )
📝 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
onKeyStroke(
e => keyboardShortcuts.value && isKeyWithoutModifiers(e, 'f') && !isEditableElement(e.target),
e => {
if (!fundingUrl.value) return
e.preventDefault()
navigateTo(fundingUrl.value, { external: true, open: { target: '_blank' } })
},
{ dedupe: true },
)
onKeyStroke(
e => keyboardShortcuts.value && isKeyWithoutModifiers(e, 'f') && !isEditableElement(e.target),
e => {
if (!fundingUrl.value) return
let safeFundingUrl: string | null = null
try {
const parsed = new URL(fundingUrl.value, window.location.origin)
if (parsed.protocol === 'http:' || parsed.protocol === 'https:') {
safeFundingUrl = parsed.toString()
}
} catch {
return
}
if (!safeFundingUrl) return
e.preventDefault()
navigateTo(safeFundingUrl, { external: true, open: { target: '_blank' } })
},
{ dedupe: true },
)

Comment on lines +870 to +879
<LinkBase
variant="button-secondary"
v-if="fundingUrl"
:to="fundingUrl"
aria-keyshortcuts="f"
classicon="i-lucide:heart"
:title="$t('package.links.fund')"
>
<span class="max-sm:sr-only">{{ $t('package.links.fund') }}</span>
</LinkBase>
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

Only advertise the f shortcut when shortcuts are enabled.

This button always exposes aria-keyshortcuts="f", but the handler only runs when useKeyboardShortcuts() is enabled. When the setting is off, assistive tech is told about a shortcut that does nothing.

Proposed fix
             <LinkBase
               variant="button-secondary"
               v-if="fundingUrl"
               :to="fundingUrl"
-              aria-keyshortcuts="f"
+              :aria-keyshortcuts="keyboardShortcuts ? 'f' : undefined"
               classicon="i-lucide:heart"
               :title="$t('package.links.fund')"
             >
📝 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
<LinkBase
variant="button-secondary"
v-if="fundingUrl"
:to="fundingUrl"
aria-keyshortcuts="f"
classicon="i-lucide:heart"
:title="$t('package.links.fund')"
>
<span class="max-sm:sr-only">{{ $t('package.links.fund') }}</span>
</LinkBase>
<LinkBase
variant="button-secondary"
v-if="fundingUrl"
:to="fundingUrl"
:aria-keyshortcuts="keyboardShortcuts ? 'f' : undefined"
classicon="i-lucide:heart"
:title="$t('package.links.fund')"
>
<span class="max-sm:sr-only">{{ $t('package.links.fund') }}</span>
</LinkBase>

@RevanthPrk
Copy link

RevanthPrk commented Mar 8, 2026

Hey @parion,

This looks really cool❤️
But I just felt one thing after seeing your screen shots

Can we change the order of button group? to this
Docs, Code, Compare, Fund

Instead of Fund coming first?

Just my thought and perspective 😇

@parion
Copy link
Contributor Author

parion commented Mar 8, 2026

image

How's that looking?

@RevanthPrk
Copy link

@parion This is great now🥳

@danielroe
Copy link
Member

that button bar is semantically only for things that are 'on npmx' rather than links out

... so I love the highlighting for funding, but I think we need another place for it

@parion parion closed this Mar 9, 2026
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.

Make the "fund" link more visible

3 participants