153 lines
6.1 KiB
Markdown
153 lines
6.1 KiB
Markdown
# Sir Blob's Desktop
|
|
|
|
A portfolio website that recreates my Arch Linux desktop (Hyprland, Quickshell bar, kitty terminals) in the browser. Built with SvelteKit 3, Svelte 5 runes and Tailwind CSS 4.
|
|
|
|
## Running
|
|
|
|
`start` builds the site with Bun (so it does not depend on the system Node version) and serves it with Bun on `PORT` (default 3000), reading `.env` for the Discord variables.
|
|
|
|
```bash
|
|
bun install
|
|
bun run dev
|
|
bun run build
|
|
bun run start
|
|
bun run check
|
|
```
|
|
|
|
## How the desktop works
|
|
|
|
- The top bar mirrors the blob-shell Quickshell bar: chai menu (app launcher), workspaces 1-9, clock, Discord status and theme picker.
|
|
- Every page (`/about`, `/projects/hackathons`, ...) opens as a tiled window, so old resume links still work.
|
|
- Terminals open next to it and tile with the Hyprland dwindle layout.
|
|
- Desktop icons open a page, a terminal running a command, or an external link.
|
|
- On small screens the focused window goes fullscreen and open windows are listed as tabs.
|
|
|
|
### Keybinds
|
|
|
|
| Keys | Action |
|
|
| --- | --- |
|
|
| Alt + Enter | Open a kitty terminal |
|
|
| Alt + Space | App launcher |
|
|
| Alt + Q | Close focused window |
|
|
| Alt + F | Fullscreen the page window |
|
|
| Alt + J / K | Focus next / previous window |
|
|
| Alt + 1-9 | Switch workspace |
|
|
| Alt + T | Next theme |
|
|
|
|
Alt stands in for Super, which browsers do not receive.
|
|
|
|
## Editing content
|
|
|
|
Everything you would normally change lives in `content/`. No code changes needed.
|
|
|
|
| File | Contents |
|
|
| --- | --- |
|
|
| `content/profile.json` | name (shown only on the portfolio page), bio, avatar, education, socials (also used by the links page), skills, interests |
|
|
| `content/experience.json` | experience with highlights, tech, awards and links |
|
|
| `content/leadership.json` | leadership roles |
|
|
| `content/about.json` | hobbies, games, shows, movies |
|
|
| `content/projects/opensource.json` | open source projects |
|
|
| `content/projects/packages.json` | published packages |
|
|
| `content/projects/hackathons.json` | hackathon projects, events and awards |
|
|
| `content/projects/research.json` | research roles and projects |
|
|
| `content/models.json` | 3D models (files go in `static/models/`) |
|
|
| `content/desktop.json` | default theme, workspaces, desktop icons, startup command |
|
|
| `content/blog.json` | blog name, tagline, posts per page |
|
|
| `content/blog/*.md` | blog posts |
|
|
|
|
### Projects
|
|
|
|
Every project in every category uses the same shape. Only `name`, `description`, `tags` and `links` are required.
|
|
|
|
```json
|
|
{
|
|
"name": "HushMap",
|
|
"description": "What it does.",
|
|
"image": "/hacks/hushmap.png",
|
|
"tags": ["Svelte", "FastAPI"],
|
|
"featured": true,
|
|
"event": { "name": "Bitcamp 2026", "university": "University of Maryland", "location": "College Park, MD", "year": "2026" },
|
|
"awards": [{ "track": "Best UI/UX Hack", "place": "Winner" }],
|
|
"demoMayBeOffline": false,
|
|
"version": "2.2.0",
|
|
"links": { "demo": "https://...", "code": "https://...", "devpost": "https://...", "package": "https://...", "article": "https://..." }
|
|
}
|
|
```
|
|
|
|
Featured projects are listed first.
|
|
|
|
### Desktop icons
|
|
|
|
Each icon in `content/desktop.json` has a `label`, an Iconify `icon` and one `open` action:
|
|
|
|
```json
|
|
{ "label": "about", "icon": "mdi:account", "open": { "page": "/about" } }
|
|
{ "label": "skills.sh", "icon": "mdi:script-text", "open": { "terminal": "skills" } }
|
|
{ "label": "github", "icon": "mdi:github", "open": { "url": "https://github.com/SirBlobby" } }
|
|
```
|
|
|
|
`{ "terminal": "" }` opens an empty terminal.
|
|
|
|
### Blog posts
|
|
|
|
Add a markdown file to `content/blog/`. The file name is the URL slug.
|
|
|
|
```markdown
|
|
---
|
|
title: My Post Title
|
|
author: Sir Blob
|
|
date: 2026-01-01
|
|
tags: meta, notes
|
|
excerpt: One line summary for the list and the RSS feed.
|
|
---
|
|
|
|
Post content in markdown.
|
|
```
|
|
|
|
The RSS feed is at `/blog/rss.xml`.
|
|
|
|
## Themes
|
|
|
|
Themes live in `src/lib/theme/themes.ts` and use the same keys as a blomarchy `colors.toml`, so a theme can be copied over from the dotfiles. Each theme can set a `wallpaper` (from `static/wallpapers/`) and an `activeBorder` gradient. The default theme is set in `content/desktop.json`.
|
|
|
|
Shipped themes: Flats (default), Retro 82, Tokyo Night, Catppuccin, Arch Linux, Gruvbox, Nord, Kanagawa, Wintry, Rose, Cerberus, Catppuccin Latte, Rose Pine Dawn.
|
|
|
|
## Terminal commands
|
|
|
|
`help`, `whoami`, `fastfetch`, `skills`, `contact`, `email`, `experience`, `projects [category]`, `ls`, `cd <page>`, `theme [name]`, `echo`, `cowsay`, `date`, `clear`, `exit`. Page names (`about`, `hackathons`, ...) and social names (`github`, `linkedin`, ...) also work as commands. Tab completes commands, pages after `cd`, themes after `theme` and categories after `projects`; when several match it lists them like bash. Up/Down walk history, Ctrl+L clears.
|
|
|
|
Commands live in `src/lib/terminal/commands/`.
|
|
|
|
## Code layout
|
|
|
|
| Path | Contents |
|
|
| --- | --- |
|
|
| `src/lib/content/` | typed loader for `content/` |
|
|
| `src/lib/blog/` | markdown renderer, frontmatter, highlighting, dates |
|
|
| `src/lib/theme/` | theme palettes, stylesheet generation, current theme state |
|
|
| `src/lib/desktop/` | window manager, dwindle tiling, keybinds, desktop actions |
|
|
| `src/lib/terminal/` | terminal output model and commands |
|
|
| `src/lib/site/pages.ts` | page list used by the terminal and launcher |
|
|
| `src/lib/components/shell/` | bar, workspaces, clock, theme menu, Discord status |
|
|
| `src/lib/server/discord.ts` | Discord bot and presence lookup |
|
|
| `src/lib/components/desktop/` | desktop, windows, icons, launcher |
|
|
| `src/lib/components/terminal/` | kitty terminal |
|
|
| `src/lib/components/ui/` | shared page pieces |
|
|
| `src/routes/` | pages |
|
|
|
|
## Discord status
|
|
|
|
The bar shows live Discord presence (status, avatar, guild tag, activities). A discord.js bot starts with the server (`src/hooks.server.ts`) and the bar polls `/api/discord` every 30 seconds. Copy `.env.example` to `.env` and fill in:
|
|
|
|
| Variable | Value |
|
|
| --- | --- |
|
|
| `DISCORD_TOKEN` | bot token, with the Server Members and Presence intents enabled |
|
|
| `DISCORD_USER_ID` | your user id |
|
|
| `DISCORD_GUILD_ID` | a server both you and the bot are in |
|
|
|
|
Variables are declared in `src/env.ts`. Without them the widget shows your profile name as offline.
|
|
|
|
## Analytics
|
|
|
|
Umami is loaded in `src/app.html`.
|