From 74f960493cc3b5c86c2507f7fe0bfa1114fa384b Mon Sep 17 00:00:00 2001 From: Rafael Teixeira Date: Fri, 6 Nov 2026 14:15:17 -0300 Subject: [PATCH] Ship the de-slop redesign that never made it to main The redesign (thin theme over the VitePress default, stock hero with HomeSpotlight, plain ApiCard, Lucide sidebar icons) was done on top of fc10708 but never committed, so #3 merged without it and the live site kept the old HeroSection/SpotlightBackground look. This merges that work onto main and keeps what #3 added: CI, typecheck, the browser-language redirect on /, localized Scalar loading/error messages, Node 22 / pnpm 10 and the Scalar pin. --- CHANGELOG.md | 13 + README.md | 15 +- README.pt-br.md | 15 +- docs/.vitepress/components/ApiCard.vue | 227 ++------- docs/.vitepress/components/HeroSection.vue | 408 ---------------- docs/.vitepress/components/HomeSpotlight.vue | 108 +++++ docs/.vitepress/components/ScalarApi.vue | 221 +++------ .../components/SpotlightBackground.vue | 255 ---------- docs/.vitepress/config.ts | 400 +++++++--------- docs/.vitepress/theme/api-docs-responsive.css | 258 ---------- docs/.vitepress/theme/fonts.css | 8 +- docs/.vitepress/theme/index.ts | 16 +- docs/.vitepress/theme/sidebar.css | 117 ----- docs/.vitepress/theme/style.css | 443 +++++++++--------- docs/.vitepress/theme/theme.css | 106 ----- docs/en/authentication.md | 6 +- docs/en/errors.md | 12 +- docs/en/index.md | 26 +- docs/en/rate-limits.md | 16 +- docs/es/authentication.md | 6 +- docs/es/errors.md | 12 +- docs/es/index.md | 26 +- docs/es/rate-limits.md | 16 +- docs/fr/authentication.md | 6 +- docs/fr/errors.md | 12 +- docs/fr/index.md | 26 +- docs/fr/rate-limits.md | 16 +- docs/pt/authentication.md | 6 +- docs/pt/errors.md | 12 +- docs/pt/index.md | 26 +- docs/pt/rate-limits.md | 16 +- docs/public/preview-1080.webp | Bin 0 -> 42616 bytes docs/public/preview-1761.webp | Bin 0 -> 86570 bytes package.json | 2 +- pnpm-lock.yaml | 28 +- 35 files changed, 817 insertions(+), 2063 deletions(-) delete mode 100644 docs/.vitepress/components/HeroSection.vue create mode 100644 docs/.vitepress/components/HomeSpotlight.vue delete mode 100644 docs/.vitepress/components/SpotlightBackground.vue delete mode 100644 docs/.vitepress/theme/api-docs-responsive.css delete mode 100644 docs/.vitepress/theme/sidebar.css delete mode 100644 docs/.vitepress/theme/theme.css create mode 100644 docs/public/preview-1080.webp create mode 100644 docs/public/preview-1761.webp diff --git a/CHANGELOG.md b/CHANGELOG.md index b79ecf0..d07650e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,19 @@ Notable changes to this project are recorded here. The format follows ## [Unreleased] +### Changed + +- The theme is a thin layer over the VitePress default theme: one + `style.css`, Lucide icons in the sidebar, and the same header geometry on + every page. `ApiCard` is a plain key/description list. +- Each home page is the stock VitePress hero with a pointer-following + `HomeSpotlight` behind it and a screenshot of the portal below. + +### Removed + +- `HeroSection` and `SpotlightBackground`, and the `theme.css`, `sidebar.css` + and `api-docs-responsive.css` stylesheets. + ## [0.1.0] - 2026-11-05 ### Added diff --git a/README.md b/README.md index 167b610..6a8aee3 100644 --- a/README.md +++ b/README.md @@ -44,8 +44,8 @@ raw spec ──► hydrate ► fix ► validate ──► docs/public/openapi./index.md`, with `HomeSpotlight` (a glow that follows the pointer) behind it. - **Language routing**: `/` (`docs/index.md`) sends the browser to `/pt/`, `/es/` or `/fr/` based on its language, and to `/en/` otherwise. Without JavaScript it shows a list of the four languages. ## Project structure @@ -53,12 +53,13 @@ raw spec ──► hydrate ► fix ► validate ──► docs/public/openapi./` and adjust the sidebars in `docs/.vitepress/config.ts`. -3. Change the brand block in `docs/.vitepress/theme/theme.css` and the logos in `docs/public/`. -4. Take a new `docs/public/preview.png` (the hero shows it inside a MacBook frame: screenshot at 1440×932 and composite it into the screen area). +3. Change the brand block in `docs/.vitepress/theme/style.css` and the logos in `docs/public/`. +4. Replace `docs/public/preview.png` and the two `preview-*.webp` files that the home pages show (1761×1075, a laptop frame with a 1440×932 screenshot composited into the screen). 5. Deploy: any static host works. The live demo runs on Cloudflare Workers Static Assets: `pnpm run deploy` builds the site and runs `wrangler deploy` (config in `wrangler.jsonc`). ## Contributing diff --git a/README.pt-br.md b/README.pt-br.md index 385deee..7d04c34 100644 --- a/README.pt-br.md +++ b/README.pt-br.md @@ -44,8 +44,8 @@ spec crua ──► hydrate ► fix ► validate ──► docs/public/openapi.< - **Guias** são Markdown em `docs/{en,pt,es,fr}/`. Cada idioma tem nav e sidebar próprios em `docs/.vitepress/config.ts`. - **Referência da API**: `docs/.vitepress/components/ScalarApi.vue` embute o Scalar e escolhe a spec pelo idioma da página (`pt` → `openapi.pt-BR.json`, `en` → `openapi.en.json`, ...). Use `spec-url` para sobrescrever. -- **Tema**: o Scalar roda com `theme: 'none'` e suas variáveis CSS são mapeadas para as do VitePress, então a referência segue cores, fontes e modo escuro do site. A paleta fica em `docs/.vitepress/theme/theme.css`. -- **Componentes**: `ApiCard` (tabelas chave/descrição dos guias), `HeroSection` + `SpotlightBackground` (página inicial). +- **Tema**: o Scalar roda com `theme: 'none'` e suas variáveis CSS são mapeadas para as do VitePress, então a referência segue cores, fontes e modo escuro do site. A cor da marca e as fontes ficam em `docs/.vitepress/theme/style.css`, uma camada fina sobre o tema padrão do VitePress. +- **Componentes**: `ApiCard` (tabelas chave/descrição dos guias), A página inicial de cada idioma é o hero padrão do VitePress, configurado em `docs//index.md`, com o `HomeSpotlight` (um brilho que segue o ponteiro) por trás. - **Idioma**: `/` (`docs/index.md`) leva o navegador para `/pt/`, `/es/` ou `/fr/` conforme o idioma dele, e para `/en/` nos demais casos. Sem JavaScript, mostra a lista dos quatro idiomas. ## Estrutura do projeto @@ -53,12 +53,13 @@ spec crua ──► hydrate ► fix ► validate ──► docs/public/openapi.< ```text docs/ ├── .vitepress/ -│ ├── components/ ApiCard, HeroSection, ScalarApi, SpotlightBackground -│ ├── theme/ theme.css (paleta), style.css, api-docs-responsive.css, sidebar.css, fonts.css +│ ├── components/ ApiCard, HomeSpotlight, ScalarApi +│ ├── theme/ style.css (marca, fontes, superfícies), fonts.css │ └── config.ts idiomas, nav, sidebars ├── public/ │ ├── openapi.{en,pt-BR,es,fr}.json uma spec por idioma -│ ├── preview.png imagem da página inicial (também usada acima) +│ ├── preview.png screenshot usado acima +│ ├── preview-{1080,1761}.webp a mesma imagem nas páginas iniciais │ └── favicon.svg, logo-{light,dark}.svg ├── en/ pt/ es/ fr/ intro, authentication, rate-limits, examples, pagination, errors, api-reference └── index.md redirecionamento de idioma @@ -68,8 +69,8 @@ docs/ 1. Substitua `docs/public/openapi.*.json` pelas suas specs (uma por idioma, ou aponte todos os idiomas para o mesmo arquivo em `SPEC_BY_LANG`, dentro de `ScalarApi.vue`). 2. Reescreva os guias em `docs//` e ajuste as sidebars em `docs/.vitepress/config.ts`. -3. Troque o bloco de marca em `docs/.vitepress/theme/theme.css` e os logos em `docs/public/`. -4. Gere um novo `docs/public/preview.png` (a página inicial mostra a imagem dentro de um MacBook: print em 1440×932 composto na área da tela). +3. Troque o bloco de marca em `docs/.vitepress/theme/style.css` e os logos em `docs/public/`. +4. Troque o `docs/public/preview.png` e os dois `preview-*.webp` das páginas iniciais (1761×1075, um notebook com um print de 1440×932 composto na tela). 5. Publique em qualquer host estático. A demo roda no Cloudflare Workers Static Assets: `pnpm run deploy` gera o site e roda `wrangler deploy` (configuração em `wrangler.jsonc`). ## Contribuindo diff --git a/docs/.vitepress/components/ApiCard.vue b/docs/.vitepress/components/ApiCard.vue index 268d357..c347941 100644 --- a/docs/.vitepress/components/ApiCard.vue +++ b/docs/.vitepress/components/ApiCard.vue @@ -1,199 +1,74 @@ + + - - diff --git a/docs/.vitepress/components/HeroSection.vue b/docs/.vitepress/components/HeroSection.vue deleted file mode 100644 index e008393..0000000 --- a/docs/.vitepress/components/HeroSection.vue +++ /dev/null @@ -1,408 +0,0 @@ - - - - - diff --git a/docs/.vitepress/components/HomeSpotlight.vue b/docs/.vitepress/components/HomeSpotlight.vue new file mode 100644 index 0000000..f066080 --- /dev/null +++ b/docs/.vitepress/components/HomeSpotlight.vue @@ -0,0 +1,108 @@ + + + + + diff --git a/docs/.vitepress/components/ScalarApi.vue b/docs/.vitepress/components/ScalarApi.vue index 8bad8d8..1f2f5f3 100644 --- a/docs/.vitepress/components/ScalarApi.vue +++ b/docs/.vitepress/components/ScalarApi.vue @@ -1,20 +1,11 @@ - - - diff --git a/docs/.vitepress/components/SpotlightBackground.vue b/docs/.vitepress/components/SpotlightBackground.vue deleted file mode 100644 index 27f3b30..0000000 --- a/docs/.vitepress/components/SpotlightBackground.vue +++ /dev/null @@ -1,255 +0,0 @@ - - - - - diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 2ddf5fe..49d2876 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -1,258 +1,194 @@ -import { defineConfig } from 'vitepress' +import { BookOpen, Gauge, KeyRound, ListOrdered, SquareCode, TriangleAlert } from 'lucide-static' +import { defineConfig, type DefaultTheme, type LocaleSpecificConfig } from 'vitepress' -// Theme options that are the same in every locale. -const shared = { - siteTitle: false as const, - logo: { - light: '/logo-light.svg', - dark: '/logo-dark.svg', - alt: 'API Docs Starter Logo' +// Every string that changes per language. Adding a locale means adding an +// entry here, its docs// pages and docs/public/openapi..json. +const LOCALES = { + en: { + label: 'English', + lang: 'en', + description: 'Multilingual API documentation portal with VitePress and Scalar', + nav: { home: 'Home', guide: 'API guide', reference: 'API reference' }, + sidebar: { + guide: 'API guide', + intro: 'Introduction', + auth: 'Authentication', + limits: 'Rate limits', + examples: 'Examples', + reference: 'Reference', + pagination: 'Pagination & links', + errors: 'Errors' + }, + outline: 'On this page', + prev: 'Previous page', + next: 'Next page', + search: null }, - footer: { - copyright: ` - API Docs Starter © 2025 · by - - rafactx - - - - ` + pt: { + label: 'Português (Brasil)', + lang: 'pt-BR', + description: 'Portal de documentação de API multilíngue com VitePress e Scalar', + nav: { home: 'Início', guide: 'Guia da API', reference: 'Referência da API' }, + sidebar: { + guide: 'Guia da API', + intro: 'Introdução', + auth: 'Autenticação', + limits: 'Limites', + examples: 'Exemplos', + reference: 'Referência', + pagination: 'Paginação e links', + errors: 'Erros' + }, + outline: 'Nesta página', + prev: 'Página anterior', + next: 'Próxima página', + search: ['Buscar', 'Nenhum resultado para', 'Limpar busca', 'selecionar', 'navegar', 'fechar'] }, - socialLinks: [{ icon: 'github' as const, link: 'https://github.com/rafactx/api-docs-starter' }] + es: { + label: 'Español', + lang: 'es', + description: 'Portal de documentación de API multilingüe con VitePress y Scalar', + nav: { home: 'Inicio', guide: 'Guía de la API', reference: 'Referencia de la API' }, + sidebar: { + guide: 'Guía de la API', + intro: 'Introducción', + auth: 'Autenticación', + limits: 'Límites', + examples: 'Ejemplos', + reference: 'Referencia', + pagination: 'Paginación y enlaces', + errors: 'Errores' + }, + outline: 'En esta página', + prev: 'Página anterior', + next: 'Página siguiente', + search: ['Buscar', 'Sin resultados para', 'Borrar búsqueda', 'seleccionar', 'navegar', 'cerrar'] + }, + fr: { + label: 'Français', + lang: 'fr', + description: "Portail de documentation d'API multilingue avec VitePress et Scalar", + nav: { home: 'Accueil', guide: "Guide de l'API", reference: "Référence de l'API" }, + sidebar: { + guide: "Guide de l'API", + intro: 'Introduction', + auth: 'Authentification', + limits: 'Limites', + examples: 'Exemples', + reference: 'Référence', + pagination: 'Pagination et liens', + errors: 'Erreurs' + }, + outline: 'Sur cette page', + prev: 'Page précédente', + next: 'Page suivante', + search: ['Rechercher', 'Aucun résultat pour', 'Effacer la recherche', 'sélectionner', 'naviguer', 'fermer'] + } +} as const + +type Strings = (typeof LOCALES)[keyof typeof LOCALES] + +// Icons are inlined into the sidebar labels; style.css sizes them. +const icon = (svg: string) => svg.replace('