feat: Improve UI layout and navigation

- Increase logo size (48x48 desktop, 56x56 mobile) for better visibility
- Add logo as favicon
- Add logo to mobile header
- Move user menu to navigation bars (sidebar on desktop, bottom bar on mobile)
- Fix desktop chat layout - container structure prevents voice controls cutoff
- Fix mobile bottom bar - use icon-only ActionIcons instead of truncated text buttons
- Hide Create Node/New Conversation buttons on mobile to save header space
- Make fixed header and voice controls work properly with containers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-09 14:43:11 +00:00
parent 0b632a31eb
commit f0284ef813
74 changed files with 6996 additions and 629 deletions

170
lib/app-machine.ts Normal file
View File

@@ -0,0 +1,170 @@
/**
* App-Level State Machine
*
* Manages the top-level application state across three main modes:
* - convo: Active conversation (voice or text)
* - edit: Editing a node
* - galaxy: 3D visualization of node graph
*
* This machine sits above the conversation machine (which contains voice/text modes).
* It does NOT duplicate the voice mode logic - that lives in voice-machine.ts.
*/
import { setup, assign } from 'xstate';
export interface NodeDraft {
title: string;
content: string;
conversationContext?: string; // Last N messages as context
}
export interface Node {
id: string;
title: string;
content: string;
atp_uri?: string;
}
interface AppContext {
currentNodeId: string | null;
pendingNodeDraft: NodeDraft | null;
mode: 'mobile' | 'desktop';
lastError: string | null;
}
type AppEvent =
| { type: 'NAVIGATE_TO_CONVO' }
| { type: 'NAVIGATE_TO_EDIT'; nodeId?: string; draft?: NodeDraft }
| { type: 'NAVIGATE_TO_GALAXY' }
| { type: 'CREATE_NODE_FROM_CONVERSATION'; draft: NodeDraft }
| { type: 'PUBLISH_NODE_SUCCESS'; nodeId: string }
| { type: 'CANCEL_EDIT' }
| { type: 'SET_MODE'; mode: 'mobile' | 'desktop' }
| { type: 'ERROR'; message: string };
export const appMachine = setup({
types: {
context: {} as AppContext,
events: {} as AppEvent,
},
actions: {
setCurrentNode: assign({
currentNodeId: ({ event }) =>
event.type === 'NAVIGATE_TO_EDIT' ? event.nodeId || null : null,
}),
setPendingDraft: assign({
pendingNodeDraft: ({ event }) => {
if (event.type === 'NAVIGATE_TO_EDIT' && event.draft) {
console.log('[App Machine] Setting pending draft:', event.draft);
return event.draft;
}
if (event.type === 'CREATE_NODE_FROM_CONVERSATION') {
console.log('[App Machine] Creating node from conversation:', event.draft);
return event.draft;
}
return null;
},
}),
clearDraft: assign({
pendingNodeDraft: null,
currentNodeId: null,
}),
setPublishedNode: assign({
currentNodeId: ({ event }) =>
event.type === 'PUBLISH_NODE_SUCCESS' ? event.nodeId : null,
pendingNodeDraft: null,
}),
setMode: assign({
mode: ({ event }) => (event.type === 'SET_MODE' ? event.mode : 'desktop'),
}),
setError: assign({
lastError: ({ event }) => (event.type === 'ERROR' ? event.message : null),
}),
clearError: assign({
lastError: null,
}),
logTransition: ({ context, event }) => {
console.log('[App Machine] Event:', event.type);
console.log('[App Machine] Context:', {
currentNodeId: context.currentNodeId,
hasDraft: !!context.pendingNodeDraft,
mode: context.mode,
});
},
},
}).createMachine({
id: 'app',
initial: 'convo',
context: {
currentNodeId: null,
pendingNodeDraft: null,
mode: 'desktop',
lastError: null,
},
on: {
SET_MODE: {
actions: ['setMode', 'logTransition'],
},
ERROR: {
actions: ['setError', 'logTransition'],
},
},
states: {
convo: {
tags: ['conversation'],
entry: ['clearError', 'logTransition'],
on: {
NAVIGATE_TO_EDIT: {
target: 'edit',
actions: ['setCurrentNode', 'setPendingDraft', 'logTransition'],
},
CREATE_NODE_FROM_CONVERSATION: {
target: 'edit',
actions: ['setPendingDraft', 'logTransition'],
},
NAVIGATE_TO_GALAXY: {
target: 'galaxy',
actions: ['logTransition'],
},
},
},
edit: {
tags: ['editing'],
entry: ['clearError', 'logTransition'],
on: {
NAVIGATE_TO_CONVO: {
target: 'convo',
actions: ['logTransition'],
},
NAVIGATE_TO_GALAXY: {
target: 'galaxy',
actions: ['logTransition'],
},
PUBLISH_NODE_SUCCESS: {
target: 'galaxy',
actions: ['setPublishedNode', 'logTransition'],
},
CANCEL_EDIT: {
target: 'convo',
actions: ['clearDraft', 'logTransition'],
},
},
},
galaxy: {
tags: ['visualization'],
entry: ['clearError', 'logTransition'],
on: {
NAVIGATE_TO_CONVO: {
target: 'convo',
actions: ['logTransition'],
},
NAVIGATE_TO_EDIT: {
target: 'edit',
actions: ['setCurrentNode', 'setPendingDraft', 'logTransition'],
},
},
},
},
});