diff --git a/src/App.svelte b/src/App.svelte index 99b50b8..161c13b 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -29,6 +29,10 @@ let categorySearch = ''; let categoryOptions: Array<{ id: string; name: string; box_art_url: string }> = []; let categorySearchTimer: number | undefined; + let chatIdentity: 'streamer' | 'bot' = 'streamer'; + let chatMessage = ''; + let chatBusy = false; + let chatError = ''; let oauthLink = ''; let oauthIdentity: 'streamer' | 'bot' = 'streamer'; let oauthBusy = false; @@ -231,6 +235,25 @@ } } + async function sendChatMessage() { + if (!chatMessage.trim() || chatMessage.length > 500) return; + chatBusy = true; + chatError = ''; + try { + const response = await fetch(`${serverAddress}/api/v1/twitch/chat/message`, { + method: 'POST', + headers: { 'content-type': 'application/json', authorization: `Bearer ${sessionToken}` }, + body: JSON.stringify({ identity: chatIdentity, message: chatMessage }), + }); + if (!response.ok) throw new Error('The selected Twitch identity could not send the message.'); + chatMessage = ''; + } catch (error) { + chatError = error instanceof Error ? error.message : 'Chat message failed.'; + } finally { + chatBusy = false; + } + } + async function createOAuthLink(identity: 'streamer' | 'bot') { oauthBusy = true; oauthError = ''; @@ -339,7 +362,7 @@
STREAM PREVIEW⋮
{#if playerSrc}{:else}
STREAM OFFLINE
CONNECT TWITCH TO BEGIN
{/if}
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.
+
MY CHAT⋮
⌁
Chat is waitingConnect a streamer or bot account to begin.
event.key === 'Enter' && sendChatMessage()} />
{#if chatError}
{chatError}
{/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 bf752af..34eae5e 100644 --- a/src/styles.css +++ b/src/styles.css @@ -452,11 +452,29 @@ label { color: var(--ed-dim); } .chat-composer { - display: flex; - gap: 5px; + display: grid; + gap: 6px; padding: 8px; border-top: 1px solid var(--ui-divider); } +.chat-identity-toggle, +.chat-send-row { + display: flex; + gap: 5px; +} +.chat-identity { + flex: 1; + color: var(--ed-dim); + font-size: 9px; +} +.chat-identity.active { + border-color: var(--ui-line-focus); + background: var(--ui-surface-hi); + color: var(--ed-accent); +} +.chat-send-row .control { + min-width: 0; +} .chat-composer .control { min-width: 0; }