Skip to content

Commit ce98aa0

Browse files
committed
implement home page
1 parent 60cd181 commit ce98aa0

23 files changed

+859
-17
lines changed
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
# Console Carousel - Maintenance Guide
2+
3+
## Overview
4+
5+
The Console Carousel is an interactive component that showcases llms.py features through terminal-style screens. It's designed to be easy to maintain and update.
6+
7+
## File Structure
8+
9+
```
10+
app/(home)/
11+
├── console-carousel.tsx # Main carousel component
12+
├── console-screens.ts # Screen data (EDIT THIS to add/remove screens)
13+
└── page.tsx # Home page (includes the carousel)
14+
```
15+
16+
## Adding a New Console Screen
17+
18+
To add a new screen, edit `console-screens.ts` and add a new object to the `consoleScreens` array:
19+
20+
```typescript
21+
{
22+
id: 'unique-id', // Unique identifier
23+
title: '🎯 Feature Name', // Title with emoji
24+
description: 'Brief description', // Short description
25+
command: 'llms --example "query"', // The command to show
26+
output: `Output text here...` // The terminal output
27+
}
28+
```
29+
30+
### Example: Adding a Docker Command Screen
31+
32+
```typescript
33+
{
34+
id: 'docker-deploy',
35+
title: '🐳 Docker Deployment',
36+
description: 'Run llms.py in a Docker container',
37+
command: 'docker run -p 8000:8000 -e GROQ_API_KEY=$GROQ_API_KEY ghcr.io/servicestack/llms:latest',
38+
output: `🐳 Pulling image ghcr.io/servicestack/llms:latest...
39+
✓ Image pulled successfully
40+
41+
🚀 Starting container...
42+
✓ Container started
43+
44+
🌐 Server running at:
45+
• Web UI: http://localhost:8000
46+
• API: http://localhost:8000/v1/chat/completions
47+
48+
Container ID: a1b2c3d4e5f6`
49+
}
50+
```
51+
52+
## Removing a Console Screen
53+
54+
Simply delete the corresponding object from the `consoleScreens` array in `console-screens.ts`.
55+
56+
## Reordering Screens
57+
58+
The screens appear in the order they're defined in the array. To change the order, simply move the objects around in `console-screens.ts`.
59+
60+
## Tips for Creating Good Console Screens
61+
62+
### 1. Use Realistic Commands
63+
Base your commands on actual llms.py documentation. Check:
64+
- `content/docs/features/cli.mdx`
65+
- `content/docs/multimodal/*.mdx`
66+
- `content/docs/getting-started/*.mdx`
67+
68+
### 2. Keep Output Concise
69+
- Aim for 5-15 lines of output
70+
- Use clear formatting (bullets, sections, emojis)
71+
- Make it scannable and easy to read
72+
73+
### 3. Add Visual Interest
74+
- Use emojis in titles (🎯 💬 🖼️ 🎤 📄 🌐 ⚙️)
75+
- Use symbols in output (✓ ✗ • → ├ └ ┌ ┐)
76+
- Add color through formatting (the terminal uses syntax highlighting)
77+
78+
### 4. Show Real Value
79+
Each screen should demonstrate a specific, useful feature:
80+
- ✅ "Analyze images with vision models"
81+
- ✅ "Transcribe audio files"
82+
- ❌ "Run a command" (too vague)
83+
84+
### 5. Format Output Nicely
85+
```typescript
86+
output: `Section Header:
87+
88+
📊 Key Points:
89+
• Point one
90+
• Point two
91+
• Point three
92+
93+
✅ Results:
94+
Item 1: Value
95+
Item 2: Value`
96+
```
97+
98+
## Customizing the Carousel
99+
100+
### Change Auto-Play Speed
101+
102+
In `page.tsx`, modify the `autoPlayInterval` prop (in milliseconds):
103+
104+
```typescript
105+
<ConsoleCarousel
106+
screens={consoleScreens}
107+
autoPlayInterval={7000} // 7 seconds instead of default 5
108+
/>
109+
```
110+
111+
### Disable Auto-Play
112+
113+
Set a very high interval or modify the component to not auto-play by default.
114+
115+
### Styling
116+
117+
The carousel uses Tailwind CSS classes. To customize:
118+
- Edit `console-carousel.tsx` for component styling
119+
- Terminal colors are defined in the component (green prompt, slate text, etc.)
120+
121+
## Testing Your Changes
122+
123+
1. Save your changes to `console-screens.ts`
124+
2. The dev server will hot-reload automatically
125+
3. Check the home page at `http://localhost:3000`
126+
4. Navigate through all screens to verify they look good
127+
5. Test on both light and dark modes
128+
129+
## Common Issues
130+
131+
### Screen Text Too Long
132+
- Break into multiple lines using `\n`
133+
- Use template literals with backticks for multi-line strings
134+
- Keep terminal output under 20 lines for best UX
135+
136+
### Command Doesn't Fit
137+
- Commands automatically truncate on small screens
138+
- Keep commands under 80 characters when possible
139+
- Use line breaks for very long commands
140+
141+
### Emojis Not Showing
142+
- Ensure you're using standard Unicode emojis
143+
- Test in multiple browsers
144+
145+
## Best Practices
146+
147+
1. **Keep it current**: Update screens when new features are added
148+
2. **Show variety**: Mix different types of commands (chat, multimodal, config)
149+
3. **Be accurate**: Commands should actually work as shown
150+
4. **Test thoroughly**: Check all screens before deploying
151+
5. **Get feedback**: Ask users which screens are most helpful
152+
153+
## Quick Reference: Common llms.py Commands
154+
155+
```bash
156+
# Basic
157+
llms "question"
158+
llms -m model "question"
159+
llms -s "system prompt" "question"
160+
161+
# Multimodal
162+
llms --image file.png "question"
163+
llms --audio file.mp3 "question"
164+
llms --file document.pdf "question"
165+
166+
# Server
167+
llms --serve 8000
168+
llms --serve 8000 --verbose
169+
170+
# Configuration
171+
llms --init
172+
llms --list / llms ls
173+
llms --enable provider
174+
llms --disable provider
175+
llms --default model
176+
llms --check provider
177+
```
178+
179+
## Need Help?
180+
181+
- Check the docs: `/content/docs/`
182+
- See examples in: `content/docs/features/cli.mdx`
183+
- Review existing screens in: `console-screens.ts`
184+

