Skip to content
cholf5Public

About

A minimalist personal diary that lives inside your own GitHub repository.

Resources

Contributing

Security policy

Stars

17 stars

Watchers

0 watching

Forks

Repository files navigation

GitDiary logo

GitDiary

A minimalist personal diary that lives inside your own GitHub repository.

No backend. No database. No server costs. Just you, your browser, and Git.

.NET Blazor WASM Storage License PRs Welcome

English · 简体中文


🌟 Why GitDiary?

Git is your storage layer, not your backup layer.

  • 🔐 You own your data — every entry is a plain Markdown file in your repo.
  • 🪶 Zero infrastructure — a single Blazor WASM bundle, hostable on GitHub Pages.
  • 🧘 Distraction-free — one page, one editor, one keystroke to save.
  • 🕰 Full Git history — every diary edit is a commit. Time-travel included, for free.
  • 🚫 No vendor lock-in — clone the repo, cat your .md files, walk away anytime.

✨ Features

✍️ Write Daily entries, live Markdown editing
💾 Autosave 2-second debounce → IndexedDB → GitHub
📅 Browse Navigate history by year / month / day
🔍 Search Instant full-text search across every entry
👀 Preview Toggle between raw Markdown and rendered view
📶 Offline Keep writing without a network; sync resumes automatically
⚔️ Conflicts Detected on SHA mismatch — pick Overwrite or Reload
🎨 Dark theme Handcrafted CSS, no Bootstrap, no heavy UI kit

🏗 Architecture

+---------------------+
|      Browser        |
+----------+----------+
           |
           v
+---------------------+
|  Blazor WASM App    |
+----------+----------+
           |
           +----------------+
           |                |
           v                v
+----------------+  +----------------+
| IndexedDB      |  | GitHub REST    |
| (drafts/cache) |  | (source truth) |
+----------------+  +----------------+

Tech stack: Blazor WebAssembly (.NET 10) · Markdig · Blazored.LocalStorage · GitHub REST API · IndexedDB

Data layout in your repo:

Diary/
  2026/
    07/
      12.md   ← one Markdown file per day

Each file is just Markdown — no frontmatter, no proprietary schema:

# 2026-07-12

Today I set up GitDiary. It was surprisingly easy!

🚀 How to Use

This section walks you through going from zero to writing your first entry.

1. Create a GitHub repository for your diary

  1. Sign in to GitHub and go to Create a new repository.
  2. Fill in the form:
    • Repository name: anything you like — my-diary is a good default.
    • Visibility: Private is strongly recommended (this repo will hold your personal writing).
    • Initialize this repository with a README: ✅ tick it, so the default branch exists.
  3. Click Create repository.
  4. Note three values you'll need shortly:
    • Owner — your GitHub username or organization name
    • Repo — the repository name you just chose
    • Branch — usually main

💡 You can use an existing repository too. GitDiary only writes inside a top-level Diary/ folder, so it won't collide with the rest of your files.

2. Generate a Fine-Grained Personal Access Token (PAT)

GitDiary talks to GitHub directly from your browser and needs a token with write access to that one repository.

  1. Open Settings → Developer settings → Personal access tokens → Fine-grained tokens.
  2. Click Generate new token.
  3. Configure it:
    • Token name: GitDiary
    • Expiration: whatever you're comfortable with (90 days, 1 year, custom…)
    • Repository access: Only select repositories → pick the diary repo from step 1.
    • Repository permissions:
      • Contents → Read and write ✅ (required)
      • Everything else can stay No access.
  4. Click Generate token and copy the value immediately — GitHub will never show it again.

⚠️ Treat this token like a password. It's stored only in your browser's localStorage; GitDiary never sends it anywhere except to api.github.com.

3. Connect GitDiary to your repository

  1. Open GitDiary in your browser (see Run locally below, or use your hosted deployment).
  2. The Setup Wizard appears on first launch. Fill in:
    • Owner → your GitHub username
    • Repository → the repo you created
    • Branch → main (or whatever your default branch is)
    • Personal Access Token → paste the token from step 2
  3. Click Test & Save. GitDiary will:
    • ✅ read your repo tree (verifies token + repo)
    • ✅ perform a tiny write test (verifies the Contents: Read and write permission)
  4. Wizard closes → the editor opens on today's entry. Start typing!

