From ad2ac31f1a464d62a686f9cc5c96ddfae173f6dd Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Thu, 14 May 2026 07:35:33 -0400 Subject: [PATCH] feat: scaffold Vue 3 + Vuetify + Pinia frontend themed to FabledDesignSystem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Curator signature accent (#A87338, aged amber) is baked into fabled-tokens.js. Vuetify theme consumes the same tokens module the rest of the SPA does, so updating design system tokens propagates throughout. Vite dev server proxies /api and /ws to the Quart backend. App.vue references AppShell (lands in Task 9) and main.js references router.js (lands in Task 9) — these are intentionally split so Task 8 is the framework scaffold and Task 9 is the navigation/shell content. Co-Authored-By: Claude Opus 4.7 (1M context) --- frontend/index.html | 19 +++++++++++++ frontend/package.json | 26 ++++++++++++++++++ frontend/src/App.vue | 11 ++++++++ frontend/src/main.js | 26 ++++++++++++++++++ frontend/src/theme/fabled-tokens.js | 41 +++++++++++++++++++++++++++++ frontend/src/theme/vuetify-theme.js | 29 ++++++++++++++++++++ frontend/vite.config.js | 23 ++++++++++++++++ 7 files changed, 175 insertions(+) create mode 100644 frontend/index.html create mode 100644 frontend/package.json create mode 100644 frontend/src/App.vue create mode 100644 frontend/src/main.js create mode 100644 frontend/src/theme/fabled-tokens.js create mode 100644 frontend/src/theme/vuetify-theme.js create mode 100644 frontend/vite.config.js diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..0ecae7f --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,19 @@ + + + + + + + FabledCurator + + + + + +
+ + + diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..32e9f00 --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,26 @@ +{ + "name": "fabledcurator-frontend", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview", + "check": "vue-tsc --noEmit" + }, + "dependencies": { + "vue": "^3.4.0", + "vue-router": "^4.3.0", + "pinia": "^2.1.0", + "vuetify": "^3.5.0", + "@mdi/font": "^7.4.0" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^5.0.0", + "vite": "^5.2.0", + "vue-tsc": "^2.0.0", + "vite-plugin-vuetify": "^2.0.0", + "sass": "^1.71.0" + } +} diff --git a/frontend/src/App.vue b/frontend/src/App.vue new file mode 100644 index 0000000..4c51eaf --- /dev/null +++ b/frontend/src/App.vue @@ -0,0 +1,11 @@ + + + diff --git a/frontend/src/main.js b/frontend/src/main.js new file mode 100644 index 0000000..0882de9 --- /dev/null +++ b/frontend/src/main.js @@ -0,0 +1,26 @@ +import { createApp } from 'vue' +import { createPinia } from 'pinia' +import { createVuetify } from 'vuetify' +import 'vuetify/styles' +import '@mdi/font/css/materialdesignicons.css' + +import App from './App.vue' +import router from './router.js' +import { fabledCuratorTheme } from './theme/vuetify-theme.js' + +const vuetify = createVuetify({ + theme: { + defaultTheme: 'fabledCurator', + themes: { fabledCurator: fabledCuratorTheme } + }, + defaults: { + // FabledDesignSystem: pill shape for buttons + VBtn: { rounded: 'pill' } + } +}) + +createApp(App) + .use(createPinia()) + .use(router) + .use(vuetify) + .mount('#app') diff --git a/frontend/src/theme/fabled-tokens.js b/frontend/src/theme/fabled-tokens.js new file mode 100644 index 0000000..4102088 --- /dev/null +++ b/frontend/src/theme/fabled-tokens.js @@ -0,0 +1,41 @@ +// FabledDesignSystem tokens — mirrored from FabledDesignSystem-new/design-system.md. +// Do not hand-edit hexes; update the source-of-truth doc and re-mirror here. + +export const surfaces = { + obsidian: '#14171A', // page background + iron: '#1E2228', // cards + slate: '#2C313A', // hovered surfaces + pewter: '#3F4651' // borders, ghost outlines +} + +export const text = { + parchment: '#E8E4D8', // primary on dark + vellum: '#C2BFB4', // secondary + ash: '#9C9A92' // tertiary +} + +export const action = { + moss: '#4A5D3F', // primary action + bronze: '#8B7355', // secondary action + pewter: '#3F4651', // tertiary/ghost + destructive: '#6B2118' // delete/irreversible +} + +export const semantic = { + success: '#4A5D3F', + warning: '#8B6F1E', + error: '#C04A1F', + info: '#3D5A6E' +} + +// Per-app signature accent. Curator's accent was added to FabledDesignSystem +// during FC-1 (2026-05-14). Aged amber — manuscript ink, curated archive. +export const accent = { + curator: '#A87338' +} + +export const typography = { + display: 'Fraunces, Georgia, serif', + body: 'Inter, system-ui, sans-serif', + mono: '"JetBrains Mono", monospace' +} diff --git a/frontend/src/theme/vuetify-theme.js b/frontend/src/theme/vuetify-theme.js new file mode 100644 index 0000000..2211e75 --- /dev/null +++ b/frontend/src/theme/vuetify-theme.js @@ -0,0 +1,29 @@ +import { surfaces, text, action, semantic, accent } from './fabled-tokens.js' + +export const fabledCuratorTheme = { + dark: true, + colors: { + background: surfaces.obsidian, + surface: surfaces.iron, + 'surface-bright': surfaces.slate, + 'surface-light': surfaces.pewter, + + primary: action.moss, + secondary: action.bronze, + tertiary: action.pewter, + + 'on-background': text.parchment, + 'on-surface': text.parchment, + 'on-primary': text.parchment, + 'on-secondary': text.parchment, + + success: semantic.success, + warning: semantic.warning, + error: semantic.error, + info: semantic.info, + + // Curator signature accent — used for nav-active state, wordmark, selection. + // Not on action buttons (see design-system.md "Accent usage rules"). + accent: accent.curator + } +} diff --git a/frontend/vite.config.js b/frontend/vite.config.js new file mode 100644 index 0000000..b506803 --- /dev/null +++ b/frontend/vite.config.js @@ -0,0 +1,23 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import vuetify from 'vite-plugin-vuetify' + +export default defineConfig({ + plugins: [ + vue(), + vuetify({ autoImport: true }) + ], + build: { + outDir: 'dist', + emptyOutDir: true, + sourcemap: false + }, + server: { + port: 5173, + proxy: { + // Dev server proxies API to local Quart + '/api': 'http://localhost:8080', + '/ws': { target: 'ws://localhost:8080', ws: true } + } + } +})