mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 09:31:20 -04:00
chat panel fixup finally
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -11,8 +11,8 @@
|
|||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||||
<meta name="apple-mobile-web-app-title" content="Roomba Rover" />
|
<meta name="apple-mobile-web-app-title" content="Roomba Rover" />
|
||||||
<title>Roomba Rover</title>
|
<title>Roomba Rover</title>
|
||||||
<script type="module" crossorigin src="/assets/index-cdQmQokE.js"></script>
|
<script type="module" crossorigin src="/assets/index-Fc055JQt.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-Dzjs7qyo.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-iVUbccy-.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -145,6 +145,20 @@ export default function ChatPanel({
|
|||||||
|
|
||||||
const listClass = fillHeight ? 'flex-1 min-h-0 overflow-y-auto' : 'h-48 overflow-y-auto';
|
const listClass = fillHeight ? 'flex-1 min-h-0 overflow-y-auto' : 'h-48 overflow-y-auto';
|
||||||
const isStackedNickname = nicknameLayout === 'stacked';
|
const isStackedNickname = nicknameLayout === 'stacked';
|
||||||
|
// The composer is intentionally split into stable rows instead of one large
|
||||||
|
// wrapping flex line. Google TTS adds engine, voice, pitch, and speed selects;
|
||||||
|
// keeping those controls in their own bounded grid prevents their combined
|
||||||
|
// natural widths from pushing the nickname field or message input off-screen.
|
||||||
|
const composerClass = isStackedNickname
|
||||||
|
? 'grid min-w-0 grid-cols-1 gap-0.5'
|
||||||
|
: 'grid min-w-0 grid-cols-[9rem_minmax(0,1fr)_auto] items-stretch gap-0.5 sm:grid-cols-[10rem_minmax(0,1fr)_auto]';
|
||||||
|
// Every select in this compact toolbar must be allowed to shrink below the
|
||||||
|
// width of its longest option text. Native selects otherwise preserve a large
|
||||||
|
// intrinsic width, which is what made the Google TTS option set break layout.
|
||||||
|
const compactSelectClass = 'field-input min-w-0 w-full max-w-full text-xs';
|
||||||
|
const ttsGridClass = engine === 'chromegtts'
|
||||||
|
? 'grid min-w-0 grid-cols-[auto_minmax(0,1fr)_minmax(0,0.7fr)_minmax(0,0.9fr)_minmax(0,0.9fr)] items-center gap-0.5'
|
||||||
|
: 'grid min-w-0 grid-cols-[auto_minmax(0,1fr)_minmax(0,0.8fr)] items-center gap-0.5';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CardFrame
|
<CardFrame
|
||||||
@@ -165,15 +179,12 @@ export default function ChatPanel({
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
{!hideInput && (
|
{!hideInput && (
|
||||||
<form
|
<form className={composerClass} onSubmit={handleSend}>
|
||||||
className={`flex items-stretch gap-0.5 ${isStackedNickname ? 'flex-col' : 'flex-wrap'}`}
|
|
||||||
onSubmit={handleSend}
|
|
||||||
>
|
|
||||||
<div className={isStackedNickname ? 'w-full' : 'w-[9rem] sm:w-[10rem] shrink-0'}>
|
<div className={isStackedNickname ? 'w-full' : 'w-[9rem] sm:w-[10rem] shrink-0'}>
|
||||||
<NicknameForm compact />
|
<NicknameForm compact />
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
className={`field-input ${isStackedNickname ? 'w-full min-w-0' : 'flex-1 min-w-[10rem]'}`}
|
className="field-input min-w-0 w-full"
|
||||||
value={draft}
|
value={draft}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const next = e.target.value;
|
const next = e.target.value;
|
||||||
@@ -199,13 +210,20 @@ export default function ChatPanel({
|
|||||||
placeholder={canChat ? 'Type a message…' : hideSpectatorNotice ? '' : 'Spectators cannot chat'}
|
placeholder={canChat ? 'Type a message…' : hideSpectatorNotice ? '' : 'Spectators cannot chat'}
|
||||||
disabled={!canChat}
|
disabled={!canChat}
|
||||||
/>
|
/>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
disabled={!canChat || sending}
|
||||||
|
className={`button-dark shrink-0 disabled:opacity-50 ${isStackedNickname ? 'h-8 w-full' : 'h-full self-stretch'}`}
|
||||||
|
>
|
||||||
|
{sending ? '...' : 'Send'}
|
||||||
|
</button>
|
||||||
{ttsSupported && (
|
{ttsSupported && (
|
||||||
<div
|
<div
|
||||||
className={`flex flex-wrap items-center gap-0.5 ${
|
className={`${ttsGridClass} ${
|
||||||
isStackedNickname ? 'w-full' : 'basis-full sm:basis-auto'
|
isStackedNickname ? 'w-full' : 'col-span-full'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<label className="flex items-center gap-0.5 text-xs text-slate-300">
|
<label className="flex min-w-0 items-center gap-0.5 text-xs text-slate-300">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={speak}
|
checked={speak}
|
||||||
@@ -228,11 +246,11 @@ export default function ChatPanel({
|
|||||||
if (nextVoice !== voice) setVoice(nextVoice);
|
if (nextVoice !== voice) setVoice(nextVoice);
|
||||||
saveTtsSettings((current) => ({ ...(current || {}), engine: next, voice: nextVoice }));
|
saveTtsSettings((current) => ({ ...(current || {}), engine: next, voice: nextVoice }));
|
||||||
}}
|
}}
|
||||||
className="field-input text-xs"
|
className={compactSelectClass}
|
||||||
>
|
>
|
||||||
<option value="flite">flite</option>
|
<option value="flite">flite</option>
|
||||||
<option value="espeak">espeak</option>
|
<option value="espeak">espeak</option>
|
||||||
<option value="chromegtts">Google TTS (Local!!)</option>
|
<option value="chromegtts">Google</option>
|
||||||
</select>
|
</select>
|
||||||
{engine === 'flite' || engine === 'chromegtts' ? (
|
{engine === 'flite' || engine === 'chromegtts' ? (
|
||||||
<>
|
<>
|
||||||
@@ -243,7 +261,7 @@ export default function ChatPanel({
|
|||||||
setVoice(next);
|
setVoice(next);
|
||||||
saveTtsSettings((current) => ({ ...(current || {}), voice: next }));
|
saveTtsSettings((current) => ({ ...(current || {}), voice: next }));
|
||||||
}}
|
}}
|
||||||
className="field-input text-xs"
|
className={compactSelectClass}
|
||||||
>
|
>
|
||||||
{(engine === 'chromegtts' ? CHROME_TTS_VOICES : FLITE_VOICES).map((v) => (
|
{(engine === 'chromegtts' ? CHROME_TTS_VOICES : FLITE_VOICES).map((v) => (
|
||||||
<option key={v} value={v}>
|
<option key={v} value={v}>
|
||||||
@@ -260,11 +278,11 @@ export default function ChatPanel({
|
|||||||
setGooglePitch(next);
|
setGooglePitch(next);
|
||||||
saveTtsSettings((current) => ({ ...(current || {}), googlePitch: next }));
|
saveTtsSettings((current) => ({ ...(current || {}), googlePitch: next }));
|
||||||
}}
|
}}
|
||||||
className="field-input text-xs"
|
className={compactSelectClass}
|
||||||
>
|
>
|
||||||
{GOOGLE_TTS_VALUES.map((value) => (
|
{GOOGLE_TTS_VALUES.map((value) => (
|
||||||
<option key={`pitch-${value}`} value={value}>
|
<option key={`pitch-${value}`} value={value}>
|
||||||
pitch {value.toFixed(2)}
|
P {value.toFixed(2)}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
@@ -275,11 +293,11 @@ export default function ChatPanel({
|
|||||||
setGoogleSpeed(next);
|
setGoogleSpeed(next);
|
||||||
saveTtsSettings((current) => ({ ...(current || {}), googleSpeed: next }));
|
saveTtsSettings((current) => ({ ...(current || {}), googleSpeed: next }));
|
||||||
}}
|
}}
|
||||||
className="field-input text-xs"
|
className={compactSelectClass}
|
||||||
>
|
>
|
||||||
{GOOGLE_TTS_VALUES.map((value) => (
|
{GOOGLE_TTS_VALUES.map((value) => (
|
||||||
<option key={`speed-${value}`} value={value}>
|
<option key={`speed-${value}`} value={value}>
|
||||||
speed {value.toFixed(2)}
|
S {value.toFixed(2)}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
@@ -294,7 +312,7 @@ export default function ChatPanel({
|
|||||||
setPitch(next);
|
setPitch(next);
|
||||||
saveTtsSettings((current) => ({ ...(current || {}), pitch: next }));
|
saveTtsSettings((current) => ({ ...(current || {}), pitch: next }));
|
||||||
}}
|
}}
|
||||||
className="field-input text-xs"
|
className={compactSelectClass}
|
||||||
>
|
>
|
||||||
{ESPEAK_PITCHES.map((p) => (
|
{ESPEAK_PITCHES.map((p) => (
|
||||||
<option key={p} value={p}>
|
<option key={p} value={p}>
|
||||||
@@ -305,13 +323,6 @@ export default function ChatPanel({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
disabled={!canChat || sending}
|
|
||||||
className={`button-dark disabled:opacity-50 ${isStackedNickname ? 'w-full h-8' : 'h-full self-stretch'}`}
|
|
||||||
>
|
|
||||||
{sending ? '...' : 'Send'}
|
|
||||||
</button>
|
|
||||||
</form>
|
</form>
|
||||||
)}
|
)}
|
||||||
</CardFrame>
|
</CardFrame>
|
||||||
|
|||||||
Reference in New Issue
Block a user