Integrate Paskia auth UI flows, hide delete for empty pages.
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
"@codemirror/view": "^6.43.8",
|
||||
"@lezer/highlight": "^1.2.3",
|
||||
"codemirror": "^6.0.2",
|
||||
"paskia": "file:../../paskia/paskia-js",
|
||||
"transliteration": "^2.6.1",
|
||||
"vue": "^3.5.26",
|
||||
"vuedraggable": "^4.1.0"
|
||||
|
||||
@@ -142,6 +142,7 @@ function onEnd() {
|
||||
<span class="acts">
|
||||
<span v-if="!element.published" class="draft">draft</span>
|
||||
<button
|
||||
v-if="element.has_content || !element.children.length"
|
||||
type="button"
|
||||
class="act del"
|
||||
:class="{ armed: handlers.arming() === element.path }"
|
||||
|
||||
@@ -432,13 +432,14 @@ article h1 .edit-link {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Login button injected by pagerite.js for anonymous visitors when an auth
|
||||
proxy gates /_api (the settings probe answered 401). Same corner as the
|
||||
site pen, styled like the edit pens. */
|
||||
button.login-link {
|
||||
/* Login/profile buttons injected by pagerite.js when Paskia SSO is in use.
|
||||
Both sit in the banner's top-right corner, to the right of the site pen,
|
||||
and are styled like the edit pens. */
|
||||
button.login-link,
|
||||
button.profile-link {
|
||||
position: absolute;
|
||||
top: 0.6rem;
|
||||
right: 1.25rem;
|
||||
right: 0.5rem;
|
||||
z-index: 10;
|
||||
font: inherit;
|
||||
border: none;
|
||||
@@ -449,7 +450,8 @@ button.login-link {
|
||||
text-shadow: 0 0 0.1em black;
|
||||
}
|
||||
|
||||
button.login-link:hover {
|
||||
button.login-link:hover,
|
||||
button.profile-link:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
|
||||
+81
-18
@@ -4,6 +4,8 @@
|
||||
//
|
||||
// Also: scroll-reveal effects and code copy buttons. These need no
|
||||
// support from the article itself and are re-applied after each swap.
|
||||
import { showAuthIframe } from 'paskia'
|
||||
|
||||
(() => {
|
||||
if (import.meta.env.DEV) {
|
||||
// The theme is selectable; the backend names the active one in a meta
|
||||
@@ -31,11 +33,15 @@
|
||||
// only after we know the user has pagerite:admin access. We probe our own
|
||||
// /_api/settings endpoint: the same reverse proxy that gates /_api returns
|
||||
// 401/403 here, and a 200 means the permission is present.
|
||||
// 401 = anonymous: show a small login link in the banner corner instead.
|
||||
// 403 = logged in without the permission: no pens. Any other outcome
|
||||
// (network error — i.e. no auth proxy deployed, as in dev) leaves editing
|
||||
// open as before: the real gate is the proxy in front of /_api.
|
||||
let authorized = false;
|
||||
//
|
||||
// When Paskia SSO is in use, 401/403 responses carry `auth.iframe`, which
|
||||
// we use to open the login/profile dialogs inline instead of navigating
|
||||
// away. A separate probe to /auth/api/settings tells us whether Paskia is
|
||||
// available at all; if it isn't, we treat the site as dev/no-proxy and
|
||||
// leave editing open.
|
||||
let ssoAvailable = false;
|
||||
let isAdmin = false;
|
||||
let loginIframeUrl = null;
|
||||
let editorMeta = null;
|
||||
|
||||
function makePen(mode) {
|
||||
@@ -61,7 +67,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
function addLoginLink() {
|
||||
function addLoginButton(url) {
|
||||
const banner = document.getElementById("page-banner");
|
||||
if (!banner || banner.parentElement.querySelector(".login-link")) return;
|
||||
const btn = document.createElement("button");
|
||||
@@ -69,12 +75,54 @@
|
||||
btn.className = "login-link";
|
||||
btn.title = "log in";
|
||||
btn.textContent = "🔑";
|
||||
btn.addEventListener("click", () => {
|
||||
location.href = "/auth/";
|
||||
btn.addEventListener("click", async () => {
|
||||
try {
|
||||
await showAuthIframe(url);
|
||||
// Successful login: refresh the auth UI (may now show edit pens).
|
||||
setupAuth();
|
||||
} catch {
|
||||
// Cancelled or error: leave the button in place.
|
||||
}
|
||||
});
|
||||
banner.after(btn);
|
||||
}
|
||||
|
||||
function injectProfileButton() {
|
||||
const banner = document.getElementById("page-banner");
|
||||
if (!banner || banner.parentElement.querySelector(".profile-link")) return;
|
||||
const btn = document.createElement("button");
|
||||
btn.type = "button";
|
||||
btn.className = "profile-link";
|
||||
btn.title = "profile";
|
||||
btn.textContent = "👤";
|
||||
btn.addEventListener("click", () => {
|
||||
showAuthIframe("/auth/").catch(() => {});
|
||||
});
|
||||
banner.after(btn);
|
||||
}
|
||||
|
||||
function renderAuthUi() {
|
||||
const banner = document.getElementById("page-banner");
|
||||
if (banner) {
|
||||
for (const el of banner.parentElement.querySelectorAll(
|
||||
".banner-edit-link, .login-link, .profile-link",
|
||||
)) {
|
||||
el.remove();
|
||||
}
|
||||
}
|
||||
if (isAdmin) {
|
||||
injectPens();
|
||||
if (ssoAvailable) injectProfileButton();
|
||||
} else if (ssoAvailable && loginIframeUrl) {
|
||||
addLoginButton(loginIframeUrl);
|
||||
} else if (ssoAvailable) {
|
||||
injectProfileButton();
|
||||
} else {
|
||||
// No Paskia SSO: dev/no-proxy fallback, leave editing open.
|
||||
injectPens();
|
||||
}
|
||||
}
|
||||
|
||||
async function setupAuth() {
|
||||
const src = document.querySelector('meta[name="pagerite:editor-src"]')?.content;
|
||||
if (!src) return;
|
||||
@@ -82,18 +130,32 @@
|
||||
src,
|
||||
css: document.querySelector('meta[name="pagerite:editor-css"]')?.content,
|
||||
};
|
||||
|
||||
// Detect whether Paskia SSO is available on this site.
|
||||
try {
|
||||
const ssoRes = await fetch("/auth/api/settings");
|
||||
ssoAvailable = ssoRes.ok;
|
||||
} catch {
|
||||
ssoAvailable = false;
|
||||
}
|
||||
|
||||
// Check whether the current session has pagerite:admin.
|
||||
isAdmin = false;
|
||||
loginIframeUrl = null;
|
||||
let status = 0;
|
||||
try {
|
||||
status = (await fetch("/_api/settings")).status;
|
||||
const res = await fetch("/_api/settings");
|
||||
status = res.status;
|
||||
if (status === 401) {
|
||||
const data = await res.json().catch(() => ({}));
|
||||
loginIframeUrl = data.auth?.iframe || null;
|
||||
}
|
||||
} catch {
|
||||
// Auth proxy unreachable: treat as not deployed.
|
||||
}
|
||||
if (status === 401) addLoginLink();
|
||||
else if (status !== 403) {
|
||||
authorized = true;
|
||||
injectPens();
|
||||
placeEditPen();
|
||||
// No auth proxy / dev.
|
||||
}
|
||||
if (status === 200) isAdmin = true;
|
||||
|
||||
renderAuthUi();
|
||||
}
|
||||
|
||||
function runScripts(root) {
|
||||
@@ -158,8 +220,9 @@
|
||||
(window.requestIdleCallback || setTimeout)(preload);
|
||||
const main = document.getElementById("main");
|
||||
addCopyButtons(main);
|
||||
// Fetch-navigation swaps #main, discarding the article pen; re-add it.
|
||||
if (authorized) injectPens();
|
||||
// Fetch-navigation swaps #main, discarding the article pen and corner
|
||||
// buttons; re-add whichever auth UI is appropriate for this session.
|
||||
renderAuthUi();
|
||||
placeEditPen();
|
||||
// Multi-column layout only when there is enough text to justify it.
|
||||
// Split the body into columned segments: h2s and wide figures are
|
||||
|
||||
Reference in New Issue
Block a user