Compare commits

...

2 Commits

Author SHA1 Message Date
luxick 20a6bac3d6 Unify tables and listings 2026-05-27 20:09:52 +02:00
luxick e089e0b2c3 CSS Refactor 2026-05-27 10:52:47 +02:00
15 changed files with 434 additions and 805 deletions
+1 -1
View File
@@ -115,7 +115,7 @@
function wireFileLinks() {
if (!state.available) return;
document.addEventListener('click', function (e) {
var item = e.target.closest && e.target.closest('.listing-item');
var item = e.target.closest && e.target.closest('.list-item');
if (!item) return;
var anchor = e.target.closest('a');
if (!anchor) return;
+1 -1
View File
@@ -1,4 +1,4 @@
<div class="diary-cal">
<div class="diary-cal panel panel-sidebar">
<div class="panel-header"><a href="{{.DiaryURL}}">Chronological</a></div>
<div class="diary-cal-nav">
<a href="{{.MonthURL}}" class="diary-cal-heading">{{.MonthName}}</a>
+1 -1
View File
@@ -70,7 +70,7 @@
<span class="toolbar-sep"></span>
<button type="button" class="btn btn-tool" data-action="wide" data-key="Z" title="Toggle wide mode (Z)"></button>
</div>
<textarea name="content" id="editor" autofocus>{{.RawContent}}</textarea>
<textarea class="input editor-textarea" name="content" id="editor" autofocus>{{.RawContent}}</textarea>
</form>
<script src="/_/editor/lists.js"></script>
<script src="/_/editor/tables.js"></script>
+2 -2
View File
@@ -85,13 +85,13 @@
var targetWrap = document.createElement('div');
var targetInput = document.createElement('input');
targetInput.type = 'text';
targetInput.className = 'modal-input';
targetInput.className = 'input';
targetInput.placeholder = 'Page path or search…';
targetWrap.appendChild(targetInput);
var displayInput = document.createElement('input');
displayInput.type = 'text';
displayInput.className = 'modal-input';
displayInput.className = 'input';
displayInput.placeholder = 'Display text (optional)';
if (sel) displayInput.value = sel;
+2 -2
View File
@@ -105,7 +105,7 @@ window.EditorMovie = (function () {
var input = document.createElement('input');
input.type = 'text';
input.className = 'modal-input';
input.className = 'input';
input.placeholder = 'OMDb API key';
body.appendChild(input);
@@ -128,7 +128,7 @@ window.EditorMovie = (function () {
function importWithKey(textarea, key, initialTitle) {
var input = document.createElement('input');
input.type = 'text';
input.className = 'modal-input';
input.className = 'input';
input.placeholder = 'Title, optionally with (YYYY)';
input.value = initialTitle;
+3 -3
View File
@@ -17,16 +17,16 @@
</head>
<body>
<header>
<nav class="breadcrumb">
<nav class="breadcrumb row">
<a href="/" tabindex="-1" title="Home"><svg class="logo" viewBox="0 0 26.052269 26.052269" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="currentColor" stroke-linejoin="miter" transform="matrix(0.05463483,8.1519706e-6,-8.1519706e-6,0.05463483,-64.560546,-24.6949)"><rect x="1188.537" y="457.92056" width="461.87488" height="462.15189" stroke-width="20.2288"/><path d="m1348.9955 456.59572.046 309.36839" stroke-width="19.6849"/><path d="m1200.3996 765.80237 441.8362-.0659" stroke-width="19.6849"/><path d="m1648.2897 620.244-299.2012.0446" stroke-width="20.5676"/><path d="m1491.6148 909.24806-.021-136.93117" stroke-width="19.6849"/><rect x="1191.6504" y="461.66092" width="457.09634" height="457.09634" stroke-width="19.6761"/></g></svg></a>
{{if .ParentURL}}<a class="nav-up" href="{{.ParentURL}}" tabindex="-1" title="Up" aria-label="Up">Up <svg viewBox="0 0 16 16" width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linejoin="miter" stroke-linecap="square"><path d="M8 13V3M3 8l5-5 5 5"/></svg></a>{{end}}
</nav>
{{if not .EditMode}}
<form class="search-form" action="/" method="get">
<input class="search-input" type="search" name="q" value="{{block "searchQuery" .}}{{end}}" placeholder="Search…" title="Search (F)" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />
<input class="input search-input" type="search" name="q" value="{{block "searchQuery" .}}{{end}}" placeholder="Search…" title="Search (F)" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />
</form>
{{end}}
<div class="header-actions">{{block "headerActions" .}}{{end}}</div>
<div class="header-actions row">{{block "headerActions" .}}{{end}}</div>
</header>
<div class="page-wrap">
<main>
+4 -4
View File
@@ -15,20 +15,20 @@
backdrop.className = 'modal-backdrop';
modal = document.createElement('div');
modal.className = 'modal';
modal.className = 'modal panel panel-floating';
modal.setAttribute('role', 'dialog');
modal.setAttribute('aria-modal', 'true');
var header = document.createElement('div');
header.className = 'modal-header';
header.className = 'panel-header';
titleEl = document.createElement('span');
header.appendChild(titleEl);
bodyEl = document.createElement('div');
bodyEl.className = 'modal-body';
bodyEl.className = 'panel-body';
footerEl = document.createElement('div');
footerEl.className = 'modal-footer';
footerEl.className = 'panel-footer';
cancelBtn = document.createElement('button');
cancelBtn.type = 'button';
+3 -3
View File
@@ -36,7 +36,7 @@ function postReplace(action, body, target) {
function promptPageName(title, initial, confirmLabel, onName) {
var input = document.createElement('input');
input.type = 'text';
input.className = 'modal-input';
input.className = 'input';
input.placeholder = 'Page name';
if (initial) input.value = initial;
openModal({
@@ -89,7 +89,7 @@ function movePage() {
onSelect: function (newParent) {
var input = document.createElement('input');
input.type = 'text';
input.className = 'modal-input';
input.className = 'input';
input.placeholder = 'Page name';
input.value = currentName;
@@ -99,7 +99,7 @@ function movePage() {
var linksLabel = document.createElement('label');
linksLabel.htmlFor = linksCheckbox.id;
linksLabel.className = 'modal-checkbox';
linksLabel.className = 'row';
linksLabel.appendChild(linksCheckbox);
linksLabel.appendChild(document.createTextNode('Update links'));
+1 -1
View File
@@ -42,7 +42,7 @@
function addTask(sectionIndex, headingId) {
var input = document.createElement('input');
input.type = 'text';
input.className = 'modal-input';
input.className = 'input';
input.placeholder = 'Task description';
var ctrl = openModal({
title: 'Add task',
+10 -8
View File
@@ -9,15 +9,17 @@
{{end}}
{{if .Entries}}
<h2 id="files">Files <button class="btn btn-small" data-companion-reveal hidden title="Open folder in file manager">open</button></h2>
<div class="listing">
<table class="data-table panel">
<tbody>
{{range .Entries}}
<div class="listing-item" data-path="{{.URL}}">
<span class="icon">{{.Icon}}</span>
<a href="{{.URL}}">{{.Name}}</a>
<span class="meta">{{.Meta}}</span>
</div>
<tr class="list-item" data-path="{{.URL}}">
<td class="icon">{{.Icon}}</td>
<td class="name"><a href="{{.URL}}">{{.Name}}</a></td>
<td class="meta">{{.Meta}}</td>
</tr>
{{end}}
</div>
</tbody>
</table>
{{else if not .Content}}
{{if not .SpecialContent}}
<p class="empty">Empty folder — <a href="?edit">[CREATE]</a></p>
@@ -35,7 +37,7 @@
<script src="/_/page/sidebar-fab.js"></script>
{{end}}
{{define "sidebar"}}{{if .CanEdit}}<nav class="actions">
{{define "sidebar"}}{{if .CanEdit}}<nav class="actions panel panel-sidebar">
<div class="panel-header">ACTIONS</div>
<button class="btn btn-block" onclick="newPage()" title="New page (N)">NEW PAGE</button>
<a class="btn btn-block" href="?edit" title="Edit page (E)">EDIT PAGE</a>
+1 -1
View File
@@ -6,7 +6,7 @@ document.addEventListener("DOMContentLoaded", function () {
if (headings.length < 2) return;
var nav = document.createElement("nav");
nav.className = "toc";
nav.className = "toc panel panel-sidebar";
var header = document.createElement("div");
header.className = "panel-header";
+31 -21
View File
@@ -70,6 +70,15 @@
dropdown.className = 'suggest-dropdown';
host.appendChild(dropdown);
function makeRow(cls, tabbable) {
var tr = document.createElement('tr');
tr.className = cls;
if (tabbable) tr.setAttribute('tabindex', '0');
var td = document.createElement('td');
tr.appendChild(td);
return { tr: tr, td: td };
}
var state = {
results: [],
total: 0,
@@ -102,49 +111,50 @@
dropdown.classList.remove('is-open');
return;
}
var table = document.createElement('table');
table.className = 'data-table';
var tbody = document.createElement('tbody');
table.appendChild(tbody);
var tokens = tokenize(state.query);
if (state.results.length === 0) {
var empty = document.createElement('div');
empty.className = 'suggest-row is-empty';
empty.textContent = 'No matches';
dropdown.appendChild(empty);
var empty = makeRow('is-empty', false);
empty.td.textContent = 'No matches';
tbody.appendChild(empty.tr);
} else {
state.results.forEach(function (r, i) {
var row = document.createElement('button');
row.type = 'button';
row.className = 'suggest-row';
row.setAttribute('data-idx', String(i));
var row = makeRow('suggest-row', true);
row.tr.setAttribute('data-idx', String(i));
var nameEl = document.createElement('span');
nameEl.className = 'suggest-name';
nameEl.innerHTML = highlight(r.name, tokens);
var pathEl = document.createElement('span');
pathEl.className = 'suggest-path';
pathEl.textContent = '/' + r.path;
row.appendChild(nameEl);
row.appendChild(pathEl);
if (i === state.activeIdx) row.classList.add('is-active');
row.addEventListener('mousedown', function (e) {
row.td.appendChild(nameEl);
row.td.appendChild(pathEl);
if (i === state.activeIdx) row.tr.classList.add('is-active');
row.tr.addEventListener('mousedown', function (e) {
// mousedown (not click) so the input doesn't blur-close
// the dropdown before the pick handler fires.
e.preventDefault();
pick(i);
});
dropdown.appendChild(row);
tbody.appendChild(row.tr);
});
if (opts.showFooter && state.total > state.results.length) {
var footer = document.createElement('button');
footer.type = 'button';
footer.className = 'suggest-row suggest-footer';
footer.textContent = 'Show all ' + state.total + ' matches';
var footer = makeRow('suggest-row suggest-footer', true);
footer.td.textContent = 'Show all ' + state.total + ' matches';
var footerIdx = state.results.length;
if (state.activeIdx === footerIdx) footer.classList.add('is-active');
footer.addEventListener('mousedown', function (e) {
if (state.activeIdx === footerIdx) footer.tr.classList.add('is-active');
footer.tr.addEventListener('mousedown', function (e) {
e.preventDefault();
pickFooter();
});
dropdown.appendChild(footer);
tbody.appendChild(footer.tr);
}
}
dropdown.appendChild(table);
dropdown.classList.add('is-open');
}
@@ -225,7 +235,7 @@
state.activeIdx = next;
render();
// Keep the active row in view.
var active = dropdown.querySelector('.suggest-row.is-active');
var active = dropdown.querySelector('tr.is-active');
if (active && active.scrollIntoView) {
try { active.scrollIntoView({ block: 'nearest' }); } catch (e) {}
}
+368 -755
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -28,7 +28,7 @@
var container = document.createElement('div');
var treeEl = document.createElement('div');
treeEl.className = 'tree-picker';
treeEl.className = 'tree-picker panel';
var selectedPathEl = document.createElement('div');
selectedPathEl.className = 'tree-selected-path muted';
+5 -1
View File
@@ -71,7 +71,11 @@ func renderMarkdown(raw []byte) template.HTML {
if err := md.Convert(raw, &buf); err != nil {
return ""
}
return template.HTML(rewriteTaskCheckboxes(buf.Bytes()))
out := rewriteTaskCheckboxes(buf.Bytes())
// Goldmark emits a bare `<table>`; tag it so it picks up the shared
// .data-table styling with the grid modifier (per-cell borders + header).
out = bytes.ReplaceAll(out, []byte("<table>"), []byte(`<table class="data-table data-table-grid">`))
return template.HTML(out)
}
// extractFirstHeading returns the text of the first ATX heading in raw markdown,