app/(home)/console-carousel.tsx

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
'use client'
2+
3+
import { FC, useState, useEffect } from "react"
4+
import { ChevronLeft, ChevronRight, Terminal, Copy, Check } from "lucide-react"
5+
import { cn } from "@/lib/utils"
6+
7+
export interface ConsoleScreen {
8+
id: string
9+
title: string
10+
description: string
11+
command: string
12+
output: string
13+
}
14+
15+
interface ConsoleCarouselProps {
16+
screens: ConsoleScreen[]
17+
autoPlayInterval?: number
18+
className?: string
19+
}
20+
21+
export const ConsoleCarousel: FC<ConsoleCarouselProps> = ({
22+
screens,
23+
autoPlayInterval = 10_000,
24+
className
25+
}) => {
26+
const [currentIndex, setCurrentIndex] = useState(0)
27+
const [copied, setCopied] = useState(false)
28+
const [isPaused, setIsPaused] = useState(false)
29+
30+
useEffect(() => {
31+
if (isPaused || screens.length <= 1) return
32+
33+
const interval = setInterval(() => {
34+
setCurrentIndex((prev) => (prev + 1) % screens.length)
35+
}, autoPlayInterval)
36+
37+
return () => clearInterval(interval)
38+
}, [isPaused, screens.length, autoPlayInterval])
39+
40+
const goToNext = () => {
41+
setCurrentIndex((prev) => (prev + 1) % screens.length)
42+
}
43+
44+
const goToPrevious = () => {
45+
setCurrentIndex((prev) => (prev - 1 + screens.length) % screens.length)
46+
}
47+
48+
const goToSlide = (index: number) => {
49+
setCurrentIndex(index)
50+
}
51+
52+
const copyCommand = async () => {
53+
try {
54+
await navigator.clipboard.writeText(screens[currentIndex].command)
55+
setCopied(true)
56+
setTimeout(() => setCopied(false), 2000)
57+
} catch (err) {
58+
console.error('Failed to copy:', err)
59+
}
60+
}
61+
62+
const currentScreen = screens[currentIndex]
63+
64+
return (
65+
<div
66+
className={cn("relative w-full w-[780px]", className)}
67+
onMouseEnter={() => setIsPaused(true)}
68+
onMouseLeave={() => setIsPaused(false)}
69+
>
70+
{/* Header with title and description */}
71+
<div className="mb-4 text-center min-h-[60px] flex flex-col justify-center">
72+
<h3 className="text-lg font-semibold text-slate-900 dark:text-slate-100 mb-1">
73+
{currentScreen.title}
74+
</h3>
75+
<p className="text-sm text-slate-600 dark:text-slate-400">
76+
{currentScreen.description}
77+
</p>
78+
</div>
79+
80+
{/* Terminal Window */}
81+
<div className="relative w-full rounded-lg border border-slate-300 dark:border-slate-700 bg-slate-900 shadow-2xl overflow-hidden">
82+
{/* Terminal Header */}
83+
<div className="flex items-center justify-between px-4 py-2 bg-slate-800 border-b border-slate-700">
84+
<div className="flex items-center gap-2">
85+
<div className="flex gap-1.5">
86+
<div className="w-3 h-3 rounded-full bg-red-500" />
87+
<div className="w-3 h-3 rounded-full bg-yellow-500" />
88+
<div className="w-3 h-3 rounded-full bg-green-500" />
89+
</div>
90+
<Terminal className="w-4 h-4 text-slate-400 ml-2" />
91+
<span className="text-xs text-slate-400 font-mono">terminal</span>
92+
</div>
93+
<button
94+
onClick={copyCommand}
95+
className={cn(
96+
"flex items-center gap-1.5 px-2 py-1 rounded text-xs font-medium transition-all",
97+
copied
98+
? "bg-green-600 text-white"
99+
: "bg-slate-700 text-slate-300 hover:bg-slate-600"
100+
)}
101+
aria-label={copied ? "Copied!" : "Copy command"}
102+
>
103+
{copied ? (
104+
<>
105+
<Check className="w-3 h-3" />
106+
Copied
107+
</>
108+
) : (
109+
<>
110+
<Copy className="w-3 h-3" />
111+
Copy
112+
</>
113+
)}
114+
</button>
115+
</div>
116+
117+
{/* Terminal Content */}
118+
<div className="p-6 font-mono text-sm h-[450px] overflow-auto text-left">
119+
{/* Command Line */}
120+
<div className="mb-3">
121+
<span className="text-green-400 select-none">$ </span>
122+
<span className="text-slate-100">{currentScreen.command}</span>
123+
</div>
124+
125+
{/* Output */}
126+
<div className="text-slate-300 whitespace-pre-wrap leading-relaxed">
127+
{currentScreen.output}
128+
</div>
129+
</div>
130+
</div>
131+
132+
{/* Navigation Controls */}
133+
<div className="flex items-center justify-center gap-4 mt-6">
134+
<button
135+
onClick={goToPrevious}
136+
className="p-2 rounded-full bg-slate-200 dark:bg-slate-800 text-slate-700 dark:text-slate-300 hover:bg-slate-300 dark:hover:bg-slate-700 transition-colors"
137+
aria-label="Previous screen"
138+
>
139+
<ChevronLeft className="w-5 h-5" />
140+
</button>
141+
142+
{/* Dots Indicator */}
143+
<div className="flex gap-2">
144+
{screens.map((_, index) => (
145+
<button
146+
key={index}
147+
onClick={() => goToSlide(index)}
148+
className={cn(
149+
"h-2 rounded-full transition-all",
150+
index === currentIndex
151+
? "bg-slate-900 dark:bg-slate-100 w-8"
152+
: "bg-slate-300 dark:bg-slate-700 hover:bg-slate-400 dark:hover:bg-slate-600 w-2"
153+
)}
154+
aria-label={`Go to screen ${index + 1}`}
155+
/>
156+
))}
157+
</div>
158+
159+
<button
160+
onClick={goToNext}
161+
className="p-2 rounded-full bg-slate-200 dark:bg-slate-800 text-slate-700 dark:text-slate-300 hover:bg-slate-300 dark:hover:bg-slate-700 transition-colors"
162+
aria-label="Next screen"
163+
>
164+
<ChevronRight className="w-5 h-5" />
165+
</button>
166+
</div>
167+
</div>
168+
)
169+
}
170+

0 commit comments

Comments
 (0)