A twitter-esque microblogging platform for my short yaps
- Markdown Posts - Write content using Markdown with support for images, footnotes, and tags
- Threads - Organize related posts into grouped threads
- GitHub-Backed Content - All content is stored in a GitHub repository, version-controlled and easy to manage
- Search - Find posts by content, thread title, or tags
- Theming - Light and dark mode support
- Authentication - GitHub OAuth authentication for users
- Responsive Design - Works beautifully on desktop and mobile
- Framework: SvelteKit with Svelte 5
- Runtime: Bun
- Styling: Tailwind CSS v4
- UI Components: shadcn-svelte
- Authentication: Better Auth
- Content: GitHub repository via GitHub API
- Markdown: marked with DOMPurify sanitization
- Bun runtime
- GitHub Personal Access Token (for content fetching)
# Clone the repository
git clone <repository-url>
cd yaplet
# Install dependencies
bun install
# Copy environment variables
cp .env.example .envCreate a .env file with the following variables:
# GitHub PAT with repo or public_repo scope (read-only)
GITHUB_PAT=ghp_xxxxxxxxxxxxxxxxxxxx
# Base URL for content (raw.githubusercontent.com format)
CONTENT_BASE_URL=https://raw.githubusercontent.com/{owner}/{repo}/refs/heads/{branch}/{path}bun devOpen http://localhost:5173 in your browser.
bun buildPreview the production build:
bun preview| Endpoint | Description |
|---|---|
GET /api/v1/feed |
Fetch all posts and threads |
GET /api/v1/post/:id |
Fetch single post by ID |
GET /api/v1/thread/:id |
Fetch thread by ID |
POST /api/v1/batch/post |
Fetch multiple posts by ID |
Content is stored in a separate GitHub repository. The expected structure:
content/
├── manifest.json
├── standalone/
│ ├── post-1.md
│ └── post-2.md
└── threads/
├── thread-1/
│ ├── meta.json
│ └── post-1.md
└── thread-2/
├── meta.json
└── post-1.md
{
"standalone": ["post-1.md", "post-2.md"],
"threads": ["thread-1", "thread-2"]
}{
"id": "thread-1",
"title": "Discussion Title",
"description": "Brief description",
"createdAt": "2024-01-01T00:00:00Z",
"posts": ["post-1.md", "post-2.md"]
}---
createdAt: 2024-01-01T00:00:00Z
images: ['https://example.com/image.jpg']
likes: 42
tags: ['discussion', 'idea']
footnotes:
note1: 'Footnote content'
---
Your post content here...┌─────────────────────────────────────────────────────┐
│ Frontend (SvelteKit) │
│ ┌─────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ │
│ │ Threads │ │ Posts │ │ Feed │ │ Auth │ │
│ └─────────┘ └──────────┘ └──────────┘ └─────────┘ │
│ │ │ │ │ │
│ └───────────┴──────────────┴───────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ API Routes │ │
│ │ /api/v1/* │ │
│ └──────────┬──────────┘ │
└─────────────────────────┼────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ Server Modules (lib/server/) │
│ ┌─────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ │
│ │ Auth │ │ GitHub │ │ Posts │ │ Threads │ │
│ └─────────┘ └──────────┘ └──────────┘ └─────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ GitHub API │ │
│ └─────────────┘ │
└─────────────────────────────────────────────────────┘
src/
├── lib/
│ ├── components/ # Shared UI components (shadcn-svelte)
│ ├── features/ # Feature-scoped components
│ │ ├── markdown/ # Markdown rendering & sanitization
│ │ ├── post/ # Post-related components
│ │ └── thread/ # Thread-related components
│ ├── server/ # Server-side modules
│ │ ├── auth.server.ts
│ │ ├── github/ # GitHub API & caching
│ │ ├── manifest/ # Manifest fetching
│ │ ├── post/ # Post fetching & processing
│ │ └── thread/ # Thread fetching
│ └── shared/ # Shared schemas & types
├── routes/
│ ├── +layout.svelte # Global layout with auth
│ ├── +page.svelte # Feed page
│ ├── api/v1/ # API endpoints
│ ├── post/[postId]/ # Single post page
│ └── thread/[threadId]/ # Thread page
└── app.d.ts
Content is fetched server-side via lib/server/ modules, ensuring your GitHub PAT never leaks to the client.
bun dev- Start development serverbun build- Build for productionbun preview- Preview production buildbun check- Run TypeScript and Svelte checksbun format- Format code with Prettierbun lint- Lint with ESLint and Prettier
This project uses Nix for development environment reproducibility.
# Enter the dev shell (if Nix is installed)
nix-shell ./nix/devShell.nix
# Or use direnv to automatically load the environment
direnv allowMIT