A minimal, self-hosted startpage dashboard for organizing your bookmarks and services. Configure everything through a simple YAML file.
- YAML Configuration - No database, no complex setup. Just edit one file.
- Theme Presets - Nord, Catppuccin, Dracula, Gruvbox, Tokyo Night, Rose Pine
- Health Monitoring - Automatic status checks for your services
- Widgets - Clock, search bar, and more
- Responsive - Works on desktop and mobile
- Docker Ready - Mount your config and go
# Create config directory
mkdir -p config
# Create your configuration
cat > config/dashboard.yaml << 'EOF'
theme:
preset: 'dracula'
mode: 'dark'
display:
columns: 1
greeting:
enabled: true
locale: 'en'
datetime:
enabled: true
locale: 'en-US'
hour12: false
showSeconds: true
dateFormat: 'full'
healthCheck:
enabled: true
interval: 60
timeout: 5000
showStatus: true
sections:
- name: 'Apps'
items:
- name: 'GitHub'
url: 'https://github.com'
icon: 'github'
widgets:
- type: 'clock'
position: 'top-left'
config:
showDate: true
- type: 'search'
position: 'top-center'
config:
engine: 'duckduckgo'
placeholder: 'Search...'
EOF
# Run with Docker
docker run -d \
--name dashboard \
-p 5005:3000 \
-v $(pwd)/config:/config \
dashboard:latest# docker-compose.yaml
services:
dashboard:
build: .
ports:
- '5005:3000'
volumes:
- ./config:/config
restart: unless-stoppeddocker compose up -d# Install dependencies
bun install
# Start development server
bun run dev
# Build for production
bun run build
# Run production build
bun ./build/index.jsAll settings live in config/dashboard.yaml. The dashboard reloads config on each page refresh.
theme:
preset: 'dracula' # nord, catppuccin, dracula, gruvbox, tokyo-night, rose-pine
mode: 'dark' # light, dark, systemdisplay:
columns: 4 # Number of section columns (1-6)
greeting:
enabled: true
locale: 'en' # en, de, fr, es, it, pt, nl, pl, ru, ja, zh, ko
datetime:
enabled: true
locale: 'en-US'
hour12: false
showSeconds: true
dateFormat: 'full' # full, long, medium, short
healthCheck:
enabled: true
interval: 60 # Check every 60 seconds
timeout: 5000 # 5 second timeout
showStatus: true # Show status dots on itemsOrganize your bookmarks into sections:
sections:
- name: 'Media'
icon: 'tv' # Optional Lucide icon for header
items:
- name: 'Jellyfin'
url: 'https://jellyfin.example.com'
icon: 'play-circle'
description: 'Media server' # Shows on hover
- name: 'Sonarr'
url: 'https://sonarr.example.com'
icon: 'tv'
- name: 'Tools'
items:
- name: 'Portainer'
url: 'https://portainer.example.com'
icon: 'container'Icons use Lucide. Use the icon name in kebab-case:
home,settings,searchtv,film,musiccloud,download,uploadgithub,mail,rsscheck-circle,layout-grid,refresh-cw
If no icon is specified, the first letter of the name is shown.
widgets:
- type: 'clock'
position: 'top-left' # top-left, top-center, top-right, bottom-*
config:
showDate: true
showAnalog: falsewidgets:
- type: 'search'
position: 'top-center'
config:
engine: 'duckduckgo' # google, duckduckgo, brave
placeholder: 'Search the web...'Requires an OpenWeatherMap API key:
widgets:
- type: 'weather'
position: 'top-right'
variant: 'icon-info'
refreshInterval: 900 # 15 minutes
config:
apiKey: '${WEATHER_API_KEY}' # Use environment variable
location: 'Berlin,DE'
units: 'metric'Use ${VAR_NAME} syntax in YAML to reference environment variables:
config:
apiKey: '${MY_API_KEY}'Then set the variable:
docker run -e MY_API_KEY=your-key-here ...When healthCheck.enabled is true, the dashboard periodically checks if your services are reachable:
- Green dot - Service is online
- Red dot - Service is unreachable
- Gray dot - Status unknown
The dashboard makes HEAD requests to each URL. Services behind authentication may show as unreachable unless they respond to unauthenticated requests.
| Theme | Description |
|---|---|
| nord | Cool, bluish arctic colors |
| catppuccin | Soothing pastel theme |
| dracula | Dark purple with vibrant pops |
| gruvbox | Retro groove with warm colors |
| tokyo-night | Dark theme inspired by Tokyo |
| rose-pine | Natural, muted dark theme |
# Install dependencies
bun install
# Start dev server with hot reload
bun run dev
# Type check
bun run check
# Lint
bun run lint
# Format
bun run format
# Build
bun run buildconfig/
└── dashboard.yaml # Your configuration
src/
├── routes/
│ ├── +page.svelte # Main dashboard page
│ └── api/ # API endpoints
├── lib/
│ ├── components/ # Svelte components
│ ├── themes/ # Theme presets
│ ├── server/ # Config loading
│ └── types/ # TypeScript types
Icons are loaded dynamically from Lucide. Common icons are pre-bundled for performance. To add more, edit src/lib/utils/icons.ts.
- Check that
config/dashboard.yamlexists - Verify YAML syntax is valid
- Check Docker volume mount:
-v $(pwd)/config:/config
- Use valid Lucide icon names (kebab-case)
- Check browser console for errors
- Ensure services are accessible from the dashboard container
- Check
timeoutsetting (default 5000ms) - Services requiring authentication may fail health checks
MIT