🔁 Need to change repo or rotate your token later? Click the ⚙️ button in the sidebar to reopen the wizard.

4. Run locally (optional)

If you want to build and run GitDiary yourself:

# Prerequisites: .NET 10 SDK
cd src/GitDiary.Client
dotnet build            # 0 warnings enforced
dotnet run              # http://localhost:5016
# or, for hot reload:
dotnet watch run

Run the tests (the Markdown sanitizer suite is the security-critical one):

dotnet test tests/GitDiary.Tests

Publish a static build (deployable to GitHub Pages / Netlify / Cloudflare Pages / any static host):

dotnet publish src/GitDiary.Client -c Release -o publish

# REQUIRED. Without this the app hangs forever on the loading spinner.
python3 .github/scripts/pin_importmap_csp.py publish/wwwroot/index.html

# static output lives in: publish/wwwroot/

⚠️ Do not skip the second command. The app's CSP deliberately omits script-src 'unsafe-inline', so that a hypothetical XSS in the Markdown preview cannot execute and read your PAT out of localStorage. But dotnet publish generates an inline import map whose contents change on every build, and the browser blocks it unless the CSP carries its hash. The script computes that hash and pins it. Skip it and Blazor never boots — the page just spins, with no error shown. CI (deploy.yml) runs it for you; a manual publish does not.

5. Daily workflow

  • Write — open GitDiary, today's entry is already selected. Type freely.
  • Save — happens automatically 2 seconds after your last keystroke, or press Ctrl + S.
  • Preview — toggle to see the rendered Markdown.
  • Browse — pick any past date from the left sidebar.
  • Search — hit the search box to full-text search across every entry.
  • Offline — lose your connection? Keep writing. The status bar shows Pending, and GitDiary re-syncs when you're back online.

That's it. Your diary lives in Git; you can git clone it, grep it, back it up, or read it in plain text forever.

📦 Project Structure

src/GitDiary.Client/
├── Components/       # Blazor UI components
│   ├── DiaryEditor.razor
│   ├── SearchBox.razor
│   ├── SetupWizard.razor
│   ├── Sidebar.razor
│   └── StatusBar.razor
├── Infrastructure/   # Result<T>, PathHelper
├── Layout/           # MainLayout
├── Models/           # DiaryEntry, SyncState, RepositoryConfig, ...
├── Pages/            # Home.razor
├── Services/         # GitHubApiClient, DiaryRepository, SyncService, SearchService, ...
├── Stores/           # DiaryStore, SettingsStore
└── wwwroot/css/      # Custom dark-theme CSS

Architecture is enforced by convention:

UI (Components/Pages) → Store → Repository → GitHub API

The UI never talks to GitHubApiClient directly — always through DiaryStore.

🔮 Roadmap

  • v1.1 — Tags & Favorites
  • v1.2 — Image attachments
  • v1.3 — GitHub OAuth Device Flow (no more manual PATs)
  • v2.0 — GitLab / Gitea / Forgejo support

🚫 Non-goals

GitDiary is intentionally minimal (KISS / YAGNI). The following are out of scope, and PRs that add them will be politely declined:

  • Rich-text / WYSIWYG editing. Markdown is the format. If you want WYSIWYG, use a different app. There is a small syntax-insertion toolbar (bold / italic / lists / …), but the source-of-truth remains raw Markdown.
  • Binary asset upload beyond the roadmap. External image links (![](https://…)) already cover the case; a general-purpose upload pipeline (MIME sniffing, size caps, gallery UI, GitHub Contents-API base64 limits, repo bloat) is not something this project will grow.
  • Multi-user, sharing, collaboration. A GitHub repo is a single-user data store — if you want to share, git push and grant repo access.
  • Any backend service. GitDiary is a static site by design; adding a server violates the "zero infrastructure" premise.
  • Plugin / extension systems. They almost always outgrow their host.
  • Analytics / telemetry. The CSP explicitly blocks it and that is not going to change.

If you're not sure whether an idea fits, please open an Issue before writing code — I'd rather say no early than after you've invested effort.

🤝 Contributing

Issues and PRs are welcome. Please read docs/prd.md and docs/tech-design.md before proposing architectural changes.

📝 License

MIT © GitDiary contributors

About

A minimalist personal diary that lives inside your own GitHub repository.

Resources

Contributing

Security policy

Stars

17 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages