diff --git a/jottit/chrome.py b/jottit/chrome.py
index dea5464..965c2d5 100644
--- a/jottit/chrome.py
+++ b/jottit/chrome.py
@@ -31,6 +31,7 @@ def chrome_context() -> dict[str, Any]:
"is_unclaimed": False,
"site_root_path": "/",
"page_slug": page_slug,
+ "current_path": request.path,
}
conn = get_request_conn()
diff --git a/jottit/static/base.css b/jottit/static/base.css
index eff48d2..1376fd4 100644
--- a/jottit/static/base.css
+++ b/jottit/static/base.css
@@ -1,104 +1,139 @@
-html {
- font-family: var(--content-font);
- font-size: var(--content-size);
- line-height: 1.5;
- color: var(--fg);
- background: var(--bg);
+@layer base {
+ body {
+ background: #ffffff;
+ color: var(--color-text);
+ font-family: var(--font-family-content);
+ font-size: var(--font-size-base);
+ line-height: var(--line-height-normal);
+ }
+
+ body.app,
+ body.dialog-page {
+ background: var(--color-bg-app);
+ }
+
+ h1, h2, h3, h4, h5, h6 {
+ font-family: var(--font-family-headings);
+ line-height: var(--line-height-tight);
+ margin: 1em 0 0.5em 0;
+ font-weight: bold;
+ }
+
+ h1 { font-size: var(--font-size-h1); }
+ h2 { font-size: var(--font-size-h2); }
+ h3 { font-size: var(--font-size-h3); }
+ h4 { font-size: var(--font-size-h4); }
+ h5 { font-size: var(--font-size-h5); }
+ h6 { font-size: var(--font-size-h6); color: var(--color-text-muted); }
+
+ p { margin: 0 0 1em 0; }
+
+ a, a:visited {
+ color: var(--color-link);
+ text-decoration: underline;
+ }
+
+ a img, a:visited img { border: 0; }
+
+ strong { font-weight: bold; }
+ em { font-style: italic; }
+
+ ul, ol {
+ margin: 1em 0 1em 2em;
+ padding: 0;
+ }
+ ul { list-style: disc; }
+ ol { list-style: decimal; }
+
+ blockquote {
+ border-left: 3px solid var(--color-border);
+ padding: 0 0 0 12px;
+ margin: 1em 0 1em 20px;
+ color: var(--color-text-muted);
+ }
+
+ code, kbd, samp {
+ font-family: var(--font-stack-mono);
+ font-size: 1em;
+ }
+
+ pre {
+ background: var(--color-code-bg);
+ padding: 10px;
+ overflow-x: auto;
+ margin: 1em 0;
+ line-height: 1.4;
+ border: 1px solid var(--color-border);
+ }
+ pre code {
+ background: transparent;
+ padding: 0;
+ font-size: inherit;
+ }
+
+ hr {
+ border: 0;
+ border-top: 1px solid var(--color-rule);
+ margin: 1em 0;
+ }
+
+ table { margin: 1em 0; }
+ th, td {
+ padding: 4px 8px;
+ text-align: left;
+ vertical-align: top;
+ }
+
+ label {
+ font-size: 0.9em;
+ font-weight: bold;
+ color: #555;
+ line-height: 1em;
+ margin-bottom: 1px;
+ }
+
+ input, textarea, select, button {
+ font-family: inherit;
+ font-size: inherit;
+ color: inherit;
+ }
+
+ textarea {
+ font-family: var(--font-stack-mono);
+ line-height: var(--line-height-normal);
+ resize: vertical;
+ border: 1px solid var(--color-border);
+ padding: 4px;
+ background: #fff;
+ }
+
+ input[type="text"],
+ input[type="password"],
+ input[type="email"],
+ input[type="search"],
+ input[type="url"],
+ input[type="number"],
+ select {
+ border: 1px solid #ccc;
+ background: #fff;
+ padding: 2px 4px;
+ }
+
+ button,
+ input[type="submit"],
+ input[type="button"],
+ input[type="reset"],
+ [role="button"] {
+ min-height: var(--tap-target);
+ }
+
+ @media (min-width: 768px) {
+ button,
+ input[type="submit"],
+ input[type="button"],
+ input[type="reset"],
+ [role="button"] {
+ min-height: auto;
+ }
+ }
}
-
-body {
- min-height: 100vh;
-}
-
-h1, h2, h3, h4, h5, h6 {
- font-family: var(--headings-font);
- line-height: 1.2;
- margin-top: var(--space-5);
- margin-bottom: var(--space-3);
-}
-
-h1 { font-size: var(--headings-size); }
-h2 { font-size: calc(var(--headings-size) * 0.85); }
-h3 { font-size: calc(var(--headings-size) * 0.72); }
-
-p, ul, ol, dl, blockquote, pre, table, figure {
- margin-top: 0;
- margin-bottom: var(--space-4);
-}
-
-ol, ul {
- padding-left: var(--space-5);
- list-style: revert;
-}
-
-a {
- color: var(--link);
- text-decoration: underline;
- text-underline-offset: 2px;
-}
-
-a:visited { color: var(--link-visited); }
-a:hover, a:focus { text-decoration-thickness: 2px; }
-
-button {
- cursor: pointer;
- padding: var(--space-2) var(--space-4);
- border: 1px solid var(--border);
- border-radius: var(--radius);
- background: var(--surface);
-}
-
-button:hover { background: var(--surface-alt); }
-
-input[type="text"],
-input[type="password"],
-input[type="email"],
-input[type="number"],
-textarea {
- width: 100%;
- padding: var(--space-2) var(--space-3);
- border: 1px solid var(--border);
- border-radius: var(--radius);
- background: var(--surface);
-}
-
-textarea { font-family: var(--content-font); resize: vertical; min-height: 12rem; }
-
-label { display: block; }
-
-fieldset {
- border: 1px solid var(--border);
- border-radius: var(--radius);
- padding: var(--space-3) var(--space-4);
- margin-bottom: var(--space-4);
-}
-
-legend { padding: 0 var(--space-2); font-weight: 600; }
-
-hr {
- border: 0;
- border-top: 1px solid var(--border);
- margin: var(--space-5) 0;
-}
-
-code, pre, kbd, samp {
- font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
- font-size: 0.95em;
-}
-
-pre {
- padding: var(--space-3);
- background: var(--surface-alt);
- border-radius: var(--radius);
- overflow-x: auto;
-}
-
-blockquote {
- border-left: 3px solid var(--border);
- padding-left: var(--space-4);
- color: var(--muted);
-}
-
-small { color: var(--muted); }
-
-time { color: var(--muted); }
diff --git a/jottit/static/components.css b/jottit/static/components.css
index 13f6d4f..880dd73 100644
--- a/jottit/static/components.css
+++ b/jottit/static/components.css
@@ -1,238 +1,619 @@
-.page {
- max-width: 60rem;
- margin: 0 auto;
- padding: var(--space-4);
- display: grid;
- grid-template-columns: 1fr;
- gap: var(--space-5);
-}
+@layer components {
+ /* ---------- Site chrome (body.app) ---------- */
+
+ .site-header {
+ background: var(--color-header);
+ border-bottom: 1px solid var(--color-border);
+ padding: 0;
+ position: relative;
+ }
-@media (min-width: 50rem) {
- .page {
- grid-template-columns: minmax(0, 1fr) 16rem;
- grid-template-areas:
- "header header"
- "main sidebar"
- "footer footer";
- }
- .site-header { grid-area: header; }
- main { grid-area: main; }
- .site-sidebar { grid-area: sidebar; }
- .site-footer { grid-area: footer; }
-}
+ .site-header-inner {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: 16px;
+ padding: 4px 7px 4px 56px;
+ }
-.site-header {
- background: var(--header-color);
- color: var(--title-color);
- padding: var(--space-5) var(--space-5) var(--space-3);
- border-radius: var(--radius);
-}
+ .site-titles {
+ flex: 1 1 auto;
+ min-width: 0;
+ }
-.site-header a { color: var(--title-color); }
+ .site-title {
+ font-family: var(--font-family-title);
+ font-size: var(--font-size-h1);
+ line-height: var(--line-height-tight);
+ margin: 0;
+ color: var(--color-title);
+ font-weight: bold;
+ }
-.site-header hgroup h1 {
- font-family: var(--title-font);
- font-size: var(--title-size);
- margin: 0;
-}
+ .site-title:has(a:empty) { display: none; }
-.site-header .subtitle {
- font-family: var(--subtitle-font);
- font-size: var(--subtitle-size);
- color: var(--subtitle-color);
- margin: var(--space-1) 0 0;
-}
+ .site-title a {
+ color: inherit;
+ text-decoration: none;
+ }
-.claim-banner {
- background: rgba(255,255,255,0.15);
- padding: var(--space-2) var(--space-3);
- margin: 0 0 var(--space-3);
- border-radius: var(--radius);
-}
+ .site-subtitle {
+ font-family: var(--font-family-subtitle);
+ font-size: 1.1em;
+ color: var(--color-subtitle);
+ margin: 0;
+ padding-left: 0.1em;
+ }
-.site-nav {
- margin-top: var(--space-3);
-}
+ .site-subtitle:empty { display: none; }
-.site-nav ul {
- display: flex;
- flex-wrap: wrap;
- gap: var(--space-3);
- padding: 0;
- list-style: none;
- margin: 0;
-}
+ .site-nav {
+ flex: 0 0 auto;
+ font-family: var(--font-stack-system);
+ font-size: 0.9em;
+ display: flex;
+ gap: 6px;
+ align-items: center;
+ white-space: nowrap;
+ }
-.site-nav a,
-.site-nav button.link {
- color: var(--subtitle-color);
- text-decoration: none;
- font-size: 0.9em;
-}
+ .site-nav a {
+ color: var(--color-subtitle);
+ text-decoration: underline;
+ padding: 0 2px;
+ }
-.site-nav a:hover,
-.site-nav button.link:hover { text-decoration: underline; }
+ .site-nav a:hover {
+ color: #fff;
+ background: #555;
+ text-decoration: none;
+ }
-.site-sidebar {
- border-left: 1px solid var(--border);
- padding-left: var(--space-4);
-}
+ .site-nav .sep { color: var(--color-subtitle); }
+
+ .site-nav form.inline { display: inline; margin: 0; padding: 0; }
-@media (max-width: 50rem) {
- .site-sidebar {
- border-left: 0;
- border-top: 1px solid var(--border);
- padding-left: 0;
- padding-top: var(--space-4);
+ /* Site body: gray panel holding the white content card + sidebar. */
+ .site-body {
+ background: var(--color-bg-app);
+ padding: 10px var(--gutter);
+ max-width: 1000px;
+ margin: 0 auto;
}
-}
-.page-list {
- list-style: none;
- padding: 0;
- margin: 0 0 var(--space-4);
- display: flex;
- flex-direction: column;
- gap: var(--space-1);
-}
+ .site-content {
+ background: var(--color-bg-content);
+ border: 1px solid var(--color-border);
+ padding: 1em;
+ line-height: var(--line-height-normal);
+ font-family: var(--font-family-content);
+ }
-.page-list strong { color: var(--fg); }
+ .site-content > :first-child { margin-top: 0; }
-.new-page {
- display: flex;
- gap: var(--space-2);
-}
+ .site-sidebar { font-size: 1.2em; }
-.new-page input[type="text"] { flex: 1; }
+ .site-pages {
+ display: flex;
+ flex-direction: column;
+ margin: 0 0 2px 5px;
+ padding: 0 0 2px 0;
+ }
-.site-footer {
- text-align: center;
- color: var(--muted);
- font-size: 0.9em;
- padding-top: var(--space-4);
- border-top: 1px solid var(--border);
-}
+ .site-pages a,
+ .site-pages strong {
+ font-size: 0.8em;
+ padding: 0 0 0.4em 0;
+ }
-main > article {
- max-width: var(--measure);
-}
+ .site-pages a {
+ color: var(--color-link);
+ text-decoration: underline;
+ }
-.front .lede {
- font-size: 1.2em;
- color: var(--muted);
- margin-bottom: var(--space-5);
-}
+ .site-pages [aria-current="page"] {
+ font-weight: bold;
+ color: var(--color-text);
+ }
-.new-site,
-.site-form,
-.form {
- display: flex;
- flex-direction: column;
- gap: var(--space-3);
- max-width: var(--measure);
-}
+ /* ---------- Page footer (small gray, centered, under content) ---------- */
+ .page-footer {
+ background: var(--color-bg-app);
+ color: var(--color-text-quiet);
+ text-align: center;
+ font-size: 0.8em;
+ padding: 10px;
+ }
-.form-error {
- background: var(--danger-bg);
- color: var(--danger);
- padding: var(--space-2) var(--space-3);
- border-radius: var(--radius);
- border: 1px solid var(--danger);
-}
+ .page-footer a { color: var(--color-text-quiet); }
+ .page-footer p { margin: 0 0 4px 0; }
-button.destructive {
- background: var(--danger);
- color: #fff;
- border-color: var(--danger);
-}
+ /* ---------- Front-page chrome (body.site) ---------- */
+ .main-header {
+ background: #fff;
+ border-bottom: 1px solid var(--color-border);
+ padding: 20px 16px 16px;
+ text-align: center;
+ }
-button.destructive:hover { filter: brightness(0.9); }
+ .main-header img {
+ display: inline-block;
+ margin: 0 auto;
+ }
-button.link {
- background: none;
- border: 0;
- padding: 0;
- color: var(--link);
- text-decoration: underline;
- cursor: pointer;
-}
+ .page-main {
+ background: var(--color-bg-app);
+ padding: 8px 16px;
+ border-bottom: 1px solid var(--color-border);
+ }
-.form.inline,
-form.inline { display: inline; }
-
-.revision-banner {
- background: var(--surface-alt);
- border: 1px solid var(--border);
- border-radius: var(--radius);
- padding: var(--space-3);
- margin-bottom: var(--space-4);
- display: flex;
- flex-wrap: wrap;
- gap: var(--space-3);
- align-items: center;
-}
+ .page-main > * {
+ max-width: 700px;
+ margin-left: auto;
+ margin-right: auto;
+ }
-.page-meta {
- color: var(--muted);
- font-size: 0.9em;
- margin-bottom: var(--space-3);
- display: flex;
- flex-wrap: wrap;
- gap: var(--space-3);
-}
+ .main-nav {
+ background: #fff;
+ text-align: center;
+ font-size: 1em;
+ padding: 24px 0 16px 0;
+ line-height: 1.6;
+ color: var(--color-text-muted);
+ }
-.admin .admin-links {
- display: flex;
- flex-wrap: wrap;
- gap: var(--space-3);
- margin-bottom: var(--space-4);
-}
+ .main-nav a {
+ color: var(--color-link);
+ text-decoration: underline;
+ font-weight: 500;
+ }
-.revisions {
- list-style: none;
- padding: 0;
- margin: 0 0 var(--space-4);
- display: flex;
- flex-direction: column;
- gap: var(--space-2);
-}
+ .main-nav [aria-current="page"] {
+ color: var(--color-text);
+ font-weight: bold;
+ text-decoration: none;
+ }
-.revisions li {
- padding: var(--space-2) 0;
- border-bottom: 1px solid var(--border);
- display: flex;
- flex-wrap: wrap;
- gap: var(--space-3);
- align-items: baseline;
-}
+ .main-nav-sep {
+ color: var(--color-text);
+ margin: 0 0.5em;
+ }
-.revisions .changes {
- color: var(--muted);
- font-size: 0.9em;
-}
+ .front-form {
+ text-align: center;
+ margin: 16px auto;
+ max-width: 700px;
+ }
-.pagination {
- margin-top: var(--space-4);
-}
+ .front-form textarea {
+ display: block;
+ margin: 0 auto;
+ width: 450px;
+ max-width: 100%;
+ height: 250px;
+ resize: none;
+ }
-.diff-body ins {
- background: #e6ffed;
- text-decoration: none;
-}
+ .front-form p { margin: 12px 0 0 0; }
+ .front-form button { font-size: 1.1em; }
-.diff-body del {
- background: #ffebe9;
- text-decoration: line-through;
-}
+ /* ---------- Dialogs (signin, claim, change-password, deletes) ---------- */
+ .dialog-wrapper {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 40px 16px;
+ }
-.actions {
- display: flex;
- flex-wrap: wrap;
- gap: var(--space-3);
- margin-top: var(--space-4);
-}
+ .dialog {
+ border: 1px solid #aaa;
+ padding: 15px 30px;
+ background: #fff;
+ font-family: var(--font-stack-system);
+ text-align: left;
+ max-width: 500px;
+ flex: 0 1 500px;
+ }
+
+ .dialog-wide {
+ max-width: 700px;
+ flex-basis: 700px;
+ }
+
+ .dialog h1 {
+ color: #000;
+ font-size: 150%;
+ margin-top: 0;
+ }
+
+ .dialog label { color: #000; }
+ .dialog input { font-size: 120%; margin: 0; }
+ .dialog a { color: var(--color-link); padding: 2px; }
+
+ /* ---------- Buttons ---------- */
+ .button-cancel,
+ a.button-cancel {
+ color: red;
+ background: none;
+ border: 0;
+ padding: 2px;
+ text-decoration: underline;
+ cursor: pointer;
+ font-size: inherit;
+ }
+
+ .button-cancel:hover,
+ a.button-cancel:hover {
+ color: #fff;
+ background: red;
+ text-decoration: none;
+ }
+
+ .link-button {
+ background: none;
+ border: 0;
+ padding: 0;
+ color: var(--color-link);
+ cursor: pointer;
+ font: inherit;
+ text-decoration: underline;
+ min-height: auto;
+ }
+
+ /* ---------- Forms ---------- */
+ .form {
+ margin: 0;
+ padding: 0;
+ }
+
+ .form-row { margin-bottom: 12px; }
+ .form-row label {
+ display: block;
+ margin-bottom: 2px;
+ }
+
+ .form-actions {
+ margin: 10px 0;
+ font-size: 0.9em;
+ display: flex;
+ gap: 6px;
+ align-items: center;
+ flex-wrap: wrap;
+ }
+
+ .form-error {
+ background: var(--color-error-bg);
+ border: 2px solid var(--color-error-border);
+ color: var(--color-error-text);
+ padding: 5px 12px;
+ margin: 15px 0;
+ }
+
+ /* ---------- History / changes / diff ---------- */
+ .history { margin-top: 10px; }
+
+ .revisions {
+ margin: 10px 0;
+ }
+
+ .revisions li {
+ display: grid;
+ grid-template-columns: auto auto 1fr;
+ gap: 8px;
+ padding: 4px 5px;
+ align-items: baseline;
+ }
+
+ .revisions li:nth-child(even) {
+ background: var(--color-code-bg);
+ }
+
+ .revisions time {
+ color: var(--color-text-muted);
+ font-size: 0.9em;
+ }
+
+ .revisions .changes {
+ color: var(--color-text-muted);
+ font-size: 0.9em;
+ }
-.hint {
- color: var(--muted);
- font-size: 0.9em;
+ .diff-body {
+ margin: 10px 0;
+ padding: 10px;
+ border: 1px solid #999;
+ background: var(--color-code-bg);
+ font-family: var(--font-stack-mono);
+ font-size: 0.9em;
+ white-space: pre-wrap;
+ }
+
+ .diff-body ins {
+ background: var(--color-diff-insert);
+ text-decoration: none;
+ }
+
+ .diff-body del {
+ background: var(--color-diff-delete);
+ text-decoration: line-through;
+ }
+
+ span.replace { background: var(--color-diff-replace); }
+ span.insert { background: var(--color-diff-insert); }
+ span.delete { background: var(--color-diff-delete); }
+
+ /* ---------- Revision banner (browse old revisions) ---------- */
+ #browse_revs,
+ .revision-banner {
+ position: relative;
+ margin: 10px 0;
+ padding: 1em;
+ border: 1px solid #ccc;
+ background: #eee;
+ }
+
+ #browse_revs a,
+ .revision-banner a {
+ color: var(--color-link);
+ }
+
+ /* ---------- Pagination ---------- */
+ .pagination { margin: 10px 4px; }
+
+ .pagination a {
+ color: var(--color-link);
+ text-decoration: none;
+ }
+
+ /* ---------- Settings table (admin pages) ---------- */
+ .settings {
+ width: 100%;
+ border-collapse: collapse;
+ margin-top: 10px;
+ table-layout: fixed;
+ }
+
+ .settings th,
+ .settings td {
+ vertical-align: top;
+ padding: 15px 0 20px 0;
+ border-bottom: 1px solid var(--color-rule);
+ }
+
+ .settings th {
+ width: 140px;
+ white-space: nowrap;
+ padding-top: 16px;
+ padding-right: 40px;
+ text-align: left;
+ font-family: var(--font-stack-system);
+ font-weight: bold;
+ }
+
+ .settings td.explain {
+ font-size: 90%;
+ font-weight: normal;
+ width: 220px;
+ padding-left: 20px;
+ color: var(--color-text-muted);
+ }
+
+ .settings input[type="text"],
+ .settings input[type="password"],
+ .settings input[type="email"],
+ .settings input[type="url"] {
+ width: 240px;
+ max-width: 100%;
+ }
+
+ .settings .security {
+ border-collapse: collapse;
+ width: auto;
+ }
+
+ .settings .security td {
+ border: 0;
+ padding: 2px 8px 2px 0;
+ font-size: 1em;
+ }
+
+ .settings .security td.explain {
+ font-size: 0.9em;
+ width: auto;
+ padding-left: 8px;
+ color: var(--color-text-muted);
+ }
+
+ .settings .security label {
+ font-weight: normal;
+ color: var(--color-text);
+ }
+
+ #delete_site {
+ margin-top: 40px;
+ }
+
+ #delete_site h2 {
+ font-size: 1em;
+ border-bottom: 1px solid var(--color-rule);
+ margin-bottom: 10px;
+ }
+
+ #delete_site a {
+ color: red;
+ }
+
+ .admin-links {
+ margin-top: 32px;
+ font-size: 0.9em;
+ color: var(--color-text-muted);
+ }
+
+ /* ---------- Edit page ---------- */
+ .edit-page { margin-top: 0; }
+
+ .edit-heading {
+ font-size: 1.1em;
+ margin: 0 0 0.3em 0;
+ }
+
+ .edit-heading .page_name {
+ color: var(--color-page-name);
+ }
+
+ #content_text,
+ .edit-page textarea {
+ width: 100%;
+ min-height: 320px;
+ font-family: var(--font-stack-mono);
+ line-height: var(--line-height-normal);
+ }
+
+ .edit-actions {
+ margin-top: 6px;
+ }
+
+ .edit-actions #delete {
+ margin-left: auto;
+ }
+
+ /* ---------- Primer welcome banner ---------- */
+ .primer {
+ position: relative;
+ margin: 10px 0;
+ padding: 4px 8px;
+ background: var(--color-callout-bg);
+ border: 1px solid var(--color-callout-border);
+ }
+
+ .primer h1 {
+ font-size: 14px;
+ margin: 8px 2px 5px 2px;
+ font-family: var(--font-stack-system);
+ }
+
+ .primer p {
+ font-size: 11px;
+ margin: 0 2px 8px 2px;
+ font-family: var(--font-stack-system);
+ }
+
+ .primer-dismiss {
+ position: absolute;
+ top: 8px;
+ right: 8px;
+ margin: 0;
+ }
+
+ .primer .link-button {
+ color: var(--color-link);
+ font-size: 10px;
+ }
+
+ /* ---------- Dateline (view-page footer) ---------- */
+ .dateline {
+ font-family: var(--font-stack-system);
+ font-size: 0.9em;
+ margin-top: 3px;
+ padding-top: 2px;
+ border-top: 1px solid var(--color-rule);
+ text-align: right;
+ color: var(--color-text-quiet);
+ }
+
+ .dateline a {
+ color: #555;
+ background: var(--color-code-bg);
+ padding: 2px;
+ text-decoration: none;
+ margin-left: 4px;
+ }
+
+ .dateline a:hover {
+ color: #fff;
+ background: #555;
+ }
+
+ /* ---------- Claim-this-site black banner ---------- */
+ #claim_site {
+ text-align: left;
+ background: #000;
+ color: #fff;
+ padding: 0.7em 0.7em 0.7em 60px;
+ margin: 0;
+ font-size: 1em;
+ position: relative;
+ }
+
+ #claim_site a {
+ color: #fff;
+ text-decoration: none;
+ }
+
+ #claim_site label { color: #fff; font-weight: normal; }
+
+ #claim_site #pick_password {
+ position: absolute;
+ right: 0.7em;
+ top: 0.6em;
+ }
+
+ #claim_site #pick_password input,
+ #claim_site #pick_password button {
+ position: relative;
+ top: -1px;
+ margin: 0 0 0 3px;
+ font-size: 0.9em;
+ color: initial;
+ height: 22px;
+ min-height: 0;
+ box-sizing: border-box;
+ padding: 2px 4px;
+ }
+
+ /* ---------- Sidebar "Create a new page" widget ---------- */
+ #new_page button {
+ margin: 0 2px 15px 0;
+ background: #e5e5e5;
+ border: 1px solid #ccc;
+ padding: 4px 5px;
+ font-size: 0.8em;
+ font-weight: bold;
+ cursor: pointer;
+ min-height: auto;
+ }
+
+ #new_page_input {
+ font-size: 0.7em;
+ margin: 0 5px 15px 0;
+ }
+
+ #new_page_input input {
+ font-size: 1.1em;
+ padding-right: 2px;
+ }
+
+ #new_page_name {
+ margin-bottom: 7px;
+ width: 150px;
+ }
+
+ .link-close-newpage {
+ color: red;
+ padding-left: 2px;
+ }
+
+ /* ---------- ≥768px: two-column site body ---------- */
+ @media (min-width: 768px) {
+ .site-body {
+ display: grid;
+ grid-template-columns: 60px minmax(0, 1fr) 23px var(--site-sidebar-width);
+ grid-template-areas: ". main . sidebar";
+ padding: 10px 0 0 0;
+ column-gap: 0;
+ background: var(--color-bg-app);
+ }
+ .site-content-column { grid-area: main; }
+ .site-sidebar { grid-area: sidebar; background: var(--color-bg-app); }
+ }
}
diff --git a/jottit/static/logo.png b/jottit/static/logo.png
new file mode 100644
index 0000000..2b5bfd7
Binary files /dev/null and b/jottit/static/logo.png differ
diff --git a/jottit/static/reset.css b/jottit/static/reset.css
index 98538e2..deff3c9 100644
--- a/jottit/static/reset.css
+++ b/jottit/static/reset.css
@@ -1,17 +1,47 @@
-*, *::before, *::after { box-sizing: border-box; }
+@layer reset {
+ *, *::before, *::after { box-sizing: border-box; }
+ * { margin: 0; }
-html, body, h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd, ol, ul, fieldset {
- margin: 0;
- padding: 0;
-}
+ html {
+ -webkit-text-size-adjust: 100%;
+ text-size-adjust: 100%;
+ tab-size: 4;
+ }
-ol, ul { list-style: none; }
+ body {
+ min-height: 100svh;
+ line-height: var(--line-height-normal);
+ -webkit-font-smoothing: antialiased;
+ }
-img, picture, svg, video { max-width: 100%; display: block; }
+ img, picture, video, canvas, svg {
+ display: block;
+ max-width: 100%;
+ }
+ img, video { height: auto; }
-button, input, select, textarea {
- font: inherit;
- color: inherit;
-}
+ input, textarea, select {
+ font: inherit;
+ color: inherit;
+ }
+
+ p, h1, h2, h3, h4, h5, h6 { overflow-wrap: break-word; }
+
+ a {
+ color: inherit;
+ text-decoration: none;
+ }
-a { color: inherit; }
+ ul, ol {
+ padding: 0;
+ list-style: none;
+ }
+
+ table { border-collapse: collapse; }
+
+ textarea:focus, input:focus { outline: none; }
+ :focus-visible {
+ outline: 1px solid var(--color-accent);
+ outline-offset: 0;
+ }
+}
diff --git a/jottit/static/tokens.css b/jottit/static/tokens.css
index 105fb69..28e7704 100644
--- a/jottit/static/tokens.css
+++ b/jottit/static/tokens.css
@@ -1,40 +1,60 @@
-:root {
- --hue: 210;
- --brightness: 100;
-
- --header-color: hsl(var(--hue) 60% calc(var(--brightness) * 0.22%));
- --title-color: #fff;
- --subtitle-color: #bfe8ff;
-
- --bg: hsl(var(--hue) 30% calc(var(--brightness) * 0.99%));
- --fg: #222;
- --muted: #666;
- --link: #06c;
- --link-visited: #639;
- --border: #ddd;
- --surface: #fff;
- --surface-alt: #f7f7f7;
- --danger: #b00020;
- --danger-bg: #fdecea;
-
- --title-font: system-ui, sans-serif;
- --subtitle-font: system-ui, sans-serif;
- --headings-font: system-ui, sans-serif;
- --content-font: system-ui, sans-serif;
-
- --title-size: 200%;
- --subtitle-size: 100%;
- --headings-size: 150%;
- --content-size: 100%;
-
- --space-1: 0.25rem;
- --space-2: 0.5rem;
- --space-3: 0.75rem;
- --space-4: 1rem;
- --space-5: 1.5rem;
- --space-6: 2rem;
- --space-8: 3rem;
-
- --radius: 4px;
- --measure: 38rem;
+@layer tokens, reset, base, components, utilities;
+
+@layer tokens {
+ :root {
+ --color-header: #f0f0ee;
+ --color-title: #000000;
+ --color-subtitle: #555555;
+
+ --font-stack-system: system-ui, -apple-system, BlinkMacSystemFont,
+ "Segoe UI", Roboto, sans-serif;
+ --font-stack-mono: ui-monospace, SFMono-Regular, "SF Mono",
+ Menlo, Consolas, "Liberation Mono", monospace;
+
+ --font-family-title: var(--font-stack-system);
+ --font-family-subtitle: var(--font-stack-system);
+ --font-family-headings: var(--font-stack-system);
+ --font-family-content: var(--font-stack-system);
+
+ --color-bg-app: #f0f0ee;
+ --color-bg-content: #ffffff;
+ --color-text: #000000;
+ --color-text-muted: #777777;
+ --color-text-quiet: gray;
+ --color-border: #dddddd;
+ --color-rule: #dddddd;
+ --color-border-strong: #999999;
+ --color-link: blue;
+ --color-link-quiet: #555555;
+ --color-page-name: maroon;
+ --color-accent: #4a90e2;
+
+ --color-code-bg: #eeeeee;
+ --color-callout-bg: #ffff99;
+ --color-callout-border: #cccc00;
+ --color-success-bg: #ddffdd;
+ --color-success-border: #bbeebb;
+ --color-success-text: #225522;
+ --color-error-bg: #ffd6d8;
+ --color-error-border: red;
+ --color-error-text: red;
+ --color-diff-insert: #aaffaa;
+ --color-diff-delete: #ffaaaa;
+ --color-diff-replace: #ffdd88;
+
+ --font-size-base: 13px;
+ --line-height-tight: 1.2;
+ --line-height-normal: 1.5em;
+
+ --font-size-h1: clamp(1.5em, 1.3em + 0.6vw, 2em);
+ --font-size-h2: 1.5em;
+ --font-size-h3: 1.2em;
+ --font-size-h4: 1.05em;
+ --font-size-h5: 1em;
+ --font-size-h6: 0.9em;
+
+ --site-sidebar-width: 200px;
+ --gutter: 16px;
+ --tap-target: 44px;
+ }
}
diff --git a/jottit/static/utilities.css b/jottit/static/utilities.css
index 19a3c90..c9b0400 100644
--- a/jottit/static/utilities.css
+++ b/jottit/static/utilities.css
@@ -1,19 +1,15 @@
-.visually-hidden {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip: rect(0 0 0 0);
- white-space: nowrap;
- border: 0;
+@layer utilities {
+ .visually-hidden {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ white-space: nowrap;
+ border: 0;
+ }
+
+ .text-muted { color: var(--color-text-muted); }
}
-
-.deleted { color: var(--muted); }
-
-.empty { color: var(--muted); }
-
-.cancel { color: var(--muted); }
-
-.count { color: var(--muted); }
diff --git a/jottit/templates/admin_change_password.html b/jottit/templates/admin_change_password.html
index 4895e5a..0a2d798 100644
--- a/jottit/templates/admin_change_password.html
+++ b/jottit/templates/admin_change_password.html
@@ -1,25 +1,23 @@
-{% extends "base.html" %}
+{% extends "site_base.html" %}
{% block title %}Change password{% endblock %}
-{% block content %}
- Change password
Change password
-
+ {% include "partials/form_error.html" %}
-
-
This will remove the site from public listings and free its subdomain. Pages and revisions stay on file in case we ever add a restore path.
+This will remove the site from public listings and free its subdomain. Pages and revisions stay on file in case we ever add a restore path.
- -| Hue | ++ | 0–360 | +
|---|---|---|
| Brightness | ++ | 0–300 | +
Deleting this site will immediately take it down. Delete this site.
+No changes yet.
+ {% if older_before %} + {% endif %} + {% else %} +No changes yet.
+ {% endif %} - -Set a password and pick how open you want this site to be. We'll email you a recovery link if you forget the password later.
+{% block dialog_class %}dialog-wide{% endblock %} - {% include "partials/form_error.html" %} +{% block content %} +Set a password and pick how open you want this site to be. We'll email you a recovery link if you forget the password later.
- -“{{ page_name }}” is gone. Append ?r=N to view a specific revision, or restore it from the page's history.
- Comparing - revision {{ a.revision }} - with - revision {{ b.revision }}. -
-+ Comparing + revision {{ a.revision }} + with + revision {{ b.revision }}. +
-We've emailed a password-reset link to the address on file. The link works once — if you need another, come back to this page.
- {% else %} -We'll email a one-time password-reset link to the email address on file for this site.
- - {% endif %} -We've emailed a password-reset link to the address on file. The link works once — if you need another, come back to this page.
+ + {% else %} +We'll email a one-time password-reset link to the email address on file for this site.
+ + {% endif %} {% endblock %} diff --git a/jottit/templates/history.html b/jottit/templates/history.html index 3a9e384..939c2a1 100644 --- a/jottit/templates/history.html +++ b/jottit/templates/history.html @@ -1,4 +1,4 @@ -{% extends "base.html" %} +{% extends "site_base.html" %} {% block title %}History: {{ page_name or "Home" }}{% endblock %} {% block head %} @@ -11,26 +11,22 @@ {% endblock %} {% block content %} -{{ total }} revision{{ "s" if total != 1 }}.
-{{ total }} revision{{ "s" if total != 1 }}.
-Getting a website should be as easy as filling out a textbox.
-
+ {% endblock %}
+ There's no page named “{{ page_name }}” on this site.
- {% if is_signed_in or is_unclaimed %} - - {% endif %} -There's no page named “{{ page_name }}” on this site.
+ {% if is_signed_in or is_unclaimed %} + + {% endif %} {% endblock %} diff --git a/jottit/templates/partials/design_style.html b/jottit/templates/partials/design_style.html index 628f361..0b5cbc1 100644 --- a/jottit/templates/partials/design_style.html +++ b/jottit/templates/partials/design_style.html @@ -1,23 +1,14 @@ -{# Inline CSS variables sourced from the site's design row. - - The 2007 site embedded full per-site CSS rules here; we surface the - values as custom properties instead and let the global stylesheet - reference them. That keeps the per-request payload small and lets - the M9 stylesheet rewrite without coordinating with this template. #} +{# Per-site overrides written into :root so the global stylesheet + picks them up via var(--…). Empty values leave the token defaults + from tokens.css in place. #} diff --git a/jottit/templates/partials/site_header.html b/jottit/templates/partials/site_header.html deleted file mode 100644 index 3cf80fe..0000000 --- a/jottit/templates/partials/site_header.html +++ /dev/null @@ -1,34 +0,0 @@ -{# Header chrome rendered on every site page: title, subtitle, primary nav. - The unclaimed-site banner sits above the header so it's the most visible - action for a brand-new site. #} -{{ site.subtitle }}
{% endif %} - - - -+ Viewing revision {{ revision.revision }} of {{ latest_revision_number }}. + Latest + {% if revision.revision > 1 %} + | « prev + {% endif %} + {% if revision.revision < latest_revision_number %} + | next » {% endif %} +
+ {% if is_signed_in or is_unclaimed %} + {% endif %} - - -