1
0

feat: introduce surface variables, text variables & shades (#4413)

* feat: surface variables & gradients

* feat: text vars

* fix: lint

* chore: remove L from surface vars

* fix: fully remove L from surface vars

---------

Co-authored-by: --global <--global>
This commit is contained in:
Calum H.
2025-10-07 17:35:45 +01:00
committed by GitHub
parent 87f8773401
commit ad705fa66f
5 changed files with 444 additions and 53 deletions

View File

@@ -1,5 +1,6 @@
/** @type {import('tailwindcss').Config} */
export default {
import type { Config } from 'tailwindcss'
const config: Config = {
content: [
'./src/components/**/*.{js,vue,ts}',
'./src/layouts/**/*.vue',
@@ -13,18 +14,116 @@ export default {
theme: {
extend: {
colors: {
surface: {
1: 'var(--surface-1)',
2: 'var(--surface-2)',
3: 'var(--surface-3)',
4: 'var(--surface-4)',
5: 'var(--surface-5)',
},
/// TODO: Clean up these aliases within codebase to use default, primary, tertiary.
// text-default
primary: 'var(--color-text-default)',
// text-primary
contrast: 'var(--color-text-primary)',
// text-tertiary
secondary: 'var(--color-text-tertiary)',
red: {
DEFAULT: 'var(--color-red)',
50: 'var(--color-red-50)',
100: 'var(--color-red-100)',
200: 'var(--color-red-200)',
300: 'var(--color-red-300)',
400: 'var(--color-red-400)',
500: 'var(--color-red-500)',
600: 'var(--color-red-600)',
700: 'var(--color-red-700)',
800: 'var(--color-red-800)',
900: 'var(--color-red-900)',
950: 'var(--color-red-950)',
},
orange: {
DEFAULT: 'var(--color-orange)',
50: 'var(--color-orange-50)',
100: 'var(--color-orange-100)',
200: 'var(--color-orange-200)',
300: 'var(--color-orange-300)',
400: 'var(--color-orange-400)',
500: 'var(--color-orange-500)',
600: 'var(--color-orange-600)',
700: 'var(--color-orange-700)',
800: 'var(--color-orange-800)',
900: 'var(--color-orange-900)',
950: 'var(--color-orange-950)',
},
green: {
DEFAULT: 'var(--color-green)',
50: 'var(--color-green-50)',
100: 'var(--color-green-100)',
200: 'var(--color-green-200)',
300: 'var(--color-green-300)',
400: 'var(--color-green-400)',
500: 'var(--color-green-500)',
600: 'var(--color-green-600)',
700: 'var(--color-green-700)',
800: 'var(--color-green-800)',
900: 'var(--color-green-900)',
950: 'var(--color-green-950)',
},
blue: {
DEFAULT: 'var(--color-blue)',
50: 'var(--color-blue-50)',
100: 'var(--color-blue-100)',
200: 'var(--color-blue-200)',
300: 'var(--color-blue-300)',
400: 'var(--color-blue-400)',
500: 'var(--color-blue-500)',
600: 'var(--color-blue-600)',
700: 'var(--color-blue-700)',
800: 'var(--color-blue-800)',
900: 'var(--color-blue-900)',
950: 'var(--color-blue-950)',
},
purple: {
DEFAULT: 'var(--color-purple)',
50: 'var(--color-purple-50)',
100: 'var(--color-purple-100)',
200: 'var(--color-purple-200)',
300: 'var(--color-purple-300)',
400: 'var(--color-purple-400)',
500: 'var(--color-purple-500)',
600: 'var(--color-purple-600)',
700: 'var(--color-purple-700)',
800: 'var(--color-purple-800)',
900: 'var(--color-purple-900)',
950: 'var(--color-purple-950)',
},
gray: {
DEFAULT: 'var(--color-gray)',
50: 'var(--color-gray-50)',
100: 'var(--color-gray-100)',
200: 'var(--color-gray-200)',
300: 'var(--color-gray-300)',
400: 'var(--color-gray-400)',
500: 'var(--color-gray-500)',
600: 'var(--color-gray-600)',
700: 'var(--color-gray-700)',
800: 'var(--color-gray-800)',
900: 'var(--color-gray-900)',
950: 'var(--color-gray-950)',
},
/// === LEGACY ===
icon: 'var(--color-base)',
// Text
primary: 'var(--color-base)',
contrast: 'var(--color-contrast)',
secondary: 'var(--color-secondary)',
inactive: 'var(--color-text-inactive)',
dark: 'var(--color-text-dark)',
inverted: 'var(--color-text-inverted)',
heading: 'var(--color-heading)',
red: 'var(--color-red)',
orange: 'var(--color-orange)',
purple: 'var(--color-purple)',
bg: {
DEFAULT: 'var(--color-bg)',
red: 'var(--color-red-bg)',
@@ -125,6 +224,7 @@ export default {
backgroundImage: {
mazeBg: 'var(--landing-maze-bg)',
mazeGradientBg: 'var(--landing-maze-gradient-bg)',
// @ts-ignore
landing: {
mazeOuterBg: 'var(--landing-maze-outer-bg)',
colorHeading: 'var(--landing-color-heading)',
@@ -151,3 +251,5 @@ export default {
preflight: false,
},
}
export default config

View File

@@ -2,7 +2,7 @@
<div class="flex h-full w-full items-center justify-center gap-6 p-20">
<FileIcon class="size-28" />
<div class="flex flex-col gap-2">
<h3 class="text-red-500 m-0 text-2xl font-bold">{{ title }}</h3>
<h3 class="m-0 text-2xl font-bold text-red-500">{{ title }}</h3>
<p class="m-0 text-sm text-secondary">
{{ message }}
</p>

View File

@@ -14,28 +14,124 @@ const config: Config = {
theme: {
extend: {
colors: {
surface: {
1: 'var(--surface-1)',
2: 'var(--surface-2)',
3: 'var(--surface-3)',
4: 'var(--surface-4)',
5: 'var(--surface-5)',
},
/// TODO: Clean up these aliases within codebase to use default, primary, tertiary.
// text-default
primary: 'var(--color-text-default)',
// text-primary
contrast: 'var(--color-text-primary)',
// text-tertiary
secondary: 'var(--color-text-tertiary)',
red: {
DEFAULT: 'var(--color-red)',
50: 'var(--color-red-50)',
100: 'var(--color-red-100)',
200: 'var(--color-red-200)',
300: 'var(--color-red-300)',
400: 'var(--color-red-400)',
500: 'var(--color-red-500)',
600: 'var(--color-red-600)',
700: 'var(--color-red-700)',
800: 'var(--color-red-800)',
900: 'var(--color-red-900)',
950: 'var(--color-red-950)',
},
orange: {
DEFAULT: 'var(--color-orange)',
50: 'var(--color-orange-50)',
100: 'var(--color-orange-100)',
200: 'var(--color-orange-200)',
300: 'var(--color-orange-300)',
400: 'var(--color-orange-400)',
500: 'var(--color-orange-500)',
600: 'var(--color-orange-600)',
700: 'var(--color-orange-700)',
800: 'var(--color-orange-800)',
900: 'var(--color-orange-900)',
950: 'var(--color-orange-950)',
},
green: {
DEFAULT: 'var(--color-green)',
50: 'var(--color-green-50)',
100: 'var(--color-green-100)',
200: 'var(--color-green-200)',
300: 'var(--color-green-300)',
400: 'var(--color-green-400)',
500: 'var(--color-green-500)',
600: 'var(--color-green-600)',
700: 'var(--color-green-700)',
800: 'var(--color-green-800)',
900: 'var(--color-green-900)',
950: 'var(--color-green-950)',
},
blue: {
DEFAULT: 'var(--color-blue)',
50: 'var(--color-blue-50)',
100: 'var(--color-blue-100)',
200: 'var(--color-blue-200)',
300: 'var(--color-blue-300)',
400: 'var(--color-blue-400)',
500: 'var(--color-blue-500)',
600: 'var(--color-blue-600)',
700: 'var(--color-blue-700)',
800: 'var(--color-blue-800)',
900: 'var(--color-blue-900)',
950: 'var(--color-blue-950)',
},
purple: {
DEFAULT: 'var(--color-purple)',
50: 'var(--color-purple-50)',
100: 'var(--color-purple-100)',
200: 'var(--color-purple-200)',
300: 'var(--color-purple-300)',
400: 'var(--color-purple-400)',
500: 'var(--color-purple-500)',
600: 'var(--color-purple-600)',
700: 'var(--color-purple-700)',
800: 'var(--color-purple-800)',
900: 'var(--color-purple-900)',
950: 'var(--color-purple-950)',
},
gray: {
DEFAULT: 'var(--color-gray)',
50: 'var(--color-gray-50)',
100: 'var(--color-gray-100)',
200: 'var(--color-gray-200)',
300: 'var(--color-gray-300)',
400: 'var(--color-gray-400)',
500: 'var(--color-gray-500)',
600: 'var(--color-gray-600)',
700: 'var(--color-gray-700)',
800: 'var(--color-gray-800)',
900: 'var(--color-gray-900)',
950: 'var(--color-gray-950)',
},
/// === LEGACY ===
icon: 'var(--color-base)',
// Text
primary: 'var(--color-base)',
contrast: 'var(--color-contrast)',
secondary: 'var(--color-secondary)',
inactive: 'var(--color-text-inactive)',
dark: 'var(--color-text-dark)',
inverted: 'var(--color-text-inverted)',
heading: 'var(--color-heading)',
red: 'var(--color-red)',
orange: 'var(--color-orange)',
green: 'var(--color-green)',
blue: 'var(--color-blue)',
purple: 'var(--color-purple)',
bg: {
DEFAULT: 'var(--color-bg)',
DEFAULT: 'var(--surface-1)', // var(--color-bg)
red: 'var(--color-red-bg)',
orange: 'var(--color-orange-bg)',
green: 'var(--color-green-bg)',
blue: 'var(--color-blue-bg)',
purple: 'var(--color-purple-bg)',
raised: 'var(--color-raised-bg)',
raised: 'var(--surface-3)', // var(--color-raised-bg)
},
banners: {
error: {

View File

@@ -1,26 +1,110 @@
.light-properties {
--color-bg: #ebebeb;
--color-raised-bg: #ffffff;
--color-super-raised-bg: #e9e9e9;
--color-button-bg: #f5f5f5;
--surface-1: #ebebeb;
--surface-2: #f5f5f5;
--surface-3: #f8f8f8;
--surface-4: #ffffff;
--surface-5: #e6e6e6;
--color-red-50: #fef2f2;
--color-red-100: #fee5e7;
--color-red-200: #fccfd3;
--color-red-300: #faa7b1;
--color-red-400: #f67687;
--color-red-500: #ed4661;
--color-red-600: #cb2245;
--color-red-700: #b7193d;
--color-red-800: #9a1739;
--color-red-900: #841738;
--color-red-950: #490819;
--color-red: var(--color-red-600);
--color-orange-50: #fdf8ed;
--color-orange-100: #f9eacc;
--color-orange-200: #f2d495;
--color-orange-300: #ecb85d;
--color-orange-400: #e7a038;
--color-orange-500: #e08325;
--color-orange-600: #c66019;
--color-orange-700: #a44419;
--color-orange-800: #86351a;
--color-orange-900: #6e2d19;
--color-orange-950: #3f1509;
--color-orange: var(--color-orange-500);
--color-green-50: #eefff6;
--color-green-100: #d7ffeb;
--color-green-200: #b2ffd9;
--color-green-300: #76ffbc;
--color-green-400: #33f598;
--color-green-500: #09de78;
--color-green-600: #00af5c;
--color-green-700: #04914f;
--color-green-800: #0a7141;
--color-green-900: #0a5d38;
--color-green-950: #00341d;
--color-green: var(--color-green-600);
--color-blue-50: #f2f7fd;
--color-blue-100: #e4ecfa;
--color-blue-200: #c3d9f4;
--color-blue-300: #8ebaeb;
--color-blue-400: #5196df;
--color-blue-500: #2b79cc;
--color-blue-600: #1f68c0;
--color-blue-700: #184b8c;
--color-blue-800: #184174;
--color-blue-900: #193861;
--color-blue-950: #112340;
--color-blue: var(--color-blue-600);
--color-purple-50: #faf5ff;
--color-purple-100: #f2e7ff;
--color-purple-200: #e7d3ff;
--color-purple-300: #d4b1ff;
--color-purple-400: #ba7eff;
--color-purple-500: #9f4dff;
--color-purple-600: #8e32f3;
--color-purple-700: #761ad6;
--color-purple-800: #651bae;
--color-purple-900: #53178c;
--color-purple-950: #370368;
--color-purple: var(--color-purple-600);
--color-gray-50: #f5f5f6;
--color-gray-100: #e5e5e8;
--color-gray-200: #cecfd3;
--color-gray-300: #adb0b3;
--color-gray-400: #83868d;
--color-gray-500: #686a72;
--color-gray-600: #595b61;
--color-gray-700: #4c4e52;
--color-gray-800: #434447;
--color-gray-900: #3b3b3e;
--color-gray-950: #252627;
--color-gray: var(--color-gray-600);
--color-text-primary: #1a202c;
--color-text-default: #2c2e31;
--color-text-tertiary: #484d54;
// ===
--color-bg: var(--surface-1);
--color-raised-bg: var(--surface-3);
--color-super-raised-bg: var(--surface-4);
--color-button-bg: var(--surface-4);
--color-button-border: rgba(161, 161, 161, 0.35);
--color-scrollbar: #96a2b0;
--color-divider: #babfc5;
--color-divider: var(--surface-2);
--color-divider-dark: #c8cdd3;
--color-base: #2c2e31;
--color-secondary: #484d54;
--color-contrast: #1a202c;
--color-base: var(--color-text-default);
--color-secondary: var(--color-text-tertiary);
--color-contrast: var(--color-text-primary);
--color-accent-contrast: #ffffff;
--color-red: #cb2245;
--color-orange: #e08325;
--color-green: #00af5c;
--color-blue: #1f68c0;
--color-purple: #8e32f3;
--color-gray: #595b61;
--color-red-highlight: rgba(203, 34, 69, 0.25);
--color-orange-highlight: rgba(224, 131, 37, 0.25);
--color-green-highlight: rgba(0, 175, 92, 0.25);
@@ -133,28 +217,112 @@ html {
.dark-mode,
.dark,
:root[data-theme='dark'] {
--color-bg: #16181c;
--color-raised-bg: #26292f;
--color-super-raised-bg: #40434a;
--color-button-bg: #33363d;
--surface-1: #16181c;
--surface-2: #1d1f23;
--surface-3: #27292e;
--surface-4: #34363c;
--surface-5: #42444a;
--color-red-50: #fff0f1;
--color-red-100: #ffe2e6;
--color-red-200: #ffcad3;
--color-red-300: #ff9fae;
--color-red-400: #ff6984;
--color-red-500: #ff496e;
--color-red-600: #ed1148;
--color-red-700: #c8083d;
--color-red-800: #a8093a;
--color-red-900: #8f0c38;
--color-red-950: #50011a;
--color-red: var(--color-red-500);
--color-orange-50: #fff8ed;
--color-orange-100: #ffefd4;
--color-orange-200: #ffdba8;
--color-orange-300: #ffc171;
--color-orange-400: #ffa347;
--color-orange-500: #fe7e11;
--color-orange-600: #ef6307;
--color-orange-700: #c64808;
--color-orange-800: #9d3a0f;
--color-orange-900: #7e3110;
--color-orange-950: #441606;
--color-orange: var(--color-orange-400);
--color-green-50: #effef5;
--color-green-100: #dafee8;
--color-green-200: #b8fad2;
--color-green-300: #81f4af;
--color-green-400: #42e686;
--color-green-500: #1bd96a;
--color-green-600: #0faa4f;
--color-green-700: #0f8642;
--color-green-800: #126937;
--color-green-900: #11562f;
--color-green-950: #033018;
--color-green: var(--color-green-500);
--color-blue-50: #eef6ff;
--color-blue-100: #daeaff;
--color-blue-200: #bddaff;
--color-blue-300: #90c4ff;
--color-blue-400: #4f9cff;
--color-blue-500: #357ffc;
--color-blue-600: #1f5ff1;
--color-blue-700: #1749de;
--color-blue-800: #193cb4;
--color-blue-900: #1a378e;
--color-blue-950: #152356;
--color-blue: var(--color-blue-400);
--color-purple-50: #faf5ff;
--color-purple-100: #f4e7ff;
--color-purple-200: #ead4ff;
--color-purple-300: #dab2ff;
--color-purple-400: #c78aff;
--color-purple-500: #ac51fb;
--color-purple-600: #972eef;
--color-purple-700: #821ed2;
--color-purple-800: #6e1eab;
--color-purple-900: #5a198a;
--color-purple-950: #3d0566;
--color-purple: var(--color-purple-400);
--color-gray-50: #f5f7f8;
--color-gray-100: #edeff2;
--color-gray-200: #dfe2e6;
--color-gray-300: #cad0d7;
--color-gray-400: #b4bac5;
--color-gray-500: #9fa4b3;
--color-gray-600: #8a8da1;
--color-gray-700: #777b8b;
--color-gray-800: #616472;
--color-gray-900: #52555d;
--color-gray-950: #303136;
--color-gray: var(--color-gray-500);
--color-text-primary: #ffffff;
--color-text-default: #b0bac5;
--color-text-tertiary: #80878f;
// ===
--color-bg: var(--surface-1);
--color-raised-bg: var(--surface-3);
--color-super-raised-bg: var(--surface-4);
--color-button-bg: var(--surface-4);
--color-button-border: rgba(193, 190, 209, 0.12);
--color-scrollbar: var(--color-button-bg);
--color-divider: var(--color-button-bg);
--color-divider-dark: #646c75;
--color-base: var(--dark-color-base);
--color-secondary: #96a2b0;
--color-contrast: var(--dark-color-contrast);
--color-base: var(--color-text-default);
--color-secondary: var(--color-text-tertiary);
--color-contrast: var(--color-text-primary);
--color-accent-contrast: #000000;
--color-red: #ff496e;
--color-orange: #ffa347;
--color-green: #1bd96a;
--color-blue: #4f9cff;
--color-purple: #c78aff;
--color-gray: #9fa4b3;
--color-red-highlight: rgba(255, 73, 110, 0.25);
--color-orange-highlight: rgba(255, 163, 71, 0.25);
--color-green-highlight: rgba(27, 217, 106, 0.25);
@@ -220,9 +388,11 @@ html {
.oled-mode {
@extend .dark-mode;
--color-bg: #000000;
--color-raised-bg: #101013;
--color-button-bg: #222329;
--surface-1: #000000;
--surface-2: #101013;
--surface-3: #1b1b20;
--surface-4: #25262b;
--surface-5: #2e2f34;
--color-ad: #0d1828;

View File

@@ -4,7 +4,7 @@ import { defineMessages, useVIntl } from '@vintl/vintl'
const { formatMessage } = useVIntl()
defineProps<{
const { updateColorTheme, currentTheme, themeOptions, systemThemeColor } = defineProps<{
updateColorTheme: (theme: T) => void
currentTheme: T
themeOptions: readonly T[]
@@ -53,6 +53,11 @@ const colorTheme = defineMessages({
function asString(theme: T): string {
return theme
}
function getPreviewClass(option: T): string {
const base = option === 'system' ? systemThemeColor : option
return base.endsWith('-mode') ? base : `${base}-mode`
}
</script>
<template>
@@ -64,7 +69,7 @@ function asString(theme: T): string {
:class="{ selected: currentTheme === option }"
@click="() => updateColorTheme(option)"
>
<div class="preview" :class="`${option === 'system' ? systemThemeColor : option}-mode`">
<div class="preview" :class="getPreviewClass(option)">
<div class="example-card card card">
<div class="example-icon"></div>
<div class="example-text-1"></div>
@@ -96,6 +101,24 @@ function asString(theme: T): string {
grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
gap: var(--gap-lg);
.preview {
&.light-mode {
@extend .light-mode;
}
&.dark-mode {
@extend .dark-mode;
}
&.oled-mode {
@extend .oled-mode;
}
&.retro-mode {
@extend .retro-mode;
}
}
.preview .example-card {
margin: 0;
padding: 1rem;