v0.2.85
This commit is contained in:
1 parent
90e3c399ea
commit
57ad26878b
12 files changed
+477
-31
No files matched your search
+26
-17
@@ -26,7 +26,7 @@ import { bindIdentityDialog, validateCurrentSession } from "@rustpad/auth-ui";
|
||||
import { bindNoteFiles } from "@rustpad/note-files";
|
||||
import { currentShareUrl, readEditorState, writeEditorState } from "@rustpad/url-state";
|
||||
import { toast } from "@rustpad/toast";
|
||||
import { formatDateTime, formatNumber, formatTime, t, translateSource } from "@rustpad/i18n";
|
||||
import { formatDateTime, formatNumber, formatTime, getLocale, t, tp, translateSource } from "@rustpad/i18n";
|
||||
import { getTheme } from "@rustpad/theme";
|
||||
import { isResourceAccessError } from "@rustpad/security";
|
||||
import { syncSelectControl } from "@rustpad/select";
|
||||
@@ -2442,16 +2442,17 @@ export function startNoteEditor(adapter) {
|
||||
}
|
||||
|
||||
function historyRevisionCard(revision, compact = false) {
|
||||
const snippet = escapeHtml(revision.content.trim().split("\n").slice(0, compact ? 2 : 3).join(" · ").slice(0, compact ? 110 : 150) || "Empty note");
|
||||
const author = revision.author || "Unknown author";
|
||||
return `<article class="revision${compact ? " revision--compact" : ""}" data-history-revision="${revision.id}"><span class="revision__marker" style="--owner:${colorFor(author)}"></span><div><div class="revision__meta"><strong>${escapeHtml(author)}</strong><time>${formatDate(revision.created_at)}</time></div><p class="revision__snippet">${snippet}</p><button type="button" data-preview="${revision.id}">Preview</button><button type="button" data-revision="${revision.id}">Restore</button><div class="revision__preview" hidden></div></div></article>`;
|
||||
const emptyNote = t("editor.historyEmptyNote", {}, "Empty note");
|
||||
const snippet = escapeHtml(revision.content.trim().split("\n").slice(0, compact ? 2 : 3).join(" · ").slice(0, compact ? 110 : 150) || emptyNote);
|
||||
const author = revision.author || t("editor.historyUnknownAuthor", {}, "Unknown author");
|
||||
return `<article class="revision${compact ? " revision--compact" : ""}" data-history-revision="${revision.id}"><span class="revision__marker" style="--owner:${colorFor(author)}"></span><div><div class="revision__meta"><strong>${escapeHtml(author)}</strong><time>${formatDate(revision.created_at)}</time></div><p class="revision__snippet">${snippet}</p><button type="button" data-preview="${revision.id}">${escapeHtml(t("common.preview", {}, "Preview"))}</button><button type="button" data-revision="${revision.id}">${escapeHtml(t("editor.historyRestore", {}, "Restore"))}</button><div class="revision__preview" hidden></div></div></article>`;
|
||||
}
|
||||
|
||||
function renderHistoryListView() {
|
||||
historyList.classList.remove("history-list--archive");
|
||||
historyList.innerHTML = historyRevisions.length
|
||||
? historyRevisions.map(revision => historyRevisionCard(revision)).join("")
|
||||
: '<p class="empty">No history yet.</p>';
|
||||
: `<p class="empty">${escapeHtml(t("editor.historyEmpty", {}, "No history yet."))}</p>`;
|
||||
}
|
||||
|
||||
function dayKey(date) {
|
||||
@@ -2468,8 +2469,8 @@ export function startNoteEditor(adapter) {
|
||||
.filter(item => item.date);
|
||||
if (!dated.length) {
|
||||
historyList.innerHTML = historyRevisions.length
|
||||
? '<p class="empty">Archive view needs valid revision timestamps.</p>'
|
||||
: '<p class="empty">No history yet.</p>';
|
||||
? `<p class="empty">${escapeHtml(t("editor.historyArchiveInvalidDates", {}, "Archive view needs valid revision timestamps."))}</p>`
|
||||
: `<p class="empty">${escapeHtml(t("editor.historyEmpty", {}, "No history yet."))}</p>`;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2486,13 +2487,18 @@ export function startNoteEditor(adapter) {
|
||||
});
|
||||
const maxMonthCount = Math.max(1, ...monthCounts);
|
||||
const months = Array.from({ length: 12 }, (_, month) => month);
|
||||
const monthNames = new Intl.DateTimeFormat(undefined, { month: "short" });
|
||||
const monthNamesLong = new Intl.DateTimeFormat(undefined, { month: "long" });
|
||||
const locale = getLocale();
|
||||
const monthNames = new Intl.DateTimeFormat(locale, { month: "short" });
|
||||
const monthNamesLong = new Intl.DateTimeFormat(locale, { month: "long" });
|
||||
const weekdayNames = Array.from({ length: 7 }, (_, index) =>
|
||||
new Intl.DateTimeFormat(locale, { weekday: "narrow" }).format(new Date(2024, 0, 1 + index))
|
||||
);
|
||||
const yearButtons = years.map(year => `<button type="button" data-history-year="${year}" class="${year === historyArchiveYear ? "active" : ""}" aria-pressed="${year === historyArchiveYear}">${year}</button>`).join("");
|
||||
const histogram = months.map(month => {
|
||||
const count = monthCounts[month];
|
||||
const height = count ? Math.max(12, Math.round((count / maxMonthCount) * 72)) : 3;
|
||||
return `<div class="history-archive__bar-cell" title="${escapeHtml(monthNamesLong.format(new Date(historyArchiveYear, month, 1)))}: ${count} revisions"><span class="history-archive__bar" style="--history-bar-height:${height}px"></span><small>${escapeHtml(monthNames.format(new Date(historyArchiveYear, month, 1)))}</small></div>`;
|
||||
const revisionLabel = tp("editor.historyRevisionCount", count, {}, "{count} revisions");
|
||||
return `<div class="history-archive__bar-cell" title="${escapeHtml(monthNamesLong.format(new Date(historyArchiveYear, month, 1)))}: ${escapeHtml(revisionLabel)}"><span class="history-archive__bar" style="--history-bar-height:${height}px"></span><small>${escapeHtml(monthNames.format(new Date(historyArchiveYear, month, 1)))}</small></div>`;
|
||||
}).join("");
|
||||
|
||||
const calendars = months.filter(month => monthCounts[month] > 0).map(month => {
|
||||
@@ -2505,19 +2511,22 @@ export function startNoteEditor(adapter) {
|
||||
const key = `${historyArchiveYear}-${String(month + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
|
||||
const revisions = byDay.get(key) || [];
|
||||
const active = historyArchiveDay === key;
|
||||
const revisionLabel = tp("editor.historyRevisionCount", revisions.length, {}, "{count} revisions");
|
||||
days += revisions.length
|
||||
? `<button type="button" class="history-calendar__day${active ? " active" : ""}" data-history-day="${key}" title="${revisions.length} revision${revisions.length === 1 ? "" : "s"}"><span>${day}</span><small>${revisions.length}</small></button>`
|
||||
? `<button type="button" class="history-calendar__day${active ? " active" : ""}" data-history-day="${key}" title="${escapeHtml(revisionLabel)}"><span>${day}</span><small>${revisions.length}</small></button>`
|
||||
: `<span class="history-calendar__day history-calendar__day--empty"><span>${day}</span></span>`;
|
||||
}
|
||||
return `<section class="history-calendar__month"><div class="history-calendar__month-head"><strong>${escapeHtml(monthNamesLong.format(first))}</strong><span>${monthCounts[month]} revisions</span></div><div class="history-calendar__weekdays"><span>M</span><span>T</span><span>W</span><span>T</span><span>F</span><span>S</span><span>S</span></div><div class="history-calendar__days">${blanks}${days}</div></section>`;
|
||||
const monthRevisionLabel = tp("editor.historyRevisionCount", monthCounts[month], {}, "{count} revisions");
|
||||
const weekdayHtml = weekdayNames.map(name => `<span>${escapeHtml(name)}</span>`).join("");
|
||||
return `<section class="history-calendar__month"><div class="history-calendar__month-head"><strong>${escapeHtml(monthNamesLong.format(first))}</strong><span>${escapeHtml(monthRevisionLabel)}</span></div><div class="history-calendar__weekdays">${weekdayHtml}</div><div class="history-calendar__days">${blanks}${days}</div></section>`;
|
||||
}).join("");
|
||||
|
||||
const selected = historyArchiveDay && byDay.get(historyArchiveDay);
|
||||
const selectedHtml = selected?.length
|
||||
? `<section class="history-archive__selected"><div class="history-archive__selected-head"><strong>${escapeHtml(historyArchiveDay)}</strong><span>${selected.length} saved version${selected.length === 1 ? "" : "s"}</span></div>${selected.map(revision => historyRevisionCard(revision, true)).join("")}</section>`
|
||||
: '<p class="history-archive__hint">Select a highlighted day to inspect saved versions.</p>';
|
||||
? `<section class="history-archive__selected"><div class="history-archive__selected-head"><strong>${escapeHtml(historyArchiveDay)}</strong><span>${escapeHtml(tp("editor.historySavedVersionCount", selected.length, {}, "{count} saved versions"))}</span></div>${selected.map(revision => historyRevisionCard(revision, true)).join("")}</section>`
|
||||
: `<p class="history-archive__hint">${escapeHtml(t("editor.historyArchiveHint", {}, "Select a highlighted day to inspect saved versions."))}</p>`;
|
||||
|
||||
historyList.innerHTML = `<div class="history-archive"><div class="history-archive__years" aria-label="Archive year">${yearButtons}</div><div class="history-archive__histogram" aria-label="Revision activity by month">${histogram}</div><div class="history-calendar">${calendars}</div>${selectedHtml}</div>`;
|
||||
historyList.innerHTML = `<div class="history-archive"><div class="history-archive__years" aria-label="${escapeHtml(t("editor.historyArchiveYear", {}, "Archive year"))}">${yearButtons}</div><div class="history-archive__histogram" aria-label="${escapeHtml(t("editor.historyArchiveActivity", {}, "Revision activity by month"))}">${histogram}</div><div class="history-calendar">${calendars}</div>${selectedHtml}</div>`;
|
||||
}
|
||||
|
||||
function renderHistory() {
|
||||
@@ -2581,7 +2590,7 @@ export function startNoteEditor(adapter) {
|
||||
historyPanel.classList.add("open");
|
||||
historyPanel.setAttribute("aria-hidden", "false");
|
||||
document.body.classList.add("history-open");
|
||||
historyList.innerHTML = '<p class="empty">Loading…</p>';
|
||||
historyList.innerHTML = `<p class="empty">${escapeHtml(t("common.loading", {}, "Loading…"))}</p>`;
|
||||
try {
|
||||
historyRevisions = await adapter.loadHistory(accessToken);
|
||||
historyArchiveYear = null;
|
||||
@@ -2589,7 +2598,7 @@ export function startNoteEditor(adapter) {
|
||||
renderHistory();
|
||||
} catch (e) {
|
||||
historyList.innerHTML = `<p class="error">${escapeHtml(e.message)}</p>`;
|
||||
toast.danger(e.message, { title: "Could not load version history" });
|
||||
toast.danger(e.message, { title: t("editor.historyLoadFailed", {}, "Could not load version history") });
|
||||
}
|
||||
});
|
||||
document.querySelector("#close-history").addEventListener("click", () => {
|
||||
|
||||
Reference in new issue
Block a user