Abmelden nur noch in den Einstellungen, App-Menue statt Zahnrad
Marcs Entscheidung: In der HoneyBar fremder Apps steht kein Abmelden mehr — es war dort ohnehin nur ein Link auf den Schreibtisch. Als einzige Schaltflaeche, die eine Sitzung beendet, steht es jetzt an genau einer Stelle: unten in den Einstellungen, sichtbar nur bei eigener Anmeldung. Damit faellt auch der ?abmelden=1-Pfad wieder weg und /api/apps braucht das oidc-Feld nicht mehr. Das Zahnrad rechts in der Menueleiste ist durch den Pfeil mit der App-Liste ersetzt — derselbe wie in der HoneyBar. Beide Leisten tragen damit dieselben vier Dinge: Logo, Apps, Wetter/Uhr, Aufklappmenue.
This commit is contained in:
1 parent
0a5cd94ba0
commit
6d75ce78c2
7 files changed
+136
-65
No files matched your search
@@ -41,8 +41,16 @@ Eine Annahme von damals hat sich nicht gehalten: „ohne sie zu verlassen"
|
||||
schreibt, und die HoneyBar darf in einer fremden App nicht schreiben — die
|
||||
Sitzung kommt über die Site-Grenze nicht mit, und selbst unter einer Domain
|
||||
liegt das CSRF-Prüfwort in einem Cookie, das nur HoneyOS' eigene Seiten lesen.
|
||||
Also reicht die HoneyBar die Frage als `?einstellungen=1` / `?abmelden=1` an den
|
||||
Schreibtisch weiter. Ein Klick, ein Seitenwechsel — dort, wo man angemeldet ist.
|
||||
Also reicht die HoneyBar die Frage als `?einstellungen=1` an den Schreibtisch
|
||||
weiter. Ein Klick, ein Seitenwechsel — dort, wo man angemeldet ist.
|
||||
|
||||
**Abmelden ist ganz aus den Leisten verschwunden** und steht unten in den
|
||||
Einstellungen (Marcs Entscheidung, 29.08.2026). Aus fremden Apps war es ohnehin
|
||||
nur ein Link auf den Schreibtisch gewesen; als einzige Schaltfläche, die eine
|
||||
Sitzung beendet, gehört es an eine Stelle statt an drei. Im selben Zug ist das
|
||||
Zahnrad aus der Menüleiste des Schreibtischs gefallen und durch den Pfeil mit
|
||||
der App-Liste ersetzt worden — damit tragen beide Leisten wirklich dieselben
|
||||
vier Dinge: Logo, Apps, Wetter/Uhr, Aufklappmenü.
|
||||
|
||||
**Was ohne Seitenwechsel ginge, wenn es je stört:** die reinen Aussehensschalter
|
||||
(Röhre, Leuchten, Scanlines) direkt im Menü. Sie kämen ohne Prüfwort aus, wenn
|
||||
|
||||
@@ -395,25 +395,28 @@ Das `■ HONEYOS` links ist ein Menü — auf dem Schreibtisch wie in jeder App:
|
||||
| Schreibtisch | Über HoneyOS |
|
||||
| Einstellungen … | Einstellungen |
|
||||
| HoneyBar einklappen | Terminal-/Desktop-Modus |
|
||||
| Abmelden | Abmelden |
|
||||
|
||||
Rechts daneben bleibt der Pfeil mit den Apps. Eines auf heißt anderes zu.
|
||||
Rechts daneben klappt ein Pfeil die App-Liste auf — in beiden Leisten gleich.
|
||||
Das Zahnrad, das dort früher stand, ist weg: Einstellungen stehen jetzt links
|
||||
im Systemmenü, wo sie in jeder App auch stehen.
|
||||
|
||||
**In den Apps sind es Links auf den Schreibtisch, keine Handlungen** — und das
|
||||
ist eine Grenze, keine Bequemlichkeit. Einstellungen und Abmelden schreiben, und
|
||||
**In den Apps sind die Punkte Links auf den Schreibtisch, keine Handlungen** —
|
||||
und das ist eine Grenze, keine Bequemlichkeit. Einstellungen schreiben, und
|
||||
dafür braucht der Server die HoneyOS-Sitzung: Aus einer fremden Site schickt der
|
||||
Browser sie nicht mit, und selbst unter einer Domain liegt das CSRF-Prüfwort in
|
||||
einem Cookie, das nur HoneyOS' eigene Seiten lesen dürfen. Ein Abmelden, das ein
|
||||
einfacher Aufruf erledigt, könnte außerdem jede beliebige Seite auslösen.
|
||||
einem Cookie, das nur HoneyOS' eigene Seiten lesen dürfen. Also stellt die
|
||||
HoneyBar die Frage in der Adresse (`?einstellungen=1`), und der Schreibtisch
|
||||
beantwortet sie: Er macht dasselbe Feld auf, das auch `[S]` öffnet, und nimmt
|
||||
den Anhang danach wieder aus der Adresse.
|
||||
|
||||
Also stellt die HoneyBar die Frage in der Adresse (`?einstellungen=1`,
|
||||
`?abmelden=1`), und der Schreibtisch beantwortet sie: Er macht dasselbe
|
||||
Einstellungsfeld auf, das auch `[S]` öffnet, und meldet mit einem echten POST
|
||||
ab. Danach nimmt er den Anhang aus der Adresse wieder heraus.
|
||||
|
||||
`Abmelden` steht nur da, wenn HoneyOS überhaupt anmeldet — im offenen Betrieb
|
||||
oder hinter einem Proxy fehlt der Punkt. Deshalb gibt `/api/apps` neben Liste
|
||||
und Aussehen auch `oidc` heraus.
|
||||
**Abmelden steht in den Einstellungen, ganz unten — und sonst nirgends.** Nicht
|
||||
in der HoneyBar fremder Apps, nicht im Systemmenü, nicht im Startmenü. Es ist
|
||||
die einzige Schaltfläche, die eine Sitzung beendet statt etwas einzustellen, und
|
||||
sie gehört dorthin, wo man sich angemeldet hat. Wer es aus einer App heraus
|
||||
braucht, geht über „Einstellungen …" — ein Klick mehr, dafür kann kein
|
||||
eingebettetes Bild einer fremden Seite eine Abmeldung auslösen. Der Punkt
|
||||
erscheint nur, wenn HoneyOS selbst anmeldet; hinter einem Proxy oder im offenen
|
||||
Betrieb fehlt er.
|
||||
|
||||
## Wer angemeldet ist
|
||||
|
||||
|
||||
@@ -316,9 +316,6 @@ func (s *Server) handleApps(w http.ResponseWriter, r *http.Request, sub string)
|
||||
writeJSON(w, http.StatusOK, map[string]any{
|
||||
"apps": s.store.Apps(),
|
||||
"settings": s.store.SettingsFor(sub),
|
||||
// Fuer das Systemmenue der HoneyBar: ohne Anbieter gibt es nichts
|
||||
// abzumelden, dann steht der Punkt dort auch nicht.
|
||||
"oidc": s.auth.Enabled(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -777,6 +777,25 @@ body {
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
.mb-logo[aria-expanded="true"] { background: var(--p-faint); }
|
||||
/* Das App-Menü hängt am Pfeil rechts — sonst dasselbe Feld. */
|
||||
.appmenu {
|
||||
top: calc(32px + env(safe-area-inset-top) + 2px);
|
||||
bottom: auto;
|
||||
left: auto;
|
||||
right: 6px;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
/* Abmelden steht unten in den Einstellungen, abgesetzt vom Rest: Es ist die
|
||||
einzige Schaltfläche dort, die nicht etwas einstellt, sondern etwas beendet. */
|
||||
.field-out {
|
||||
border-top: 1px solid var(--p-faint);
|
||||
padding-top: 12px;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.btn-out { width: 100%; color: var(--p-mid); }
|
||||
.btn-out:hover { color: var(--bg); background: var(--p); }
|
||||
.startmenu .sm-head {
|
||||
padding: 4px 8px;
|
||||
font-size: 10px;
|
||||
|
||||
+14
-25
@@ -56,8 +56,6 @@
|
||||
|
||||
let apps = DEFAULT_APPS;
|
||||
let settings = null;
|
||||
// Ob HoneyOS ueberhaupt anmeldet — ohne Anbieter gaebe es nichts abzumelden.
|
||||
let oidc = false;
|
||||
// Was die Seite oben schon hatte, bevor die HoneyBar sie heruntergeschoben hat.
|
||||
let urspruenglichesPolster = null;
|
||||
|
||||
@@ -222,8 +220,6 @@
|
||||
<a id="mSettings" role="menuitem">Einstellungen …</a>
|
||||
<hr />
|
||||
<button id="hide" role="menuitem">HoneyBar einklappen</button>
|
||||
<hr id="mLogoutSep" hidden />
|
||||
<a id="mLogout" role="menuitem" hidden>Abmelden</a>
|
||||
</div>
|
||||
|
||||
<div class="menu" id="menu" role="menu">
|
||||
@@ -400,31 +396,25 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* Die drei Wege ins System. Alle drei sind Links auf den Schreibtisch, keine
|
||||
* Die zwei Wege ins System. Beides sind Links auf den Schreibtisch, keine
|
||||
* Aktionen hier — und das ist keine Bequemlichkeit, sondern die Grenze:
|
||||
*
|
||||
* Einstellungen und Abmelden **schreiben**. Dafuer braucht der Server die
|
||||
* HoneyOS-Sitzung, und die schickt der Browser aus einer fremden App nicht
|
||||
* mit; liegt alles unter einer Domain, kommt sie zwar mit, aber das
|
||||
* CSRF-Prüfwort steht in einem Cookie der HoneyOS-Adresse, das dieses Skript
|
||||
* von hier aus nicht lesen darf. Und ein Abmelden, das ein simpler Aufruf
|
||||
* erledigt, koennte jede fremde Seite ausloesen.
|
||||
* Einstellungen **schreiben**. Dafuer braucht der Server die HoneyOS-Sitzung,
|
||||
* und die schickt der Browser aus einer fremden App nicht mit; liegt alles
|
||||
* unter einer Domain, kommt sie zwar mit, aber das CSRF-Prüfwort steht in
|
||||
* einem Cookie der HoneyOS-Adresse, das dieses Skript von hier aus nicht
|
||||
* lesen darf.
|
||||
*
|
||||
* Also: die HoneyBar zeigt den Weg, gehandelt wird dort, wo man angemeldet
|
||||
* ist. Der Schreibtisch sieht die Frage in der Adresse und macht sie auf.
|
||||
* Abmelden steht hier bewusst gar nicht: Es gehoert dorthin, wo man sich
|
||||
* angemeldet hat. Wer es aus einer App heraus braucht, geht ueber
|
||||
* „Einstellungen …" — dort unten steht der Knopf.
|
||||
*/
|
||||
function systemZiele() {
|
||||
const ziel = (q) => {
|
||||
const u = new URL(homeUrl, location.href);
|
||||
u.search = q;
|
||||
return u.href;
|
||||
};
|
||||
root.getElementById("mHome").href = new URL(homeUrl, location.href).href;
|
||||
root.getElementById("mSettings").href = ziel("einstellungen=1");
|
||||
const ab = root.getElementById("mLogout");
|
||||
ab.href = ziel("abmelden=1");
|
||||
ab.hidden = !oidc;
|
||||
root.getElementById("mLogoutSep").hidden = !oidc;
|
||||
const heim = new URL(homeUrl, location.href);
|
||||
root.getElementById("mHome").href = heim.href;
|
||||
const einst = new URL(homeUrl, location.href);
|
||||
einst.search = "einstellungen=1";
|
||||
root.getElementById("mSettings").href = einst.href;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -520,7 +510,6 @@
|
||||
apps = [{ id: "honeyos", name: "DESKTOP", url: homeUrl }].concat(data.apps);
|
||||
}
|
||||
settings = data.settings || null;
|
||||
oidc = !!data.oidc;
|
||||
}
|
||||
} catch {
|
||||
/* nicht angemeldet, kein CORS, kein Netz → eingebaute Liste;
|
||||
|
||||
+4
-1
@@ -39,7 +39,10 @@
|
||||
<div class="mb-right">
|
||||
<span class="mb-wx" id="mbWx" hidden></span>
|
||||
<span class="mb-clock" id="clock">--:--</span>
|
||||
<button class="mb-btn" id="btnSettings" title="Einstellungen (S)">⚙</button>
|
||||
<!-- Derselbe Pfeil wie in der HoneyBar: die Apps zum Aufklappen,
|
||||
fuer schmale Fenster, in denen der Streifen oben nicht alles
|
||||
zeigt. Einstellungen stehen im Systemmenü links. -->
|
||||
<button class="mb-btn" id="btnAppMenu" title="Apps" aria-haspopup="true" aria-expanded="false">▾</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
+72
-20
@@ -590,7 +590,15 @@ function openSettings() {
|
||||
<p class="login-note" style="margin-top:4px">
|
||||
Diese Einstellungen liegen auf dem Server, nicht im Browser — auf jedem
|
||||
Gerät, an dem du angemeldet bist, sieht HoneyOS gleich aus.
|
||||
</p>`,
|
||||
</p>` +
|
||||
// Abmelden steht hier und nur hier: Es ist das Einzige, was man aus einer
|
||||
// fremden App heraus nicht anklicken können soll (siehe honeybar.js), und
|
||||
// von HoneyOS aus findet man es dort, wo alles andere auch steht.
|
||||
(state.oidc
|
||||
? `<div class="field field-out">
|
||||
<button class="btn btn-out" id="btnLogout">⏻ Abmelden</button>
|
||||
</div>`
|
||||
: ""),
|
||||
(root) => {
|
||||
root.querySelectorAll(".seg").forEach((segEl) => {
|
||||
segEl.addEventListener("click", (e) => {
|
||||
@@ -662,6 +670,7 @@ function openSettings() {
|
||||
});
|
||||
|
||||
root.querySelector("#btnApps").addEventListener("click", openApps);
|
||||
root.querySelector("#btnLogout")?.addEventListener("click", logout);
|
||||
},
|
||||
420
|
||||
);
|
||||
@@ -791,6 +800,58 @@ function openAbout() {
|
||||
/* ── Hilfsmittel ───────────────────────────────────────────────────────── */
|
||||
|
||||
|
||||
/* ── App-Menü im Pfeil rechts ──────────────────────────────────────────────
|
||||
* Der Zwilling des Pfeils in honeybar.js. Die Apps stehen zwar schon als
|
||||
* Streifen in der Leiste, aber der schiebt bei vielen Apps seitwärts — das
|
||||
* Menü zeigt sie alle untereinander. Das Zahnrad ist dafür weggefallen:
|
||||
* Einstellungen stehen im Systemmenü links, wie in jeder App.
|
||||
*/
|
||||
|
||||
function buildAppMenu() {
|
||||
const menu = document.createElement("div");
|
||||
menu.className = "startmenu appmenu";
|
||||
menu.id = "appmenu";
|
||||
$("desktop").appendChild(menu);
|
||||
|
||||
const btn = $("btnAppMenu");
|
||||
btn.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
if (menu.dataset.open === "1") return closeAppMenu();
|
||||
closeSystemMenu();
|
||||
closeStartMenu();
|
||||
|
||||
menu.innerHTML =
|
||||
`<div class="sm-head">wechseln zu</div>` +
|
||||
(state.cfg.apps.length
|
||||
? state.cfg.apps.map((a) => `<button data-app="${escapeAttr(a.id)}">${escapeHtml(a.name)}</button>`).join("")
|
||||
: `<button data-settings="1">keine app eingetragen …</button>`);
|
||||
|
||||
menu.querySelectorAll("[data-app]").forEach((b) =>
|
||||
b.addEventListener("click", () => {
|
||||
const app = state.cfg.apps.find((a) => a.id === b.dataset.app);
|
||||
closeAppMenu();
|
||||
if (app) launch(app);
|
||||
})
|
||||
);
|
||||
menu.querySelector("[data-settings]")?.addEventListener("click", () => {
|
||||
closeAppMenu();
|
||||
openApps();
|
||||
});
|
||||
|
||||
menu.dataset.open = "1";
|
||||
btn.setAttribute("aria-expanded", "true");
|
||||
});
|
||||
|
||||
document.addEventListener("click", closeAppMenu);
|
||||
}
|
||||
|
||||
function closeAppMenu() {
|
||||
const menu = $("appmenu");
|
||||
if (!menu) return;
|
||||
menu.dataset.open = "0";
|
||||
$("btnAppMenu").setAttribute("aria-expanded", "false");
|
||||
}
|
||||
|
||||
/* ── Systemmenü im Logo ────────────────────────────────────────────────────
|
||||
* Der Zwilling des Menüs in honeybar.js: gleiche Punkte, gleiche Reihenfolge.
|
||||
* Hier sind es Handlungen, dort Links hierher — denn nur hier ist man
|
||||
@@ -809,6 +870,7 @@ function buildSystemMenu() {
|
||||
e.stopPropagation();
|
||||
if (menu.dataset.open === "1") return closeSystemMenu();
|
||||
closeStartMenu();
|
||||
closeAppMenu();
|
||||
|
||||
const terminal = state.settings.mode === "terminal";
|
||||
menu.innerHTML =
|
||||
@@ -816,8 +878,7 @@ function buildSystemMenu() {
|
||||
<button data-do="about">Über HoneyOS</button>
|
||||
<button data-do="settings">Einstellungen</button>
|
||||
<hr />
|
||||
<button data-do="mode">${terminal ? "▣ Desktop-Modus" : "↩ Terminal-Modus"}</button>` +
|
||||
(state.oidc ? `<hr /><button data-do="logout">⏻ Abmelden</button>` : "");
|
||||
<button data-do="mode">${terminal ? "▣ Desktop-Modus" : "↩ Terminal-Modus"}</button>`;
|
||||
|
||||
menu.querySelectorAll("[data-do]").forEach((b) =>
|
||||
b.addEventListener("click", () => {
|
||||
@@ -826,7 +887,6 @@ function buildSystemMenu() {
|
||||
about: openAbout,
|
||||
settings: openSettings,
|
||||
mode: () => setMode(terminal ? "desktop" : "terminal"),
|
||||
logout,
|
||||
})[b.dataset.do]();
|
||||
})
|
||||
);
|
||||
@@ -858,10 +918,11 @@ function buildStartMenu() {
|
||||
e.stopPropagation();
|
||||
const open = menu.dataset.open === "1";
|
||||
if (open) return closeStartMenu();
|
||||
// Beide Menüs offen ginge, sähe aber aus wie ein Fehler: Der Klick auf den
|
||||
// Startknopf hält sein Ereignis auf, also erreicht es den Schließer des
|
||||
// Systemmenüs nicht von selbst.
|
||||
// Zwei offene Menüs sähen aus wie ein Fehler: Der Klick auf den Startknopf
|
||||
// hält sein Ereignis auf, also erreicht es die Schließer der anderen nicht
|
||||
// von selbst.
|
||||
closeSystemMenu();
|
||||
closeAppMenu();
|
||||
|
||||
menu.innerHTML = `<div class="sm-head">starten</div>` +
|
||||
state.cfg.apps.map((a) => `<button data-app="${a.id}">${escapeHtml(a.name)}</button>`).join("") +
|
||||
@@ -869,10 +930,7 @@ function buildStartMenu() {
|
||||
<button data-win="system">System</button>
|
||||
<button data-win="settings">Einstellungen</button>
|
||||
<button data-win="about">Über HoneyOS</button>
|
||||
<hr /><button data-mode="terminal">↩ Terminal-Modus</button>` +
|
||||
// Ohne Anbieter gibt es nichts abzumelden — im Systemmenü steht der
|
||||
// Punkt aus demselben Grund nur bei Anmeldung.
|
||||
(state.oidc ? `<button data-logout="1">⏻ Abmelden</button>` : "");
|
||||
<hr /><button data-mode="terminal">↩ Terminal-Modus</button>`;
|
||||
|
||||
menu.querySelectorAll("[data-app]").forEach((b) =>
|
||||
b.addEventListener("click", () => {
|
||||
@@ -893,7 +951,6 @@ function buildStartMenu() {
|
||||
closeStartMenu();
|
||||
setMode("terminal");
|
||||
});
|
||||
menu.querySelector("[data-logout]")?.addEventListener("click", logout);
|
||||
|
||||
menu.dataset.open = "1";
|
||||
btn.setAttribute("aria-expanded", "true");
|
||||
@@ -981,13 +1038,6 @@ async function main() {
|
||||
loadLocalSettings();
|
||||
applySettings();
|
||||
|
||||
// ?abmelden=1 kommt aus dem Systemmenü der HoneyBar. Es hier zu erledigen
|
||||
// statt am Server heißt: Die Abmeldung bleibt ein POST von dieser Seite aus,
|
||||
// und keine fremde Seite kann sie durch ein eingebettetes Bild auslösen.
|
||||
if (new URLSearchParams(location.search).get("abmelden") === "1") {
|
||||
return logout();
|
||||
}
|
||||
|
||||
let pub = { oidc: false, buttonLabel: "Anmelden" };
|
||||
try {
|
||||
pub = await api("/api/public");
|
||||
@@ -1015,11 +1065,11 @@ async function main() {
|
||||
renderShell();
|
||||
buildStartMenu();
|
||||
buildSystemMenu();
|
||||
buildAppMenu();
|
||||
probeApps();
|
||||
setInterval(tickClock, 15000);
|
||||
setInterval(probeApps, 120000);
|
||||
|
||||
$("btnSettings").addEventListener("click", openSettings);
|
||||
$("btnClose").addEventListener("click", closeModal);
|
||||
$("modal").addEventListener("click", (e) => {
|
||||
if (e.target === $("modal")) closeModal();
|
||||
@@ -1044,6 +1094,8 @@ async function main() {
|
||||
if (menu && menu.dataset.open === "1") return closeStartMenu();
|
||||
const sys = $("sysmenu");
|
||||
if (sys && sys.dataset.open === "1") return closeSystemMenu();
|
||||
const apps = $("appmenu");
|
||||
if (apps && apps.dataset.open === "1") return closeAppMenu();
|
||||
return state.settings.mode === "desktop" ? closeTopWindow() : closeModal();
|
||||
}
|
||||
if (typing) return;
|
||||
|
||||
Reference in new issue
Block a user