Add About & Privacy and Donate modals (M6, §01)

This commit is contained in:
2026-06-07 20:04:08 +03:00
parent 30ff7ae357
commit 123f1498b4
8 changed files with 400 additions and 2 deletions
+78
View File
@@ -0,0 +1,78 @@
/**
* About & Help modal body (spec §01B/§01C).
*
* Rendered inside ModalShell — no backdrop, close button, or focus trap here;
* the shell owns all of that (docs/architecture/03 → Layer 3). This component
* is pure content: app identity, keyboard shortcuts (§01D), and privacy posture
* (SOUL.md — local-only, no accounts, no telemetry).
*/
import styles from './AboutModal.module.css';
/** True when the user agent is macOS / iOS — drives the Cmd vs. Ctrl label. */
const isMac = /Mac|iPhone|iPad|iPod/.test(navigator.platform);
const mod = isMac ? '⌘' : 'Ctrl';
/** Keyboard shortcut rows sourced from spec §01D. */
const SHORTCUTS: readonly { keys: string; action: string }[] = [
{ keys: `${mod}+Shift+N`, action: 'Create a new snippet' },
{ keys: `${mod}+K`, action: 'Toggle the Datasets manager' },
{ keys: `${mod}+S`, action: 'Publish the current snippet draft' },
{ keys: `${mod}+,`, action: 'Open editor settings' },
{ keys: 'Esc', action: 'Close the active modal' },
];
export function AboutModal() {
return (
<div className={styles.about}>
{/* Identity */}
<section className={styles.section}>
<h3 className={styles.heading}>Astrolabe</h3>
<p className={styles.body}>
v<span className={styles.version}>{__APP_VERSION__}</span>
</p>
<p className={styles.body}>
A local-first workspace for authoring, organizing, and previewing Vega-Lite charts. Edit
JSON, see the chart update live, and keep a personal library of snippets with no
account, no server, and full offline support.
</p>
</section>
{/* Keyboard shortcuts */}
<section className={styles.section}>
<h3 className={styles.heading}>Keyboard shortcuts</h3>
<table className={styles.shortcuts} aria-label="Keyboard shortcuts">
<tbody>
{SHORTCUTS.map(({ keys, action }) => (
<tr key={keys} className={styles.row}>
<td className={styles.keys}>
<kbd className={styles.kbd}>{keys}</kbd>
</td>
<td className={styles.action}>{action}</td>
</tr>
))}
</tbody>
</table>
</section>
{/* Privacy */}
<section className={styles.section}>
<h3 className={styles.heading}>Privacy</h3>
<p className={styles.body}>
Astrolabe runs entirely in your browser. Your snippets, datasets, and settings are stored
locally and never leave your machine.
</p>
<ul className={styles.list}>
<li>No account, no sign-in, no server-side storage.</li>
<li>No telemetry, no analytics, no tracking of any kind.</li>
<li>
The only outbound network requests are ones you create: URL-sourced datasets you add
yourself.
</li>
<li>After the first load, the app works fully offline.</li>
<li>Use Import / Export to move your library between devices.</li>
</ul>
</section>
</div>
);
}