diff --git a/src/App.svelte b/src/App.svelte index 858769d..d896484 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -24,6 +24,9 @@ let streamLanguage = 'en'; let streamTags = ''; let streamClassificationLabels = ''; + let categorySearch = ''; + let categoryOptions: Array<{ id: string; name: string; box_art_url: string }> = []; + let categorySearchTimer: number | undefined; let oauthLink = ''; let oauthIdentity: 'streamer' | 'bot' = 'streamer'; let oauthBusy = false; @@ -171,9 +174,10 @@ headers: { authorization: `Bearer ${sessionToken}` }, }); if (!response.ok) return; - const info: { title: string; game_id: string; language: string; tags: string[]; content_classification_labels: string[] } = await response.json(); + const info: { title: string; game_id: string; game_name: string; language: string; tags: string[]; content_classification_labels: string[] } = await response.json(); streamTitle = info.title; streamGameId = info.game_id; + categorySearch = info.game_name; streamLanguage = info.language; streamTags = info.tags.join(', '); streamClassificationLabels = info.content_classification_labels.join(', '); @@ -182,6 +186,23 @@ } } + function searchCategories(value: string) { + categorySearch = value; + categoryOptions = []; + if (categorySearchTimer) window.clearTimeout(categorySearchTimer); + if (!value.trim()) return; + categorySearchTimer = window.setTimeout(async () => { + try { + const response = await fetch(`${serverAddress}/api/v1/twitch/games?query=${encodeURIComponent(value.trim())}`, { + headers: { authorization: `Bearer ${sessionToken}` }, + }); + if (response.ok) categoryOptions = await response.json(); + } catch { + categoryOptions = []; + } + }, 200); + } + async function saveStreamInfo() { streamBusy = true; streamError = ''; @@ -315,7 +336,7 @@
STREAM PREVIEW⋮
STREAM OFFLINE
CONNECT TWITCH TO BEGIN
ACTIVITY FEED⋮
{#if activityEvents.length}
{#each activityEvents as event}
{event.event_type}{new Date(event.occurred_at).toLocaleTimeString()}
{/each}
{:else}
◌
Nothing here yetFollows, subscriptions, raids, and server events will appear here.
{/if}
MY CHAT⋮
⌁
Chat is waitingConnect a streamer or bot account to begin.
-
QUICK ACTIONS⋮
{#if showStreamEditor}
{#if streamError}
{streamError}
{/if}
{/if}
+
QUICK ACTIONS⋮
{#if showStreamEditor}
searchCategories(event.currentTarget.value)} autocomplete="off" placeholder="Search Twitch categories" />{#if categoryOptions.length}
{#each categoryOptions as category}{/each}
{/if}{#if streamError}
{streamError}
{/if}
{/if}
{/if} diff --git a/src/styles.css b/src/styles.css index 0984dc4..a353704 100644 --- a/src/styles.css +++ b/src/styles.css @@ -477,6 +477,22 @@ label { .stream-editor label { margin-top: 4px; } +.category-options { + display: grid; + max-height: 180px; + overflow: auto; + border: 1px solid var(--ui-line); + background: var(--ed-bg); +} +.category-option { + display: flex; + justify-content: space-between; + gap: 8px; + border: 0; + border-bottom: 1px solid var(--ui-divider); + border-radius: 0; + text-align: left; +} .quick-action:hover, .quick-action.accent { border-color: var(--ui-line-focus);