Compare commits

...
3 Commits
Author SHA1 Message Date
ReaperOfVeriod 5298c6870b feat: add initial client shell
Client checks / checks (push) Canceled after 0s
Client dependency and security checks / audit (push) Canceled after 0s
2026-10-25 03:52:37 +01:00
ReaperOfVeriod 67a8a06268 chore: document branch workflow and security checks
Client checks / checks (push) Canceled after 0s
Client dependency and security checks / audit (push) Canceled after 0s
2026-10-25 03:48:58 +01:00
ReaperOfVeriod 51c4853d51 chore: add MIT license
Client checks / checks (push) Canceled after 0s
2026-10-25 03:45:43 +01:00
15 changed files with 1868 additions and 4 deletions
+16
View File
@@ -0,0 +1,16 @@
name: Client dependency and security checks
on:
push:
pull_request:
jobs:
audit:
runs-on: debian-latest
steps:
- uses: actions/checkout@v4
- name: Audit JavaScript dependencies when a lockfile exists
run: |
if test -f package-lock.json; then
npm audit --audit-level=high
fi
-1
View File
@@ -7,4 +7,3 @@ Read the parent `AGENTS.md`, `PLAN.md`, `TODO.md`, and `docs/wiki/README.md` bef
- Use Prettier for Svelte, JavaScript/TypeScript, JSON, YAML, and Markdown. - Use Prettier for Svelte, JavaScript/TypeScript, JSON, YAML, and Markdown.
- Never store passwords, tokens, or secrets in source, settings, fixtures, logs, or artifacts. - Never store passwords, tokens, or secrets in source, settings, fixtures, logs, or artifacts.
- Do not edit the parent `PLAN.md` without explicit user permission. - Do not edit the parent `PLAN.md` without explicit user permission.
-1
View File
@@ -1,4 +1,3 @@
# Contributing # Contributing
Run formatting, linting, type checks, tests, and the AppImage build before submission. Use deterministic mocked server/API fixtures. Run formatting, linting, type checks, tests, and the AppImage build before submission. Use deterministic mocked server/API fixtures.
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 ReaperOfVeriod
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-1
View File
@@ -7,4 +7,3 @@ The client is a Svelte-based control surface distributed as an x86-64 AppImage.
Implementation has not started. See the parent workspace's `PLAN.md`, `TODO.md`, and `AGENTS.md` before beginning work. Implementation has not started. See the parent workspace's `PLAN.md`, `TODO.md`, and `AGENTS.md` before beginning work.
Consumes the versioned contracts from the sibling `trixie-api` repository. Consumes the versioned contracts from the sibling `trixie-api` repository.
-1
View File
@@ -1,4 +1,3 @@
# Security # Security
Report vulnerabilities privately through the hosting instance. Never include credentials, tokens, or real user data in issues or fixtures. Report vulnerabilities privately through the hosting instance. Never include credentials, tokens, or real user data in issues or fixtures.
+12
View File
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Trixie</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
+1554
View File
File diff suppressed because it is too large Load Diff
+22
View File
@@ -0,0 +1,22 @@
{
"name": "trixy-linux-client",
"private": true,
"version": "0.1.0-dev",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"check": "svelte-check --tsconfig ./tsconfig.json",
"format": "prettier --write .",
"format:check": "prettier --check ."
},
"devDependencies": {
"@tsconfig/svelte": "^5.0.0",
"@sveltejs/vite-plugin-svelte": "^5.0.0",
"prettier": "^3.5.0",
"svelte": "^5.0.0",
"svelte-check": "^4.0.0",
"typescript": "^5.7.0",
"vite": "^6.0.0"
}
}
+54
View File
@@ -0,0 +1,54 @@
<script lang="ts">
let serverAddress = 'http://127.0.0.1:8787';
let connectionState = 'Not connected';
let serverVersion = '—';
async function checkServer() {
connectionState = 'Connecting…';
try {
const response = await fetch(`${serverAddress}/api/v1/server/info`);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const info: { server_version: string } = await response.json();
serverVersion = info.server_version;
connectionState = 'Connected';
} catch {
connectionState = 'Server unavailable';
}
}
</script>
<svelte:head>
<meta name="theme-color" content="#2575e6" />
</svelte:head>
<main class="shell">
<header class="topbar">
<div>
<p class="eyebrow">TRIXIE</p>
<h1>Twitch control center</h1>
</div>
<span class:connected={connectionState === 'Connected'} class="status">{connectionState}</span>
</header>
<section class="hero panel">
<div>
<p class="eyebrow">SERVER CONNECTION</p>
<h2>Ready to build the dashboard</h2>
<p class="muted">The client and server now share a versioned readiness contract.</p>
</div>
<div class="connection-form">
<label for="server-address">Server address</label>
<div class="input-row">
<input id="server-address" bind:value={serverAddress} spellcheck="false" />
<button on:click={checkServer}>Test connection</button>
</div>
<small>Server version: {serverVersion}</small>
</div>
</section>
<section class="dashboard-grid">
<article class="panel card"><span class="icon">◈</span><h3>Live dashboard</h3><p>Stream preview, activity, chat, and controls will live here.</p></article>
<article class="panel card"><span class="icon">⌁</span><h3>Bot and plugins</h3><p>Modular commands and safe WASM extensions are planned next.</p></article>
<article class="panel card"><span class="icon">◎</span><h3>Overlays</h3><p>Browser-source alerts will be editable and previewable.</p></article>
</section>
</main>
+8
View File
@@ -0,0 +1,8 @@
import './styles.css';
import App from './App.svelte';
const app = new App({
target: document.getElementById('app')!,
});
export default app;
+154
View File
@@ -0,0 +1,154 @@
:root {
font-family: Inter, ui-sans-serif, system-ui, sans-serif;
color: #f3f5fb;
background: #10131a;
font-synthesis: none;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
min-width: 320px;
min-height: 100vh;
background: radial-gradient(circle at 85% 0%, #17325e 0, #10131a 42rem);
}
button,
input {
font: inherit;
}
button {
border: 0;
border-radius: 8px;
padding: 0.7rem 1rem;
color: white;
background: #2575e6;
cursor: pointer;
}
button:hover {
background: #4189ed;
}
.shell {
width: min(1180px, calc(100% - 3rem));
margin: 0 auto;
padding: 2rem 0;
}
.topbar,
.input-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
}
.topbar {
margin-bottom: 2rem;
}
.eyebrow {
margin: 0 0 0.35rem;
color: #78aef5;
font-size: 0.72rem;
font-weight: 800;
letter-spacing: 0.14em;
}
h1,
h2,
h3,
p {
margin-top: 0;
}
h1 {
margin-bottom: 0;
font-size: clamp(1.6rem, 3vw, 2.4rem);
}
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;
}
label {
display: block;
margin-bottom: 0.5rem;
color: #c9d2e3;
font-size: 0.85rem;
}
input {
min-width: 0;
flex: 1;
border: 1px solid #3a4354;
border-radius: 8px;
padding: 0.7rem 0.8rem;
color: #f3f5fb;
background: #10131a;
}
.input-row {
justify-content: stretch;
}
small {
display: block;
margin-top: 0.55rem;
}
.dashboard-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
margin-top: 1rem;
}
.card {
min-height: 180px;
padding: 1.4rem;
}
.card p {
color: #9aa5b8;
line-height: 1.5;
}
.icon {
display: inline-block;
margin-bottom: 1rem;
color: #5d9bf0;
font-size: 1.8rem;
}
@media (max-width: 760px) {
.shell {
width: min(100% - 1.5rem, 600px);
padding-top: 1rem;
}
.hero,
.dashboard-grid {
grid-template-columns: 1fr;
}
.hero {
padding: 1.25rem;
}
.topbar {
align-items: flex-start;
}
}
+5
View File
@@ -0,0 +1,5 @@
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
export default {
preprocess: vitePreprocess(),
};
+16
View File
@@ -0,0 +1,16 @@
{
"extends": "@tsconfig/svelte/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"moduleResolution": "bundler"
},
"include": ["src/**/*.ts", "src/**/*.svelte", "vite.config.ts"],
"exclude": ["dist", "node_modules"]
}
+6
View File
@@ -0,0 +1,6 @@
import { svelte } from '@sveltejs/vite-plugin-svelte';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [svelte()],
});