Repository navigation
Expand file tree
/
Copy pathindex.html
More file actions
134 lines (133 loc) · 8.19 KB
/
Copy pathindex.html
File metadata and controls
134 lines (133 loc) · 8.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Heldnote — local-first notes with version history</title>
<meta name="description" content="A local-first browser notepad that keeps every version of every note. No account, no server — notes stay in your own browser storage.">
<link rel="canonical" href="https://heldnote.app/">
<script>
// Apply the stored theme and writing face before first paint to avoid a
// flash. editor.js owns the font preference; this only mirrors it early,
// so a monospace note does not paint in serif and then reflow.
try {
const theme = localStorage.getItem('heldnote-theme');
if (theme === 'dark' || theme === 'light') {
document.documentElement.dataset.theme = theme;
}
if (localStorage.getItem('heldnote-editor-font') === 'mono') {
document.documentElement.dataset.editorFont = 'mono';
}
} catch (e) { /* storage may be blocked; system preference applies */ }
</script>
<link rel="preload" href="fonts/source-serif-4-latin.woff2" as="font" type="font/woff2" crossorigin>
<link rel="stylesheet" href="styles.css">
<link rel="manifest" href="manifest.webmanifest">
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 36 36'%3E%3Crect x='2' y='3' width='32' height='22' rx='2' fill='%234E7A62' stroke='%2378A98D' stroke-width='1.5'/%3E%3Crect x='4' y='5' width='28' height='18' rx='1' fill='%230E1116'/%3E%3Cline x1='7' y1='10' x2='24' y2='10' stroke='%239FC7AE' stroke-width='1.2' stroke-linecap='round'/%3E%3Cline x1='7' y1='13.5' x2='22' y2='13.5' stroke='%239FC7AE' stroke-width='1.2' stroke-linecap='round'/%3E%3Cline x1='7' y1='17' x2='19' y2='17' stroke='%239FC7AE' stroke-width='1.2' stroke-linecap='round'/%3E%3Crect x='19.5' y='15.5' width='1.2' height='3' fill='%2378A98D'/%3E%3Crect x='15' y='25' width='6' height='4' fill='%234E7A62'/%3E%3Crect x='11' y='29' width='14' height='2.5' rx='1' fill='%234E7A62'/%3E%3C/svg%3E">
<link rel="icon" type="image/png" sizes="32x32" href="icon-32.png">
<link rel="apple-touch-icon" href="icon-180.png">
<meta name="theme-color" content="#FFFBEB" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#1C1917" media="(prefers-color-scheme: dark)">
<meta name="theme-color" content="#FFFBEB">
<meta property="og:title" content="Heldnote — local-first notes with version history">
<meta property="og:description" content="A local-first browser notepad that keeps every version of every note. No account, no server — notes stay in your own browser storage.">
<meta property="og:url" content="https://heldnote.app/">
<meta property="og:image" content="https://heldnote.app/icon-512.png">
<meta property="og:image:alt" content="The Heldnote mark: a small monitor showing three lines of text and a caret.">
<meta property="og:type" content="website">
<meta property="og:site_name" content="Heldnote">
<meta property="og:locale" content="en">
<meta property="og:locale:alternate" content="tr">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Heldnote — local-first notes with version history">
<meta name="twitter:description" content="A local-first browser notepad that keeps every version of every note. No account, no server — notes stay in your own browser storage.">
<meta name="twitter:image" content="https://heldnote.app/icon-512.png">
<!-- Structured data. Two jobs: let a search engine render a rich result, and
give an answer engine something exact to quote when someone asks for "a
notepad that keeps old versions without an account". Every claim here is
one the app actually keeps — featureList is not a wishlist, and the
author block exists because the person behind the tool was hard to find.
Deliberately absent: any offline-capability claim. There is no service
worker yet, so the app is not guaranteed to open without a network. -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebApplication",
"name": "Heldnote",
"url": "https://heldnote.app/",
"description": "A local-first browser notepad that keeps every version of every note. Notes are stored in the browser's own IndexedDB storage, with no account, no server and no third-party dependencies. Version history lets any earlier state of a note be restored, and backups go to a file or the user's own Google Drive.",
"applicationCategory": "ProductivityApplication",
"applicationSubCategory": "Note-taking",
"operatingSystem": "Any (modern web browser)",
"browserRequirements": "Requires JavaScript and IndexedDB.",
"isAccessibleForFree": true,
"inLanguage": ["en", "tr"],
"offers": {
"@type": "Offer",
"price": "0",
"priceCurrency": "USD"
},
"featureList": [
"Local-first storage — notes stay in the browser, never sent to a server",
"Version history for every note, with restore",
"No account and no sign-up",
"Serif or monospace writing font, for prose or for ASCII diagrams and tables",
"Full-text search across notes, plus find and replace",
"Trash with undo",
"Export and import a JSON backup, or back up to your own Google Drive",
"Light and dark theme",
"Dependency-free: no build step, no framework, no analytics"
],
"softwareHelp": "https://heldnote.app/about",
"sameAs": "https://github.com/OFCode-dev/heldnote",
"author": {
"@type": "Person",
"name": "Ömer Faruk Bayrak",
"sameAs": "https://github.com/OFCode-dev"
}
}
</script>
</head>
<body>
<!-- The app shell below is empty until app.js runs, so this document has no
prose of its own. That is a real gap for anything that reads the page
without executing scripts — a crawler, an answer engine, a text browser,
or a visitor with JS disabled, who would otherwise see a blank cream
page and no explanation. /about carries the full description. -->
<noscript>
<div id="noscript-note">
<h1>Heldnote — local-first notes with version history</h1>
<p>Heldnote is a browser notepad that keeps every version of every note. Notes are stored in your own browser, with no account and no server. It needs JavaScript to run, because the notes live in the browser's IndexedDB storage rather than on a server.</p>
<p><a href="/about">Read what Heldnote does</a> · <a href="/privacy">Privacy</a> · <a href="/terms">Terms</a> · <a href="https://github.com/OFCode-dev/heldnote">Source on GitHub</a></p>
</div>
</noscript>
<div id="app">
<div id="app-notices" aria-live="polite"></div>
<aside id="notes-panel"></aside>
<main id="editor-panel"></main>
<aside id="history-panel" hidden></aside>
<footer id="status-bar">
<span id="status-revision"></span>
<span id="status-retention"></span>
<span id="status-notice" role="status" aria-live="polite" aria-atomic="true" hidden></span>
<span id="status-counts"></span>
<!-- The only route from the app itself to the policy. The noscript
block above serves crawlers; a user with JS never sees it. One
link, not two: #status-bar is flex-wrap:nowrap from 768px up
(styles.css @media min-width:768px) and already carries three
spans, so a second link risks overflow in that single-row band.
Below 768px the bar wraps freely. /privacy links onward to
/terms. -->
<a id="status-legal" href="/privacy">Privacy</a>
<!-- The save state, for assistive technology only. #status-revision
cannot carry the live region itself: its visible text ends in a
timestamp that changes on every flush, so a screen reader would
re-announce "Saved locally" continuously while someone types. app.js
writes the bare state phrase here, and only when it changes. Cursor
position and word count are deliberately never announced. -->
<span id="status-a11y" class="sr-only" role="status" aria-live="polite" aria-atomic="true"></span>
</footer>
</div>
<script type="module" src="app.js"></script>
</body>
</html>