From 450503afc3bbb76be2811f9da18952bc2a5d0d64 Mon Sep 17 00:00:00 2001 From: ReaperOfVeriod Date: Sun, 25 Oct 2026 05:09:25 +0100 Subject: [PATCH] add bot command catalog view --- src/App.svelte | 16 ++++++++++++++++ src/styles.css | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/App.svelte b/src/App.svelte index 5186382..f5debb7 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -61,6 +61,8 @@ let oauthIdentity: 'streamer' | 'bot' = 'streamer'; let oauthBusy = false; let oauthError = ''; + let botCommands: Array<{ id: string; name: string; description: string; permission_level: string; aliases: string[]; tags: string[]; cooldown_seconds: number; cooldown_scope: string; response_template: string; error_template: string | null; enabled: boolean }> = []; + let botCommandError = ''; let oauthScopes: Record<'streamer' | 'bot', { connected: boolean; missing_scopes: string[]; reauthorization_required: boolean }> = { streamer: { connected: false, missing_scopes: [], reauthorization_required: false }, bot: { connected: false, missing_scopes: [], reauthorization_required: false }, @@ -113,6 +115,7 @@ await loadDiagnostics(); await loadOAuthStatus(); await loadCollaboration(); + await loadBotCommands(); await loadStreamInfo(); connectRealtime(); if (!mustReplaceCredentials) password = ''; @@ -515,6 +518,17 @@ } } + async function loadBotCommands() { + try { + const response = await fetch(`${serverAddress}/api/v1/bot/commands`); + if (!response.ok) throw new Error('Commands could not be loaded.'); + botCommands = await response.json(); + botCommandError = ''; + } catch (error) { + botCommandError = error instanceof Error ? error.message : 'Commands could not be loaded.'; + } + } + async function revokeOAuth(identity: 'streamer' | 'bot') { oauthBusy = true; oauthError = ''; @@ -627,6 +641,8 @@ {#if authError}
{authError}
{/if} + {:else if activeView === 'Bot'} +
BOT COMMANDS
PUBLIC COMMAND CATALOG
{#if botCommandError}
{botCommandError}
{:else if botCommands.length}
{#each botCommands as command}
!{command.name}{command.description}{#if command.tags.length}
{command.tags.join(' · ')}
{/if}
{command.permission_level.toUpperCase()}{#if command.cooldown_seconds}{command.cooldown_seconds}s / {command.cooldown_scope}{/if}
{/each}
{:else}
No enabled commandsCreate commands on the server to make them available here.
{/if}
{:else}
STREAM PREVIEW⋮
{#if playerSrc}{:else}
STREAM OFFLINE
CONNECT TWITCH TO BEGIN
{/if}
diff --git a/src/styles.css b/src/styles.css index beb627f..16a296d 100644 --- a/src/styles.css +++ b/src/styles.css @@ -510,6 +510,41 @@ label { margin-top: auto; border-bottom: 0; } +.bot-page { + min-height: 100%; +} +.bot-page-body { + padding: 18px; +} +.bot-command-list { + margin-top: 12px; + border-top: 1px solid var(--ui-divider); +} +.bot-command-row { + display: flex; + justify-content: space-between; + gap: 20px; + padding: 13px 4px; + border-bottom: 1px solid var(--ui-divider); +} +.bot-command-row strong { + display: block; + color: var(--ed-cyan); + font-family: var(--font-data); +} +.bot-command-description { + display: block; + margin-top: 4px; + color: var(--ed-dim); +} +.bot-command-meta { + display: flex; + gap: 10px; + align-items: flex-start; + color: var(--ed-dim); + font: 10px var(--font-data); + white-space: nowrap; +} .version-label { display: block; margin-top: 13px;