diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml index b10b2fb3fb..0dbd53aed5 100644 --- a/.github/workflows/website.yml +++ b/.github/workflows/website.yml @@ -44,6 +44,12 @@ jobs: - name: Check links run: python3 scripts/check_links.py dist + - name: Install browser + run: npx playwright install --with-deps chromium + + - name: Check branding and responsive navigation + run: npm test + - name: Upload site if: github.event_name != 'pull_request' uses: actions/upload-pages-artifact@v3 diff --git a/website/.gitignore b/website/.gitignore index ddce69b680..4faa99dd86 100644 --- a/website/.gitignore +++ b/website/.gitignore @@ -1,3 +1,5 @@ node_modules/ dist/ .astro/ +test-results/ +playwright-report/ diff --git a/website/README.md b/website/README.md index b920a0a57f..7800276220 100644 --- a/website/README.md +++ b/website/README.md @@ -6,6 +6,7 @@ The SQLBuild website: the homepage at `/` and the documentation at `/docs/`, bui - `src/content/docs/docs/`: the documentation pages (MDX), first ported from the Mintlify docs and now edited here. `src/navigation.mjs` holds the sidebar and redirects. - `src/components/`: the page layout, header and page title, replacing Starlight's defaults. `src/components/mintlify/` has drop-in versions of the Mintlify components the pages use (`Card`, `CardGroup`, `Frame`, `Note`, `Warning`). - `public/fonts/`: self-hosted fonts, each with its licence. +- `public/brand.css`: shared SQLStack attribution styling for the homepage and docs. The SQLStack symbols in `public/assets/sqlstack*.png` are unchanged copies from `sqlstack-io/sqlstack` at revision `9b37b9e128d36930e1fe0c5880606525100b228b` (`assets/icons/sqlstack.png` and `sqlstack-dark.png`). Search uses Pagefind, and `llms.txt`, `llms-small.txt` and `llms-full.txt` are generated at build time. diff --git a/website/astro.config.mjs b/website/astro.config.mjs index 3b47d41c91..594c8e1665 100644 --- a/website/astro.config.mjs +++ b/website/astro.config.mjs @@ -18,6 +18,7 @@ export default defineConfig({ }, favicon: '/favicon.png', head: [ + { tag: 'link', attrs: { rel: 'stylesheet', href: '/brand.css' } }, { tag: 'meta', attrs: { property: 'og:image', content: 'https://sqlbuild.com/assets/og-sqlbuild-docs.png' } }, { tag: 'meta', attrs: { property: 'og:image:width', content: '1200' } }, { tag: 'meta', attrs: { property: 'og:image:height', content: '630' } }, @@ -35,6 +36,7 @@ export default defineConfig({ SiteTitle: './src/components/SiteTitle.astro', Pagination: './src/components/Pagination.astro', ThemeSelect: './src/components/ThemeSelect.astro', + Footer: './src/components/Footer.astro', }, customCss: ['./src/styles/fonts.css', './src/styles/sqlbuild.css'], expressiveCode: { diff --git a/website/package-lock.json b/website/package-lock.json index f69819c3ee..e99ca21c9e 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -12,6 +12,9 @@ "sharp": "^0.35.4", "starlight-llms-txt": "^0.12.0" }, + "devDependencies": { + "@playwright/test": "^1.64.1" + }, "engines": { "node": ">=22.12.0" } @@ -1733,6 +1736,22 @@ "win32" ] }, + "node_modules/@playwright/test": { + "version": "1.64.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.64.1.tgz", + "integrity": "sha512-IaYGml/nSOiZWROfPtuIL7neuu9qDOZ3TNvNljUIrhDMxiGTgPjzj/g9p9RxpS2tSepPDRY+UwAaEeiKtUvIAg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.64.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/@rolldown/binding-android-arm-eabi": { "version": "1.2.11", "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.11.tgz", @@ -4960,6 +4979,35 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/playwright": { + "version": "1.64.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.64.1.tgz", + "integrity": "sha512-HCrVhHr5QQuwYoswEUGTb7gGp522yflbv/ST8nF4sFWGuLjQCt17Q/EubpGGSNKYn1tsTCPZxqHhHCfVURu7UA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.64.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/playwright-core": { + "version": "1.64.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.64.1.tgz", + "integrity": "sha512-BC4s8y6SEVA6Q1rSxZTto8hI1KUI3xXlHGZgvGqP4IqPdI/a6FX9H29IDNz7vKo9l21b6LfYosScPL6M3xxyDQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/postcss": { "version": "8.5.28", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz", diff --git a/website/package.json b/website/package.json index 0576825801..3df87e0ac7 100644 --- a/website/package.json +++ b/website/package.json @@ -8,7 +8,8 @@ "scripts": { "dev": "astro dev", "build": "astro build", - "preview": "astro preview" + "preview": "astro preview", + "test": "playwright test" }, "dependencies": { "@astrojs/starlight": "^0.42.4", @@ -16,5 +17,8 @@ "astro": "^7.3.5", "sharp": "^0.35.4", "starlight-llms-txt": "^0.12.0" + }, + "devDependencies": { + "@playwright/test": "^1.64.1" } } diff --git a/website/playwright.config.mjs b/website/playwright.config.mjs new file mode 100644 index 0000000000..8aafb91d47 --- /dev/null +++ b/website/playwright.config.mjs @@ -0,0 +1,14 @@ +import { defineConfig } from '@playwright/test'; + +export default defineConfig({ + testDir: './tests', + use: { + baseURL: process.env.SITE_URL || 'http://127.0.0.1:4174', + deviceScaleFactor: 2, + launchOptions: process.env.CHROME_PATH ? { executablePath: process.env.CHROME_PATH } : {}, + }, + webServer: process.env.SITE_URL ? undefined : { + command: 'npm run preview -- --host 127.0.0.1 --port 4174 --ignore-lock', + url: 'http://127.0.0.1:4174', + }, +}); diff --git a/website/public/assets/sqlstack-dark.png b/website/public/assets/sqlstack-dark.png new file mode 100644 index 0000000000..d29890b7dd Binary files /dev/null and b/website/public/assets/sqlstack-dark.png differ diff --git a/website/public/assets/sqlstack.png b/website/public/assets/sqlstack.png new file mode 100644 index 0000000000..ac560230ea Binary files /dev/null and b/website/public/assets/sqlstack.png differ diff --git a/website/public/brand.css b/website/public/brand.css new file mode 100644 index 0000000000..1e3042bd0b --- /dev/null +++ b/website/public/brand.css @@ -0,0 +1,67 @@ +/* Shared attribution for the static homepage and Starlight documentation. */ +.brand-group { + display: grid; + flex-shrink: 0; +} + +.brand-byline { + display: flex; + align-items: center; + min-height: 24px; + /* The wordmark starts at x=447 in the unchanged 1626px-wide lockup. */ + margin-inline-start: 27.5%; + color: var(--sqb-muted, var(--muted-foreground)); + font-size: 11px; + line-height: 14px; + text-decoration: none; + white-space: nowrap; +} + +.sqlstack-family { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + gap: 16px; + margin-top: 20px; + padding-top: 20px; + border-top: 1px solid var(--sqb-line, var(--inner-line)); + font-size: 13px; +} + +.sqlstack-parent { + display: inline-flex; + align-items: center; + gap: 10px; +} + +.sqlstack-parent img { + width: 28px; + height: auto; +} + +.sqlstack-for-dark, +:root[data-theme='dark'] .sqlstack-for-light { + display: none; +} + +:root[data-theme='dark'] .sqlstack-for-dark { + display: block; +} + +.sqlstack-products { + display: flex; + flex-wrap: wrap; + gap: 8px 20px; +} + +.sqlstack-family a { + color: var(--sqb-muted, var(--muted-foreground)); + text-decoration: none; +} + +.brand-byline:hover, +.sqlstack-family a:hover { + color: var(--sqb-fg, var(--foreground)); + text-decoration: underline; +} diff --git a/website/public/index.html b/website/public/index.html index 57a33059b1..1c33ebbcf0 100644 --- a/website/public/index.html +++ b/website/public/index.html @@ -24,6 +24,7 @@ +