From 11311316fd6aecc3ae48554858ef4711925e8527 Mon Sep 17 00:00:00 2001 From: Infi Date: Wed, 24 Sep 2025 22:57:22 +0200 Subject: [PATCH] - Add textarea for input - Remove channel switch button - Integrate channel switch selection into channel name - Fix state() warnings --- .../src/components/ChannelSelector.svelte | 79 +++++++++++++++++++ .../src/components/DynamicTextArea.svelte | 57 +++++++++++++ .../src/lib/{chat.ts => chat.svelte.ts} | 61 ++++---------- .../Http/Frontend/src/lib/shared.svelte.ts | 8 ++ ChatTwo/Http/Frontend/src/routes/+page.svelte | 2 +- .../Frontend/src/routes/chat/+page.svelte | 14 ++-- ChatTwo/Http/Frontend/static/static/start.css | 54 ++++++------- ChatTwo/Http/MessageProtocol/DataStructure.cs | 4 +- ChatTwo/Http/Processing.cs | 2 +- ChatTwo/Http/ServerCore.cs | 3 +- 10 files changed, 194 insertions(+), 90 deletions(-) create mode 100644 ChatTwo/Http/Frontend/src/components/ChannelSelector.svelte create mode 100644 ChatTwo/Http/Frontend/src/components/DynamicTextArea.svelte rename ChatTwo/Http/Frontend/src/lib/{chat.ts => chat.svelte.ts} (86%) create mode 100644 ChatTwo/Http/Frontend/src/lib/shared.svelte.ts diff --git a/ChatTwo/Http/Frontend/src/components/ChannelSelector.svelte b/ChatTwo/Http/Frontend/src/components/ChannelSelector.svelte new file mode 100644 index 0000000..1dbee98 --- /dev/null +++ b/ChatTwo/Http/Frontend/src/components/ChannelSelector.svelte @@ -0,0 +1,79 @@ + + + + + \ No newline at end of file diff --git a/ChatTwo/Http/Frontend/src/components/DynamicTextArea.svelte b/ChatTwo/Http/Frontend/src/components/DynamicTextArea.svelte new file mode 100644 index 0000000..b29d977 --- /dev/null +++ b/ChatTwo/Http/Frontend/src/components/DynamicTextArea.svelte @@ -0,0 +1,57 @@ + + + + + \ No newline at end of file diff --git a/ChatTwo/Http/Frontend/src/lib/chat.ts b/ChatTwo/Http/Frontend/src/lib/chat.svelte.ts similarity index 86% rename from ChatTwo/Http/Frontend/src/lib/chat.ts rename to ChatTwo/Http/Frontend/src/lib/chat.svelte.ts index 2277c35..896d5d8 100644 --- a/ChatTwo/Http/Frontend/src/lib/chat.ts +++ b/ChatTwo/Http/Frontend/src/lib/chat.svelte.ts @@ -1,9 +1,7 @@ import {type Source, source} from "sveltekit-sse"; +import {channelOptions, isChannelLocked} from "$lib/shared.svelte"; interface ChatElements { - channelHint: HTMLElement | null, - channelSelect: HTMLElement | null, - messagesContainer: Element | null, messagesList: HTMLElement | null, @@ -35,6 +33,7 @@ interface Template { // ref `DataStructure.SwitchChannel` interface SwitchChannel { channelName: Template[]; + channelValue: number; channelLocked: boolean; } @@ -58,7 +57,6 @@ export class ChatTwoWeb { elements!: ChatElements; maxTimestampWidth: number = 0; scrolledToBottom: boolean = true; - channelLocked: boolean = false; sse!: EventSource; connection!: Source; @@ -70,8 +68,8 @@ export class ChatTwoWeb { setupDOMElements() { this.elements = { - channelHint: document.getElementById('channel-hint'), - channelSelect: document.getElementById('channel-select'), + // channelHint: document.getElementById('channel-hint'), + // channelSelect: document.getElementById('channel-select'), messagesContainer: document.querySelector('#messages > .scroll-container')!, messagesList: document.getElementById('messages-list'), @@ -82,23 +80,6 @@ export class ChatTwoWeb { chatInput: document.getElementById('chat-input') }; - // channel selector - this.elements.channelSelect?.addEventListener('change', async (event) => { - if (event.currentTarget === null) - return; - - const rawResponse = await fetch('/channel', { - method: 'POST', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ channel: (event.currentTarget as HTMLSelectElement).value }) - }); - // const content = await rawResponse.json(); - // TODO: use the response - }); - // add indicator signaling more messages below this.elements.messagesContainer?.addEventListener('scroll', (event) => { if (event.currentTarget === null) @@ -167,39 +148,25 @@ export class ChatTwoWeb { } updateChannelHint(channel: SwitchChannel) { - if (this.elements.channelHint === null || this.elements.channelSelect === null) - return; - - this.elements.channelHint.innerHTML = ''; + // Set storage to the current lock state + isChannelLocked.locked = channel.channelLocked; const channelElement = this.processTemplate(channel.channelName); + if (!channelElement.firstChild) + return; - // Makes the channel selector unclickable if the channel is fixed - this.channelLocked = channel.channelLocked; - if (this.channelLocked) { - if (channelElement.firstChild === null) - return; + let channelName = (channelElement.firstChild as HTMLSpanElement).innerText; + if (channel.channelLocked) + channelName = `(Locked) ${channelName}`; - // @ts-ignore - channelElement.firstChild.innerText = `(Locked) ${channelElement.firstChild.innerText}`; - this.elements.channelSelect.style.pointerEvents = 'none'; - } else { - this.elements.channelSelect.style.removeProperty('pointer-events'); - } - - this.elements.channelHint.appendChild(channelElement); + channelOptions[0] = {text: channelName, value: 0, preview: true } } updateChannels(channelList: ChannelList) { - if (this.elements.channelSelect === null) - return; + channelOptions.length = 1; - this.elements.channelSelect.innerHTML = ''; for (const [ label, channel ] of Object.entries(channelList.channels)) { - const option = document.createElement('option'); - option.value = channel.toString(); - option.innerText = label; - this.elements.channelSelect.appendChild(option); + channelOptions.push( { text: label, value: channel, preview: false } ) } } diff --git a/ChatTwo/Http/Frontend/src/lib/shared.svelte.ts b/ChatTwo/Http/Frontend/src/lib/shared.svelte.ts new file mode 100644 index 0000000..4fbb944 --- /dev/null +++ b/ChatTwo/Http/Frontend/src/lib/shared.svelte.ts @@ -0,0 +1,8 @@ +export const isChannelLocked: { locked: boolean } = $state({ locked: false }); +export const channelOptions: ChannelOption[] = $state([ { text: 'Invalid', value: 0, preview: true } ]); + +export interface ChannelOption { + text: string; + value: number; + preview: boolean; +} \ No newline at end of file diff --git a/ChatTwo/Http/Frontend/src/routes/+page.svelte b/ChatTwo/Http/Frontend/src/routes/+page.svelte index c3f2a6a..3889db3 100644 --- a/ChatTwo/Http/Frontend/src/routes/+page.svelte +++ b/ChatTwo/Http/Frontend/src/routes/+page.svelte @@ -2,7 +2,7 @@ import { page } from '$app/state' import { Alert } from '@sveltestrap/sveltestrap'; - let data: App.Warning | null = null; + let data: App.Warning = $state({ hasWarning: false, content: '' }); $effect.pre(() => { if (page.url.searchParams.has('message')) { data = { diff --git a/ChatTwo/Http/Frontend/src/routes/chat/+page.svelte b/ChatTwo/Http/Frontend/src/routes/chat/+page.svelte index c23b9b3..0407be5 100644 --- a/ChatTwo/Http/Frontend/src/routes/chat/+page.svelte +++ b/ChatTwo/Http/Frontend/src/routes/chat/+page.svelte @@ -2,10 +2,12 @@ import { page } from '$app/state' import {Alert} from "@sveltestrap/sveltestrap"; import { onMount } from 'svelte'; - import { ChatTwoWeb } from '$lib/chat' + import {ChatTwoWeb} from '$lib/chat.svelte' import {addGfdStylesheet} from "$lib/gfd"; + import DynamicTextArea from "../../components/DynamicTextArea.svelte"; + import ChannelSelector from "../../components/ChannelSelector.svelte"; - let data: App.Warning | null = null; + let data: App.Warning = $state({ hasWarning: false, content: '' }); $effect.pre(() => { if (page.url.searchParams.has('message')) { data = { @@ -51,13 +53,9 @@
-
- -
-
- -
+ +
diff --git a/ChatTwo/Http/Frontend/static/static/start.css b/ChatTwo/Http/Frontend/static/static/start.css index bb16843..54a74ea 100644 --- a/ChatTwo/Http/Frontend/static/static/start.css +++ b/ChatTwo/Http/Frontend/static/static/start.css @@ -183,7 +183,7 @@ section#input { gap: 10px; } - input, button, select { + input, button { font-size: 1rem; border: 3px solid transparent; border-radius: 20px; @@ -194,7 +194,7 @@ section#input { } } - button, select { + button { padding: 5px 15px; border: 3px solid var(--bg-input); background-image: var(--gradient-clickable); @@ -207,29 +207,12 @@ section#input { } } - .select-container, button { + button { position: relative; flex-grow: 0; flex-shrink: 0; } - .select-container { - flex-basis: 0; - - &::before { - /* "message-circle" icon from https://github.com/feathericons/feather, under MIT license */ - mask-image: url('data:image/svg+xml,'); - } - - select { - width: 100%; - padding-left: 1.5rem; - padding-right: 1.5rem; - appearance: none; - color: transparent; - } - } - button { padding-left: calc(20px + 1.5rem); @@ -239,7 +222,7 @@ section#input { } } - .select-container::before, button::before { + button::before { content: ''; position: absolute; left: 15px; @@ -252,11 +235,6 @@ section#input { pointer-events: none; } - .select-container::before { - left: 50%; - transform: translateX(-50%) translateY(-50%); - } - .input-container { flex: 1; position: relative; @@ -266,9 +244,9 @@ section#input { padding: 5px 20px; } - #channel-hint { + #channel-select { position: absolute; - top: -1.2em; + top: -1.5em; left: 23px; max-width: 100%; overflow: hidden; @@ -276,7 +254,23 @@ section#input { font-weight: 550; white-space: nowrap; text-overflow: ellipsis; - pointer-events: none; + + border: 0; + border-radius: 0; + background-color: transparent; + + padding: 5px 15px; + cursor: pointer; + + &:hover { + border-color: var(--bg-input-hover); + background-color: var(--bg-input-hover); + background-image: var(--gradient-clickable-hover); + } + + &:focus { + outline: 2px solid var(--focus-color); + } } } @@ -360,7 +354,7 @@ section#input { transform: translateX(-50%) translateY(-50%); } - .input-container #channel-hint { + .input-container #channel-select { font-size: 0.9rem; } } diff --git a/ChatTwo/Http/MessageProtocol/DataStructure.cs b/ChatTwo/Http/MessageProtocol/DataStructure.cs index ecd7bfc..d410682 100644 --- a/ChatTwo/Http/MessageProtocol/DataStructure.cs +++ b/ChatTwo/Http/MessageProtocol/DataStructure.cs @@ -24,9 +24,9 @@ public struct ChatTabList(ChatTab[] tabs) /// /// Contains the current channel name /// -public struct SwitchChannel((MessageTemplate[] ChannelName, bool Locked) channel) +public struct SwitchChannel((MessageTemplate[] Name, bool Locked) channel) { - [JsonProperty("channelName")] public MessageTemplate[] ChannelName = channel.ChannelName; + [JsonProperty("channelName")] public MessageTemplate[] ChannelName = channel.Name; [JsonProperty("channelLocked")] public bool Locked = channel.Locked; } diff --git a/ChatTwo/Http/Processing.cs b/ChatTwo/Http/Processing.cs index 450dded..169bd7a 100644 --- a/ChatTwo/Http/Processing.cs +++ b/ChatTwo/Http/Processing.cs @@ -15,7 +15,7 @@ public class Processing Plugin = plugin; } - internal (MessageTemplate[] ChannelName, bool Locked) ReadChannelName(Chunk[] channelName) + internal (MessageTemplate[] Name, bool Locked) ReadChannelName(Chunk[] channelName) { var locked = Plugin.CurrentTab is not { Channel: null }; return (channelName.Select(ProcessChunk).ToArray(), locked); diff --git a/ChatTwo/Http/ServerCore.cs b/ChatTwo/Http/ServerCore.cs index fab0396..fa4acd3 100644 --- a/ChatTwo/Http/ServerCore.cs +++ b/ChatTwo/Http/ServerCore.cs @@ -1,4 +1,5 @@ -using ChatTwo.Http.MessageProtocol; +using ChatTwo.Code; +using ChatTwo.Http.MessageProtocol; namespace ChatTwo.Http;