Add dark theme support and bookmark status to share view
- Implement dark/light theme toggle with persistent preference via localStorage - Add a sticky toolbar with theme toggle, Markdown export, and PDF export buttons - Update bookmark button to reflect current state with visual feedback - Introduce CSS custom properties for theming and responsive layout improvements
This commit is contained in:
+41
-5
@@ -2812,12 +2812,48 @@ async def public_share_view(token: str):
|
||||
post = parse_markdown_file(raw)
|
||||
html = _render_markdown(post.content, share["vault"], file_path)
|
||||
title = post.metadata.get("title", file_path.stem)
|
||||
return HTMLResponse(f"""<!DOCTYPE html><html lang="fr"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
return HTMLResponse(f"""<!DOCTYPE html><html lang="fr" data-theme="dark"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>{title} — ObsiGate Share</title>
|
||||
<style>body{{font-family:system-ui,sans-serif;max-width:800px;margin:0 auto;padding:20px;line-height:1.6;color:#1a1a2e;background:#f8f9fa}}
|
||||
pre{{background:#eee;padding:12px;border-radius:6px;overflow-x:auto}}code{{font-size:0.9em}}a{{color:#6366f1}}.wikilink{{color:#6366f1;cursor:default}}
|
||||
img{{max-width:100%}}.share-banner{{background:#6366f1;color:#fff;padding:8px 16px;border-radius:6px;margin-bottom:20px;font-size:0.85rem}}</style></head>
|
||||
<body><div class="share-banner">📄 Document partagé via ObsiGate</div><h1>{title}</h1>{html}</body></html>""")
|
||||
<style>
|
||||
:root {{ --bg:#1a1a2e; --bg-card:#16213e; --text:#e0e0e0; --text-muted:#888; --accent:#6366f1; --border:#2a2a4a; }}
|
||||
[data-theme="light"] {{ --bg:#f8f9fa; --bg-card:#fff; --text:#1a1a2e; --text-muted:#666; --accent:#4f46e5; --border:#ddd; }}
|
||||
*{{box-sizing:border-box;margin:0;padding:0}}
|
||||
body{{font-family:system-ui,-apple-system,sans-serif;background:var(--bg);color:var(--text);line-height:1.7;min-height:100vh}}
|
||||
.toolbar{{position:sticky;top:0;z-index:10;background:var(--bg-card);border-bottom:1px solid var(--border);padding:8px 16px;display:flex;align-items:center;gap:8px;flex-wrap:wrap}}
|
||||
.toolbar-title{{font-weight:600;font-size:0.9rem;margin-right:auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}}
|
||||
.toolbar-btn{{padding:6px 12px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--text);cursor:pointer;font-size:0.8rem;display:flex;align-items:center;gap:4px;transition:all .15s}}
|
||||
.toolbar-btn:hover{{background:var(--accent);color:#fff;border-color:var(--accent)}}
|
||||
.share-banner{{background:var(--accent);color:#fff;padding:6px 16px;font-size:0.8rem;text-align:center}}
|
||||
.content{{max-width:820px;margin:0 auto;padding:24px 20px 60px}}
|
||||
.content h1{{font-size:1.8rem;margin-bottom:16px;border-bottom:2px solid var(--border);padding-bottom:8px}}
|
||||
.content h2{{font-size:1.4rem;margin:24px 0 12px}}
|
||||
.content h3{{font-size:1.15rem;margin:20px 0 8px}}
|
||||
.content p{{margin:8px 0}}
|
||||
.content pre{{background:var(--bg-card);border:1px solid var(--border);border-radius:8px;padding:12px 16px;overflow-x:auto;font-size:0.85rem}}
|
||||
.content code{{font-size:0.9em;background:var(--bg-card);padding:1px 4px;border-radius:3px}}
|
||||
.content pre code{{background:none;padding:0}}
|
||||
.content a{{color:var(--accent)}}.content img{{max-width:100%;border-radius:6px}}
|
||||
.content blockquote{{border-left:3px solid var(--accent);padding-left:16px;color:var(--text-muted);margin:12px 0}}
|
||||
.content table{{border-collapse:collapse;width:100%;margin:12px 0}}
|
||||
.content th,.content td{{border:1px solid var(--border);padding:8px 12px;text-align:left}}
|
||||
.content th{{background:var(--bg-card)}}
|
||||
@media(max-width:600px){{.content{{padding:16px 12px 40px}}.toolbar{{gap:4px}}.toolbar-btn{{padding:4px 8px;font-size:0.7rem}}}}
|
||||
</style></head>
|
||||
<body>
|
||||
<div class="share-banner">📄 Document partagé via ObsiGate</div>
|
||||
<div class="toolbar">
|
||||
<span class="toolbar-title">{title}</span>
|
||||
<button class="toolbar-btn" onclick="toggleTheme()" title="Thème clair/sombre">🌓</button>
|
||||
<button class="toolbar-btn" onclick="exportMD()" title="Exporter en Markdown">📥 .md</button>
|
||||
<button class="toolbar-btn" onclick="exportPDF()" title="Exporter en PDF">📄 PDF</button>
|
||||
</div>
|
||||
<div class="content" id="content">{html}</div>
|
||||
<script>
|
||||
function toggleTheme(){{var t=document.documentElement;t.dataset.theme=t.dataset.theme==="light"?"dark":"light";localStorage.setItem("obsigate-share-theme",t.dataset.theme)}}
|
||||
(function(){{var s=localStorage.getItem("obsigate-share-theme");if(s)document.documentElement.dataset.theme=s}})();
|
||||
function exportMD(){{var t=document.getElementById("content").innerText;var b=new Blob([t],{{type:"text/markdown"}});var a=document.createElement("a");a.href=URL.createObjectURL(b);a.download="{title}.md";a.click()}}
|
||||
function exportPDF(){{window.print()}}
|
||||
</script></body></html>""")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
+14
-2
@@ -3283,11 +3283,23 @@
|
||||
})();
|
||||
shareBtn.addEventListener("click", () => openShareDialog(data.vault, data.path));
|
||||
|
||||
// Bookmark button
|
||||
const bookmarkBtn = el("button", { class: "btn-action", title: "Ajouter/Retirer des bookmarks" }, [icon("bookmark-plus", 14), document.createTextNode("Bookmark")]);
|
||||
// Bookmark button — check if already bookmarked
|
||||
const bookmarkBtn = el("button", { class: "btn-action btn-bookmark", title: "Ajouter/Retirer des bookmarks" }, [icon("bookmark-plus", 14), document.createTextNode("Bookmark")]);
|
||||
// Check bookmark status and color the button
|
||||
(async () => {
|
||||
try {
|
||||
const bms = await api("/api/bookmarks");
|
||||
if (Array.isArray(bms) && bms.some(b => b.vault === data.vault && b.path === data.path)) {
|
||||
bookmarkBtn.classList.add("active");
|
||||
bookmarkBtn.title = "Retirer des bookmarks";
|
||||
}
|
||||
} catch (e) { /* ignore */ }
|
||||
})();
|
||||
bookmarkBtn.addEventListener("click", async () => {
|
||||
try {
|
||||
const res = await api("/api/bookmarks/toggle", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ vault: data.vault, path: data.path, title: data.title }) });
|
||||
bookmarkBtn.classList.toggle("active", res.bookmarked);
|
||||
bookmarkBtn.title = res.bookmarked ? "Retirer des bookmarks" : "Ajouter aux bookmarks";
|
||||
showToast(res.bookmarked ? "Ajouté aux bookmarks" : "Retiré des bookmarks", "success");
|
||||
if (typeof DashboardBookmarkWidget !== "undefined") DashboardBookmarkWidget.load();
|
||||
} catch (err) { showToast("Erreur: " + err.message, "error"); }
|
||||
|
||||
@@ -5830,6 +5830,15 @@ body.popup-mode .content-area {
|
||||
.search-replace-btn.destructive { border-color: var(--text-error); color: var(--text-error); }
|
||||
|
||||
/* ── Active search result highlight ── */
|
||||
.btn-bookmark.active {
|
||||
color: #059669;
|
||||
border-color: #059669;
|
||||
background: rgba(5, 150, 105, 0.08);
|
||||
}
|
||||
.btn-bookmark.active:hover {
|
||||
background: rgba(5, 150, 105, 0.15);
|
||||
}
|
||||
|
||||
.btn-share.shared {
|
||||
color: #059669;
|
||||
border-color: #059669;
|
||||
|
||||
Reference in New Issue
Block a user