diff --git a/app/assets/css/main.css b/app/assets/css/main.css index 07016375..f498ad7a 100644 --- a/app/assets/css/main.css +++ b/app/assets/css/main.css @@ -4,6 +4,22 @@ @import '@fontsource/ibm-plex-sans/600.css'; @import '@fontsource/ibm-plex-mono/400.css'; @import '@fontsource/ibm-plex-mono/500.css'; +/* Fonts an admin can pick (shared/utils/appearance.ts): declared here, only + downloaded by browsers when the theme uses them */ +@import '@fontsource/inter/400.css'; +@import '@fontsource/inter/500.css'; +@import '@fontsource/inter/600.css'; +@import '@fontsource/space-grotesk/400.css'; +@import '@fontsource/space-grotesk/500.css'; +@import '@fontsource/space-grotesk/600.css'; +@import '@fontsource/nunito/400.css'; +@import '@fontsource/nunito/500.css'; +@import '@fontsource/nunito/600.css'; +@import '@fontsource/source-serif-4/400.css'; +@import '@fontsource/source-serif-4/500.css'; +@import '@fontsource/source-serif-4/600.css'; +@import '@fontsource/jetbrains-mono/400.css'; +@import '@fontsource/jetbrains-mono/500.css'; @tailwind base; @tailwind components; @@ -17,6 +33,11 @@ @layer base { :root { color-scheme: light; + /* Overridden by the admin appearance (app/plugins/appearance.ts) */ + --font-sans: 'IBM Plex Sans', system-ui, sans-serif; + --font-heading: var(--font-sans); + --font-mono: 'IBM Plex Mono', ui-monospace, monospace; + --radius: 0.3125rem; --bg: 243 244 246; --surface: 255 255 255; --raised: 247 248 250; @@ -83,6 +104,12 @@ @apply bg-bg-primary text-text-primary font-sans text-sm leading-6; } + h1, + h2, + h3 { + @apply font-heading; + } + ::selection { @apply bg-free/25 text-text-primary; } diff --git a/app/components/AuthShell.vue b/app/components/AuthShell.vue new file mode 100644 index 00000000..ef91b803 --- /dev/null +++ b/app/components/AuthShell.vue @@ -0,0 +1,92 @@ + + + diff --git a/app/components/AuthShellHeader.vue b/app/components/AuthShellHeader.vue new file mode 100644 index 00000000..40374638 --- /dev/null +++ b/app/components/AuthShellHeader.vue @@ -0,0 +1,14 @@ + + + diff --git a/app/components/AuthShellLogo.vue b/app/components/AuthShellLogo.vue new file mode 100644 index 00000000..33280b2e --- /dev/null +++ b/app/components/AuthShellLogo.vue @@ -0,0 +1,12 @@ + + + diff --git a/app/components/admin/Appearance.vue b/app/components/admin/Appearance.vue new file mode 100644 index 00000000..6e1274ab --- /dev/null +++ b/app/components/admin/Appearance.vue @@ -0,0 +1,100 @@ + + + diff --git a/app/components/admin/AppearanceImages.vue b/app/components/admin/AppearanceImages.vue new file mode 100644 index 00000000..b9e16a20 --- /dev/null +++ b/app/components/admin/AppearanceImages.vue @@ -0,0 +1,69 @@ + + + diff --git a/app/components/admin/AppearanceLogin.vue b/app/components/admin/AppearanceLogin.vue new file mode 100644 index 00000000..524fbf88 --- /dev/null +++ b/app/components/admin/AppearanceLogin.vue @@ -0,0 +1,72 @@ + + + diff --git a/app/components/admin/AppearanceTexts.vue b/app/components/admin/AppearanceTexts.vue new file mode 100644 index 00000000..1deeea5e --- /dev/null +++ b/app/components/admin/AppearanceTexts.vue @@ -0,0 +1,122 @@ + + + diff --git a/app/components/admin/AppearanceTheme.vue b/app/components/admin/AppearanceTheme.vue new file mode 100644 index 00000000..573ac528 --- /dev/null +++ b/app/components/admin/AppearanceTheme.vue @@ -0,0 +1,149 @@ + + + diff --git a/app/components/admin/AppearanceTypography.vue b/app/components/admin/AppearanceTypography.vue new file mode 100644 index 00000000..c6ddae12 --- /dev/null +++ b/app/components/admin/AppearanceTypography.vue @@ -0,0 +1,45 @@ + + + diff --git a/app/composables/useAppearance.ts b/app/composables/useAppearance.ts new file mode 100644 index 00000000..61342585 --- /dev/null +++ b/app/composables/useAppearance.ts @@ -0,0 +1,9 @@ +import { DEFAULT_APPEARANCE, type Appearance } from '~~/shared/utils/appearance'; + +/** + * Site appearance (theme, fonts, login design, images, texts), loaded once by + * app/plugins/appearance.ts. The admin page writes to it to preview changes. + */ +export function useAppearance() { + return useState('appearance', () => structuredClone(DEFAULT_APPEARANCE)); +} diff --git a/app/pages/admin.vue b/app/pages/admin.vue index 1b0660cc..9e1fab0f 100644 --- a/app/pages/admin.vue +++ b/app/pages/admin.vue @@ -133,6 +133,12 @@ const menuItems = computed(() => [ icon: 'ph:paint-brush', description: t('admin.nav.branding.description'), }, + { + label: t('appearance.nav.label'), + path: '/admin/appearance', + icon: 'ph:palette', + description: t('appearance.nav.description'), + }, { label: t('admin.nav.settings.label'), path: '/admin/settings', diff --git a/app/pages/admin/appearance.vue b/app/pages/admin/appearance.vue new file mode 100644 index 00000000..5701a392 --- /dev/null +++ b/app/pages/admin/appearance.vue @@ -0,0 +1,3 @@ + diff --git a/app/pages/auth/login.vue b/app/pages/auth/login.vue index 9b72e5aa..0a67d5e8 100644 --- a/app/pages/auth/login.vue +++ b/app/pages/auth/login.vue @@ -1,133 +1,100 @@