From 8931f6d241b4286ac8049229b347f930a650f2a5 Mon Sep 17 00:00:00 2001 From: dongmucat <1127093059@qq.com> Date: Tue, 12 May 2026 11:05:02 +0800 Subject: [PATCH] feat(web): add CLI install tab on landing quick start Add a third peer tab 'CLI' to LandingQuickStartSection that surfaces the official install command 'npm i -g @astron-team/skillhub'. Layout uses grid-cols-1 md:grid-cols-3 so mobile shows tabs stacked and desktop shows three equal-width columns. Addresses iflytek/skillhub#419 (homepage Quick Start part only). --- web/e2e/landing-quick-start-cli.spec.ts | 50 +++++++++++++++++++ .../i18n/landing-quick-start-locale.test.ts | 9 ++++ web/src/i18n/locales/en.json | 7 ++- web/src/i18n/locales/zh.json | 7 ++- .../shared/components/landing-quick-start.tsx | 14 ++++-- 5 files changed, 81 insertions(+), 6 deletions(-) create mode 100644 web/e2e/landing-quick-start-cli.spec.ts diff --git a/web/e2e/landing-quick-start-cli.spec.ts b/web/e2e/landing-quick-start-cli.spec.ts new file mode 100644 index 00000000..38f531db --- /dev/null +++ b/web/e2e/landing-quick-start-cli.spec.ts @@ -0,0 +1,50 @@ +import { expect, test } from '@playwright/test' +import { setEnglishLocale } from './helpers/auth-fixtures' + +test.describe('Landing Quick Start CLI Tab (Real API)', () => { + test.beforeEach(async ({ page }) => { + await setEnglishLocale(page) + }) + + test('renders three peer tabs and exposes the CLI install command', async ({ page }) => { + await page.goto('/') + + const agentTab = page.getByRole('button', { name: 'I am Agent', exact: true }) + const humanTab = page.getByRole('button', { name: 'I am Human', exact: true }) + const cliTab = page.getByRole('button', { name: 'CLI', exact: true }) + + await expect(agentTab).toBeVisible() + await expect(humanTab).toBeVisible() + await expect(cliTab).toBeVisible() + + await expect(agentTab).toHaveAttribute('aria-pressed', 'true') + + await cliTab.click() + await expect(cliTab).toHaveAttribute('aria-pressed', 'true') + await expect(agentTab).toHaveAttribute('aria-pressed', 'false') + await expect(humanTab).toHaveAttribute('aria-pressed', 'false') + + await expect( + page.getByText('Install the SkillHub CLI locally to run skillhub install for skills.'), + ).toBeVisible() + await expect(page.getByText('npm i -g @astron-team/skillhub', { exact: true })).toBeVisible() + }) + + test('agent and human tabs keep their original commands', async ({ page }) => { + await page.goto('/') + + const agentTab = page.getByRole('button', { name: 'I am Agent', exact: true }) + const humanTab = page.getByRole('button', { name: 'I am Human', exact: true }) + + await expect( + page.getByText(/Read .+\/registry\/skill\.md and follow the instructions/), + ).toBeVisible() + + await humanTab.click() + await expect(humanTab).toHaveAttribute('aria-pressed', 'true') + await expect(page.getByText('npx clawhub search ', { exact: true })).toBeVisible() + + await agentTab.click() + await expect(agentTab).toHaveAttribute('aria-pressed', 'true') + }) +}) diff --git a/web/src/i18n/landing-quick-start-locale.test.ts b/web/src/i18n/landing-quick-start-locale.test.ts index 6a36420b..0fcac247 100644 --- a/web/src/i18n/landing-quick-start-locale.test.ts +++ b/web/src/i18n/landing-quick-start-locale.test.ts @@ -12,4 +12,13 @@ describe('landing quick start locales', () => { expect(zh.landing.quickStart.agent.commandTemplate).toBe('阅读 {{url}},并按照说明完成 SkillHub Skills Registry 的配置') expect(en.landing.quickStart.agent.commandTemplate).toBe('Read {{url}} and follow the instructions to setup SkillHub Skills Registry') }) + + it('exposes CLI install command in both locales', () => { + expect(zh.landing.quickStart.tabs.cli).toBe('CLI') + expect(zh.landing.quickStart.cli.command).toBe('npm i -g @astron-team/skillhub') + expect(zh.landing.quickStart.cli.description).toBe('安装 SkillHub CLI 到本地,后续可运行 skillhub install 安装技能') + expect(en.landing.quickStart.tabs.cli).toBe('CLI') + expect(en.landing.quickStart.cli.command).toBe('npm i -g @astron-team/skillhub') + expect(en.landing.quickStart.cli.description).toBe('Install the SkillHub CLI locally to run skillhub install for skills.') + }) }) diff --git a/web/src/i18n/locales/en.json b/web/src/i18n/locales/en.json index ac0047b3..53f1197b 100644 --- a/web/src/i18n/locales/en.json +++ b/web/src/i18n/locales/en.json @@ -103,7 +103,12 @@ "tip": "💡 Tip: Visit the skill detail page for one-click install commands with environment variables", "tabs": { "agent": "I am Agent", - "human": "I am Human" + "human": "I am Human", + "cli": "CLI" + }, + "cli": { + "description": "Install the SkillHub CLI locally to run skillhub install for skills.", + "command": "npm i -g @astron-team/skillhub" }, "agent": { "description": "Send a prompt to your Agent to set up the SkillHub Registry", diff --git a/web/src/i18n/locales/zh.json b/web/src/i18n/locales/zh.json index bd1fd8ef..73029a99 100644 --- a/web/src/i18n/locales/zh.json +++ b/web/src/i18n/locales/zh.json @@ -103,7 +103,12 @@ "tip": "💡 提示:访问技能详情页可获取带环境变量的一键复制安装命令", "tabs": { "agent": "我是 Agent", - "human": "我是 Human" + "human": "我是 Human", + "cli": "CLI" + }, + "cli": { + "description": "安装 SkillHub CLI 到本地,后续可运行 skillhub install 安装技能", + "command": "npm i -g @astron-team/skillhub" }, "agent": { "description": "发送提示词给你的 Agent,以设置SkillHub Registry", diff --git a/web/src/shared/components/landing-quick-start.tsx b/web/src/shared/components/landing-quick-start.tsx index cfc7f656..9ac92437 100644 --- a/web/src/shared/components/landing-quick-start.tsx +++ b/web/src/shared/components/landing-quick-start.tsx @@ -1,9 +1,9 @@ import { useState, useMemo } from 'react' import { useTranslation } from 'react-i18next' -import { Bot, Check, Copy, UserRound } from 'lucide-react' +import { Bot, Check, Copy, Terminal, UserRound } from 'lucide-react' import { useCopyToClipboard } from '@/shared/lib/clipboard' -type LandingQuickStartTabId = 'agent' | 'human' +type LandingQuickStartTabId = 'agent' | 'human' | 'cli' interface LandingQuickStartTab { id: LandingQuickStartTabId @@ -83,6 +83,12 @@ export function LandingQuickStartSection() { description: t('landing.quickStart.human.description'), command: t('landing.quickStart.human.command'), }, + { + id: 'cli', + label: t('landing.quickStart.tabs.cli'), + description: t('landing.quickStart.cli.description'), + command: t('landing.quickStart.cli.command'), + }, ] const currentTab = tabs.find((tab) => tab.id === activeTab) ?? tabs[0] @@ -104,12 +110,12 @@ export function LandingQuickStartSection() { style={{ borderColor: 'hsl(var(--border-card))' }} >
{tabs.map((tab) => { const isActive = tab.id === currentTab.id - const Icon = tab.id === 'agent' ? Bot : UserRound + const Icon = tab.id === 'agent' ? Bot : tab.id === 'human' ? UserRound : Terminal return (