diff --git a/frontend/.gitignore b/frontend/.gitignore index cd68f14..2fbe504 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -37,3 +37,4 @@ __screenshots__/ # Vite *.timestamp-*-*.mjs +.rodney/ diff --git a/frontend/index.html b/frontend/index.html index 9e5fc8f..09d1b1b 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -1,10 +1,9 @@ - + - - Vite App + fete
diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico deleted file mode 100644 index df36fcf..0000000 Binary files a/frontend/public/favicon.ico and /dev/null differ diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 7905b05..c80ecb7 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,85 +1,9 @@ - - - + diff --git a/frontend/src/assets/base.css b/frontend/src/assets/base.css deleted file mode 100644 index 8816868..0000000 --- a/frontend/src/assets/base.css +++ /dev/null @@ -1,86 +0,0 @@ -/* color palette from */ -:root { - --vt-c-white: #ffffff; - --vt-c-white-soft: #f8f8f8; - --vt-c-white-mute: #f2f2f2; - - --vt-c-black: #181818; - --vt-c-black-soft: #222222; - --vt-c-black-mute: #282828; - - --vt-c-indigo: #2c3e50; - - --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); - --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); - --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); - --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); - - --vt-c-text-light-1: var(--vt-c-indigo); - --vt-c-text-light-2: rgba(60, 60, 60, 0.66); - --vt-c-text-dark-1: var(--vt-c-white); - --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); -} - -/* semantic color variables for this project */ -:root { - --color-background: var(--vt-c-white); - --color-background-soft: var(--vt-c-white-soft); - --color-background-mute: var(--vt-c-white-mute); - - --color-border: var(--vt-c-divider-light-2); - --color-border-hover: var(--vt-c-divider-light-1); - - --color-heading: var(--vt-c-text-light-1); - --color-text: var(--vt-c-text-light-1); - - --section-gap: 160px; -} - -@media (prefers-color-scheme: dark) { - :root { - --color-background: var(--vt-c-black); - --color-background-soft: var(--vt-c-black-soft); - --color-background-mute: var(--vt-c-black-mute); - - --color-border: var(--vt-c-divider-dark-2); - --color-border-hover: var(--vt-c-divider-dark-1); - - --color-heading: var(--vt-c-text-dark-1); - --color-text: var(--vt-c-text-dark-2); - } -} - -*, -*::before, -*::after { - box-sizing: border-box; - margin: 0; - font-weight: normal; -} - -body { - min-height: 100vh; - color: var(--color-text); - background: var(--color-background); - transition: - color 0.5s, - background-color 0.5s; - line-height: 1.6; - font-family: - Inter, - -apple-system, - BlinkMacSystemFont, - 'Segoe UI', - Roboto, - Oxygen, - Ubuntu, - Cantarell, - 'Fira Sans', - 'Droid Sans', - 'Helvetica Neue', - sans-serif; - font-size: 15px; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} diff --git a/frontend/src/assets/fonts/Sora-Variable.woff2 b/frontend/src/assets/fonts/Sora-Variable.woff2 new file mode 100644 index 0000000..ec8ecca Binary files /dev/null and b/frontend/src/assets/fonts/Sora-Variable.woff2 differ diff --git a/frontend/src/assets/logo.svg b/frontend/src/assets/logo.svg deleted file mode 100644 index 7565660..0000000 --- a/frontend/src/assets/logo.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/frontend/src/assets/main.css b/frontend/src/assets/main.css index 36fb845..62440ad 100644 --- a/frontend/src/assets/main.css +++ b/frontend/src/assets/main.css @@ -1,35 +1,181 @@ -@import './base.css'; +@font-face { + font-family: 'Sora'; + src: url('@/assets/fonts/Sora-Variable.woff2') format('woff2'); + font-weight: 100 800; + font-display: swap; + font-style: normal; +} + +:root { + /* Colors: Electric Dusk */ + --color-gradient-start: #f06292; + --color-gradient-mid: #ab47bc; + --color-gradient-end: #5c6bc0; + --color-accent: #ff7043; + --color-text: #1c1c1e; + --color-text-on-gradient: #ffffff; + --color-surface: #fff5f8; + --color-card: #ffffff; + + /* Gradient */ + --gradient-primary: linear-gradient(135deg, #f06292 0%, #ab47bc 50%, #5c6bc0 100%); + + /* Spacing */ + --spacing-xs: 0.5rem; + --spacing-sm: 0.75rem; + --spacing-md: 1rem; + --spacing-lg: 1.2rem; + --spacing-xl: 1.5rem; + --spacing-2xl: 2rem; + + /* Borders */ + --radius-card: 14px; + --radius-button: 14px; + + /* Shadows */ + --shadow-card: 0 2px 8px rgba(0, 0, 0, 0.1); + --shadow-button: 0 2px 8px rgba(0, 0, 0, 0.15); + + /* Layout */ + --content-max-width: 480px; + --content-padding: 1.2rem; +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +html { + font-family: 'Sora', system-ui, -apple-system, sans-serif; + font-size: 16px; + line-height: 1.5; + color: var(--color-text); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +body { + min-height: 100vh; + background: var(--gradient-primary); +} #app { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - font-weight: normal; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; } -a, -.green { +.app-container { + width: 100%; + max-width: var(--content-max-width); + min-height: 100vh; + padding: var(--content-padding); + display: flex; + flex-direction: column; +} + +/* Card-style form fields */ +.form-field { + background: var(--color-card); + border: none; + border-radius: var(--radius-card); + padding: var(--spacing-md) var(--spacing-md); + box-shadow: var(--shadow-card); + width: 100%; + font-family: inherit; + font-size: 0.95rem; + font-weight: 400; + color: var(--color-text); + outline: none; + transition: box-shadow 0.2s ease; +} + +.form-field:focus { + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.18); +} + +.form-field::placeholder { + color: #999; + font-weight: 400; +} + +textarea.form-field { + resize: vertical; + min-height: 5rem; +} + +/* Form group (label + input) */ +.form-group { + display: flex; + flex-direction: column; + gap: 0.35rem; +} + +.form-label { + font-size: 0.85rem; + font-weight: 700; + color: var(--color-text-on-gradient); + padding-left: 0.25rem; +} + +/* Primary action button */ +.btn-primary { + display: block; + width: 100%; + padding: var(--spacing-md) var(--spacing-lg); + background: var(--color-accent); + color: var(--color-text); + border: none; + border-radius: var(--radius-button); + font-family: inherit; + font-size: 1rem; + font-weight: 700; + cursor: pointer; + box-shadow: var(--shadow-button); + transition: opacity 0.2s ease, transform 0.1s ease; + text-align: center; text-decoration: none; - color: hsla(160, 100%, 37%, 1); - transition: 0.4s; - padding: 3px; } -@media (hover: hover) { - a:hover { - background-color: hsla(160, 100%, 37%, 0.2); - } +.btn-primary:hover { + opacity: 0.92; } -@media (min-width: 1024px) { - body { - display: flex; - place-items: center; - } - - #app { - display: grid; - grid-template-columns: 1fr 1fr; - padding: 0 2rem; - } +.btn-primary:active { + transform: scale(0.98); +} + +.btn-primary:disabled { + opacity: 0.6; + cursor: not-allowed; +} + +/* Error message */ +.field-error { + color: #fff; + font-size: 0.875rem; + font-weight: 600; + padding-left: 0.25rem; +} + +/* Utility */ +.text-center { + text-align: center; +} + +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; } diff --git a/frontend/src/components/HelloWorld.vue b/frontend/src/components/HelloWorld.vue deleted file mode 100644 index d174cf8..0000000 --- a/frontend/src/components/HelloWorld.vue +++ /dev/null @@ -1,41 +0,0 @@ - - - - - diff --git a/frontend/src/components/TheWelcome.vue b/frontend/src/components/TheWelcome.vue deleted file mode 100644 index 8b731d9..0000000 --- a/frontend/src/components/TheWelcome.vue +++ /dev/null @@ -1,95 +0,0 @@ - - - diff --git a/frontend/src/components/WelcomeItem.vue b/frontend/src/components/WelcomeItem.vue deleted file mode 100644 index 6d7086a..0000000 --- a/frontend/src/components/WelcomeItem.vue +++ /dev/null @@ -1,87 +0,0 @@ - - - diff --git a/frontend/src/components/__tests__/HelloWorld.spec.ts b/frontend/src/components/__tests__/HelloWorld.spec.ts deleted file mode 100644 index 2533202..0000000 --- a/frontend/src/components/__tests__/HelloWorld.spec.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { describe, it, expect } from 'vitest' - -import { mount } from '@vue/test-utils' -import HelloWorld from '../HelloWorld.vue' - -describe('HelloWorld', () => { - it('renders properly', () => { - const wrapper = mount(HelloWorld, { props: { msg: 'Hello Vitest' } }) - expect(wrapper.text()).toContain('Hello Vitest') - }) -}) diff --git a/frontend/src/components/icons/IconCommunity.vue b/frontend/src/components/icons/IconCommunity.vue deleted file mode 100644 index 2dc8b05..0000000 --- a/frontend/src/components/icons/IconCommunity.vue +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/frontend/src/components/icons/IconDocumentation.vue b/frontend/src/components/icons/IconDocumentation.vue deleted file mode 100644 index 6d4791c..0000000 --- a/frontend/src/components/icons/IconDocumentation.vue +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/frontend/src/components/icons/IconEcosystem.vue b/frontend/src/components/icons/IconEcosystem.vue deleted file mode 100644 index c3a4f07..0000000 --- a/frontend/src/components/icons/IconEcosystem.vue +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/frontend/src/components/icons/IconSupport.vue b/frontend/src/components/icons/IconSupport.vue deleted file mode 100644 index 7452834..0000000 --- a/frontend/src/components/icons/IconSupport.vue +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/frontend/src/components/icons/IconTooling.vue b/frontend/src/components/icons/IconTooling.vue deleted file mode 100644 index 660598d..0000000 --- a/frontend/src/components/icons/IconTooling.vue +++ /dev/null @@ -1,19 +0,0 @@ - - diff --git a/frontend/src/views/AboutView.vue b/frontend/src/views/AboutView.vue deleted file mode 100644 index 756ad2a..0000000 --- a/frontend/src/views/AboutView.vue +++ /dev/null @@ -1,15 +0,0 @@ - - - diff --git a/spec/design-system.md b/spec/design-system.md new file mode 100644 index 0000000..0ccdcda --- /dev/null +++ b/spec/design-system.md @@ -0,0 +1,85 @@ +# Design System + +This document defines the visual design language for fete. All frontend implementation must follow these specifications. + +## Principles + +- **Mobile-first / App-native feel** — not a classic website. Think installed app, not browser page. +- **Desktop:** centered narrow column (max ~480px), gradient background fills the rest. +- **Generous whitespace** — elements breathe, nothing cramped. +- **WCAG AA contrast** as baseline for all color choices. +- **Accessibility is a baseline requirement** — not an afterthought (per project statutes). + +## Color Palette: Electric Dusk + +Chosen for best balance of style, broad appeal, and accessibility. + +| Role | Hex | Description | +|--------------------|-----------|--------------------| +| Gradient Start | `#F06292` | Pink | +| Gradient Mid | `#AB47BC` | Purple | +| Gradient End | `#5C6BC0` | Indigo blue | +| Accent (CTAs) | `#FF7043` | Deep orange | +| Text (light mode) | `#1C1C1E` | Near black | +| Text (dark mode) | `#FFFFFF` | White | +| Surface (light) | `#FFF5F8` | Pinkish white | +| Surface (dark) | `#1B1730` | Deep indigo-black | +| Card (light) | `#FFFFFF` | White | +| Card (dark) | `#2A2545` | Muted indigo | + +### Primary Gradient + +```css +background: linear-gradient(135deg, #F06292 0%, #AB47BC 50%, #5C6BC0 100%); +``` + +### Usage Rules + +- Gradient for hero/splash areas and page backgrounds — not as direct text background for body copy. +- Cards and content areas use solid surface colors with high-contrast text. +- Accent color (`#FF7043`) for primary action buttons with dark text (`#1C1C1E`). +- White text on gradient mid/end passes WCAG AA (4.82:1 and 4.86:1). +- White text on gradient start passes AA-large (3.06:1) — use for headings 18px+ only. + +## Typography: Sora + +Contemporary geometric sans-serif with slightly rounded terminals. Modern and friendly without being childish. + +- **Font:** Sora +- **License:** SIL Open Font License 1.1 (OFL) +- **Source:** https://github.com/sora-xor/sora-font +- **Format:** Self-hosted WOFF2. No external CDN. No Google Fonts. +- **Weights:** 400 (Regular), 500 (Medium), 600 (SemiBold), 700 (Bold), 800 (ExtraBold) + +### Weight Usage + +| Context | Weight | Size guideline | +|------------------|--------|-----------------| +| Body text | 400 | 0.85–1rem | +| Labels | 600–700| 0.8–0.9rem | +| Headlines | 700–800| 1.2–1.6rem | +| Buttons | 700–800| 1rem | +| Small/meta text | 400–500| 0.75–0.85rem | + +## Component Patterns + +### Card-Style Form Fields + +- Rounded corners (`border-radius: 14px`) +- Generous padding (`0.9rem 1rem`) +- White/card-colored background on gradient pages +- Subtle shadow (`box-shadow: 0 2px 8px rgba(0,0,0,0.1)`) +- Bold label (font-weight 700), regular-weight input text + +### Buttons + +- Rounded corners matching card fields (`border-radius: 14px`) +- Accent color background with dark text +- Bold/ExtraBold weight (700–800) +- Subtle shadow for depth + +### Layout + +- Mobile: full-width content with horizontal padding (~1.2rem) +- Desktop: centered column, max-width ~480px, gradient background fills viewport +- Vertical spacing between elements: ~0.75rem (compact), ~1.2rem (sections)