diff --git a/.opencode/templates/fullstack/{{cookiecutter.project_name}}/frontend/package.json b/.opencode/templates/fullstack/{{cookiecutter.project_name}}/frontend/package.json index 9e6fb76..cb9f57d 100644 --- a/.opencode/templates/fullstack/{{cookiecutter.project_name}}/frontend/package.json +++ b/.opencode/templates/fullstack/{{cookiecutter.project_name}}/frontend/package.json @@ -30,6 +30,7 @@ "@sveltejs/adapter-node": "^5.0.0", "@sveltejs/kit": "^2.0.0", "@sveltejs/vite-plugin-svelte": "^4.0.0", + "@axe-core/playwright": "^4.10.0", "@biomejs/biome": "^1.9.0", "knip": "^5.30.0", "svelte": "^5.0.0", diff --git a/.opencode/templates/fullstack/{{cookiecutter.project_name}}/frontend/playwright.config.js b/.opencode/templates/fullstack/{{cookiecutter.project_name}}/frontend/playwright.config.js index d2d3bfb..4f58a92 100644 --- a/.opencode/templates/fullstack/{{cookiecutter.project_name}}/frontend/playwright.config.js +++ b/.opencode/templates/fullstack/{{cookiecutter.project_name}}/frontend/playwright.config.js @@ -12,6 +12,7 @@ export default defineConfig({ }, projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'] } }, + { name: 'mobile-chrome', use: { ...devices['iPhone SE'], isMobile: true, hasTouch: true } }, ], webServer: { command: 'npm run preview', diff --git a/.opencode/templates/fullstack/{{cookiecutter.project_name}}/frontend/src/app.html b/.opencode/templates/fullstack/{{cookiecutter.project_name}}/frontend/src/app.html index 277886b..fcba6f1 100644 --- a/.opencode/templates/fullstack/{{cookiecutter.project_name}}/frontend/src/app.html +++ b/.opencode/templates/fullstack/{{cookiecutter.project_name}}/frontend/src/app.html @@ -2,8 +2,11 @@ - + + + + %sveltekit.head% diff --git a/.opencode/templates/fullstack/{{cookiecutter.project_name}}/frontend/static/icon.svg b/.opencode/templates/fullstack/{{cookiecutter.project_name}}/frontend/static/icon.svg new file mode 100644 index 0000000..5bf6fdc --- /dev/null +++ b/.opencode/templates/fullstack/{{cookiecutter.project_name}}/frontend/static/icon.svg @@ -0,0 +1,4 @@ + + + {{ cookiecutter.project_name | first | upper }} + \ No newline at end of file diff --git a/.opencode/templates/fullstack/{{cookiecutter.project_name}}/frontend/static/manifest.webmanifest b/.opencode/templates/fullstack/{{cookiecutter.project_name}}/frontend/static/manifest.webmanifest new file mode 100644 index 0000000..ccb5351 --- /dev/null +++ b/.opencode/templates/fullstack/{{cookiecutter.project_name}}/frontend/static/manifest.webmanifest @@ -0,0 +1,17 @@ +{ + "name": "{{ cookiecutter.project_name }}", + "short_name": "{{ cookiecutter.project_name }}", + "description": "{{ cookiecutter.description }}", + "start_url": "/", + "display": "standalone", + "background_color": "#ffffff", + "theme_color": "#0f172a", + "icons": [ + { + "src": "/icon.svg", + "sizes": "any", + "type": "image/svg+xml", + "purpose": "any maskable" + } + ] +} \ No newline at end of file diff --git a/.opencode/templates/fullstack/{{cookiecutter.project_name}}/frontend/tests/e2e/accessibility.spec.ts b/.opencode/templates/fullstack/{{cookiecutter.project_name}}/frontend/tests/e2e/accessibility.spec.ts new file mode 100644 index 0000000..a398fba --- /dev/null +++ b/.opencode/templates/fullstack/{{cookiecutter.project_name}}/frontend/tests/e2e/accessibility.spec.ts @@ -0,0 +1,10 @@ +import { expect, test } from '@playwright/test'; +import AxeBuilder from '@axe-core/playwright'; + +test('dashboard has no a11y violations', async ({ page }) => { + await page.goto('/'); + const results = await new AxeBuilder({ page }) + .disableRules(['color-contrast']) + .analyze(); + expect(results.violations).toEqual([]); +}); \ No newline at end of file diff --git a/.opencode/templates/fullstack/{{cookiecutter.project_name}}/frontend/tests/e2e/mobile.spec.ts b/.opencode/templates/fullstack/{{cookiecutter.project_name}}/frontend/tests/e2e/mobile.spec.ts new file mode 100644 index 0000000..5582656 --- /dev/null +++ b/.opencode/templates/fullstack/{{cookiecutter.project_name}}/frontend/tests/e2e/mobile.spec.ts @@ -0,0 +1,7 @@ +import { expect, test } from '@playwright/test'; + +test('sidebar collapses on mobile viewport', async ({ page }) => { + await page.goto('/'); + await expect(page.locator('[data-sidebar="sidebar"]')).not.toBeVisible(); + await expect(page.locator('[data-sidebar="trigger"]')).toBeVisible(); +}); \ No newline at end of file