feat: Leiste trägt die Röhre vom Server, Einklappen ist umkehrbar
Zwei Sachen, die beim Benutzen aufgefallen sind.
- "leiste ausblenden" war eine Einbahnstraße: die Leiste verschwand ganz und
liess sich nur über die Entwicklerkonsole zurückholen. Jetzt bleibt ein
3px-Strich stehen, ein Klick darauf holt sie wieder. ?honeybar=1 an der
Adresse ist der Notausgang, falls der Strich übersehen wird.
- Die Leiste hatte ihre Farben fest eingetragen und blieb bernsteinfarben,
auch wenn der Schreibtisch auf grün stand. Genau dieser Bruch liess sie wie
etwas Angeklebtes wirken. /api/apps liefert deshalb jetzt {apps, settings};
die Leiste setzt Röhre, Glühen und Scanlines danach.
Dass das auch über Site-Grenzen geht, war so nicht erwartet: der Schlüssel
für die App-Liste trägt das Aussehen einfach mit.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1c3218939b
commit
5ed4e30179
5 files changed
+191
-41
No files matched your search
+122
-25
@@ -53,6 +53,7 @@
|
||||
const appsKey = d("key", "");
|
||||
|
||||
let apps = DEFAULT_APPS;
|
||||
let settings = null;
|
||||
|
||||
/* ── Aufbau ───────────────────────────────────────────────────────────── */
|
||||
|
||||
@@ -69,55 +70,66 @@
|
||||
root.innerHTML = `
|
||||
<style>
|
||||
:host, * { box-sizing: border-box; }
|
||||
/* Dieselben Röhren wie auf dem Schreibtisch. Welche gilt, sagt der
|
||||
Server; bis seine Antwort da ist, leuchtet Bernstein. */
|
||||
:host {
|
||||
--p: #ffb641;
|
||||
--p-mid: #c8842a;
|
||||
--p-dim: #6b4718;
|
||||
--p-faint: #2a1c0c;
|
||||
--bg: #140d07;
|
||||
--glow: 0 0 5px rgba(255, 182, 65, .4);
|
||||
--scan: rgba(0, 0, 0, .13);
|
||||
}
|
||||
.bar {
|
||||
display: flex; align-items: center; gap: 10px;
|
||||
height: ${BAR_H}px; padding: 0 8px;
|
||||
background: #140d07;
|
||||
border-bottom: 1px solid #6b4718;
|
||||
color: #ffb641;
|
||||
background: var(--bg);
|
||||
border-bottom: 1px solid var(--p-dim);
|
||||
color: var(--p);
|
||||
font: 12px/1 ui-monospace, "SF Mono", "DejaVu Sans Mono", Menlo, Consolas, monospace;
|
||||
text-shadow: 0 0 5px rgba(255,182,65,.4);
|
||||
text-shadow: var(--glow);
|
||||
user-select: none;
|
||||
}
|
||||
.bar::after {
|
||||
/* Scanlines, damit die Leiste zum Desktop gehört */
|
||||
content: ""; position: absolute; inset: 0; pointer-events: none;
|
||||
background: repeating-linear-gradient(to bottom, rgba(0,0,0,.13) 0 1px, transparent 1px 3px);
|
||||
background: repeating-linear-gradient(to bottom, var(--scan) 0 1px, transparent 1px 3px);
|
||||
}
|
||||
a, button {
|
||||
font: inherit; color: inherit; background: none;
|
||||
border: 1px solid transparent; cursor: pointer;
|
||||
text-decoration: none; padding: 3px 9px; white-space: nowrap;
|
||||
}
|
||||
.home { letter-spacing: .14em; color: #ffb641; padding-left: 2px; }
|
||||
.home b { color: #c8842a; font-weight: 400; }
|
||||
.home:hover { border-color: #6b4718; }
|
||||
.home { letter-spacing: .14em; color: var(--p); padding-left: 2px; }
|
||||
.home b { color: var(--p-mid); font-weight: 400; }
|
||||
.home:hover { border-color: var(--p-dim); }
|
||||
.apps { display: flex; gap: 4px; flex: 1; overflow-x: auto; scrollbar-width: none; }
|
||||
.apps::-webkit-scrollbar { display: none; }
|
||||
.app { color: #c8842a; letter-spacing: .08em; }
|
||||
.app:hover { color: #ffb641; border-color: #6b4718; }
|
||||
.app { color: var(--p-mid); letter-spacing: .08em; }
|
||||
.app:hover { color: var(--p); border-color: var(--p-dim); }
|
||||
.app[aria-current="page"] {
|
||||
background: #ffb641; border-color: #ffb641; color: #140d07; text-shadow: none;
|
||||
background: var(--p); border-color: var(--p); color: var(--bg); text-shadow: none;
|
||||
}
|
||||
.right { display: flex; align-items: center; gap: 8px; }
|
||||
.user { color: #ffb641; max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.user { color: var(--p); max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.user[hidden] { display: none; }
|
||||
.clock { color: #c8842a; font-variant-numeric: tabular-nums; }
|
||||
.menu-btn { border-color: #6b4718; line-height: 1; padding: 3px 7px; }
|
||||
.menu-btn:hover { background: #2a1c0c; }
|
||||
.clock { color: var(--p-mid); font-variant-numeric: tabular-nums; }
|
||||
.menu-btn { border-color: var(--p-dim); line-height: 1; padding: 3px 7px; }
|
||||
.menu-btn:hover { background: var(--p-faint); }
|
||||
.menu {
|
||||
position: absolute; top: ${BAR_H + 2}px; right: 6px; min-width: 190px;
|
||||
background: #140d07; border: 1px solid #6b4718; padding: 4px;
|
||||
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);
|
||||
}
|
||||
.menu[data-open="1"] { display: flex; }
|
||||
.menu a, .menu button { text-align: left; padding: 6px 8px; color: #c8842a; }
|
||||
.menu a:hover, .menu button:hover { background: #2a1c0c; color: #ffb641; }
|
||||
.menu hr { border: 0; border-top: 1px solid #2a1c0c; margin: 3px 0; }
|
||||
.menu a, .menu button { text-align: left; padding: 6px 8px; color: var(--p-mid); }
|
||||
.menu a:hover, .menu button:hover { background: var(--p-faint); color: var(--p); }
|
||||
.menu hr { border: 0; border-top: 1px solid var(--p-faint); margin: 3px 0; }
|
||||
.menu .head {
|
||||
padding: 4px 8px; font-size: 10px; letter-spacing: .18em;
|
||||
text-transform: uppercase; color: #6b4718;
|
||||
text-transform: uppercase; color: var(--p-dim);
|
||||
}
|
||||
@media (max-width: 560px) { .clock { display: none; } }
|
||||
</style>
|
||||
@@ -136,9 +148,35 @@
|
||||
<div class="head">wechseln zu</div>
|
||||
<div id="menuApps"></div>
|
||||
<hr />
|
||||
<button id="hide" role="menuitem">leiste ausblenden</button>
|
||||
<button id="hide" role="menuitem">leiste einklappen</button>
|
||||
</div>`;
|
||||
|
||||
/* ── Aussehen ─────────────────────────────────────────────────────────────
|
||||
* Dieselben drei Röhren wie in style.css. Sie hier zu wiederholen ist die
|
||||
* bewusste Entscheidung: die Leiste soll ohne zweite Datei auskommen, damit
|
||||
* sie in jeder fremden App mit einer Zeile funktioniert.
|
||||
*/
|
||||
const ROEHREN = {
|
||||
amber: { p: "#ffb641", mid: "#c8842a", dim: "#6b4718", faint: "#2a1c0c", bg: "#140d07", glow: "255,182,65" },
|
||||
green: { p: "#5cff8f", mid: "#2fa85c", dim: "#17512c", faint: "#08200f", bg: "#071206", glow: "92,255,143" },
|
||||
ice: { p: "#cfe8ff", mid: "#7fa6c4", dim: "#395366", faint: "#12202a", bg: "#0a1118", glow: "207,232,255" },
|
||||
};
|
||||
|
||||
function applySettings(s) {
|
||||
if (!s) return;
|
||||
const t = ROEHREN[s.phosphor] || ROEHREN.amber;
|
||||
const bar = root.querySelector(".bar");
|
||||
if (!bar) return;
|
||||
const set = (k, v) => bar.parentNode.host.style.setProperty(k, v);
|
||||
set("--p", t.p);
|
||||
set("--p-mid", t.mid);
|
||||
set("--p-dim", t.dim);
|
||||
set("--p-faint", t.faint);
|
||||
set("--bg", t.bg);
|
||||
set("--glow", s.glow === "off" ? "none" : `0 0 5px rgba(${t.glow},.4)`);
|
||||
set("--scan", s.scanlines === "off" ? "transparent" : "rgba(0,0,0,.13)");
|
||||
}
|
||||
|
||||
/* ── Verhalten ────────────────────────────────────────────────────────── */
|
||||
|
||||
function render() {
|
||||
@@ -219,6 +257,7 @@
|
||||
}
|
||||
|
||||
render();
|
||||
applySettings(settings);
|
||||
clock();
|
||||
setInterval(clock, 20000);
|
||||
|
||||
@@ -250,9 +289,57 @@
|
||||
/* dann eben nur für diesen Aufruf */
|
||||
}
|
||||
unmount();
|
||||
mountNub();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* ist der Weg zurück. Ganz verschwinden darf die Leiste nicht: wer sie einmal
|
||||
* weggeklickt hat, käme sonst nur noch über die Entwicklerkonsole an sie heran.
|
||||
*/
|
||||
let nub = null;
|
||||
|
||||
function mountNub() {
|
||||
if (nub) return;
|
||||
nub = document.createElement("honey-bar-nub");
|
||||
nub.style.cssText = [
|
||||
"position:fixed", "top:0", "left:0", "right:0", "height:3px",
|
||||
"z-index:2147483000", "cursor:pointer", "display:block",
|
||||
].join(";");
|
||||
nub.title = "HoneyOS-Leiste einblenden";
|
||||
const r = nub.attachShadow({ mode: "open" });
|
||||
r.innerHTML = `
|
||||
<style>
|
||||
.strich {
|
||||
height: 3px;
|
||||
background: linear-gradient(90deg, #6b4718, #ffb641 50%, #6b4718);
|
||||
opacity: .55;
|
||||
transition: opacity .15s, height .15s;
|
||||
}
|
||||
:host(:hover) .strich { opacity: 1; height: 3px; }
|
||||
</style>
|
||||
<div class="strich"></div>`;
|
||||
|
||||
nub.addEventListener("click", () => {
|
||||
forget();
|
||||
nub.remove();
|
||||
nub = null;
|
||||
mount();
|
||||
showUser();
|
||||
});
|
||||
document.body.appendChild(nub);
|
||||
}
|
||||
|
||||
function forget() {
|
||||
try {
|
||||
localStorage.removeItem(LS_HIDDEN);
|
||||
} catch {
|
||||
/* dann gilt es nur für diesen Aufruf */
|
||||
}
|
||||
}
|
||||
|
||||
function unmount() {
|
||||
host.remove();
|
||||
if (pushMode === "body") {
|
||||
@@ -269,7 +356,16 @@
|
||||
} catch {
|
||||
/* kein Speicher, Leiste bleibt sichtbar */
|
||||
}
|
||||
if (hidden) return;
|
||||
// ?honeybar=1 holt sie zurück, falls der Strich einmal übersehen wird.
|
||||
if (hidden && new URLSearchParams(location.search).get("honeybar") === "1") {
|
||||
hidden = false;
|
||||
forget();
|
||||
}
|
||||
if (hidden) {
|
||||
if (document.body) mountNub();
|
||||
else document.addEventListener("DOMContentLoaded", mountNub, { once: true });
|
||||
return;
|
||||
}
|
||||
|
||||
if (appsUrl) {
|
||||
try {
|
||||
@@ -281,10 +377,11 @@
|
||||
headers: appsKey ? { "X-HoneyOS-Key": appsKey } : {},
|
||||
});
|
||||
if (res.ok) {
|
||||
const list = await res.json();
|
||||
if (Array.isArray(list) && list.length) {
|
||||
apps = [{ id: "honeyos", name: "DESKTOP", url: homeUrl }].concat(list);
|
||||
const data = await res.json();
|
||||
if (Array.isArray(data.apps) && data.apps.length) {
|
||||
apps = [{ id: "honeyos", name: "DESKTOP", url: homeUrl }].concat(data.apps);
|
||||
}
|
||||
settings = data.settings || null;
|
||||
}
|
||||
} catch {
|
||||
/* nicht angemeldet, kein CORS, kein Netz → eingebaute Liste;
|
||||
|
||||
Reference in new issue
Block a user