feat(webui): adopt lavender mascot branding
This commit is contained in:
@@ -121,6 +121,8 @@ After changing an action name, parameter, result description/schema, example or
|
||||
|
||||
SDK breaking changes also update [CHANGELOG.md](packages/sdk/CHANGELOG.md) and [VERSIONING.md](packages/sdk/VERSIONING.md). WebUI changes follow its [interaction conventions](packages/webui/README.md). Keep user-facing documentation aligned with behavior.
|
||||
|
||||
Standalone WebUI branding uses the [SnowLuma mascot](assets/readme/mascot.png) and a lavender default accent. Keep server defaults, frontend presets and pre-mount CSS aligned as described in [WebUI default appearance](packages/webui/README.md#default-appearance), while preserving saved user choices and host appearance overlays.
|
||||
|
||||
The root [README.md](README.md) presents the project's purpose, overall capabilities, quick start and documentation entry points. Update it only when those overview details change; adding or fixing an individual feature does not justify adding a dedicated section there. Put feature-specific API usage, configuration, limitations and troubleshooting in the relevant package README or topic document, preferring existing documentation.
|
||||
|
||||
Edit sources rather than `dist` outputs. Native artifacts in `packages/runtime/native` are supplied build inputs; do not substitute arbitrary local binaries to make a build pass. Packaging changes must preserve the checks in [Core's build configuration](packages/core/vite.config.ts) and [the release layout validator](tools/check-release-layout.mjs).
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
@@ -44,7 +44,7 @@ export type SidebarStyle = 'follow' | 'panel' | 'accent';
|
||||
export type BackgroundType = 'none' | 'solid' | 'gradient' | 'image';
|
||||
export type Density = 'cozy' | 'compact';
|
||||
export type TimeFormat = '12h' | '24h';
|
||||
/** Full color scheme. 'default' keeps the sky theme (driven by `mode`); the
|
||||
/** Full color scheme. 'default' keeps the lavender theme (driven by `mode`); the
|
||||
* Catppuccin flavors are complete palettes that also fix light/dark. */
|
||||
export type Palette =
|
||||
| 'default'
|
||||
@@ -85,7 +85,7 @@ export interface UiAppearance {
|
||||
accentCustom: string;
|
||||
accentScope: AccentScope;
|
||||
darkIntensity: DarkIntensity;
|
||||
/** Full color scheme; 'default' = the built-in sky theme. */
|
||||
/** Full color scheme; 'default' = the built-in lavender theme. */
|
||||
palette: Palette;
|
||||
sidebarStyle: SidebarStyle;
|
||||
background: UiBackground;
|
||||
@@ -203,12 +203,12 @@ export interface UiConfig {
|
||||
}
|
||||
|
||||
// ─── Defaults ────────────────────────────────────────────────────────────
|
||||
// Mirror the pre-existing ThemeContext defaults so an upgrade is a no-op
|
||||
// visually until the operator changes something.
|
||||
// Keep these defaults aligned with ThemeContext. Saved appearance choices
|
||||
// are normalized independently and remain the operator's preference.
|
||||
|
||||
const DEFAULT_BACKGROUND: UiBackground = {
|
||||
type: 'none',
|
||||
color: '#0ea5e9',
|
||||
color: '#b99ae6',
|
||||
gradient: 'none',
|
||||
imageOpacity: 0.15,
|
||||
imageBlur: 0,
|
||||
@@ -220,8 +220,8 @@ const DEFAULT_BACKGROUND: UiBackground = {
|
||||
const DEFAULT_APPEARANCE: UiAppearance = {
|
||||
mode: 'system',
|
||||
accentMode: 'preset',
|
||||
accentPreset: 'sky',
|
||||
accentCustom: '#38bdf8',
|
||||
accentPreset: 'lavender',
|
||||
accentCustom: '#8561bd',
|
||||
accentScope: 'global',
|
||||
darkIntensity: 'soft',
|
||||
palette: 'default',
|
||||
|
||||
@@ -3,6 +3,23 @@
|
||||
SnowLuma's browser console is a Vite + React application for managing runtime
|
||||
status, OneBot configuration, logs, storage, and server settings.
|
||||
|
||||
## Default appearance
|
||||
|
||||
New installations and appearance resets use the mascot's lavender accent.
|
||||
The light variant uses a deeper purple for readable button labels; dark mode
|
||||
uses a softer lavender. Existing saved accents and custom colors are preserved.
|
||||
The original sky-blue accent remains available in Settings.
|
||||
|
||||
Keep the server defaults in `packages/core/src/webui/ui-config.ts`, the frontend
|
||||
defaults and preset in `src/contexts/ThemeContext.tsx`, and the pre-mount tokens
|
||||
in `src/index.css` aligned when changing the default accent.
|
||||
|
||||
The browser favicon, home-screen icon and in-app logo share the mascot avatar
|
||||
in [`assets/brand/mascot-avatar.png`](../../assets/brand/mascot-avatar.png).
|
||||
Its exported sizes live in `public/`: `logo.png` (512 px), `favicon.png` (64 px),
|
||||
and `apple-touch-icon.png` (180 px). Export from the master without redrawing
|
||||
individual sizes.
|
||||
|
||||
## Host appearance integration
|
||||
|
||||
`SNOWLUMA_WEBUI_TARGET=maibot` opts a deployment into a reversible millennium
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
<html lang="zh-CN" class="light" data-theme="light">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/png" href="/logo.png" />
|
||||
<link rel="icon" type="image/png" sizes="64x64" href="/favicon.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
||||
<meta name="theme-color" content="#0ea5e9" />
|
||||
<meta name="theme-color" content="#8561bd" />
|
||||
<!-- WebUI is an admin surface; tell every compliant crawler to skip it. -->
|
||||
<meta name="robots" content="noindex, nofollow, noarchive, nosnippet" />
|
||||
<meta name="googlebot" content="noindex, nofollow, noarchive, nosnippet" />
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 9.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 269 KiB |
@@ -147,7 +147,7 @@ export function Sidebar({ collapsed = false, onItemClick }: SidebarProps) {
|
||||
<div className="flex h-16 shrink-0 items-center px-2">
|
||||
<div className="grid w-12 shrink-0 place-items-center">
|
||||
<div className="relative flex size-9 items-center justify-center overflow-hidden rounded-xl bg-primary/10 ring-1 ring-primary/20">
|
||||
<img src="/logo.png" alt="SnowLuma" className="size-7 object-contain" />
|
||||
<img src="/logo.png" alt="SnowLuma" className="size-full object-cover" />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
|
||||
@@ -319,7 +319,7 @@ function LoginBrand({ subtitle }: { subtitle: string }) {
|
||||
return (
|
||||
<div className="flex flex-col items-center gap-3 text-center">
|
||||
<div className="flex size-14 items-center justify-center rounded-2xl bg-primary/10 shadow-sm ring-1 ring-primary/20">
|
||||
<img src="/logo.png" alt="SnowLuma" className="size-10 object-contain" />
|
||||
<img src="/logo.png" alt="SnowLuma" className="size-10 rounded-xl object-cover" />
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex items-center justify-center gap-2">
|
||||
|
||||
@@ -2078,7 +2078,7 @@ function AboutPanel() {
|
||||
<img
|
||||
src="/logo.png"
|
||||
alt="SnowLuma"
|
||||
className="size-20 object-contain drop-shadow-sm"
|
||||
className="size-20 rounded-2xl object-cover drop-shadow-sm"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
|
||||
@@ -46,7 +46,8 @@ export type AppearancePatch = Partial<Omit<UiAppearance, 'background'>> & {
|
||||
|
||||
// ─── Frontend catalogues (the server stores only ids; the visuals live here) ───
|
||||
|
||||
export type AccentColor = 'sky' | 'blue' | 'violet' | 'rose' | 'emerald' | 'amber' | 'orange';
|
||||
export type AccentColor =
|
||||
'lavender' | 'sky' | 'blue' | 'violet' | 'rose' | 'emerald' | 'amber' | 'orange';
|
||||
|
||||
export interface AccentSpec {
|
||||
id: AccentColor;
|
||||
@@ -57,6 +58,13 @@ export interface AccentSpec {
|
||||
}
|
||||
|
||||
export const ACCENTS: AccentSpec[] = [
|
||||
{
|
||||
id: 'lavender',
|
||||
label: '薰衣草',
|
||||
swatch: '#8561bd',
|
||||
light: { primary: 'oklch(57% 0.14 300)', ring: 'oklch(57% 0.14 300)' },
|
||||
dark: { primary: 'oklch(78% 0.115 300)', ring: 'oklch(78% 0.115 300)' },
|
||||
},
|
||||
{
|
||||
id: 'sky',
|
||||
label: '天蓝',
|
||||
@@ -198,15 +206,15 @@ export const UI_SCALE = { min: 0.9, max: 1.2, step: 0.05 } as const;
|
||||
export const DEFAULT_APPEARANCE: UiAppearance = {
|
||||
mode: 'system',
|
||||
accentMode: 'preset',
|
||||
accentPreset: 'sky',
|
||||
accentCustom: '#38bdf8',
|
||||
accentPreset: 'lavender',
|
||||
accentCustom: '#8561bd',
|
||||
accentScope: 'global',
|
||||
darkIntensity: 'soft',
|
||||
palette: 'default',
|
||||
sidebarStyle: 'follow',
|
||||
background: {
|
||||
type: 'none',
|
||||
color: '#0ea5e9',
|
||||
color: '#b99ae6',
|
||||
gradient: 'none',
|
||||
imageOpacity: 0.15,
|
||||
imageBlur: 0,
|
||||
@@ -327,7 +335,7 @@ function accentVarsCss(a: UiAppearance): string {
|
||||
const surf = a.palette === 'default';
|
||||
|
||||
if (a.accentMode === 'custom') {
|
||||
const hex = safeHex(a.accentCustom, '#38bdf8');
|
||||
const hex = safeHex(a.accentCustom, DEFAULT_APPEARANCE.accentCustom);
|
||||
const lightFg = readableForeground(hex);
|
||||
// Dark mode: lighten the accent for contrast on dark surfaces, and pick
|
||||
// the foreground from the *lightened* colour (a light accent needs dark text).
|
||||
@@ -590,7 +598,7 @@ export const PALETTE_OPTIONS: PaletteSpec[] = [
|
||||
{
|
||||
id: 'default',
|
||||
label: '默认',
|
||||
preview: { bg: '#f1f5f9', surface: '#ffffff', dots: ['#0ea5e9', '#10b981', '#f43f5e'] },
|
||||
preview: { bg: '#f1f5f9', surface: '#ffffff', dots: ['#8561bd', '#10b981', '#f43f5e'] },
|
||||
},
|
||||
{
|
||||
id: 'catppuccin-latte',
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
@custom-variant dark (&:where(.dark, .dark *));
|
||||
|
||||
/* ──────────────────────────────────────────────
|
||||
Theme tokens (sky-blue accent)
|
||||
Theme tokens (mascot lavender accent)
|
||||
────────────────────────────────────────────── */
|
||||
:root {
|
||||
--radius: 0.75rem;
|
||||
@@ -18,8 +18,8 @@
|
||||
--popover: oklch(100% 0 0);
|
||||
--popover-foreground: oklch(20% 0.03 250);
|
||||
|
||||
/* sky-500 */
|
||||
--primary: oklch(68.5% 0.155 230);
|
||||
/* A deeper lavender keeps light-mode button labels readable. */
|
||||
--primary: oklch(57% 0.14 300);
|
||||
--primary-foreground: oklch(99% 0.005 240);
|
||||
|
||||
--secondary: oklch(96% 0.012 240);
|
||||
@@ -28,8 +28,8 @@
|
||||
--muted: oklch(96% 0.012 240);
|
||||
--muted-foreground: oklch(50% 0.02 250);
|
||||
|
||||
--accent: oklch(94% 0.03 230);
|
||||
--accent-foreground: oklch(35% 0.07 230);
|
||||
--accent: oklch(94% 0.03 300);
|
||||
--accent-foreground: oklch(35% 0.07 300);
|
||||
|
||||
--destructive: oklch(60% 0.22 27);
|
||||
--destructive-foreground: oklch(99% 0.005 240);
|
||||
@@ -49,16 +49,16 @@
|
||||
|
||||
--border: oklch(92% 0.01 240);
|
||||
--input: oklch(94% 0.012 240);
|
||||
--ring: oklch(68.5% 0.155 230);
|
||||
--ring: oklch(57% 0.14 300);
|
||||
|
||||
--sidebar: oklch(94% 0.008 240);
|
||||
--sidebar-foreground: oklch(25% 0.03 250);
|
||||
--sidebar-primary: oklch(68.5% 0.155 230);
|
||||
--sidebar-primary: oklch(57% 0.14 300);
|
||||
--sidebar-primary-foreground: oklch(99% 0.005 240);
|
||||
--sidebar-accent: oklch(90% 0.025 230);
|
||||
--sidebar-accent-foreground: oklch(35% 0.08 230);
|
||||
--sidebar-accent: oklch(90% 0.025 300);
|
||||
--sidebar-accent-foreground: oklch(35% 0.08 300);
|
||||
--sidebar-border: oklch(92% 0.01 240);
|
||||
--sidebar-ring: oklch(68.5% 0.155 230);
|
||||
--sidebar-ring: oklch(57% 0.14 300);
|
||||
--media-outline: oklch(0% 0 0 / 0.1);
|
||||
|
||||
/* Cards need depth without turning every surface into a hard outlined box.
|
||||
@@ -79,7 +79,7 @@
|
||||
--popover: oklch(20% 0.025 250);
|
||||
--popover-foreground: oklch(96% 0.01 240);
|
||||
|
||||
--primary: oklch(75% 0.14 230);
|
||||
--primary: oklch(78% 0.115 300);
|
||||
--primary-foreground: oklch(15% 0.02 250);
|
||||
|
||||
--secondary: oklch(25% 0.025 250);
|
||||
@@ -88,8 +88,8 @@
|
||||
--muted: oklch(24% 0.02 250);
|
||||
--muted-foreground: oklch(68% 0.02 240);
|
||||
|
||||
--accent: oklch(28% 0.05 230);
|
||||
--accent-foreground: oklch(85% 0.1 230);
|
||||
--accent: oklch(28% 0.05 300);
|
||||
--accent-foreground: oklch(85% 0.1 300);
|
||||
|
||||
--destructive: oklch(62% 0.2 27);
|
||||
--destructive-foreground: oklch(98% 0.005 240);
|
||||
@@ -106,16 +106,16 @@
|
||||
|
||||
--border: oklch(28% 0.02 250);
|
||||
--input: oklch(26% 0.02 250);
|
||||
--ring: oklch(75% 0.14 230);
|
||||
--ring: oklch(78% 0.115 300);
|
||||
|
||||
--sidebar: oklch(12% 0.018 250);
|
||||
--sidebar-foreground: oklch(92% 0.01 240);
|
||||
--sidebar-primary: oklch(75% 0.14 230);
|
||||
--sidebar-primary: oklch(78% 0.115 300);
|
||||
--sidebar-primary-foreground: oklch(15% 0.02 250);
|
||||
--sidebar-accent: oklch(28% 0.05 230);
|
||||
--sidebar-accent-foreground: oklch(85% 0.1 230);
|
||||
--sidebar-accent: oklch(28% 0.05 300);
|
||||
--sidebar-accent-foreground: oklch(85% 0.1 300);
|
||||
--sidebar-border: oklch(26% 0.02 250);
|
||||
--sidebar-ring: oklch(75% 0.14 230);
|
||||
--sidebar-ring: oklch(78% 0.115 300);
|
||||
--media-outline: oklch(100% 0 0 / 0.12);
|
||||
|
||||
--shadow-card:
|
||||
|
||||
Reference in New Issue
Block a user