Systemmenue im Logo, in beiden Leisten
Das ■ HONEYOS ist jetzt ein Menue statt eines Links: Schreibtisch, Einstellungen, HoneyBar einklappen, Abmelden. In fremden Apps sind es Links auf den Schreibtisch (?einstellungen=1 / ?abmelden=1), weil die HoneyBar dort nicht schreiben darf — Sitzung und CSRF-Pruefwort ueber- leben die Site-Grenze nicht, und ein Abmelden per Aufruf koennte jede Seite ausloesen. Der Abmeldeknopf in der Menueleiste faellt weg (stand doppelt), und Abmelden erscheint nur, wenn HoneyOS ueberhaupt anmeldet — dafuer gibt /api/apps jetzt oidc mit heraus. Nebenbei: restliche 'Leiste' im Text zu 'HoneyBar' vereinheitlicht.
This commit is contained in:
1 parent
52deffa30e
commit
0a5cd94ba0
12 files changed
+244
-51
No files matched your search
+80
-16
@@ -56,6 +56,8 @@
|
||||
|
||||
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;
|
||||
|
||||
@@ -149,6 +151,7 @@
|
||||
wie ein anderes Logo aus. */
|
||||
.home .hex { font-size: 10px; vertical-align: 2px; }
|
||||
.home:hover { border-color: var(--p-dim); }
|
||||
.home[aria-expanded="true"] { border-color: var(--p-dim); background: var(--p-faint); }
|
||||
/* Bei vielen Apps schiebt man den Streifen seitwärts. Ohne
|
||||
flex-shrink:0 an den Knöpfen quetscht das Raster sie stattdessen
|
||||
zusammen, bis nur noch Buchstabenreste dastehen — am Handy sofort.
|
||||
@@ -183,6 +186,11 @@
|
||||
background: var(--bg); border: 1px solid var(--p-dim); padding: 4px;
|
||||
display: none; flex-direction: column; gap: 2px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,.6);
|
||||
/* Die Menues haengen neben der HoneyBar, nicht darin — ohne eigene
|
||||
Schrift erben sie die der fremden App und stehen dann in deren
|
||||
Fliesstext da. Genau so sah es aus. */
|
||||
font: 12px/1.2 ui-monospace, "SF Mono", "DejaVu Sans Mono", Menlo, Consolas, monospace;
|
||||
color: var(--p); text-shadow: var(--glow);
|
||||
}
|
||||
.menu[data-open="1"] { display: flex; }
|
||||
.menu a, .menu button { text-align: left; padding: 6px 8px; color: var(--p-mid); }
|
||||
@@ -192,11 +200,14 @@
|
||||
padding: 4px 8px; font-size: 10px; letter-spacing: .18em;
|
||||
text-transform: uppercase; color: var(--p-dim);
|
||||
}
|
||||
/* Dasselbe Menue, nur an der anderen Seite: das Systemmenue haengt am
|
||||
Logo links, das App-Menue am Pfeil rechts. */
|
||||
.menu.sys { left: 6px; right: auto; }
|
||||
@media (max-width: 560px) { .clock { display: none; } }
|
||||
</style>
|
||||
|
||||
<div class="bar">
|
||||
<a class="home" id="home" title="HoneyOS"><span class="hex">■</span> HONEY<b>OS</b></a>
|
||||
<button class="home" id="home" title="HoneyOS-Menü" aria-haspopup="true" aria-expanded="false"><span class="hex">■</span> HONEY<b>OS</b></button>
|
||||
<nav class="apps" id="apps"></nav>
|
||||
<div class="right">
|
||||
<span class="wx" id="wx" hidden></span>
|
||||
@@ -205,11 +216,19 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="menu sys" id="sysmenu" role="menu">
|
||||
<div class="head">honeyos</div>
|
||||
<a id="mHome" role="menuitem">Schreibtisch</a>
|
||||
<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">
|
||||
<div class="head">wechseln zu</div>
|
||||
<div id="menuApps"></div>
|
||||
<hr />
|
||||
<button id="hide" role="menuitem">honeybar einklappen</button>
|
||||
</div>`;
|
||||
|
||||
/* ── Aussehen ─────────────────────────────────────────────────────────────
|
||||
@@ -327,30 +346,46 @@
|
||||
clock();
|
||||
setInterval(clock, 20000);
|
||||
|
||||
root.getElementById("home").href = homeUrl;
|
||||
systemZiele();
|
||||
}
|
||||
|
||||
function verdrahten() {
|
||||
if (verdrahtet) return;
|
||||
verdrahtet = true;
|
||||
|
||||
const menu = root.getElementById("menu");
|
||||
const btn = root.getElementById("menuBtn");
|
||||
btn.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
const open = menu.dataset.open === "1";
|
||||
menu.dataset.open = open ? "0" : "1";
|
||||
btn.setAttribute("aria-expanded", String(!open));
|
||||
// Zwei Menues, gleiche Mechanik: links das System, rechts die Apps.
|
||||
// Eines auf heisst anderes zu — zwei offene Felder in 32 px Hoehe
|
||||
// ueberdecken sich gegenseitig.
|
||||
const paare = [
|
||||
[root.getElementById("sysmenu"), root.getElementById("home")],
|
||||
[root.getElementById("menu"), root.getElementById("menuBtn")],
|
||||
];
|
||||
|
||||
const close = () => {
|
||||
paare.forEach(([m, b]) => {
|
||||
m.dataset.open = "0";
|
||||
b.setAttribute("aria-expanded", "false");
|
||||
});
|
||||
};
|
||||
|
||||
paare.forEach(([menu, btn]) => {
|
||||
btn.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
const auf = menu.dataset.open === "1";
|
||||
close();
|
||||
if (!auf) {
|
||||
menu.dataset.open = "1";
|
||||
btn.setAttribute("aria-expanded", "true");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Klick daneben schließt — das Ereignis muss die Grenze des Shadow DOM
|
||||
// in beide Richtungen überleben, deshalb beide Wurzeln.
|
||||
const close = () => {
|
||||
menu.dataset.open = "0";
|
||||
btn.setAttribute("aria-expanded", "false");
|
||||
};
|
||||
document.addEventListener("click", close);
|
||||
root.addEventListener("click", (e) => {
|
||||
if (!e.composedPath().includes(menu) && e.target !== btn) close();
|
||||
const drin = paare.some(([m, b]) => e.composedPath().includes(m) || e.target === b);
|
||||
if (!drin) close();
|
||||
});
|
||||
|
||||
root.getElementById("hide").addEventListener("click", () => {
|
||||
@@ -364,6 +399,34 @@
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Die drei Wege ins System. Alle drei 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eingeklappt bleibt ein 3 px hoher Strich am oberen Rand stehen. Er nimmt
|
||||
* praktisch keinen Platz, liegt über dem Inhalt statt ihn zu schieben — und
|
||||
@@ -457,6 +520,7 @@
|
||||
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;
|
||||
|
||||
Reference in new issue
Block a user