Diffdown is a real-time collaborative Markdown editor/previewer built on the AT Protocol
diffdown.com
1{{define "base"}}
2<!DOCTYPE html>
3<html lang="en">
4<head>
5 <meta charset="utf-8">
6 <meta name="viewport" content="width=device-width, initial-scale=1">
7 <link rel="icon" href="/favicon.ico" sizes="any">
8 <link rel="icon" href="/favicon.svg" type="image/svg+xml">
9 <link rel="apple-touch-icon" href="/favicon/apple-touch-icon.png">
10 <link rel="manifest" href="/favicon/site.webmanifest">
11 <title>{{.Title}} — Diffdown</title>
12 <meta name="description" content="{{if .Description}}{{.Description}}{{else}}Diffdown — collaborative Markdown editing on AT Protocol.{{end}}">
13 <!-- Open Graph -->
14 <meta property="og:type" content="website">
15 <meta property="og:site_name" content="Diffdown">
16 <meta property="og:title" content="{{.Title}} — Diffdown">
17 <meta property="og:description" content="{{if .Description}}{{.Description}}{{else}}Diffdown — collaborative Markdown editing on AT Protocol.{{end}}">
18 <meta property="og:image" content="{{if .OGImage}}{{.OGImage}}{{else}}/favicon/android-chrome-512x512.png{{end}}">
19 <!-- Twitter Card -->
20 <meta name="twitter:card" content="summary">
21 <meta name="twitter:title" content="{{.Title}} — Diffdown">
22 <meta name="twitter:description" content="{{if .Description}}{{.Description}}{{else}}Diffdown — collaborative markdown editing on AT Protocol.{{end}}">
23 <meta name="twitter:image" content="{{if .OGImage}}{{.OGImage}}{{else}}/favicon/android-chrome-512x512.png{{end}}">
24 <link rel="stylesheet" href="/static/css/style.css">
25 {{block "head" .}}{{end}}
26 <script>
27 (function() {
28 var stored = localStorage.getItem('theme');
29 if (stored) document.documentElement.setAttribute('data-theme', stored);
30 })();
31 </script>
32</head>
33<body>
34 <nav class="navbar">
35 <a href="/" class="logo">
36 <img src="/static/img/dd-logo.svg" alt="" width="22" height="28" style="vertical-align:middle;margin-right:0.4rem">Diffdown
37 </a>
38 <div class="nav-right">
39 {{if .User}}
40 <a href="/">Documents</a>
41 <a href="/about">About</a>
42 <span class="nav-user">{{.UserHandle}}</span>
43 <form method="post" action="/auth/logout" style="display:inline">
44 <button type="submit" class="btn-link">Log out</button>
45 </form>
46 {{else}}
47 <a href="/auth/atproto" class="btn btn-sm">Log in</a>
48 <a href="/about">About</a>
49 {{end}}
50 <button id="theme-toggle" class="btn-link" aria-label="Toggle dark mode" onclick="toggleTheme()" style="font-size:1.1rem;padding:0.25rem">☀</button>
51 </div>
52 </nav>
53 <main>
54 {{if .Error}}
55 <div class="alert alert-error">{{.Error}}</div>
56 {{end}}
57 {{block "content" .}}{{end}}
58 </main>
59 {{block "scripts" .}}{{end}}
60 <script>
61 function getEffectiveTheme() {
62 var stored = localStorage.getItem('theme');
63 if (stored) return stored;
64 return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
65 }
66 function applyThemeIcon(theme) {
67 document.getElementById('theme-toggle').textContent = theme === 'dark' ? '☀' : '🌙';
68 }
69 function toggleTheme() {
70 var current = getEffectiveTheme();
71 var next = current === 'dark' ? 'light' : 'dark';
72 localStorage.setItem('theme', next);
73 document.documentElement.setAttribute('data-theme', next);
74 applyThemeIcon(next);
75 if (window.__cmSetTheme) window.__cmSetTheme(next);
76 }
77 applyThemeIcon(getEffectiveTheme());
78 </script>
79</body>
80</html>
81{{end}}