Skip to content

TRIOS Theme Central: shared/src/constants/theme.ts → CSS → Chromium #501

@gHashTag

Description

@gHashTag

TRIOS Theme Central Control

AEL v2.0 | GO. Target: /Users/playra/BrowserOS


ЧТО ДЕЛАТЬ

Создать единый файл theme.ts — всё читает из него.

packages/shared/src/constants/theme.ts   ← ТОЛЬКО ЗДЕСЬ меняй цвет
        │
        ├── global.css (авто-генерация через generate:css)
        ├── theme-storage.ts (импорт напрямую)
        └── browseros_prefs.cc (через generate:cpp)

Step 1: Создать packages/shared/src/constants/theme.ts

// TRIOS Theme — Single Source of Truth
// Изменяй ТОЛЬКО ЗДЕСЬ

export const TRIOS_THEME = {
  // Дефолт режим: 'dark' | 'light' | 'system'
  defaultMode: 'dark' as const,

  // Основные цвета (oklch)
  dark: {
    background:         'oklch(0 0 0)',
    foreground:         'oklch(0.93 0 0)',
    card:               'oklch(0.04 0 0)',
    cardForeground:     'oklch(0.93 0 0)',
    popover:            'oklch(0.04 0 0)',
    popoverForeground:  'oklch(0.93 0 0)',
    primary:            'oklch(0.705 0.213 47.604)',
    primaryForeground:  'oklch(0.98 0.016 73.684)',
    secondary:          'oklch(0.08 0 0)',
    secondaryForeground:'oklch(0.93 0 0)',
    muted:              'oklch(0.08 0 0)',
    mutedForeground:    'oklch(0.60 0 0)',
    accent:             'oklch(0.12 0 0)',
    accentForeground:   'oklch(0.93 0 0)',
    destructive:        'oklch(0.704 0.191 22.216)',
    destructiveForeground: 'oklch(0.93 0 0)',
    border:             'oklch(0.16 0 0)',
    input:              'oklch(0.12 0 0)',
    ring:               'oklch(0.408 0.123 38.172)',
    sidebar:            'oklch(0 0 0)',
    sidebarForeground:  'oklch(0.93 0 0)',
    sidebarBorder:      'oklch(0.16 0 0)',
    // BrowserOS brand
    accentOrange:       'oklch(0.6781 0.1663 43.21)',
    accentOrangeBright: 'oklch(0.7531 0.1963 43.21)',
  },

  light: {
    background:         'oklch(0 0 0)',      // тоже чёрный — TRIOS всегда тёмный
    foreground:         'oklch(0.93 0 0)',
    card:               'oklch(0.04 0 0)',
    cardForeground:     'oklch(0.93 0 0)',
    popover:            'oklch(0.04 0 0)',
    popoverForeground:  'oklch(0.93 0 0)',
    primary:            'oklch(0.705 0.213 47.604)',
    primaryForeground:  'oklch(0.98 0.016 73.684)',
    secondary:          'oklch(0.06 0 0)',
    secondaryForeground:'oklch(0.93 0 0)',
    muted:              'oklch(0.06 0 0)',
    mutedForeground:    'oklch(0.58 0 0)',
    accent:             'oklch(0.10 0 0)',
    accentForeground:   'oklch(0.93 0 0)',
    destructive:        'oklch(0.577 0.245 27.325)',
    destructiveForeground: 'oklch(0.99 0 0)',
    border:             'oklch(0.14 0 0)',
    input:              'oklch(0.10 0 0)',
    ring:               'oklch(0.75 0.183 55.934)',
    sidebar:            'oklch(0 0 0)',
    sidebarForeground:  'oklch(0.93 0 0)',
    sidebarBorder:      'oklch(0.14 0 0)',
    accentOrange:       'oklch(0.6781 0.1663 43.21)',
    accentOrangeBright: 'oklch(0.7531 0.1963 43.21)',
  },

  // Chromium C++ значения
  chromium: {
    // RGB(0,0,0) = 0x000000 = pure black frame
    frameColorR: 0x00,
    frameColorG: 0x00,
    frameColorB: 0x00,
    // BrowserColorScheme: 0=system, 1=light, 2=dark
    colorScheme: 2,
  },
} as const

export type ThemeMode = typeof TRIOS_THEME.defaultMode
export type ThemeColors = typeof TRIOS_THEME.dark

Step 2: Обновить packages/shared/src/index.ts

export * from './constants/theme'
// ... остальные экспорты

Step 3: Обновить theme-storage.ts — импорт из shared

File: packages/browseros-agent/apps/agent/lib/theme/theme-storage.ts

import { storage } from '@wxt-dev/storage'
import { TRIOS_THEME } from '@browseros/shared/constants/theme'

export type Theme = 'light' | 'dark' | 'system'

const DEV_FALLBACK: Theme = TRIOS_THEME.defaultMode
const isWxtContext = typeof chrome !== 'undefined' && chrome?.storage != null

export const themeStorage = isWxtContext
  ? storage.defineItem<Theme>('local:theme', { fallback: DEV_FALLBACK })
  : {
      getValue: async (): Promise<Theme> => {
        try { return (localStorage.getItem('theme') as Theme) ?? DEV_FALLBACK }
        catch { return DEV_FALLBACK }
      },
      setValue: async (value: Theme): Promise<void> => {
        try { localStorage.setItem('theme', value) } catch {}
      },
      watch: (_cb: (value: Theme) => void) => () => {},
    }

Step 4: Генерация global.css из theme.ts

Создать packages/browseros/tools/generate_css_from_theme.mjs:

#!/usr/bin/env node
// Reads TRIOS_THEME from shared/src/constants/theme.ts
// Writes :root and .dark blocks in global.css

import { readFileSync, writeFileSync } from 'fs'
import { resolve, dirname } from 'path'
import { fileURLToPath } from 'url'

const __dir = dirname(fileURLToPath(import.meta.url))
const ROOT = resolve(__dir, '../..')

// Dynamic import of theme constants
const { TRIOS_THEME } = await import(
  resolve(ROOT, 'shared/src/constants/theme.ts')
).catch(() => {
  // Fallback: read raw TS and eval with regex
  const src = readFileSync(
    resolve(ROOT, 'shared/src/constants/theme.ts'), 'utf8'
  )
  // Simple extraction via regex
  const match = src.match(/dark:\s*\{([\s\S]+?)\},\s*light:/)
  if (!match) throw new Error('Cannot parse theme.ts')
  return { TRIOS_THEME: { dark: parseCssObj(match[1]), light: {} } }
})

function camelToKebab(str) {
  return str.replace(/([A-Z])/g, '-$1').toLowerCase()
}

function themeToCSS(colors, selector) {
  const vars = Object.entries(colors)
    .map(([k, v]) => `  --${camelToKebab(k)}: ${v};`)
    .join('\n')
  return `${selector} {\n${vars}\n}`
}

const CSS_FILE = resolve(
  ROOT,
  'browseros-agent/apps/agent/styles/global.css'
)

let css = readFileSync(CSS_FILE, 'utf8')

const rootBlock = themeToCSS(TRIOS_THEME.light, ':root')
const darkBlock = themeToCSS(TRIOS_THEME.dark, '.dark')

// Preserve non-color :root vars (--radius, --chart-*, fonts, --accent-orange)
// Only replace color vars section
css = css
  .replace(/:root\s*\{[\s\S]*?\}\s*(?=\.dark)/, rootBlock + '\n\n')
  .replace(/\.dark\s*\{[\s\S]*?\}\s*(?=@theme)/, darkBlock + '\n\n')

writeFileSync(CSS_FILE, css)
console.log('✓ global.css updated from theme.ts')

Добавить в корневой package.json:

"theme:sync": "node packages/browseros/tools/generate_css_from_theme.mjs",
"theme:apply": "python3 packages/browseros/tools/set_dark_theme.py",
"theme:all": "bun run theme:sync && bun run theme:apply"

Step 5: Обновить Chromium патч browseros_prefs.cc

