mirror of
https://github.com/xpltdco/media-rip.git
synced 2026-04-03 10:54:00 -06:00
6 new themes + grouped theme picker dropdown
Dark themes: - Midnight: ultra-minimal, near-black, zero effects - Hacker: green-on-black terminal, monospace, CRT scanlines - Neon: hot pink + cyan on purple-black, synthwave, heavy glow Light themes: - Paper: warm cream/sepia, serif fonts, book-like - Arctic: cool whites and icy blues, crisp and modern - Solarized: Ethan Schoonover's solarized-light palette Theme picker: - Replaced simple dark/light toggle with grouped dropdown - Themes organized by Dark / Light sections with active checkmark - Remembers last dark and light theme separately for quick toggle - Theme metadata now includes variant field for proper grouping - Custom themes default to dark variant
This commit is contained in:
parent
4b766bb0e7
commit
2a8f59fecc
10 changed files with 424 additions and 36 deletions
|
|
@ -1,37 +1,88 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { useThemeStore } from '@/stores/theme'
|
||||
|
||||
const theme = useThemeStore()
|
||||
const showPicker = ref(false)
|
||||
|
||||
function selectTheme(id: string) {
|
||||
theme.setTheme(id)
|
||||
showPicker.value = false
|
||||
}
|
||||
|
||||
function closePicker() {
|
||||
showPicker.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button
|
||||
class="dark-mode-toggle"
|
||||
:title="theme.isDark ? 'Switch to light mode' : 'Switch to dark mode'"
|
||||
@click="theme.toggleDarkMode()"
|
||||
aria-label="Toggle dark/light mode"
|
||||
>
|
||||
<!-- Sun icon (shown in dark mode — click to go light) -->
|
||||
<svg v-if="theme.isDark" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="5"/>
|
||||
<line x1="12" y1="1" x2="12" y2="3"/>
|
||||
<line x1="12" y1="21" x2="12" y2="23"/>
|
||||
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/>
|
||||
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/>
|
||||
<line x1="1" y1="12" x2="3" y2="12"/>
|
||||
<line x1="21" y1="12" x2="23" y2="12"/>
|
||||
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/>
|
||||
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/>
|
||||
</svg>
|
||||
<!-- Moon icon (shown in light mode — click to go dark) -->
|
||||
<svg v-else xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="theme-picker-wrapper" @mouseleave="closePicker">
|
||||
<button
|
||||
class="theme-toggle-btn"
|
||||
:title="'Theme: ' + (theme.currentMeta?.name || theme.currentTheme)"
|
||||
@click="showPicker = !showPicker"
|
||||
aria-label="Theme picker"
|
||||
>
|
||||
<!-- Sun icon (dark mode active) -->
|
||||
<svg v-if="theme.isDark" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="5"/>
|
||||
<line x1="12" y1="1" x2="12" y2="3"/>
|
||||
<line x1="12" y1="21" x2="12" y2="23"/>
|
||||
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/>
|
||||
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/>
|
||||
<line x1="1" y1="12" x2="3" y2="12"/>
|
||||
<line x1="21" y1="12" x2="23" y2="12"/>
|
||||
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/>
|
||||
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/>
|
||||
</svg>
|
||||
<!-- Moon icon (light mode active) -->
|
||||
<svg v-else xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<Transition name="fade">
|
||||
<div v-if="showPicker" class="theme-dropdown">
|
||||
<div class="theme-group">
|
||||
<div class="theme-group-label">Dark</div>
|
||||
<button
|
||||
v-for="t in theme.darkThemes"
|
||||
:key="t.id"
|
||||
class="theme-option"
|
||||
:class="{ active: theme.currentTheme === t.id }"
|
||||
@click="selectTheme(t.id)"
|
||||
:title="t.description"
|
||||
>
|
||||
<span class="theme-name">{{ t.name }}</span>
|
||||
<span v-if="theme.currentTheme === t.id" class="theme-check">✓</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="theme-divider"></div>
|
||||
<div class="theme-group">
|
||||
<div class="theme-group-label">Light</div>
|
||||
<button
|
||||
v-for="t in theme.lightThemes"
|
||||
:key="t.id"
|
||||
class="theme-option"
|
||||
:class="{ active: theme.currentTheme === t.id }"
|
||||
@click="selectTheme(t.id)"
|
||||
:title="t.description"
|
||||
>
|
||||
<span class="theme-name">{{ t.name }}</span>
|
||||
<span v-if="theme.currentTheme === t.id" class="theme-check">✓</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.dark-mode-toggle {
|
||||
.theme-picker-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.theme-toggle-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
|
@ -46,7 +97,76 @@ const theme = useThemeStore()
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
.dark-mode-toggle:hover {
|
||||
.theme-toggle-btn:hover {
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
.theme-dropdown {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
right: 0;
|
||||
margin-top: 4px;
|
||||
background: var(--color-surface);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: var(--shadow-lg);
|
||||
min-width: 180px;
|
||||
z-index: 100;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.theme-group-label {
|
||||
padding: 8px 14px 4px;
|
||||
font-size: var(--font-size-xs);
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.theme-divider {
|
||||
height: 1px;
|
||||
background: var(--color-border);
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.theme-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
padding: 8px 14px;
|
||||
background: transparent;
|
||||
color: var(--color-text);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: var(--font-size-sm);
|
||||
font-family: var(--font-ui);
|
||||
text-align: left;
|
||||
transition: background var(--transition-fast);
|
||||
}
|
||||
|
||||
.theme-option:hover {
|
||||
background: var(--color-surface-hover);
|
||||
}
|
||||
|
||||
.theme-option.active {
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
.theme-check {
|
||||
color: var(--color-accent);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.15s ease, transform 0.15s ease;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateY(-4px);
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,12 @@ import './assets/base.css'
|
|||
import './themes/cyberpunk.css'
|
||||
import './themes/dark.css'
|
||||
import './themes/light.css'
|
||||
import './themes/midnight.css'
|
||||
import './themes/hacker.css'
|
||||
import './themes/neon.css'
|
||||
import './themes/paper.css'
|
||||
import './themes/arctic.css'
|
||||
import './themes/solarized.css'
|
||||
|
||||
import App from './App.vue'
|
||||
|
||||
|
|
|
|||
|
|
@ -17,15 +17,24 @@ export interface ThemeMeta {
|
|||
author?: string
|
||||
description?: string
|
||||
builtin: boolean
|
||||
variant: 'dark' | 'light'
|
||||
}
|
||||
|
||||
const STORAGE_KEY = 'mrip-theme'
|
||||
const DEFAULT_THEME = 'cyberpunk'
|
||||
|
||||
const BUILTIN_THEMES: ThemeMeta[] = [
|
||||
{ id: 'cyberpunk', name: 'Cyberpunk', author: 'media.rip()', description: 'Electric blue + orange, scanlines, grid overlay', builtin: true },
|
||||
{ id: 'dark', name: 'Dark', author: 'media.rip()', description: 'Clean neutral dark theme', builtin: true },
|
||||
{ id: 'light', name: 'Light', author: 'media.rip()', description: 'Clean light theme for daylight use', builtin: true },
|
||||
// Dark themes
|
||||
{ id: 'cyberpunk', name: 'Cyberpunk', author: 'media.rip()', description: 'Electric blue + orange, scanlines, grid overlay', builtin: true, variant: 'dark' },
|
||||
{ id: 'dark', name: 'Dark', author: 'media.rip()', description: 'Clean neutral dark theme', builtin: true, variant: 'dark' },
|
||||
{ id: 'midnight', name: 'Midnight', author: 'media.rip()', description: 'Ultra-minimal, near-black, zero effects', builtin: true, variant: 'dark' },
|
||||
{ id: 'hacker', name: 'Hacker', author: 'media.rip()', description: 'Green-on-black terminal aesthetic', builtin: true, variant: 'dark' },
|
||||
{ id: 'neon', name: 'Neon', author: 'media.rip()', description: 'Hot pink + cyan on deep purple, synthwave vibes', builtin: true, variant: 'dark' },
|
||||
// Light themes
|
||||
{ id: 'light', name: 'Light', author: 'media.rip()', description: 'Clean light theme for daylight use', builtin: true, variant: 'light' },
|
||||
{ id: 'paper', name: 'Paper', author: 'media.rip()', description: 'Warm cream and sepia, book-like', builtin: true, variant: 'light' },
|
||||
{ id: 'arctic', name: 'Arctic', author: 'media.rip()', description: 'Cool whites and icy blues, crisp and sharp', builtin: true, variant: 'light' },
|
||||
{ id: 'solarized', name: 'Solarized', author: 'media.rip()', description: 'Solarized Light — easy on the eyes', builtin: true, variant: 'light' },
|
||||
]
|
||||
|
||||
export const useThemeStore = defineStore('theme', () => {
|
||||
|
|
@ -33,8 +42,14 @@ export const useThemeStore = defineStore('theme', () => {
|
|||
const customThemes = ref<ThemeMeta[]>([])
|
||||
const customThemeCSS = ref<Map<string, string>>(new Map())
|
||||
|
||||
/** Whether the current theme is a dark variant (cyberpunk and dark are dark; light is light). */
|
||||
const isDark = computed(() => currentTheme.value !== 'light')
|
||||
/** Whether the current theme is a dark variant. */
|
||||
const isDark = computed(() => {
|
||||
const meta = allThemes.value.find(t => t.id === currentTheme.value)
|
||||
return meta ? meta.variant === 'dark' : true
|
||||
})
|
||||
|
||||
const darkThemes = computed(() => allThemes.value.filter(t => t.variant === 'dark'))
|
||||
const lightThemes = computed(() => allThemes.value.filter(t => t.variant === 'light'))
|
||||
|
||||
const allThemes = computed<ThemeMeta[]>(() => [
|
||||
...BUILTIN_THEMES,
|
||||
|
|
@ -64,11 +79,13 @@ export const useThemeStore = defineStore('theme', () => {
|
|||
*/
|
||||
function toggleDarkMode(): void {
|
||||
if (isDark.value) {
|
||||
setTheme('light')
|
||||
// Switch to last used light theme, or first available
|
||||
const lastLight = localStorage.getItem(STORAGE_KEY + '-light') || 'light'
|
||||
setTheme(lastLight)
|
||||
} else {
|
||||
// Return to the last dark theme, defaulting to cyberpunk
|
||||
const lastDark = localStorage.getItem(STORAGE_KEY + '-dark') || DEFAULT_THEME
|
||||
setTheme(lastDark === 'light' ? DEFAULT_THEME : lastDark)
|
||||
setTheme(lastDark)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -82,8 +99,11 @@ export const useThemeStore = defineStore('theme', () => {
|
|||
currentTheme.value = themeId
|
||||
localStorage.setItem(STORAGE_KEY, themeId)
|
||||
// Remember the last dark theme for toggle
|
||||
if (themeId !== 'light') {
|
||||
const meta = allThemes.value.find(t => t.id === themeId)
|
||||
if (meta?.variant === 'dark') {
|
||||
localStorage.setItem(STORAGE_KEY + '-dark', themeId)
|
||||
} else {
|
||||
localStorage.setItem(STORAGE_KEY + '-light', themeId)
|
||||
}
|
||||
_apply(themeId)
|
||||
}
|
||||
|
|
@ -104,6 +124,7 @@ export const useThemeStore = defineStore('theme', () => {
|
|||
author: t.author,
|
||||
description: t.description,
|
||||
builtin: false,
|
||||
variant: t.variant || 'dark', // default custom themes to dark
|
||||
}))
|
||||
|
||||
// If saved theme is a custom theme, validate it still exists
|
||||
|
|
@ -159,6 +180,8 @@ export const useThemeStore = defineStore('theme', () => {
|
|||
currentTheme,
|
||||
customThemes,
|
||||
allThemes,
|
||||
darkThemes,
|
||||
lightThemes,
|
||||
currentMeta,
|
||||
isDark,
|
||||
init,
|
||||
|
|
|
|||
|
|
@ -73,10 +73,13 @@ describe('theme store', () => {
|
|||
expect(store.currentTheme).toBe('cyberpunk')
|
||||
})
|
||||
|
||||
it('lists 3 built-in themes', () => {
|
||||
it('lists 9 built-in themes', () => {
|
||||
const store = useThemeStore()
|
||||
expect(store.allThemes).toHaveLength(3)
|
||||
expect(store.allThemes.map(t => t.id)).toEqual(['cyberpunk', 'dark', 'light'])
|
||||
expect(store.allThemes).toHaveLength(9)
|
||||
expect(store.allThemes.map(t => t.id)).toEqual([
|
||||
'cyberpunk', 'dark', 'midnight', 'hacker', 'neon',
|
||||
'light', 'paper', 'arctic', 'solarized',
|
||||
])
|
||||
})
|
||||
|
||||
it('all built-in themes are marked builtin: true', () => {
|
||||
|
|
|
|||
35
frontend/src/themes/arctic.css
Normal file
35
frontend/src/themes/arctic.css
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/* media.rip() — Arctic Theme
|
||||
*
|
||||
* Cool whites, icy blues, crisp edges.
|
||||
* Modern, clean, and sharp — like fresh snow.
|
||||
*/
|
||||
|
||||
:root[data-theme="arctic"] {
|
||||
--color-bg: #f0f4f8;
|
||||
--color-surface: #ffffff;
|
||||
--color-surface-hover: #e8eef4;
|
||||
--color-border: #c8d6e5;
|
||||
|
||||
--color-text: #1a2a3a;
|
||||
--color-text-muted: #5a7a94;
|
||||
|
||||
--color-accent: #0088cc;
|
||||
--color-accent-hover: #006da6;
|
||||
--color-accent-secondary: #0066aa;
|
||||
|
||||
--color-success: #00a878;
|
||||
--color-warning: #e8a317;
|
||||
--color-error: #d63031;
|
||||
|
||||
--font-display: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
|
||||
|
||||
--effect-scanlines: none;
|
||||
--effect-grid: none;
|
||||
--effect-grid-size: 0px 0px;
|
||||
--effect-glow: none;
|
||||
|
||||
--shadow-sm: 0 1px 3px rgba(26, 42, 58, 0.06);
|
||||
--shadow-md: 0 4px 12px rgba(26, 42, 58, 0.08);
|
||||
--shadow-lg: 0 8px 24px rgba(26, 42, 58, 0.12);
|
||||
--shadow-glow: none;
|
||||
}
|
||||
43
frontend/src/themes/hacker.css
Normal file
43
frontend/src/themes/hacker.css
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/* media.rip() — Hacker Theme
|
||||
*
|
||||
* Green-on-black terminal aesthetic. Monospace everything,
|
||||
* phosphor glow, CRT scanlines. You're in the Matrix.
|
||||
*/
|
||||
|
||||
:root[data-theme="hacker"] {
|
||||
--color-bg: #0a0a0a;
|
||||
--color-surface: #0f1a0f;
|
||||
--color-surface-hover: #152215;
|
||||
--color-border: #1a3a1a;
|
||||
|
||||
--color-text: #33ff33;
|
||||
--color-text-muted: #1a8c1a;
|
||||
|
||||
--color-accent: #00ff41;
|
||||
--color-accent-hover: #33ff66;
|
||||
--color-accent-secondary: #ffcc00;
|
||||
|
||||
--color-success: #00ff41;
|
||||
--color-warning: #ffcc00;
|
||||
--color-error: #ff3333;
|
||||
|
||||
--font-ui: 'Cascadia Code', 'Fira Code', 'JetBrains Mono', 'Courier New', monospace;
|
||||
--font-mono: 'Cascadia Code', 'Fira Code', 'JetBrains Mono', 'Courier New', monospace;
|
||||
--font-display: 'Cascadia Code', 'Fira Code', 'JetBrains Mono', 'Courier New', monospace;
|
||||
|
||||
--effect-scanlines: repeating-linear-gradient(
|
||||
0deg,
|
||||
transparent,
|
||||
transparent 1px,
|
||||
rgba(0, 255, 65, 0.03) 1px,
|
||||
rgba(0, 255, 65, 0.03) 2px
|
||||
);
|
||||
--effect-grid: none;
|
||||
--effect-grid-size: 0px 0px;
|
||||
--effect-glow: 0 0 12px rgba(0, 255, 65, 0.2);
|
||||
|
||||
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.4);
|
||||
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.5);
|
||||
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.6);
|
||||
--shadow-glow: 0 0 15px rgba(0, 255, 65, 0.12);
|
||||
}
|
||||
40
frontend/src/themes/midnight.css
Normal file
40
frontend/src/themes/midnight.css
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/* media.rip() — Midnight Theme
|
||||
*
|
||||
* Ultra-minimal dark theme. Near-black backgrounds,
|
||||
* muted steel blue accents, zero visual effects.
|
||||
* For people who want the UI to disappear.
|
||||
*/
|
||||
|
||||
:root[data-theme="midnight"] {
|
||||
--color-bg: #060608;
|
||||
--color-surface: #0e0e12;
|
||||
--color-surface-hover: #16161c;
|
||||
--color-border: #1c1c24;
|
||||
|
||||
--color-text: #c8ccd0;
|
||||
--color-text-muted: #5c6370;
|
||||
|
||||
--color-accent: #6b8aaf;
|
||||
--color-accent-hover: #8aa4c4;
|
||||
--color-accent-secondary: #af6b8a;
|
||||
|
||||
--color-success: #5faa7c;
|
||||
--color-warning: #c4a35a;
|
||||
--color-error: #c45a5a;
|
||||
|
||||
--font-display: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
|
||||
|
||||
--effect-scanlines: none;
|
||||
--effect-grid: none;
|
||||
--effect-grid-size: 0px 0px;
|
||||
--effect-glow: none;
|
||||
|
||||
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.5);
|
||||
--shadow-md: 0 4px 8px rgba(0, 0, 0, 0.6);
|
||||
--shadow-lg: 0 8px 16px rgba(0, 0, 0, 0.7);
|
||||
--shadow-glow: none;
|
||||
|
||||
--radius-sm: 3px;
|
||||
--radius-md: 6px;
|
||||
--radius-lg: 8px;
|
||||
}
|
||||
42
frontend/src/themes/neon.css
Normal file
42
frontend/src/themes/neon.css
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/* media.rip() — Neon Theme
|
||||
*
|
||||
* Hot pink + cyan on deep purple-black. Vibrant, edgy,
|
||||
* synthwave-inspired. Glow effects cranked up.
|
||||
*/
|
||||
|
||||
:root[data-theme="neon"] {
|
||||
--color-bg: #0d0014;
|
||||
--color-surface: #150022;
|
||||
--color-surface-hover: #1e0033;
|
||||
--color-border: #2a0044;
|
||||
|
||||
--color-text: #f0e0ff;
|
||||
--color-text-muted: #9966bb;
|
||||
|
||||
--color-accent: #ff2d95;
|
||||
--color-accent-hover: #ff5cae;
|
||||
--color-accent-secondary: #00e5ff;
|
||||
|
||||
--color-success: #00e676;
|
||||
--color-warning: #ffab00;
|
||||
--color-error: #ff1744;
|
||||
|
||||
--font-display: 'JetBrains Mono', 'Cascadia Code', 'Fira Code', monospace;
|
||||
|
||||
--effect-scanlines: repeating-linear-gradient(
|
||||
0deg,
|
||||
transparent,
|
||||
transparent 3px,
|
||||
rgba(255, 45, 149, 0.04) 3px,
|
||||
rgba(255, 45, 149, 0.04) 4px
|
||||
);
|
||||
--effect-grid: linear-gradient(rgba(0, 229, 255, 0.02) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(0, 229, 255, 0.02) 1px, transparent 1px);
|
||||
--effect-grid-size: 40px 40px;
|
||||
--effect-glow: 0 0 25px rgba(255, 45, 149, 0.2);
|
||||
|
||||
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.4);
|
||||
--shadow-md: 0 4px 12px rgba(13, 0, 20, 0.6);
|
||||
--shadow-lg: 0 8px 24px rgba(13, 0, 20, 0.8);
|
||||
--shadow-glow: 0 0 20px rgba(255, 45, 149, 0.15);
|
||||
}
|
||||
40
frontend/src/themes/paper.css
Normal file
40
frontend/src/themes/paper.css
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/* media.rip() — Paper Theme
|
||||
*
|
||||
* Warm cream and sepia tones. Book-like reading feel.
|
||||
* Soft, easy on the eyes in bright environments.
|
||||
*/
|
||||
|
||||
:root[data-theme="paper"] {
|
||||
--color-bg: #f5f0e8;
|
||||
--color-surface: #fffdf7;
|
||||
--color-surface-hover: #f0ebe0;
|
||||
--color-border: #d6cebf;
|
||||
|
||||
--color-text: #2c2416;
|
||||
--color-text-muted: #7a705e;
|
||||
|
||||
--color-accent: #b85c38;
|
||||
--color-accent-hover: #a04e2e;
|
||||
--color-accent-secondary: #2e6b5e;
|
||||
|
||||
--color-success: #3a7d44;
|
||||
--color-warning: #c48a1a;
|
||||
--color-error: #b83838;
|
||||
|
||||
--font-ui: 'Georgia', 'Palatino Linotype', 'Book Antiqua', serif;
|
||||
--font-display: 'Georgia', 'Palatino Linotype', 'Book Antiqua', serif;
|
||||
|
||||
--effect-scanlines: none;
|
||||
--effect-grid: none;
|
||||
--effect-grid-size: 0px 0px;
|
||||
--effect-glow: none;
|
||||
|
||||
--shadow-sm: 0 1px 2px rgba(44, 36, 22, 0.06);
|
||||
--shadow-md: 0 3px 8px rgba(44, 36, 22, 0.08);
|
||||
--shadow-lg: 0 8px 20px rgba(44, 36, 22, 0.1);
|
||||
--shadow-glow: none;
|
||||
|
||||
--radius-sm: 3px;
|
||||
--radius-md: 6px;
|
||||
--radius-lg: 10px;
|
||||
}
|
||||
36
frontend/src/themes/solarized.css
Normal file
36
frontend/src/themes/solarized.css
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/* media.rip() — Solarized Light Theme
|
||||
*
|
||||
* Based on Ethan Schoonover's Solarized palette.
|
||||
* Developer favorite — designed for extended use
|
||||
* with carefully selected contrast ratios.
|
||||
*/
|
||||
|
||||
:root[data-theme="solarized"] {
|
||||
--color-bg: #fdf6e3;
|
||||
--color-surface: #eee8d5;
|
||||
--color-surface-hover: #e8e1cc;
|
||||
--color-border: #d3cbaf;
|
||||
|
||||
--color-text: #586e75;
|
||||
--color-text-muted: #93a1a1;
|
||||
|
||||
--color-accent: #268bd2;
|
||||
--color-accent-hover: #1a6da3;
|
||||
--color-accent-secondary: #d33682;
|
||||
|
||||
--color-success: #859900;
|
||||
--color-warning: #b58900;
|
||||
--color-error: #dc322f;
|
||||
|
||||
--font-display: 'Cascadia Code', 'Fira Code', 'JetBrains Mono', monospace;
|
||||
|
||||
--effect-scanlines: none;
|
||||
--effect-grid: none;
|
||||
--effect-grid-size: 0px 0px;
|
||||
--effect-glow: none;
|
||||
|
||||
--shadow-sm: 0 1px 2px rgba(88, 110, 117, 0.08);
|
||||
--shadow-md: 0 3px 8px rgba(88, 110, 117, 0.1);
|
||||
--shadow-lg: 0 8px 20px rgba(88, 110, 117, 0.12);
|
||||
--shadow-glow: none;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue