diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..6afc133 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,49 @@ +name: CI + +on: + pull_request: + branches: [main] + push: + branches: [main] + +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + verify: + runs-on: ubuntu-24.04 + timeout-minutes: 20 + + steps: + - name: Check out the repository + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + + - name: Set up pnpm + uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa # v4 + with: + version: 10.33.4 + + - name: Set up Node.js + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + with: + node-version-file: .node-version + cache: pnpm + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Run static checks and unit tests + run: pnpm check + + - name: Build and validate the static site + run: pnpm --filter @weapp.dev/web build + + - name: Install the Playwright browser + run: pnpm --filter @weapp.dev/web exec playwright install --with-deps chromium + + - name: Run end-to-end tests + run: pnpm --filter @weapp.dev/web test:e2e diff --git a/apps/web/package.json b/apps/web/package.json index bad3bb0..6318bab 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -12,9 +12,9 @@ "lint": "eslint .", "lint:styles": "stylelint 'src/**/*.css'", "metrics": "tsx scripts/generate-metrics.ts", + "metrics:sync": "tsx scripts/generate-metrics.ts --update-fallback --require-fresh", "media:generate": "tsx scripts/generate-media.ts", "metrics:update-fallback": "tsx scripts/generate-metrics.ts --update-fallback", - "metrics:sync": "tsx scripts/generate-metrics.ts --update-fallback --require-fresh", "og:generate": "tsx scripts/generate-og.ts", "preview": "astro preview", "test": "vitest run", diff --git a/apps/web/scripts/generate-metrics.ts b/apps/web/scripts/generate-metrics.ts index a148c89..6c189e1 100644 --- a/apps/web/scripts/generate-metrics.ts +++ b/apps/web/scripts/generate-metrics.ts @@ -8,6 +8,7 @@ interface ProjectSource { slug: string packageName: string github: string + npmUrl?: string } const root = resolve(import.meta.dirname, '..') @@ -26,6 +27,7 @@ async function loadProjectSources(): Promise { slug: basename(file, '.json'), packageName: definition.packageName, github: definition.github, + npmUrl: typeof definition.npmUrl === 'string' ? definition.npmUrl : undefined, } })) } @@ -85,6 +87,13 @@ const requireFresh = process.argv.includes('--require-fresh') const updateFallback = process.argv.includes('--update-fallback') await Promise.all(projectSources.map(async (project) => { + if (!project.npmUrl) { + if (!fallback[project.slug]) { + failures.push(project.slug) + } + console.log(`Using fallback metrics for ${project.slug}: no public npm package`) + return + } try { next[project.slug] = await fetchMetrics(project) console.log(`Updated metrics for ${project.slug}`) diff --git a/apps/web/src/components/Header.astro b/apps/web/src/components/Header.astro index 951b604..7983864 100644 --- a/apps/web/src/components/Header.astro +++ b/apps/web/src/components/Header.astro @@ -92,4 +92,17 @@ const navLink = 'inline-flex items-center gap-1.5 whitespace-nowrap py-2 text-sm document.querySelectorAll('[data-mobile-menu] nav a').forEach((link) => { link.addEventListener('click', () => link.closest('details')?.removeAttribute('open')) }) + + document.querySelectorAll('[data-mobile-menu]').forEach((menu) => { + menu.addEventListener('toggle', () => { + if (!menu.open) return + const closeOnEscape = (event) => { + if (event.key !== 'Escape') return + menu.removeAttribute('open') + menu.querySelector('summary')?.focus() + document.removeEventListener('keydown', closeOnEscape) + } + document.addEventListener('keydown', closeOnEscape) + }) + }) diff --git a/apps/web/src/components/HomePage.astro b/apps/web/src/components/HomePage.astro index 61bdea9..d36cada 100644 --- a/apps/web/src/components/HomePage.astro +++ b/apps/web/src/components/HomePage.astro @@ -19,8 +19,8 @@ const numberLocale = locale === 'zh-CN' ? 'zh-CN' : 'en-US' const stepIcons = [Layers2, ScanLine, Package] const principleIcons = [Layers2, ShieldCheck, BadgeCheck] const projectStages: Record = locale === 'zh-CN' - ? { 'weapp-tailwindcss': '样式', 'weapp-vite': '构建', varo: '组件' } - : { 'weapp-tailwindcss': 'STYLE', 'weapp-vite': 'BUILD', varo: 'COMPOSE' } + ? { 'weapp-tailwindcss': '样式', 'weapp-vite': '构建', varo: '组件', 'weapp-sqlite': '数据' } + : { 'weapp-tailwindcss': 'STYLE', 'weapp-vite': 'BUILD', varo: 'COMPOSE', 'weapp-sqlite': 'DATA' } ---
@@ -105,16 +105,11 @@ const projectStages: Record = locale === 'zh-CN'
- -
{project.data.packageName}
- {project.id === 'weapp-tailwindcss' &&
utility-first
p-4flexgap-2
} - {project.id === 'weapp-vite' &&
$ vite build --mode weapp✓ built in 1.42sdist/weapp / 24 modules
} - {project.id === 'varo' &&
} + + + {visualCopy.alt} + + {project.data.packageName}
{visualCopy.caption}
@@ -151,6 +146,7 @@ const projectStages: Record = locale === 'zh-CN' ) })} +
@@ -217,9 +213,9 @@ const projectStages: Record = locale === 'zh-CN'

{copy.releases.released} {formatReleaseDate(projectMetrics.releasedAt, numberLocale)}

v{projectMetrics.version} -
+ {project.data.npmUrl && + } ) })} @@ -258,8 +254,5 @@ const projectStages: Record = locale === 'zh-CN' .home-project-link, .home-project-link:first-child { grid-template-columns: 1.4rem 2rem minmax(0, 1fr) auto; padding: .85rem 0; border-right: 0; border-bottom: 1px solid color-mix(in srgb, var(--surface) 18%, transparent); } .home-project-link:last-child { border-bottom: 0; } .home-project-link img { width: 2rem; height: 2rem; } - .art-vite, .art-varo { padding: .85rem; } - .art-component { padding: .85rem; } - .art-canvas { padding: 1rem; } } diff --git a/apps/web/src/components/ProjectPage.astro b/apps/web/src/components/ProjectPage.astro index 8132fdb..b3d6e37 100644 --- a/apps/web/src/components/ProjectPage.astro +++ b/apps/web/src/components/ProjectPage.astro @@ -48,10 +48,10 @@ const secondaryVisualCopy = secondaryVisual.locales[locale]