File: packages/browseros/chromium_patches/chrome/browser/browseros/core/browseros_prefs.cc

Изменить SyncDefaultTheme:

 void SyncDefaultTheme(PrefService* pref_service) {
   const PrefService::Preference* user_color_pref =
       pref_service->FindPreference(::prefs::kUserColor);
   if (user_color_pref && user_color_pref->IsDefaultValue()) {
     pref_service->SetInteger(::prefs::kUserColor,
-                             static_cast<int>(SkColorSetRGB(136, 136, 136)));
+                             static_cast<int>(SkColorSetRGB(0x00, 0x00, 0x00)));
     pref_service->SetString(::prefs::kCurrentThemeID,
                             "user_color_theme_id");
     pref_service->SetInteger(
         ::prefs::kBrowserColorVariant,
         static_cast<int>(ui::mojom::BrowserColorVariant::kNeutral));
+    pref_service->SetInteger(
+        ::prefs::kBrowserColorScheme,
+        2);  // kDark = 2
   }
 }

File: packages/browseros/chromium_patches/chrome/browser/themes/theme_service.cc

-  static_cast<int>(ThemeService::BrowserColorScheme::kLight),
+  static_cast<int>(ThemeService::BrowserColorScheme::kDark),

-  static_cast<int>(ThemeService::BrowserColorScheme::kLight));
+  static_cast<int>(ThemeService::BrowserColorScheme::kDark));

Step 6: Runtime fix — set_dark_theme.py

Создать packages/browseros/tools/set_dark_theme.py:

#!/usr/bin/env python3
"""Apply TRIOS ultra-black theme to BrowserOS profile. No rebuild needed."""
import json, pathlib, sys

PREFS = pathlib.Path.home() / \
    'Library/Application Support/BrowserOS/Default/Preferences'

if not PREFS.exists():
    sys.exit(f'Profile not found: {PREFS}')

data = json.loads(PREFS.read_text())
browser = data.setdefault('browser', {})

# kDark = 2
browser['color_scheme2'] = 2
# Pure black: SkColor ARGB = 0xFF000000 = 4278190080
browser['user_color2'] = 4278190080

# Clear cached theme to force recompute
if 'extensions' in data and 'theme' in data['extensions']:
    data['extensions']['theme'] = {'id': '', 'pack_hash': ''}

PREFS.write_text(json.dumps(data, indent=2))
print('✓ TRIOS ultra-black applied. Restart BrowserOS.')

Step 7: Проверить что @browseros/shared есть в workspace

# Проверить package.json shared
cat packages/shared/package.json | grep '"name"'
# Должно быть: "@browseros/shared"

# Проверить workspace
cat package.json | grep -A5 'workspaces'

Если packages/shared не есть — создать:

mkdir -p packages/shared/src/constants
cat > packages/shared/package.json << 'EOF'
{
  "name": "@browseros/shared",
  "version": "0.0.1",
  "exports": {
    "./constants/theme": "./src/constants/theme.ts"
  }
}
EOF

Verification

# 1. Создать theme.ts
ls packages/shared/src/constants/theme.ts

# 2. Синх CSS
bun run theme:sync
# Должно вывести: ✓ global.css updated from theme.ts

# 3. Runtime применение
bun run theme:apply

# 4. Проверить CSS
grep 'background' packages/browseros-agent/apps/agent/styles/global.css | head -3
# Должно: --background: oklch(0 0 0);

# 5. bun dev — чёрный фон
bun dev
  • packages/shared/src/constants/theme.ts создан
  • theme-storage.ts импортирует TRIOS_THEME.defaultMode
  • generate_css_from_theme.mjs обновляет global.css
  • set_dark_theme.py применяет рунтайм
  • browseros_prefs.cc использует RGB(0,0,0) и kDark=2
  • theme_service.cc использует kDark
  • bun dev → чистый чёрный фон
  • Одно место для изменения всего цвета

Commit

feat(theme): TRIOS_THEME central control — shared/constants/theme.ts | Closes #[this]

φ² + 1/φ² = 3 | TRINITY DARK #000000

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions