Skip to content

Commit be9f863

Browse files
committed
feat: dual install methods in skills modal
1 parent d784256 commit be9f863

2 files changed

Lines changed: 84 additions & 21 deletions

File tree

app/components/PackageSkillsModal.vue

Lines changed: 82 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,18 @@ function toggleSkill(dirName: string) {
2727
expandedSkills.value = new Set(expandedSkills.value)
2828
}
2929
30-
const requestUrl = useRequestURL()
31-
const baseUrl = computed(() => `${requestUrl.protocol}//${requestUrl.host}`)
30+
type InstallMethod = 'skills-npm' | 'skills-cli'
31+
const selectedMethod = ref<InstallMethod>('skills-npm')
32+
33+
const baseUrl = computed(() =>
34+
typeof window !== 'undefined' ? window.location.origin : 'https://npmx.dev',
35+
)
3236
3337
const installCommand = computed(() => {
3438
if (!props.skills.length) return null
35-
return `npx skills add ${baseUrl.value}/${props.packageName}`
39+
return selectedMethod.value === 'skills-npm'
40+
? `npm i ${props.packageName}`
41+
: `npx skills add ${baseUrl.value}/${props.packageName}`
3642
})
3743
3844
const { copied, copy } = useClipboard({ copiedDuring: 2000 })
@@ -94,40 +100,96 @@ function handleKeydown(event: KeyboardEvent) {
94100
</button>
95101
</div>
96102

103+
<!-- Install header with tabs -->
104+
<div class="flex flex-wrap items-center justify-between gap-2 mb-3">
105+
<h3 class="text-xs text-fg-subtle uppercase tracking-wider">Install</h3>
106+
<div
107+
class="flex items-center gap-1 p-0.5 bg-bg-subtle border border-border-subtle rounded-md"
108+
role="tablist"
109+
aria-label="Installation method"
110+
>
111+
<button
112+
role="tab"
113+
:aria-selected="selectedMethod === 'skills-npm'"
114+
:tabindex="selectedMethod === 'skills-npm' ? 0 : -1"
115+
type="button"
116+
class="px-2 py-1 font-mono text-xs rounded transition-colors duration-150 border border-solid focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50"
117+
:class="
118+
selectedMethod === 'skills-npm'
119+
? 'bg-bg border-border shadow-sm text-fg'
120+
: 'border-transparent text-fg-subtle hover:text-fg'
121+
"
122+
@click="selectedMethod = 'skills-npm'"
123+
>
124+
skills-npm
125+
</button>
126+
<button
127+
role="tab"
128+
:aria-selected="selectedMethod === 'skills-cli'"
129+
:tabindex="selectedMethod === 'skills-cli' ? 0 : -1"
130+
type="button"
131+
class="px-2 py-1 font-mono text-xs rounded transition-colors duration-150 border border-solid focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50"
132+
:class="
133+
selectedMethod === 'skills-cli'
134+
? 'bg-bg border-border shadow-sm text-fg'
135+
: 'border-transparent text-fg-subtle hover:text-fg'
136+
"
137+
@click="selectedMethod = 'skills-cli'"
138+
>
139+
skills CLI
140+
</button>
141+
</div>
142+
</div>
143+
97144
<!-- Terminal-style install command -->
98145
<div
99146
v-if="installCommand"
100147
class="bg-bg-subtle border border-border rounded-lg overflow-hidden mb-5"
101148
>
102149
<div class="flex gap-1.5 px-3 pt-2 sm:px-4 sm:pt-3">
103-
<span class="size-2.5 rounded-full bg-fg-subtle/50" />
104-
<span class="size-2.5 rounded-full bg-fg-subtle/50" />
105-
<span class="size-2.5 rounded-full bg-fg-subtle/50" />
150+
<span class="w-2.5 h-2.5 rounded-full bg-fg-subtle" />
151+
<span class="w-2.5 h-2.5 rounded-full bg-fg-subtle" />
152+
<span class="w-2.5 h-2.5 rounded-full bg-fg-subtle" />
106153
</div>
107154
<div class="px-3 pt-2 pb-3 sm:px-4 sm:pt-3 sm:pb-4 overflow-x-auto">
108-
<div class="flex items-center gap-2">
155+
<div class="flex items-center gap-2 group/cmd">
109156
<span class="text-fg-subtle font-mono text-sm select-none shrink-0">$</span>
110-
<code class="font-mono text-sm text-fg-muted whitespace-nowrap">
111-
npx skills add {{ baseUrl }}/{{ packageName }}
112-
</code>
157+
<code v-if="selectedMethod === 'skills-npm'" class="font-mono text-sm"
158+
><span class="text-fg">npm</span>
159+
<span class="text-fg-muted">i {{ packageName }}</span></code
160+
>
161+
<code v-else class="font-mono text-sm"
162+
><span class="text-fg">npx</span>
163+
<span class="text-fg-muted"
164+
>skills add {{ baseUrl }}/{{ packageName }}</span
165+
></code
166+
>
113167
<button
114168
type="button"
115-
class="p-1.5 text-fg-muted rounded transition-colors duration-200 hover:text-fg hover:bg-bg-muted active:scale-95 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 shrink-0"
169+
class="px-2 py-0.5 font-mono text-xs text-fg-muted bg-bg-subtle/80 border border-border rounded transition-colors duration-200 opacity-0 group-hover/cmd:opacity-100 hover:(text-fg border-border-hover) active:scale-95 focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50"
116170
:aria-label="$t('package.get_started.copy_command')"
117171
@click.stop="copyCommand"
118172
>
119-
<span
120-
v-if="copied"
121-
class="i-carbon:checkmark size-4 block"
122-
aria-hidden="true"
123-
/>
124-
<span v-else class="i-carbon:copy size-4 block" aria-hidden="true" />
173+
<span aria-live="polite">{{
174+
copied ? $t('common.copied') : $t('common.copy')
175+
}}</span>
125176
</button>
126177
</div>
127178
</div>
179+
180+
<!-- Learn more link (skills-npm only) -->
181+
<a
182+
v-if="selectedMethod === 'skills-npm'"
183+
href="/skills-npm"
184+
class="flex items-center gap-1.5 px-3 py-2 sm:px-4 text-xs text-fg-subtle hover:text-fg transition-colors border-t border-border"
185+
>
186+
<span class="i-carbon:arrow-right w-3 h-3" />
187+
Learn more about skills-npm
188+
</a>
128189
</div>
129190

130-
<!-- Skills list with expandable descriptions -->
191+
<!-- Skills list -->
192+
<h3 class="text-xs text-fg-subtle uppercase tracking-wider mb-2">Available Skills</h3>
131193
<ul class="space-y-0.5 list-none m-0 p-0">
132194
<li v-for="skill in skills" :key="skill.dirName">
133195
<button
@@ -137,14 +199,14 @@ function handleKeydown(event: KeyboardEvent) {
137199
@click="toggleSkill(skill.dirName)"
138200
>
139201
<span
140-
class="i-carbon:chevron-right w-3.5 h-3.5 text-fg-subtle shrink-0 transition-transform duration-200"
202+
class="i-carbon:chevron-right w-3 h-3 text-fg-subtle shrink-0 transition-transform duration-200"
141203
:class="{ 'rotate-90': expandedSkills.has(skill.dirName) }"
142204
aria-hidden="true"
143205
/>
144206
<span class="font-mono text-sm text-fg-muted">{{ skill.name }}</span>
145207
<span
146208
v-if="skill.warnings?.length"
147-
class="i-carbon:warning size-3.5 text-amber-500 shrink-0"
209+
class="i-carbon:warning w-3.5 h-3.5 text-amber-500 shrink-0"
148210
:title="getWarningTooltip(skill)"
149211
/>
150212
</button>

app/pages/[...package].vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,8 @@ function handleClick(event: MouseEvent) {
656656

657657
<!-- Stats grid -->
658658
<dl
659-
class="grid grid-cols-2 sm:grid-cols-12 gap-3 sm:gap-4 py-4 sm:py-6 mt-4 sm:mt-6 border-t border-border"
659+
class="grid grid-cols-2 gap-3 sm:gap-4 py-4 sm:py-6 mt-4 sm:mt-6 border-t border-border"
660+
:class="skillsData?.skills?.length ? 'sm:grid-cols-12' : 'sm:grid-cols-11'"
660661
>
661662
<div v-if="pkg.license" class="space-y-1 sm:col-span-2">
662663
<dt class="text-xs text-fg-subtle uppercase tracking-wider">

0 commit comments

Comments
 (0)