mirror of
https://github.com/wahyd4/links.git
synced 2026-08-09 05:06:16 +10:00
jbot: reorganize layout — memory+hint to right, interval to settings
- Move MemoryPanel from bottom of left column to top of right column
(above chat messages, with a clean border-bottom separator)
- Move hint text ('按住 Space 或按钮说话 · 音色') from left column
to a compact bar on the right column between chat and voice button;
hidden on mobile to save space
- Remove 切换间隔 slider from left column; add it to Settings page
under 🤖 机器人身份 section with proper slider+value layout
- Add switchIntervalMs:10000 to DEFAULT_SETTINGS in settingsStore so
the value persists across sessions; App.jsx reads it on mount
- Left column is now much leaner: face + interaction buttons + micro
expression grid + auto-rotate toggle only
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+3
-3
File diff suppressed because one or more lines are too long
+38
-2
@@ -597,13 +597,29 @@ kbd {
|
||||
|
||||
/* Chat padding tighter on mobile */
|
||||
.chat-panel { padding: 10px 12px; }
|
||||
|
||||
/* Right hint hidden on mobile — space is tight */
|
||||
.right-hint { display: none; }
|
||||
}
|
||||
|
||||
|
||||
/* ── Right column hint bar ────────────────────────────────── */
|
||||
.right-hint {
|
||||
flex: 0 0 auto;
|
||||
font-size: 0.72rem;
|
||||
color: var(--text3);
|
||||
text-align: center;
|
||||
padding: 3px 16px 2px;
|
||||
line-height: 1.7;
|
||||
border-top: 1px solid var(--border);
|
||||
background: var(--surface);
|
||||
}
|
||||
|
||||
|
||||
/* ── Memory panel ─────────────────────────────────────────── */
|
||||
.memory-panel {
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
flex: 0 0 auto;
|
||||
border-bottom: 1px solid var(--border);
|
||||
overflow: hidden;
|
||||
}
|
||||
.memory-toggle {
|
||||
@@ -992,3 +1008,23 @@ kbd {
|
||||
padding-bottom: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Settings slider row ──────────────────────────────────── */
|
||||
.settings-slider-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
.settings-slider {
|
||||
flex: 1;
|
||||
accent-color: var(--accent);
|
||||
cursor: pointer;
|
||||
}
|
||||
.settings-slider-val {
|
||||
font-size: 0.82rem;
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
min-width: 36px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
+11
-25
@@ -82,17 +82,17 @@ export default function App() {
|
||||
const [exprId, setExprId] = useState(ALL_AUTO_IDS[0]);
|
||||
const [autoRotate, setAutoRotate] = useState(true);
|
||||
const [scale, setScale] = useState(1);
|
||||
const [switchMs, setSwitchMs] = useState(10000);
|
||||
// switchMs is read from settings on mount (changed only via Settings page)
|
||||
const [switchMs] = useState(() => getSettings().switchIntervalMs ?? 10000);
|
||||
|
||||
const autoTimerRef = useRef(null);
|
||||
const autoRotateRef = useRef(true);
|
||||
const exprIdRef = useRef(ALL_AUTO_IDS[0]);
|
||||
const scheduleRef = useRef(null);
|
||||
const switchMsRef = useRef(10000);
|
||||
const switchMsRef = useRef(switchMs);
|
||||
|
||||
useEffect(() => { autoRotateRef.current = autoRotate; }, [autoRotate]);
|
||||
useEffect(() => { exprIdRef.current = exprId; }, [exprId]);
|
||||
useEffect(() => { switchMsRef.current = switchMs; }, [switchMs]);
|
||||
|
||||
const clearAuto = useCallback(() => {
|
||||
clearTimeout(autoTimerRef.current);
|
||||
@@ -373,33 +373,19 @@ export default function App() {
|
||||
<input type="checkbox" checked={autoRotate} onChange={ev => setAutoRotate(ev.target.checked)} />
|
||||
<span>自动轮换微表情</span>
|
||||
</label>
|
||||
|
||||
<div className="switch-interval">
|
||||
<div className="switch-interval-label">
|
||||
切换间隔 <span className="interval-val">{Math.round(switchMs / 1000)} 秒</span>
|
||||
</div>
|
||||
<input
|
||||
type="range" min="3" max="30" step="1"
|
||||
value={Math.round(switchMs / 1000)}
|
||||
onChange={ev => setSwitchMs(Number(ev.target.value) * 1000)}
|
||||
/>
|
||||
<div className="interval-ticks"><span>3s</span><span>30s</span></div>
|
||||
</div>
|
||||
|
||||
<p className="hint">
|
||||
按住 <kbd>Space</kbd> 或按钮说话 · 松开发送 · <button className="hist-inline-link" onClick={() => navigate('/history')}>历史记录</button>
|
||||
</p>
|
||||
<p className="hint voice-hint">
|
||||
🔊 音色: <button className="hist-inline-link" onClick={() => navigate('/settings')}>{currentVoiceLabel}</button>
|
||||
</p>
|
||||
|
||||
<MemoryPanel memories={memories} onMemoriesChange={refreshMemories} />
|
||||
</section>
|
||||
</aside>
|
||||
|
||||
{/* ── Right column: chat + voice button ── */}
|
||||
{/* ── Right column: memory + chat + hint + voice button ── */}
|
||||
<div className="right-col">
|
||||
<MemoryPanel memories={memories} onMemoriesChange={refreshMemories} />
|
||||
<ChatPanel messages={chatMessages} voiceStatus={voiceStatus} />
|
||||
<p className="right-hint">
|
||||
按住 <kbd>Space</kbd> 或按钮说话 · 松开发送 ·{' '}
|
||||
<button className="hist-inline-link" onClick={() => navigate('/history')}>历史记录</button>
|
||||
{' '}· 🔊{' '}
|
||||
<button className="hist-inline-link" onClick={() => navigate('/settings')}>{currentVoiceLabel}</button>
|
||||
</p>
|
||||
<VoiceButton phase={voicePhase} onStart={handleSpaceDown} onEnd={handleSpaceUp} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -163,6 +163,19 @@ export default function Settings() {
|
||||
placeholder="你是一个友好、简洁、偶尔幽默的AI机器人助手。回复控制在80字以内。"
|
||||
/>
|
||||
</label>
|
||||
|
||||
<div className="settings-label">
|
||||
微表情切换间隔
|
||||
<div className="settings-slider-row">
|
||||
<input
|
||||
type="range" min="3" max="30" step="1"
|
||||
value={Math.round((form.switchIntervalMs ?? 10000) / 1000)}
|
||||
onChange={e => set('switchIntervalMs', Number(e.target.value) * 1000)}
|
||||
className="settings-slider"
|
||||
/>
|
||||
<span className="settings-slider-val">{Math.round((form.switchIntervalMs ?? 10000) / 1000)} 秒</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── User context ── */}
|
||||
|
||||
@@ -9,6 +9,7 @@ export const DEFAULT_SETTINGS = {
|
||||
voiceId: DEFAULT_VOICE,
|
||||
customVoiceId: '', // overrides voiceId if non-empty
|
||||
responseMaxWords: 80,
|
||||
switchIntervalMs: 10000, // micro-expression auto-rotate interval
|
||||
};
|
||||
|
||||
export function getSettings() {
|
||||
|
||||
Reference in New Issue
Block a user