diff --git a/src/App.svelte b/src/App.svelte index e744691..ac35461 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -1,54 +1,58 @@ - - - +Trixie -
-
-
-

TRIXIE

-

Twitch control center

-
- {connectionState} +
+
+
TTRIXIE
+ +
{connectionState}
-
-
-

SERVER CONNECTION

-

Ready to build the dashboard

-

The client and server now share a versioned readiness contract.

-
-
- -
- - +
+
-
+
CHANNEL
No Twitch account connected
+ + -
-
◈

Live dashboard

Stream preview, activity, chat, and controls will live here.

-
⌁

Bot and plugins

Modular commands and safe WASM extensions are planned next.

-
◎

Overlays

Browser-source alerts will be editable and previewable.

-
-
+
+
LIVE DASHBOARD / {activeView.toUpperCase()}

{activeView}

+
+
STREAM PREVIEW⋮
STREAM OFFLINE
CONNECT TWITCH TO BEGIN
+
ACTIVITY FEED⋮
◌
Nothing here yetFollows, subscriptions, raids, and server events will appear here.
+
MY CHAT⋮
⌁
Chat is waitingConnect a streamer or bot account to begin.
+
QUICK ACTIONS⋮
+
+
+ + diff --git a/src/main.ts b/src/main.ts index efb8d4c..919b913 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,7 +1,8 @@ import './styles.css'; import App from './App.svelte'; +import { mount } from 'svelte'; -const app = new App({ +const app = mount(App, { target: document.getElementById('app')!, }); diff --git a/src/styles.css b/src/styles.css index 32ffebd..bb77222 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1,154 +1,412 @@ +@font-face { + font-family: 'Rajdhani'; + src: url('/fonts/Rajdhani-Regular.ttf') format('truetype'); + font-weight: 400; +} +@font-face { + font-family: 'Rajdhani'; + src: url('/fonts/Rajdhani-SemiBold.ttf') format('truetype'); + font-weight: 600; +} +@font-face { + font-family: 'Rajdhani'; + src: url('/fonts/Rajdhani-Bold.ttf') format('truetype'); + font-weight: 700; +} +@font-face { + font-family: 'Inter'; + src: url('/fonts/Inter-Variable.ttf') format('truetype'); +} +@font-face { + font-family: 'JetBrains Mono'; + src: url('/fonts/JetBrainsMono-Variable.ttf') format('truetype'); +} :root { - font-family: Inter, ui-sans-serif, system-ui, sans-serif; - color: #f3f5fb; - background: #10131a; - font-synthesis: none; + --ed-accent: #00b3ff; + --ed-accent2: #ff7f00; + --ed-bg: #06080c; + --ed-panel: #0d1117; + --ed-edge: #1d2630; + --ed-fg: #dde6ec; + --ed-dim: #7d8b96; + --ed-success: #35d073; + --ed-warn: #ffb400; + --ed-danger: #ff5436; + --ed-info: #00b3ff; + --ed-love: #ff5ca8; + --font-display: 'Rajdhani', 'Inter', sans-serif; + --font-data: 'JetBrains Mono', monospace; + --font-body: 'Inter', sans-serif; + --panel-radius: 2px; + --ui-line: color-mix(in srgb, var(--ed-accent) 28%, var(--ed-edge)); + --ui-line-soft: color-mix(in srgb, var(--ed-accent) 16%, var(--ed-edge)); + --ui-line-focus: color-mix(in srgb, var(--ed-accent) 62%, var(--ed-edge)); + --ui-surface: color-mix(in srgb, var(--ed-accent) 8%, var(--ed-bg)); + --ui-surface-hi: color-mix(in srgb, var(--ed-accent) 14%, var(--ed-bg)); + --ui-divider: color-mix(in srgb, var(--ed-fg) 7%, transparent); } - * { box-sizing: border-box; } +html, body { margin: 0; - min-width: 320px; - min-height: 100vh; - background: radial-gradient(circle at 85% 0%, #17325e 0, #10131a 42rem); + min-height: 100%; + background: var(--ed-bg); + color: var(--ed-fg); + font-family: var(--font-body); + font-size: 13px; } button, input { font: inherit; + color: inherit; } button { border: 0; - border-radius: 8px; - padding: 0.7rem 1rem; - color: white; - background: #2575e6; cursor: pointer; + background: none; } -button:hover { - background: #4189ed; +.app-shell { + min-height: 100vh; + background: linear-gradient( + 135deg, + var(--ed-bg), + color-mix(in srgb, var(--ed-bg) 90%, var(--ed-accent)) + ); } -.shell { - width: min(1180px, calc(100% - 3rem)); - margin: 0 auto; - padding: 2rem 0; +.app-bar { + height: 54px; + display: flex; + align-items: center; + gap: 24px; + padding: 0 18px; + border-bottom: 1px solid var(--ed-edge); + background: var(--ed-panel); } -.topbar, -.input-row { +.brand { + display: flex; + align-items: center; + gap: 9px; + min-width: 170px; + font: 600 18px var(--font-display); + letter-spacing: 0.12em; +} +.brand-mark { + display: grid; + place-items: center; + width: 26px; + height: 26px; + color: var(--ed-bg); + background: var(--ed-accent); + font-weight: 700; +} +.top-nav { + display: flex; + align-self: stretch; + gap: 4px; +} +.nav-item { + position: relative; + padding: 0 14px; + color: var(--ed-dim); + font: 600 13px var(--font-display); +} +.nav-item:hover, +.nav-item.active { + color: var(--ed-fg); + background: var(--ui-surface); +} +.nav-item.active::after { + position: absolute; + right: 10px; + bottom: 0; + left: 10px; + height: 2px; + background: var(--ed-accent); + content: ''; +} +.app-actions { + display: flex; + align-items: center; + gap: 10px; + margin-left: auto; +} +.connection-state, +.badge { + padding: 3px 7px; + border: 1px solid var(--ed-warn); + color: var(--ed-warn); + font: 10px var(--font-data); + letter-spacing: 0.04em; +} +.connection-state.online { + border-color: var(--ed-success); + color: var(--ed-success); +} +.icon-button, +.secondary { + color: var(--ed-dim); + font-size: 18px; +} +.workspace { + display: grid; + grid-template-columns: 220px 1fr; + min-height: calc(100vh - 54px); +} +.side-panel { + border-right: 1px solid var(--ed-edge); + background: color-mix(in srgb, var(--ed-panel) 80%, var(--ed-bg)); +} +.panel-header { display: flex; align-items: center; justify-content: space-between; - gap: 1rem; + min-height: 34px; + padding: 0 10px; + border-bottom: 1px solid var(--ed-edge); + color: var(--ed-fg); + font: 600 13px var(--font-display); + letter-spacing: 0.04em; } -.topbar { - margin-bottom: 2rem; +.panel-kicker, +.micro { + color: var(--ed-dim); + font: 10px var(--font-data); + letter-spacing: 0.08em; } -.eyebrow { - margin: 0 0 0.35rem; - color: #78aef5; - font-size: 0.72rem; - font-weight: 800; - letter-spacing: 0.14em; +.server-card, +.side-section { + padding: 16px 12px; + border-bottom: 1px solid var(--ed-edge); } -h1, -h2, -h3, -p { - margin-top: 0; +.server-status { + display: flex; + align-items: center; + gap: 7px; + margin: 13px 0 18px; + font: 11px var(--font-data); } -h1 { - margin-bottom: 0; - font-size: clamp(1.6rem, 3vw, 2.4rem); +.status-dot { + width: 7px; + height: 7px; + border-radius: 50%; + background: var(--ed-danger); } -h2 { - font-size: clamp(1.4rem, 3vw, 2.1rem); -} -.status { - border: 1px solid #3a4354; - border-radius: 999px; - padding: 0.45rem 0.8rem; - color: #a9b1c2; - font-size: 0.85rem; -} -.status.connected { - border-color: #2f9d70; - color: #77e0ae; -} -.panel { - border: 1px solid #2b3342; - border-radius: 14px; - background: rgba(24, 29, 39, 0.88); - box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.18); -} -.hero { - display: grid; - grid-template-columns: 1.2fr 1fr; - gap: 2rem; - padding: 2rem; -} -.muted, -small { - color: #9aa5b8; -} -.connection-form { - align-self: center; +.status-dot.good { + background: var(--ed-success); } label { display: block; - margin-bottom: 0.5rem; - color: #c9d2e3; - font-size: 0.85rem; + margin-bottom: 5px; } -input { +.control { + width: 100%; + padding: 7px 8px; + border: 1px solid var(--ui-line); + border-radius: 2px; + outline: none; + background: var(--ed-bg); + color: var(--ed-fg); + font: 11px var(--font-data); +} +.control:focus { + border-color: var(--ui-line-focus); +} +.control-button { + width: 100%; + margin-top: 8px; +} +.primary { + padding: 7px 10px; + border: 1px solid var(--ed-accent); + background: color-mix(in srgb, var(--ed-accent) 20%, var(--ed-bg)); + color: var(--ed-fg); + font: 600 11px var(--font-data); +} +.primary:hover { + background: color-mix(in srgb, var(--ed-accent) 34%, var(--ed-bg)); +} +.empty-row, +.mono { + margin-top: 8px; + color: var(--ed-dim); + font-size: 11px; +} +.mono { + font-family: var(--font-data); +} +.side-footer { + margin-top: auto; + border-bottom: 0; +} +.content-area { min-width: 0; - flex: 1; - border: 1px solid #3a4354; - border-radius: 8px; - padding: 0.7rem 0.8rem; - color: #f3f5fb; - background: #10131a; + padding: 16px; } -.input-row { - justify-content: stretch; +.content-heading { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 12px; } -small { - display: block; - margin-top: 0.55rem; +.content-heading h1 { + margin: 4px 0 0; + font: 600 24px var(--font-display); } .dashboard-grid { display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 1rem; - margin-top: 1rem; + grid-template-columns: 1.25fr 1fr 1fr; + grid-template-rows: minmax(280px, 1fr) 180px; + gap: 10px; + min-height: calc(100vh - 110px); } -.card { - min-height: 180px; - padding: 1.4rem; +.panel { + min-width: 0; + border: 1px solid var(--ed-edge); + border-radius: var(--panel-radius); + background: var(--ed-panel); } -.card p { - color: #9aa5b8; +.preview-panel { + grid-column: span 2; +} +.chat-panel { + grid-row: span 2; +} +.preview-stage { + display: grid; + place-content: center; + min-height: 220px; + border-bottom: 1px solid var(--ed-edge); + background: radial-gradient( + circle, + color-mix(in srgb, var(--ed-accent) 10%, var(--ed-panel)), + var(--ed-bg) 70% + ); + text-align: center; +} +.offline-mark { + color: var(--ed-fg); + font: 700 24px var(--font-display); + letter-spacing: 0.18em; +} +.offline-subtitle { + margin-top: 5px; + color: var(--ed-dim); + font: 10px var(--font-data); + letter-spacing: 0.1em; +} +.panel-footer { + display: flex; + justify-content: space-between; + padding: 9px 10px; +} +.panel-tabs { + display: flex; + gap: 14px; + padding: 9px 10px; + border-bottom: 1px solid var(--ed-edge); +} +.tab { + padding: 0 0 5px; + color: var(--ed-dim); + font: 10px var(--font-data); +} +.tab.active { + border-bottom: 2px solid var(--ed-accent); + color: var(--ed-accent); +} +.empty-state, +.chat-empty { + display: grid; + place-items: center; + gap: 6px; + height: calc(100% - 75px); + padding: 24px; + color: var(--ed-dim); + text-align: center; +} +.empty-state strong, +.chat-empty strong { + color: var(--ed-fg); + font: 600 16px var(--font-display); +} +.empty-state span, +.chat-empty span { + max-width: 220px; line-height: 1.5; } -.icon { - display: inline-block; - margin-bottom: 1rem; - color: #5d9bf0; - font-size: 1.8rem; +.empty-glyph { + color: var(--ed-accent); + font-size: 28px; } -@media (max-width: 760px) { - .shell { - width: min(100% - 1.5rem, 600px); - padding-top: 1rem; +.chat-composer { + display: flex; + gap: 5px; + padding: 8px; + border-top: 1px solid var(--ed-edge); +} +.chat-composer .control { + min-width: 0; +} +.chat-composer .primary { + opacity: 0.5; +} +.quick-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 6px; + padding: 10px; +} +.quick-action { + min-height: 52px; + border: 1px solid var(--ui-line-soft); + background: var(--ui-surface); + color: var(--ed-dim); + font: 10px var(--font-data); +} +.quick-action:hover, +.quick-action.accent { + border-color: var(--ui-line-focus); + color: var(--ed-fg); + background: var(--ui-surface-hi); +} +@media (max-width: 900px) { + .workspace { + grid-template-columns: 170px 1fr; } - .hero, .dashboard-grid { - grid-template-columns: 1fr; + grid-template-columns: 1fr 1fr; + grid-template-rows: auto auto auto; } - .hero { - padding: 1.25rem; + .preview-panel { + grid-column: span 2; } - .topbar { - align-items: flex-start; + .chat-panel { + grid-row: span 1; + grid-column: span 2; + } +} +@media (max-width: 640px) { + .top-nav { + display: none; + } + .workspace { + display: block; + } + .side-panel { + display: none; + } + .content-area { + padding: 10px; + } + .dashboard-grid { + display: block; + } + .panel { + margin-bottom: 10px; + } + .chat-panel { + min-height: 280px; } } diff --git a/static/fonts/Inter-Variable.ttf b/static/fonts/Inter-Variable.ttf new file mode 100644 index 0000000..047c92f Binary files /dev/null and b/static/fonts/Inter-Variable.ttf differ diff --git a/static/fonts/JetBrainsMono-Variable.ttf b/static/fonts/JetBrainsMono-Variable.ttf new file mode 100644 index 0000000..aa310be Binary files /dev/null and b/static/fonts/JetBrainsMono-Variable.ttf differ diff --git a/static/fonts/Rajdhani-Bold.ttf b/static/fonts/Rajdhani-Bold.ttf new file mode 100644 index 0000000..47af157 Binary files /dev/null and b/static/fonts/Rajdhani-Bold.ttf differ diff --git a/static/fonts/Rajdhani-Medium.ttf b/static/fonts/Rajdhani-Medium.ttf new file mode 100644 index 0000000..a6960c6 Binary files /dev/null and b/static/fonts/Rajdhani-Medium.ttf differ diff --git a/static/fonts/Rajdhani-Regular.ttf b/static/fonts/Rajdhani-Regular.ttf new file mode 100644 index 0000000..d25bd37 Binary files /dev/null and b/static/fonts/Rajdhani-Regular.ttf differ diff --git a/static/fonts/Rajdhani-SemiBold.ttf b/static/fonts/Rajdhani-SemiBold.ttf new file mode 100644 index 0000000..d43750b Binary files /dev/null and b/static/fonts/Rajdhani-SemiBold.ttf differ