fix: improve HypaV3 modal responsive for mobile

This commit is contained in:
Bo26fhmC5M
2025-01-21 00:26:51 +09:00
parent e3d95107a3
commit 463dcc66b1

View File

@@ -32,12 +32,12 @@
interface SummaryUI { interface SummaryUI {
isTranslating: boolean; isTranslating: boolean;
translation: string | null; translation: string | null;
translationRef: HTMLDivElement; translationRef: HTMLTextAreaElement;
isRerolling: boolean; isRerolling: boolean;
rerolledText: string | null; rerolledText: string | null;
isRerolledTranslating: boolean; isRerolledTranslating: boolean;
rerolledTranslation: string | null; rerolledTranslation: string | null;
rerolledTranslationRef: HTMLDivElement; rerolledTranslationRef: HTMLTextAreaElement;
} }
interface ExpandedMessageUI { interface ExpandedMessageUI {
@@ -45,7 +45,7 @@
selectedChatMemo: string; selectedChatMemo: string;
isTranslating: boolean; isTranslating: boolean;
translation: string | null; translation: string | null;
translationRef: HTMLDivElement; translationRef: HTMLTextAreaElement;
} }
const hypaV3DataState = $derived( const hypaV3DataState = $derived(
@@ -531,21 +531,23 @@
</script> </script>
<!-- Modal backdrop --> <!-- Modal backdrop -->
<div class="fixed inset-0 z-50 bg-black/50 p-4"> <div class="fixed inset-0 z-50 p-1 sm:p-2 bg-black/50">
<!-- Modal wrapper --> <!-- Modal wrapper -->
<div class="flex justify-center w-full h-full">
<!-- Modal window -->
<div <div
class="w-full flex justify-center {hypaV3DataState.summaries.length === 0 class="flex flex-col p-3 sm:p-6 rounded-lg bg-zinc-900 w-full max-w-3xl {hypaV3DataState
.summaries.length === 0
? 'h-fit' ? 'h-fit'
: 'h-full'}" : 'h-full'}"
>
<!-- Modal window -->
<div
class="bg-zinc-900 p-6 rounded-lg flex flex-col w-full max-w-3xl max-h-full"
> >
<!-- Header --> <!-- Header -->
<div class="flex justify-between items-center w-full mb-4"> <div class="flex justify-between items-center mb-2 sm:mb-4">
<h1 class="text-2xl font-semibold text-zinc-100">HypaV3 Data</h1> <!-- Modal Title -->
<!-- Button Container --> <h1 class="text-lg sm:text-2xl font-semibold text-zinc-300">
HypaV3 Data
</h1>
<!-- Buttons Container -->
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<!-- Settings Button --> <!-- Settings Button -->
<button <button
@@ -560,12 +562,12 @@
SettingsMenuIndex.set(2); // Other bot settings SettingsMenuIndex.set(2); // Other bot settings
}} }}
> >
<SettingsIcon size={24} /> <SettingsIcon class="w-6 h-6" />
</button> </button>
<!-- Reset Button --> <!-- Reset Button -->
<button <button
class="p-2 text-zinc-400 hover:text-zinc-200 hover:text-rose-300 transition-colors" class="p-2 text-zinc-400 hover:text-rose-300 transition-colors"
onclick={async () => { onclick={async () => {
if ( if (
await alertConfirmTwice( await alertConfirmTwice(
@@ -584,12 +586,12 @@
} }
}} }}
> >
<Trash2Icon size={24} /> <Trash2Icon class="w-6 h-6" />
</button> </button>
<!-- Close Button --> <!-- Close Button -->
<button <button
class="p-2 text-zinc-400 hover:text-zinc-200 hover:text-rose-300 transition-colors" class="p-2 text-zinc-400 hover:text-zinc-200 transition-colors"
onclick={() => { onclick={() => {
alertStore.set({ alertStore.set({
type: "none", type: "none",
@@ -597,25 +599,25 @@
}); });
}} }}
> >
<XIcon size={24} /> <XIcon class="w-6 h-6" />
</button> </button>
</div> </div>
</div> </div>
<!-- Scrollable Container --> <!-- Scrollable Container -->
<div class="flex flex-col gap-3 w-full overflow-y-auto"> <div class="flex flex-col gap-2 sm:gap-4 overflow-y-auto">
{#if hypaV3DataState.summaries.length === 0} {#if hypaV3DataState.summaries.length === 0}
<!-- Conversion Section --> <!-- Conversion Section -->
{#if isHypaV2ConversionPossible()} {#if isHypaV2ConversionPossible()}
<div <div
class="flex flex-col p-4 rounded-lg border border-zinc-700 bg-zinc-800/50" class="flex flex-col p-2 sm:p-4 rounded-lg border border-zinc-700 bg-zinc-800/50"
>
<div class="mt-4 flex flex-col items-center gap-2">
<span class="text-textcolor2 text-center p-4"
>No summaries yet, but you may convert HypaV2 data to V3.</span
> >
<div class="flex flex-col items-center">
<div class="my-1 sm:my-2 text-center text-zinc-300">
No summaries yet, but you may convert HypaV2 data to V3.
</div>
<button <button
class="px-4 py-2 bg-zinc-800 text-zinc-200 rounded-md hover:bg-zinc-700 transition-colors" class="my-1 sm:my-2 px-4 py-2 rounded-md text-zinc-300 font-semibold bg-zinc-700 hover:bg-zinc-600 transition-colors"
onclick={async () => { onclick={async () => {
const conversionResult = convertHypaV2ToV3(); const conversionResult = convertHypaV2ToV3();
@@ -637,8 +639,9 @@
</div> </div>
</div> </div>
{:else} {:else}
<span class="text-textcolor2 text-center p-4">No summaries yet</span <div class="p-4 sm:p-3 md:p-4 text-center text-zinc-400">
> No summaries yet
</div>
{/if} {/if}
{/if} {/if}
@@ -647,12 +650,13 @@
{#if summaryUIStates[i]} {#if summaryUIStates[i]}
<!-- Summary Item --> <!-- Summary Item -->
<div <div
class="flex flex-col p-4 rounded-lg border border-zinc-700 bg-zinc-800/50" class="flex flex-col p-2 sm:p-4 rounded-lg border border-zinc-700 bg-zinc-800/50"
> >
<!-- Summary Header --> <!-- Original Summary Header -->
<div class="flex justify-between items-center mb-2"> <div class="flex justify-between items-center">
<span class="text-sm text-textcolor2">Summary #{i + 1}</span> <span class="text-sm text-zinc-400">Summary #{i + 1}</span>
<div class="flex items-center gap-4">
<div class="flex items-center gap-2">
<!-- Translate Button --> <!-- Translate Button -->
<button <button
class="p-2 text-zinc-400 hover:text-zinc-200 transition-colors" class="p-2 text-zinc-400 hover:text-zinc-200 transition-colors"
@@ -661,19 +665,19 @@
onAlternativeAction: () => toggleTranslate(i, true), onAlternativeAction: () => toggleTranslate(i, true),
}} }}
> >
<LanguagesIcon size={16} /> <LanguagesIcon class="w-4 h-4" />
</button> </button>
<!-- Important Button --> <!-- Important Button -->
<button <button
class="p-2 hover:text-zinc-200 hover:text-amber-300 transition-colors {summary.isImportant class="p-2 hover:text-zinc-200 transition-colors {summary.isImportant
? 'text-yellow-500' ? 'text-yellow-500'
: 'text-zinc-400'}" : 'text-zinc-400'}"
onclick={() => { onclick={() => {
summary.isImportant = !summary.isImportant; summary.isImportant = !summary.isImportant;
}} }}
> >
<StarIcon size={16} /> <StarIcon class="w-4 h-4" />
</button> </button>
<!-- Reroll Button --> <!-- Reroll Button -->
@@ -682,12 +686,12 @@
onclick={async () => await toggleReroll(i)} onclick={async () => await toggleReroll(i)}
disabled={!isRerollable(i)} disabled={!isRerollable(i)}
> >
<RefreshCw size={16} /> <RefreshCw class="w-4 h-4" />
</button> </button>
<!-- Delete After Button --> <!-- Delete After Button -->
<button <button
class="p-2 text-zinc-400 hover:text-zinc-200 hover:text-rose-300 transition-colors" class="p-2 text-zinc-400 hover:text-rose-300 transition-colors"
onclick={async () => { onclick={async () => {
if ( if (
await alertConfirmTwice( await alertConfirmTwice(
@@ -701,39 +705,42 @@
showHypaV3Alert(); showHypaV3Alert();
}} }}
> >
<ScissorsLineDashed size={16} /> <ScissorsLineDashed class="w-4 h-4" />
</button> </button>
</div> </div>
</div> </div>
<!-- Original Summary --> <!-- Original Summary -->
<TextAreaInput <div class="mt-2 sm:mt-4">
<textarea
class="p-2 sm:p-4 w-full min-h-40 sm:min-h-56 resize-vertical rounded border border-zinc-700 focus:outline-none focus:ring-2 focus:ring-zinc-600 transition-colors text-zinc-200 bg-zinc-900"
bind:value={summary.text} bind:value={summary.text}
className="w-full bg-zinc-900 text-zinc-200 rounded-md p-3 min-h-[100px] resize-y"
/>
<!-- Translation (if exists) -->
{#if summaryUIStates[i].translation}
<div class="mt-4">
<span class="text-sm text-textcolor2 mb-2 block"
>Translation</span
> >
<div </textarea>
class="p-2 max-h-48 overflow-y-auto bg-zinc-800 rounded-md whitespace-pre-wrap" </div>
<!-- Original Summary Translation -->
{#if summaryUIStates[i].translation}
<div class="mt-2 sm:mt-4">
<div class="mb-2 sm:mb-4 text-sm text-zinc-400">
Translation
</div>
<textarea
readonly
class="p-2 sm:p-4 w-full min-h-40 sm:min-h-56 resize-vertical rounded border border-zinc-700 focus:outline-none transition-colors text-zinc-200 bg-zinc-900"
bind:this={summaryUIStates[i].translationRef} bind:this={summaryUIStates[i].translationRef}
tabindex="-1" tabindex="-1"
> value={summaryUIStates[i].translation}
{summaryUIStates[i].translation} ></textarea>
</div>
</div> </div>
{/if} {/if}
<!-- Rerolled Summary (if exists) -->
{#if summaryUIStates[i].rerolledText} {#if summaryUIStates[i].rerolledText}
<div class="mt-4"> <!-- Rerolled Summary Header -->
<div class="flex justify-between items-center mb-2"> <div class="mt-2 sm:mt-4">
<span class="text-sm text-textcolor2">Rerolled Summary</span <div class="flex justify-between items-center">
> <span class="text-sm text-zinc-400">Rerolled Summary</span>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<!-- Translate Rerolled Button --> <!-- Translate Rerolled Button -->
<button <button
@@ -744,23 +751,23 @@
toggleTranslateRerolled(i, true), toggleTranslateRerolled(i, true),
}} }}
> >
<LanguagesIcon size={16} /> <LanguagesIcon class="w-4 h-4" />
</button> </button>
<!-- Cancel Button --> <!-- Cancel Button -->
<button <button
class="p-2 text-zinc-400 hover:text-zinc-200 hover:text-rose-300 transition-colors" class="p-2 text-zinc-400 hover:text-zinc-200 transition-colors"
onclick={() => { onclick={() => {
summaryUIStates[i].rerolledText = null; summaryUIStates[i].rerolledText = null;
summaryUIStates[i].rerolledTranslation = null; summaryUIStates[i].rerolledTranslation = null;
}} }}
> >
<XIcon size={16} /> <XIcon class="w-4 h-4" />
</button> </button>
<!-- Apply Button --> <!-- Apply Button -->
<button <button
class="p-2 text-zinc-400 hover:text-zinc-200 transition-colors" class="p-2 text-zinc-400 hover:text-rose-300 transition-colors"
onclick={() => { onclick={() => {
summary.text = summaryUIStates[i].rerolledText!; summary.text = summaryUIStates[i].rerolledText!;
summaryUIStates[i].translation = null; summaryUIStates[i].translation = null;
@@ -768,61 +775,72 @@
summaryUIStates[i].rerolledTranslation = null; summaryUIStates[i].rerolledTranslation = null;
}} }}
> >
<CheckIcon size={16} /> <CheckIcon class="w-4 h-4" />
</button> </button>
</div> </div>
</div> </div>
<TextAreaInput </div>
bind:value={summaryUIStates[i].rerolledText}
className="w-full bg-zinc-900 text-zinc-200 rounded-md p-3 min-h-[100px] resize-y"
/>
<!-- Rerolled Translation (if exists) --> <!-- Rerolled Summary -->
{#if summaryUIStates[i].rerolledTranslation} <div class="mt-2 sm:mt-4">
<div class="mt-4"> <textarea
<span class="text-sm text-textcolor2 mb-2 block" class="p-2 sm:p-4 w-full min-h-40 sm:min-h-56 resize-vertical rounded border border-zinc-700 focus:outline-none focus:ring-2 focus:ring-zinc-600 transition-colors text-zinc-200 bg-zinc-900"
>Rerolled Translation</span bind:value={summaryUIStates[i].rerolledText}
> >
<div </textarea>
class="p-2 max-h-48 overflow-y-auto bg-zinc-800 rounded-md whitespace-pre-wrap" </div>
<!-- Rerolled Summary Translation -->
{#if summaryUIStates[i].rerolledTranslation}
<div class="mt-2 sm:mt-4">
<div class="mb-2 sm:mb-4 text-sm text-zinc-400">
Rerolled Translation
</div>
<textarea
readonly
class="p-2 sm:p-4 w-full min-h-40 sm:min-h-56 resize-vertical rounded border border-zinc-700 focus:outline-none transition-colors text-zinc-200 bg-zinc-900"
bind:this={summaryUIStates[i].rerolledTranslationRef} bind:this={summaryUIStates[i].rerolledTranslationRef}
tabindex="-1" tabindex="-1"
> value={summaryUIStates[i].rerolledTranslation}
{summaryUIStates[i].rerolledTranslation} ></textarea>
</div>
</div> </div>
{/if} {/if}
</div>
{/if} {/if}
<!-- Connected Messages --> <!-- Connected Messages Header -->
<div class="mt-4"> <div class="mt-2 sm:mt-4">
<div class="flex justify-between items-center mb-2"> <div class="flex justify-between items-center">
<span class="text-sm text-textcolor2"> <span class="text-sm text-zinc-400"
Connected Messages ({summary.chatMemos.length}) >Connected Messages ({summary.chatMemos.length})</span
</span> >
<div class="flex items-center gap-2">
<!-- Translate Message Button --> <!-- Translate Message Button -->
<button <button
class="p-2 text-zinc-400 hover:text-zinc-200 transition-colors" class="p-2 text-zinc-400 hover:text-zinc-200 transition-colors"
use:handleDualAction={{ use:handleDualAction={{
onMainAction: () => toggleTranslateExpandedMessage(false), onMainAction: () =>
toggleTranslateExpandedMessage(false),
onAlternativeAction: () => onAlternativeAction: () =>
toggleTranslateExpandedMessage(true), toggleTranslateExpandedMessage(true),
}} }}
> >
<LanguagesIcon size={16} /> <LanguagesIcon class="w-4 h-4" />
</button> </button>
</div> </div>
</div>
</div>
<!-- Message IDs --> <!-- Connected Message IDs -->
<div class="flex flex-wrap gap-1"> <div class="flex flex-wrap mt-2 sm:mt-4 gap-2">
{#each summary.chatMemos as chatMemo} {#each summary.chatMemos as chatMemo}
<button <button
class="text-xs px-3 py-1.5 bg-zinc-900 text-zinc-300 rounded-full hover:bg-zinc-800 transition-colors {isMessageExpanded( class="px-3 py-2 rounded-full text-xs text-zinc-200 hover:bg-zinc-800 transition-colors bg-zinc-900 {isMessageExpanded(
i, i,
chatMemo chatMemo
) )
? 'ring-1 ring-blue-500' ? 'ring-2 ring-zinc-500'
: ''}" : ''}"
onclick={() => toggleExpandMessage(i, chatMemo)} onclick={() => toggleExpandMessage(i, chatMemo)}
> >
@@ -831,56 +849,57 @@
{/each} {/each}
</div> </div>
<!-- Selected Message (if selected) -->
{#if expandedMessageUIState?.summaryIndex === i} {#if expandedMessageUIState?.summaryIndex === i}
<div class="mt-4"> <!-- Expanded Message -->
<div class="mt-2 sm:mt-4">
<!-- Processed Message --> <!-- Processed Message -->
{#await getProcessedMessageFromChatMemo(expandedMessageUIState.selectedChatMemo) then expandedMessage} {#await getProcessedMessageFromChatMemo(expandedMessageUIState.selectedChatMemo) then expandedMessage}
{#if expandedMessage} {#if expandedMessage}
<!-- Role --> <!-- Role -->
<div class="text-sm text-textcolor2 mb-2 block"> <div class="mb-2 sm:mb-4 text-sm text-zinc-400">
{expandedMessage.role}'s Message {expandedMessage.role}'s Message
</div> </div>
<!-- Content --> <!-- Content -->
<div <textarea
class="p-2 max-h-48 overflow-y-auto bg-zinc-800 rounded-md whitespace-pre-wrap" readonly
> class="p-2 sm:p-4 w-full min-h-40 sm:min-h-56 resize-vertical rounded border border-zinc-700 focus:outline-none transition-colors text-zinc-200 bg-zinc-900"
{expandedMessage.data} value={expandedMessage.data}
</div> ></textarea>
{:else} {:else}
<div class="text-sm text-red-500"> <span class="text-sm text-red-500">Message not found</span
Message not found >
</div>
{/if} {/if}
{:catch error} {:catch error}
<div class="text-sm text-red-500 mb-2"> <span class="text-sm text-red-500"
Error loading expanded message: {error.message} >Error loading expanded message: {error.message}</span
</div>
{/await}
<!-- Message Translation -->
{#if expandedMessageUIState.translation}
<div class="mt-4">
<span class="text-sm text-textcolor2 mb-2 block"
>Translation</span
> >
<div {/await}
class="p-2 max-h-48 overflow-y-auto bg-zinc-800 rounded-md whitespace-pre-wrap" </div>
<!-- Expanded Message Translation -->
{#if expandedMessageUIState.translation}
<div class="mt-2 sm:mt-4">
<div class="mb-2 sm:mb-4 text-sm text-zinc-400">
Translation
</div>
<textarea
readonly
class="p-2 sm:p-4 w-full min-h-40 sm:min-h-56 resize-vertical rounded border border-zinc-700 focus:outline-none transition-colors text-zinc-200 bg-zinc-900"
bind:this={expandedMessageUIState.translationRef} bind:this={expandedMessageUIState.translationRef}
tabindex="-1" tabindex="-1"
> value={expandedMessageUIState.translation}
{expandedMessageUIState.translation} ></textarea>
</div>
</div> </div>
{/if} {/if}
</div>
{/if} {/if}
</div> </div>
</div>
{/if} {/if}
{/each} {/each}
<!-- Next Summarization Target --> <!-- Next Summarization Target -->
<div class="mt-2 sm:mt-4">
{#await getProcessedNextSummarizationTarget() then nextMessage} {#await getProcessedNextSummarizationTarget() then nextMessage}
{#if nextMessage} {#if nextMessage}
{@const chatId = {@const chatId =
@@ -889,29 +908,31 @@
: nextMessage.chatId == null : nextMessage.chatId == null
? "No Message ID" ? "No Message ID"
: nextMessage.chatId} : nextMessage.chatId}
<div class="mt-4"> <div class="mb-2 sm:mb-4 text-sm text-zinc-400">
<span class="text-sm text-textcolor2 mb-2 block">
HypaV3 will summarize [{chatId}] HypaV3 will summarize [{chatId}]
</span>
<div
class="p-2 max-h-48 overflow-y-auto bg-zinc-800 rounded-md whitespace-pre-wrap"
>
{nextMessage.data}
</div>
</div> </div>
<textarea
readonly
class="p-2 sm:p-4 w-full min-h-40 sm:min-h-56 resize-none overflow-y-auto rounded border border-zinc-700 focus:outline-none transition-colors text-zinc-200 bg-zinc-900"
value={nextMessage.data}
></textarea>
{:else}
<span class="text-sm text-red-500">WARN: No messages found</span>
{/if} {/if}
{:catch error} {:catch error}
<div class="text-sm text-red-500 mb-2"> <span class="text-sm text-red-500"
Error loading next message: {error.message} >Error loading next message: {error.message}</span
</div> >
{/await} {/await}
</div>
<!-- No First Message --> <!-- No First Message -->
{#if !getFirstMessage()} {#if !getFirstMessage()}
<div class="mt-4"> <div class="mt-2 sm:mt-4">
<div class="text-sm text-red-500 mb-2"> <span class="text-sm text-red-500"
WARN: Selected first message is empty >WARN: Selected first message is empty</span
</div> >
</div> </div>
{/if} {/if}
</div> </div>