Pure SSG (Snapshot Model) - Zero runtime fetch architecture:
- All data is fetched during build process via widget fetchers
- No client-side API calls
- Each widget has its own fetcher that runs during Astro build
- Data is embedded directly into static HTML
- Core: Astro (latest), React (Islands), TypeScript
- Styling: Tailwind CSS v4 (Oxide engine), Framer Motion
- UI: shadcn/ui, Magic UI, Lucide React icons
- Layout: CSS Grid-based Bento Grid (responsive)
- Tooling: Biome (Lint/Format), Bun (Runtime & Scripting)
- Bun (latest version)
# Install dependencies
bun install
# Start development server (fetches data automatically)
bun run dev
# Build for production (includes data fetching)
bun run build
# Preview production build
bun run preview- Fork this repository
- Enable GitHub Actions: Go to the Actions tab in your forked repository and click "I understand my workflows, go ahead and enable them"
- Go to Settings → Pages and set source to GitHub Actions
- Push any change to trigger the deployment workflow
The site will be deployed to https://<your-username>.github.io/gaze/
Note: GitHub disables workflows in forked repositories by default for security reasons. You must manually enable them in step 2.
By default, the dashboard rebuilds every 6 hours to fetch fresh data. To change this schedule:
- Edit .github/workflows/deploy.yml
- Modify the
cronexpression in theschedulesection:schedule: - cron: '0 */6 * * *' # Every 6 hours
Common schedules:
- Every hour:
'0 * * * *' - Every 3 hours:
'0 */3 * * *' - Every 12 hours:
'0 */12 * * *' - Daily at midnight UTC:
'0 0 * * *'
Learn more about cron syntax at crontab.guru.
Configure your dashboard in src/config/gaze.ts using a declarative, type-safe approach.
export const gazeConfig = {
pages: [
{
name: 'Home',
width: 'wide',
columns: [
{
size: 'small',
widgets: [
{ type: 'weather', location: 'Shanghai' }
]
},
{
size: 'full',
widgets: [
{ type: 'hacker-news', limit: 15 }
]
}
]
}
]
} satisfies GazeConfig📖 Configuration Guide (CONFIG.md) - Complete guide covering:
- Page layouts and column structures
- All available widgets with parameters
- Data structures and type definitions
- Complete examples and best practices
🔧 Widget Development (src/widgets/README.md) - Learn how to create custom widgets
Layout Widgets:
- Group - Display widgets with tab navigation
- Split Column - Place widgets side-by-side
Content Widgets:
- Weather - Current weather & 24-hour forecast
- RSS - RSS/Atom feed reader
- YouTube - Recent videos from channels
- Hacker News - Top stories from HN
- Lobsters - Posts from Lobsters community
The dashboard uses a pure SSG (Static Site Generator) architecture:
- ✅ All data fetched during build time (
bun run buildorbun run dev) - ✅ Zero runtime fetch - no client-side API calls
- ✅ Parallel widget data fetching (max 10 concurrent)
- ✅ Graceful error handling - failed widgets show error state
gaze/
├── src/
│ ├── components/ # React components (BentoGrid, etc.)
│ ├── config/ # Dashboard configuration
│ ├── layouts/ # Astro layouts
│ ├── lib/ # Utility functions (widgetData.ts)
│ ├── pages/ # Astro pages (index.astro)
│ ├── styles/ # Global styles & Tailwind config
│ └── widgets/ # Widget definitions (component + fetcher)
├── public/ # Static assets
└── astro.config.mjs # Astro configuration
- Dark Mode by default
- Glassmorphism effect (blur, subtle borders)
- Instant load (static HTML)
- Animated transitions via Framer Motion
# Check code quality
bun run lint
# Format code
bun run format
# Check and fix
bun run checkYou can set your deployed Gaze dashboard as your browser's new tab page using the New Tab Redirect Chrome extension:
- Install New Tab Redirect from Chrome Web Store
- Click the extension icon and go to Options
- In the Redirect URL field, enter your GitHub Pages URL (e.g.,
https://yourusername.github.io/gaze/) - Click Save
Now every new tab will open your personalized Gaze dashboard.
MIT

