Update demo with expanded component showcase and styling
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -7,9 +7,59 @@ import {
|
||||
AiConfidenceMeterComponent,
|
||||
AiSkeletonLoaderComponent,
|
||||
AiCodeBlockComponent,
|
||||
AiConversationHistoryComponent
|
||||
AiConversationHistoryComponent,
|
||||
AiFeedbackComponent,
|
||||
AiProgressStepperComponent,
|
||||
AiTokenCounterComponent,
|
||||
AiRateLimitIndicatorComponent,
|
||||
AiSessionHeaderComponent,
|
||||
AiModelSelectorComponent,
|
||||
AiSourceCitationComponent,
|
||||
AiDiffViewerComponent,
|
||||
AiErrorStateComponent,
|
||||
AiResponseActionsComponent,
|
||||
AiToolCallDisplayComponent,
|
||||
AiSuggestedPromptsComponent,
|
||||
AiCardComponent,
|
||||
AiCardGridComponent,
|
||||
AiFileUploadComponent,
|
||||
AiPromptTemplatesComponent,
|
||||
AiMarkdownRendererComponent,
|
||||
AiAnnotationLayerComponent,
|
||||
AiImageGalleryComponent,
|
||||
VoiceCommandComponent,
|
||||
PredictiveInputComponent,
|
||||
SmartNotificationComponent,
|
||||
AiChatComponent,
|
||||
AiAgentActivityComponent,
|
||||
AiAgentHandoffComponent,
|
||||
AiAgentMessageComponent,
|
||||
AiAgentProfileComponent,
|
||||
AiAgentSelectorComponent,
|
||||
AiAgentSwitcherComponent
|
||||
} from 'ai-elements-ui';
|
||||
import type {
|
||||
Conversation,
|
||||
AiStep,
|
||||
TokenUsage,
|
||||
RateLimitInfo,
|
||||
SessionInfo,
|
||||
AiModel,
|
||||
AiSource,
|
||||
AiError,
|
||||
ToolCall,
|
||||
SuggestedPrompt,
|
||||
CanvasCard,
|
||||
PromptTemplate,
|
||||
Annotation,
|
||||
GeneratedImage,
|
||||
AiNotification,
|
||||
AiAgent,
|
||||
AgentMessage,
|
||||
AgentConversation,
|
||||
AgentHandoff,
|
||||
AgentActivityEntry
|
||||
} from 'ai-elements-ui';
|
||||
import type { Conversation } from 'ai-elements-ui';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
@@ -22,7 +72,36 @@ import type { Conversation } from 'ai-elements-ui';
|
||||
AiConfidenceMeterComponent,
|
||||
AiSkeletonLoaderComponent,
|
||||
AiCodeBlockComponent,
|
||||
AiConversationHistoryComponent
|
||||
AiConversationHistoryComponent,
|
||||
AiFeedbackComponent,
|
||||
AiProgressStepperComponent,
|
||||
AiTokenCounterComponent,
|
||||
AiRateLimitIndicatorComponent,
|
||||
AiSessionHeaderComponent,
|
||||
AiModelSelectorComponent,
|
||||
AiSourceCitationComponent,
|
||||
AiDiffViewerComponent,
|
||||
AiErrorStateComponent,
|
||||
AiResponseActionsComponent,
|
||||
AiToolCallDisplayComponent,
|
||||
AiSuggestedPromptsComponent,
|
||||
AiCardComponent,
|
||||
AiCardGridComponent,
|
||||
AiFileUploadComponent,
|
||||
AiPromptTemplatesComponent,
|
||||
AiMarkdownRendererComponent,
|
||||
AiAnnotationLayerComponent,
|
||||
AiImageGalleryComponent,
|
||||
VoiceCommandComponent,
|
||||
PredictiveInputComponent,
|
||||
SmartNotificationComponent,
|
||||
AiChatComponent,
|
||||
AiAgentActivityComponent,
|
||||
AiAgentHandoffComponent,
|
||||
AiAgentMessageComponent,
|
||||
AiAgentProfileComponent,
|
||||
AiAgentSelectorComponent,
|
||||
AiAgentSwitcherComponent
|
||||
],
|
||||
templateUrl: './app.component.html',
|
||||
styleUrl: './app.component.scss'
|
||||
@@ -31,6 +110,9 @@ export class AppComponent {
|
||||
// Demo state
|
||||
currentView = signal<'canvas' | 'components'>('components');
|
||||
avatarState = signal<'idle' | 'thinking' | 'speaking'>('idle');
|
||||
darkMode = signal(false);
|
||||
sidebarOpen = signal(false);
|
||||
currentTheme = signal<'apple' | 'mist'>('apple');
|
||||
|
||||
// Conversations
|
||||
conversations: Conversation[] = [
|
||||
@@ -49,6 +131,226 @@ export class AppComponent {
|
||||
const results = Array.from({ length: 10 }, (_, i) => fibonacci(i));
|
||||
console.log(results);`;
|
||||
|
||||
// Feedback
|
||||
feedbackMessageId = 'msg-demo-001';
|
||||
|
||||
// Progress Stepper
|
||||
steps: AiStep[] = [
|
||||
{ id: '1', label: 'Analyzing query', description: 'Parsing your request', status: 'complete', substeps: [
|
||||
{ id: '1a', label: 'Tokenizing input', status: 'complete' },
|
||||
{ id: '1b', label: 'Extracting intent', status: 'complete' }
|
||||
]},
|
||||
{ id: '2', label: 'Searching knowledge base', description: 'Finding relevant information', status: 'complete' },
|
||||
{ id: '3', label: 'Generating response', description: 'Composing answer', status: 'active', substeps: [
|
||||
{ id: '3a', label: 'Drafting content', status: 'active' },
|
||||
{ id: '3b', label: 'Fact checking', status: 'pending' }
|
||||
]},
|
||||
{ id: '4', label: 'Review & citations', description: 'Adding source references', status: 'pending' }
|
||||
];
|
||||
|
||||
// Token Counter
|
||||
tokenUsage: TokenUsage = { used: 3420, limit: 8192, promptTokens: 1200, completionTokens: 2220 };
|
||||
|
||||
// Rate Limit
|
||||
rateLimit: RateLimitInfo = {
|
||||
requestsUsed: 42,
|
||||
requestsLimit: 60,
|
||||
tokensUsed: 28500,
|
||||
tokensLimit: 100000,
|
||||
resetsAt: new Date(Date.now() + 45000),
|
||||
tier: 'Pro'
|
||||
};
|
||||
|
||||
// Session Header
|
||||
session: SessionInfo = {
|
||||
id: 'sess-abc123',
|
||||
model: 'Claude Opus 4.6',
|
||||
context: 'Code Review',
|
||||
tokenUsage: { used: 3420, limit: 8192, promptTokens: 1200, completionTokens: 2220 },
|
||||
startedAt: new Date(Date.now() - 1800000),
|
||||
lastActivity: new Date()
|
||||
};
|
||||
|
||||
// Model Selector
|
||||
models: AiModel[] = [
|
||||
{ id: 'opus-4.6', name: 'Claude Opus 4.6', provider: 'Anthropic', description: 'Most capable model', contextWindow: 200000, capabilities: ['reasoning', 'code', 'analysis', 'vision'], badge: 'Latest' },
|
||||
{ id: 'sonnet-4.5', name: 'Claude Sonnet 4.5', provider: 'Anthropic', description: 'Balanced performance', contextWindow: 200000, capabilities: ['reasoning', 'code', 'analysis'] },
|
||||
{ id: 'haiku-4.5', name: 'Claude Haiku 4.5', provider: 'Anthropic', description: 'Fast and efficient', contextWindow: 200000, capabilities: ['code', 'analysis'] },
|
||||
{ id: 'gpt-4o', name: 'GPT-4o', provider: 'OpenAI', description: 'Multimodal flagship', contextWindow: 128000, capabilities: ['reasoning', 'code', 'vision'] },
|
||||
{ id: 'gemini-2', name: 'Gemini 2.0 Flash', provider: 'Google', description: 'Fast multimodal model', contextWindow: 1000000, capabilities: ['reasoning', 'code', 'vision'] }
|
||||
];
|
||||
selectedModelId = 'opus-4.6';
|
||||
|
||||
// Source Citations
|
||||
sources: AiSource[] = [
|
||||
{ id: '1', title: 'Angular Signals Documentation', url: 'https://angular.dev/guide/signals', type: 'web', snippet: 'Angular Signals is a system that granularly tracks how and where your state is used...', confidence: 0.95 },
|
||||
{ id: '2', title: 'Component Design Patterns', author: 'Angular Team', type: 'document', snippet: 'Best practices for building reusable Angular components...', confidence: 0.88 },
|
||||
{ id: '3', title: 'TypeScript 5.7 Release Notes', url: 'https://devblogs.microsoft.com/typescript/', type: 'web', snippet: 'New features include improved type inference and performance...', confidence: 0.82 }
|
||||
];
|
||||
|
||||
// Diff Viewer
|
||||
diffBefore = `function greet(name: string) {
|
||||
console.log("Hello " + name);
|
||||
return name;
|
||||
}`;
|
||||
|
||||
diffAfter = `function greet(name: string, greeting = 'Hello') {
|
||||
const message = \`\${greeting}, \${name}!\`;
|
||||
console.log(message);
|
||||
return message;
|
||||
}`;
|
||||
|
||||
// Error State
|
||||
sampleError: AiError = {
|
||||
code: 'RATE_LIMIT_EXCEEDED',
|
||||
message: 'You\'ve exceeded the rate limit for this model.',
|
||||
severity: 'warning',
|
||||
details: 'Current usage: 62/60 requests per minute. Limit resets in 45 seconds.',
|
||||
retryable: true,
|
||||
helpUrl: 'https://docs.example.com/rate-limits'
|
||||
};
|
||||
|
||||
// Response Actions
|
||||
responseMessageId = 'msg-resp-001';
|
||||
|
||||
// Tool Calls
|
||||
toolCalls: ToolCall[] = [
|
||||
{ id: 'tc-1', name: 'search_codebase', description: 'Searching for relevant files', status: 'complete', startedAt: new Date(Date.now() - 3000), completedAt: new Date(Date.now() - 1500), result: '3 files found' },
|
||||
{ id: 'tc-2', name: 'read_file', description: 'Reading src/app/app.component.ts', status: 'complete', startedAt: new Date(Date.now() - 1500), completedAt: new Date(Date.now() - 800) },
|
||||
{ id: 'tc-3', name: 'run_tests', description: 'Executing test suite', status: 'running', startedAt: new Date(Date.now() - 500) },
|
||||
{ id: 'tc-4', name: 'deploy', description: 'Deploy to staging', status: 'pending' }
|
||||
];
|
||||
|
||||
// Suggested Prompts
|
||||
suggestedPrompts: SuggestedPrompt[] = [
|
||||
{ id: '1', text: 'Explain this code', icon: 'code', category: 'Code', description: 'Get a detailed explanation of selected code' },
|
||||
{ id: '2', text: 'Find bugs', icon: 'bug', category: 'Code', description: 'Scan for potential issues' },
|
||||
{ id: '3', text: 'Write tests', icon: 'test', category: 'Testing', description: 'Generate unit tests' },
|
||||
{ id: '4', text: 'Refactor this', icon: 'refactor', category: 'Code', description: 'Suggest improvements' },
|
||||
{ id: '5', text: 'Summarize changes', icon: 'diff', category: 'Git', description: 'Summarize recent changes' }
|
||||
];
|
||||
|
||||
// Cards
|
||||
demoCards: CanvasCard[] = [
|
||||
{ id: '1', title: 'Neural Network Basics', subtitle: 'Machine Learning', description: 'Introduction to neural network architectures and training.', badges: [{ label: 'Popular', variant: 'success' }], actions: [{ id: 'view', label: 'View', variant: 'primary' }, { id: 'save', label: 'Save', variant: 'secondary' }] },
|
||||
{ id: '2', title: 'Transformer Architecture', subtitle: 'Deep Learning', description: 'How attention mechanisms revolutionized NLP.', badges: [{ label: 'Advanced', variant: 'warning' }], actions: [{ id: 'view', label: 'View', variant: 'primary' }] },
|
||||
{ id: '3', title: 'Prompt Engineering', subtitle: 'AI Techniques', description: 'Best practices for crafting effective prompts.', badges: [{ label: 'New', variant: 'info' }], actions: [{ id: 'view', label: 'View', variant: 'primary' }] }
|
||||
];
|
||||
|
||||
// Prompt Templates
|
||||
promptTemplates: PromptTemplate[] = [
|
||||
{ id: '1', name: 'Code Review', description: 'Review code for bugs and improvements', content: 'Review the following {{language}} code for bugs, performance issues, and best practices:\n\n{{code}}', category: 'Development', variables: [{ name: 'language', label: 'Language', type: 'select', options: ['TypeScript', 'Python', 'Go', 'Rust'] }, { name: 'code', label: 'Code', type: 'textarea', required: true }], isFavorite: true, usageCount: 24 },
|
||||
{ id: '2', name: 'Explain Concept', description: 'Get a clear explanation of a topic', content: 'Explain {{topic}} in simple terms, suitable for a {{level}} audience.', category: 'Learning', variables: [{ name: 'topic', label: 'Topic', type: 'text', required: true }, { name: 'level', label: 'Level', type: 'select', options: ['beginner', 'intermediate', 'advanced'] }], usageCount: 18 },
|
||||
{ id: '3', name: 'Write Tests', description: 'Generate test cases', content: 'Write comprehensive unit tests for:\n\n{{code}}', category: 'Development', variables: [{ name: 'code', label: 'Code to test', type: 'textarea', required: true }], usageCount: 15 }
|
||||
];
|
||||
|
||||
// Markdown
|
||||
markdownContent = `## AI Response
|
||||
|
||||
Here's a summary of the changes:
|
||||
|
||||
- **Added** new authentication middleware
|
||||
- **Fixed** the race condition in \`useEffect\`
|
||||
- **Removed** deprecated API calls
|
||||
|
||||
> Note: These changes require a database migration.
|
||||
|
||||
\`\`\`typescript
|
||||
const result = await auth.verify(token);
|
||||
\`\`\`
|
||||
|
||||
Visit the [documentation](https://example.com) for more details.`;
|
||||
|
||||
// Annotations
|
||||
annotationText = 'Angular Signals provide a way to define reactive state. When a signal value changes, any computed signals or effects that depend on it are automatically updated. This makes it easy to build responsive UIs without manual change detection.';
|
||||
annotations: Annotation[] = [
|
||||
{ id: '1', startOffset: 0, endOffset: 15, text: 'Angular Signals', note: 'Core reactivity primitive in Angular 16+', color: '#ffeb3b', createdAt: new Date() },
|
||||
{ id: '2', startOffset: 96, endOffset: 113, text: 'computed signals', note: 'Derived values that auto-update', color: '#4caf50', createdAt: new Date() },
|
||||
{ id: '3', startOffset: 198, endOffset: 214, text: 'change detection', note: 'Zone.js-based detection is the alternative', color: '#2196f3', createdAt: new Date() }
|
||||
];
|
||||
|
||||
// Image Gallery
|
||||
demoImages: GeneratedImage[] = [
|
||||
{ id: '1', url: 'https://picsum.photos/seed/ai1/400/300', thumbnailUrl: 'https://picsum.photos/seed/ai1/200/150', prompt: 'A futuristic city skyline at sunset', model: 'DALL-E 3', size: '1024x1024', createdAt: new Date(), isFavorite: true },
|
||||
{ id: '2', url: 'https://picsum.photos/seed/ai2/400/300', thumbnailUrl: 'https://picsum.photos/seed/ai2/200/150', prompt: 'An abstract neural network visualization', model: 'DALL-E 3', size: '1024x1024', createdAt: new Date() },
|
||||
{ id: '3', url: 'https://picsum.photos/seed/ai3/400/300', thumbnailUrl: 'https://picsum.photos/seed/ai3/200/150', prompt: 'A robot learning to paint', model: 'Midjourney', size: '1024x1024', createdAt: new Date() }
|
||||
];
|
||||
|
||||
// Notifications
|
||||
demoNotifications: AiNotification[] = [
|
||||
{ id: '1', title: 'Model Updated', message: 'Claude Opus 4.6 is now available', priority: 'high', category: 'System', timestamp: new Date(), read: false, aiSummary: 'New model release with improved reasoning' },
|
||||
{ id: '2', title: 'Rate Limit Warning', message: 'Approaching 80% of hourly limit', priority: 'medium', category: 'Usage', timestamp: new Date(Date.now() - 300000), read: false },
|
||||
{ id: '3', title: 'Task Complete', message: 'Code review finished with 3 suggestions', priority: 'low', category: 'Tasks', timestamp: new Date(Date.now() - 600000), read: true }
|
||||
];
|
||||
|
||||
// Multi-Agent: Sample Agents
|
||||
sampleAgents: AiAgent[] = [
|
||||
{ id: 'research', name: 'Research Agent', description: 'Searches the web, reads documents, and synthesizes findings into concise reports.', status: 'online', capabilities: ['web-search', 'summarization', 'fact-checking'], category: 'Research', model: 'Claude Opus 4.6', accentColor: '#6366f1', fallbackInitials: 'RA', isFavorite: true },
|
||||
{ id: 'code', name: 'Code Agent', description: 'Writes, reviews, and debugs code across multiple languages and frameworks.', status: 'online', capabilities: ['code-generation', 'debugging', 'refactoring', 'testing'], category: 'Development', model: 'Claude Sonnet 4.5', accentColor: '#10b981', fallbackInitials: 'CA' },
|
||||
{ id: 'writing', name: 'Writing Agent', description: 'Crafts polished prose, edits drafts, and adapts tone for different audiences.', status: 'busy', capabilities: ['copywriting', 'editing', 'translation'], category: 'Creative', model: 'Claude Opus 4.6', accentColor: '#f59e0b', fallbackInitials: 'WA' },
|
||||
{ id: 'data', name: 'Data Agent', description: 'Analyzes datasets, creates visualizations, and extracts actionable insights.', status: 'online', capabilities: ['data-analysis', 'visualization', 'statistics'], category: 'Research', model: 'Claude Sonnet 4.5', accentColor: '#ec4899', fallbackInitials: 'DA', isFavorite: true },
|
||||
{ id: 'creative', name: 'Creative Agent', description: 'Generates images, brainstorms ideas, and designs creative concepts.', status: 'offline', capabilities: ['ideation', 'image-generation', 'storytelling'], category: 'Creative', model: 'Claude Haiku 4.5', accentColor: '#8b5cf6', fallbackInitials: 'CR' }
|
||||
];
|
||||
selectedAgentId = signal('research');
|
||||
|
||||
// Multi-Agent: Messages
|
||||
agentMessages: AgentMessage[] = [
|
||||
{ id: 'm1', role: 'user', content: 'Can you research the latest trends in AI agents?', timestamp: new Date(Date.now() - 120000) },
|
||||
{ id: 'm2', role: 'assistant', content: 'I\'ll look into that for you. The key trends in AI agents for 2026 include multi-agent collaboration, tool-use orchestration, and memory-augmented reasoning.', timestamp: new Date(Date.now() - 90000), agent: { agentId: 'research', agentName: 'Research Agent', agentFallbackInitials: 'RA', accentColor: '#6366f1' } },
|
||||
{ id: 'm3', role: 'system', content: '', timestamp: new Date(Date.now() - 60000), systemEvent: { type: 'handoff', agentId: 'research', agentName: 'Research Agent', targetAgentId: 'code', targetAgentName: 'Code Agent', reason: 'Implementation requested', timestamp: new Date(Date.now() - 60000) } },
|
||||
{ id: 'm4', role: 'assistant', content: 'I can help implement an agent orchestration system. Here\'s a basic architecture using an event-driven pattern with a central coordinator.', timestamp: new Date(Date.now() - 30000), agent: { agentId: 'code', agentName: 'Code Agent', agentFallbackInitials: 'CA', accentColor: '#10b981' } },
|
||||
{ id: 'm5', role: 'system', content: '', timestamp: new Date(Date.now() - 15000), systemEvent: { type: 'joined', agentId: 'writing', agentName: 'Writing Agent', timestamp: new Date(Date.now() - 15000) } }
|
||||
];
|
||||
|
||||
// Multi-Agent: Conversations
|
||||
agentConversations: AgentConversation[] = [
|
||||
{ id: 'conv-1', agent: this.sampleAgents[0], unreadCount: 0, lastMessage: 'Here are the key findings...', lastActivity: new Date(), isActive: true },
|
||||
{ id: 'conv-2', agent: this.sampleAgents[1], unreadCount: 3, lastMessage: 'Code review complete.', lastActivity: new Date(Date.now() - 30000), isActive: false },
|
||||
{ id: 'conv-3', agent: this.sampleAgents[2], unreadCount: 1, lastMessage: 'Draft is ready for review.', lastActivity: new Date(Date.now() - 60000), isActive: false },
|
||||
{ id: 'conv-4', agent: this.sampleAgents[3], unreadCount: 0, lastMessage: 'Analysis exported to CSV.', lastActivity: new Date(Date.now() - 300000), isActive: false }
|
||||
];
|
||||
activeConversationId = signal('conv-1');
|
||||
|
||||
// Multi-Agent: Handoff
|
||||
sampleHandoff: AgentHandoff = {
|
||||
id: 'handoff-1',
|
||||
sourceAgent: this.sampleAgents[0],
|
||||
targetAgent: this.sampleAgents[1],
|
||||
reason: 'Implementation of agent orchestration system requested by user',
|
||||
context: 'The user wants to build an event-driven multi-agent architecture with a central coordinator pattern.',
|
||||
status: 'in-progress',
|
||||
initiatedAt: new Date(Date.now() - 5000)
|
||||
};
|
||||
|
||||
sampleHandoffComplete: AgentHandoff = {
|
||||
id: 'handoff-2',
|
||||
sourceAgent: this.sampleAgents[1],
|
||||
targetAgent: this.sampleAgents[2],
|
||||
reason: 'Code complete, documentation needed',
|
||||
status: 'complete',
|
||||
initiatedAt: new Date(Date.now() - 60000),
|
||||
completedAt: new Date(Date.now() - 30000)
|
||||
};
|
||||
|
||||
// Multi-Agent: Activity
|
||||
activityEntries: AgentActivityEntry[] = [
|
||||
{ id: 'act-1', agentId: 'research', agentName: 'Research Agent', agentFallbackInitials: 'RA', action: 'Searching web for AI agent trends', detail: 'Querying multiple sources including academic papers and tech blogs.', status: 'complete', startedAt: new Date(Date.now() - 120000), completedAt: new Date(Date.now() - 90000) },
|
||||
{ id: 'act-2', agentId: 'research', agentName: 'Research Agent', agentFallbackInitials: 'RA', action: 'Synthesizing findings', status: 'complete', startedAt: new Date(Date.now() - 90000), completedAt: new Date(Date.now() - 60000) },
|
||||
{ id: 'act-3', agentId: 'code', agentName: 'Code Agent', agentFallbackInitials: 'CA', action: 'Generating orchestration architecture', detail: 'Building event-driven coordinator with TypeScript interfaces.', status: 'active', startedAt: new Date(Date.now() - 30000) },
|
||||
{ id: 'act-4', agentId: 'code', agentName: 'Code Agent', agentFallbackInitials: 'CA', action: 'Running test suite', status: 'active', startedAt: new Date(Date.now() - 10000) },
|
||||
{ id: 'act-5', agentId: 'writing', agentName: 'Writing Agent', agentFallbackInitials: 'WA', action: 'Failed to access document store', status: 'error', startedAt: new Date(Date.now() - 15000), completedAt: new Date(Date.now() - 14000) }
|
||||
];
|
||||
|
||||
onAgentSelect(agent: AiAgent) {
|
||||
this.selectedAgentId.set(agent.id);
|
||||
console.log('[Demo] Agent selected:', agent.name);
|
||||
}
|
||||
|
||||
onConversationSwitch(conversation: AgentConversation) {
|
||||
this.activeConversationId.set(conversation.id);
|
||||
console.log('[Demo] Conversation switched:', conversation.agent.name);
|
||||
}
|
||||
|
||||
setView(view: 'canvas' | 'components') {
|
||||
this.currentView.set(view);
|
||||
}
|
||||
@@ -57,10 +359,30 @@ console.log(results);`;
|
||||
console.log('Selected conversation:', conversation);
|
||||
}
|
||||
|
||||
toggleTheme() {
|
||||
const next = this.currentTheme() === 'apple' ? 'mist' : 'apple';
|
||||
document.body.classList.remove(`theme-${this.currentTheme()}`);
|
||||
document.body.classList.add(`theme-${next}`);
|
||||
this.currentTheme.set(next);
|
||||
}
|
||||
|
||||
toggleDarkMode() {
|
||||
this.darkMode.update(v => !v);
|
||||
document.body.classList.toggle('theme-dark', this.darkMode());
|
||||
}
|
||||
|
||||
toggleSidebar() {
|
||||
this.sidebarOpen.update(v => !v);
|
||||
}
|
||||
|
||||
cycleAvatarState() {
|
||||
const states: ('idle' | 'thinking' | 'speaking')[] = ['idle', 'thinking', 'speaking'];
|
||||
const currentIndex = states.indexOf(this.avatarState());
|
||||
const nextIndex = (currentIndex + 1) % states.length;
|
||||
this.avatarState.set(states[nextIndex]);
|
||||
}
|
||||
|
||||
onLog(event: string, data?: unknown) {
|
||||
console.log(`[Demo] ${event}`, data);
|
||||
}
|
||||
}
|
||||
|
||||
123
src/styles.scss
123
src/styles.scss
@@ -3,8 +3,9 @@
|
||||
@use '../../sda-frontend/libs/base-ui/src/styles/tokens/semantic';
|
||||
@use '../../sda-frontend/libs/base-ui/src/styles/tokens/component';
|
||||
|
||||
// Import Apple theme (applies via class)
|
||||
// Import themes (applied via class)
|
||||
@use '../../sda-frontend/libs/base-ui/src/styles/themes/apple';
|
||||
@use '../../sda-frontend/libs/base-ui/src/styles/themes/mist';
|
||||
|
||||
// Base resets
|
||||
*,
|
||||
@@ -15,9 +16,12 @@
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100%;
|
||||
font-family: var(--font-family-sans, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);
|
||||
font-size: var(--font-size-base, 16px);
|
||||
line-height: var(--line-height-base, 1.5);
|
||||
@@ -27,7 +31,7 @@ body {
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
// Apply theme class to body
|
||||
// Default theme class (overridden by JS theme switching)
|
||||
body {
|
||||
@extend .theme-apple;
|
||||
}
|
||||
@@ -57,11 +61,51 @@ body {
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.app__sidebar-toggle {
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
border-radius: var(--radius-md, 8px);
|
||||
cursor: pointer;
|
||||
color: var(--color-text-secondary);
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
background: var(--color-bg-tertiary, #ebebeb);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.app__nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-md, 16px);
|
||||
}
|
||||
|
||||
.app__theme-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border: 1px solid var(--color-border-primary, #e0e0e0);
|
||||
background: var(--color-bg-tertiary, #ebebeb);
|
||||
border-radius: var(--radius-md, 8px);
|
||||
cursor: pointer;
|
||||
font-size: 18px;
|
||||
line-height: 1;
|
||||
transition: all 0.2s ease;
|
||||
margin-left: var(--spacing-sm, 8px);
|
||||
|
||||
&:hover {
|
||||
background: var(--color-bg-primary, #fff);
|
||||
}
|
||||
}
|
||||
|
||||
.app__nav-link {
|
||||
padding: var(--spacing-sm, 8px) var(--spacing-md, 16px);
|
||||
color: var(--color-text-secondary);
|
||||
@@ -90,17 +134,24 @@ body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.app__sidebar-backdrop {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.app__sidebar {
|
||||
width: 280px;
|
||||
background: var(--color-bg-secondary, #f5f5f5);
|
||||
border-right: 1px solid var(--color-border-primary, #e0e0e0);
|
||||
overflow-y: auto;
|
||||
flex-shrink: 0;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.app__content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: var(--spacing-lg, 24px);
|
||||
background-color: var(--color-bg-primary);
|
||||
}
|
||||
|
||||
// Demo sections
|
||||
@@ -146,3 +197,67 @@ body {
|
||||
border-bottom: 1px solid var(--color-border-primary, #e0e0e0);
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// RESPONSIVE — Tablet & Mobile
|
||||
// =============================================================================
|
||||
|
||||
// Tablet: sidebar becomes a slide-over drawer
|
||||
@media (max-width: 1024px) {
|
||||
.app__sidebar-toggle {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.app__sidebar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
z-index: 200;
|
||||
transform: translateX(-100%);
|
||||
box-shadow: none;
|
||||
|
||||
&--open {
|
||||
transform: translateX(0);
|
||||
box-shadow: 4px 0 24px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
.app__sidebar-backdrop {
|
||||
display: block;
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 199;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
animation: fadeIn 0.2s ease;
|
||||
}
|
||||
}
|
||||
|
||||
// Mobile: tighter spacing, single-column demo grid
|
||||
@media (max-width: 640px) {
|
||||
.app__header {
|
||||
padding: var(--spacing-sm, 8px) var(--spacing-md, 16px);
|
||||
}
|
||||
|
||||
.app__nav-link {
|
||||
padding: var(--spacing-xs, 4px) var(--spacing-sm, 8px);
|
||||
font-size: var(--font-size-sm, 14px);
|
||||
}
|
||||
|
||||
.app__content {
|
||||
padding: var(--spacing-md, 16px);
|
||||
}
|
||||
|
||||
.demo-section {
|
||||
padding: var(--spacing-md, 16px);
|
||||
}
|
||||
|
||||
.demo-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user