Schublade: Symbol, Name, Untertitel

Der Pfeil rechts klappt in beiden Leisten ein Raster auf statt einer
Liste. Symbol gross, Name, Untertitel als dritte Zeile — der stand
bisher nur auf den Kacheln.

Entschieden gegen Symbol allein: Acht geteilte Glyphen identifizieren
nicht, zwei Apps koennen dieselbe Wolke tragen. Und die Schublade macht
man auf, weil man sucht — der Streifen ist der Ort fuers Wiedererkennen,
dort sind die Symbole abschaltbar.

Dazu 1.4 (CORS in Aether) und 1.5 (Cookie-Sitzung fuer InkNote) aus den
Ideen gestrichen: Widgets, die Daten aus den eigenen Apps holen, sind
nicht mehr gewollt. Der Rest ist neu durchnummeriert.
This commit is contained in:
marc committed 2026-08-29 22:57:01 +02:00
1 parent 6fe6533667
commit e27d1cb56b
5 files changed
+144 -48

No files matched your search

+30 -40
View File
@@ -59,7 +59,7 @@ hält — dieselbe Liste, die heute schon die CORS-Freigabe steuert. Das ist ein
Sicherheitsentscheidung und keine Kleinigkeit; erst bauen, wenn der Umweg über Sicherheitsentscheidung und keine Kleinigkeit; erst bauen, wenn der Umweg über
den Schreibtisch wirklich nervt. den Schreibtisch wirklich nervt.
### 1.3 App-Schublade mit Symbolen — ✅ halb gebaut (29.08.2026) ### 1.3 App-Schublade mit Symbolen — ✅ gebaut (29.08.2026)
**Gebaut: die geteilte Symbolquelle.** Die Raster liegen in `web/glyphs.json`, **Gebaut: die geteilte Symbolquelle.** Die Raster liegen in `web/glyphs.json`,
der Schreibtisch lädt sie, die HoneyBar bekommt sie mit der App-Liste mit der Schreibtisch lädt sie, die HoneyBar bekommt sie mit der App-Liste mit
@@ -71,9 +71,20 @@ aus, für beide Leisten zugleich. In den Aufklappmenüs und auf den Kacheln
stehen sie immer — dort ist Platz, und dort sucht man eine App, statt sie im stehen sie immer — dort ist Platz, und dort sucht man eine App, statt sie im
Vorbeigehen wiederzuerkennen. Vorbeigehen wiederzuerkennen.
**Offen bleibt die Schublade selbst:** ein Raster aus Symbolen statt einer **Ebenfalls gebaut: die Schublade.** Der Pfeil rechts klappt in beiden Leisten
Liste, wenn es viele Apps werden. Heute reicht der Streifen samt Menü; das ist ein Raster auf — Symbol groß, Name, Untertitel als dritte Zeile. Drei Spalten,
erst ab sechs, sieben Apps eine echte Frage. am Handy dieselben drei.
Entschieden (29.08.2026): **Symbol und Name, nie nur Symbol.** Der Grund ist
nicht Geschmack, sondern der geteilte Satz von acht generischen Glyphen — zwei
Apps können dieselbe Wolke tragen, und bei Homelab-Diensten ist das der
Normalfall. Ein Symbol identifiziert erst, wenn es einzigartig ist. Dazu: Den
Streifen sieht man im Vorbeigehen, die Schublade macht man auf, *weil man
sucht* — Suchen heißt Lesen, und Platz ist dort genug. Namen wegzunehmen ist
später eine CSS-Zeile; ohne sie anzufangen kostet die Zeit, in der man rät.
Der Untertitel bekommt damit endlich einen Ort: Er stand bisher nur auf den
Kacheln und beantwortet genau die Frage, die ein generisches Symbol offenlässt.
**Ebenfalls offen: eigene Logos hochladen** (beschlossen als Planung, **Ebenfalls offen: eigene Logos hochladen** (beschlossen als Planung,
25.08.2026). Je App ein Bild in HoneyOS, die Pixelglyphe als Rückfall, wenn 25.08.2026). Je App ein Bild in HoneyOS, die Pixelglyphe als Rückfall, wenn
@@ -121,28 +132,7 @@ HoneyBar. Zählen, wie oft etwas benutzt wird, heißt Nutzungsdaten speichern
dafür ist der Nutzen hier zu klein. **Zu entscheiden, sobald die vierte App dafür ist der Nutzen hier zu klein. **Zu entscheiden, sobald die vierte App
dazukommt**, nicht vorher. dazukommt**, nicht vorher.
### 1.4 CORS in Aether ### 1.4 HoneyOS selbst als PWA
Damit der Desktop Aether überhaupt etwas fragen darf. Aethers Sitzung ist ein
Cookie, und weil alles unter derselben Domain liegt, schickt der Browser es
schon heute mit — es fehlt allein die Freigabe im Go-Backend
(`Access-Control-Allow-Origin` für `os.…` plus `Allow-Credentials`).
Kleiner Eingriff, aber **die Voraussetzung für jedes Aether-Widget** und
nebenbei auch für die Anmeldeanzeige auf der Kachel.
### 1.5 InkNote: Sitzung zusätzlich als Cookie
InkNote weist sich mit einem Bearer-Token aus, der im localStorage liegt. Der
ist **pro Domain** — von `os.…` aus grundsätzlich unerreichbar, und daran ändert
keine Konfiguration etwas.
Solange das so bleibt, kann HoneyOS **keine InkNote-Daten anzeigen**. Der Weg
wäre, dass InkNote seine Sitzung zusätzlich als `HttpOnly`-Cookie setzt; der
Token-Weg kann daneben bleiben, damit PWA und Offline-Betrieb unangetastet sind.
### 1.5b HoneyOS selbst als PWA
Heute ist HoneyOS eine Website: Es hat `theme-color`, aber kein Manifest, kein Heute ist HoneyOS eine Website: Es hat `theme-color`, aber kein Manifest, kein
Symbol und keinen Service Worker — installierbar ist es damit nicht. Am Handy Symbol und keinen Service Worker — installierbar ist es damit nicht. Am Handy
@@ -179,7 +169,7 @@ Cache nur als Rückfall.
Ursprungswechsel macht aus einer installierten PWA eine fremde App — wer Ursprungswechsel macht aus einer installierten PWA eine fremde App — wer
vorher installiert, installiert zweimal. vorher installiert, installiert zweimal.
### 1.6 Widget-Rahmen ### 1.5 Widget-Rahmen
Ein Fenstertyp, der einen Inhalt holt, ihn anzeigt und sich benimmt, wenn es Ein Fenstertyp, der einen Inhalt holt, ihn anzeigt und sich benimmt, wenn es
schiefgeht: lädt gerade, nichts da, nicht angemeldet, Fehler. Einmal richtig schiefgeht: lädt gerade, nichts da, nicht angemeldet, Fehler. Einmal richtig
@@ -192,9 +182,9 @@ Terminal als Kachel.
Eines bauen, benutzen, dann entscheiden. Eines bauen, benutzen, dann entscheiden.
- **Letzte Dateien** (Aether) — die naheliegendste; braucht nur 1.2 Widgets, die Daten aus den eigenen Apps holen, sind gestrichen (siehe „Bewusst
- **Speicherplatz** (Aether) — eine Zahl, ein Balken, billig zu bauen nicht geplant"). Was bleibt, ist alles, was für sich allein steht: Wetter
- **Letzte Notizen** (InkNote) — braucht 1.3, kommt also später (gebaut), ein Bild, später vielleicht Uhr, Notizzettel, Systemzustand.
### Wetter in der HoneyBar, neben der Uhr — ✅ gebaut (25.08.2026) ### Wetter in der HoneyBar, neben der Uhr — ✅ gebaut (25.08.2026)
@@ -338,7 +328,7 @@ schon gebaut) oder am Handy Pfeiltasten statt Ziehen anbieten. Nicht vergessen:
Ohne das ist die Funktion am Handy schlicht nicht da. Ohne das ist die Funktion am Handy schlicht nicht da.
Voraussetzung ist ein Widget-Verzeichnis — heute stehen Benutzer und Wetter Voraussetzung ist ein Widget-Verzeichnis — heute stehen Benutzer und Wetter
fest im HTML. Sinnvoll zusammen mit dem Widget-Rahmen (1.6) zu bauen, nicht fest im HTML. Sinnvoll zusammen mit dem Widget-Rahmen (1.5) zu bauen, nicht
davor. davor.
### Widgets in der HoneyBar selbst ### Widgets in der HoneyBar selbst
@@ -348,17 +338,12 @@ ist aber die Seite, die man am seltensten offen hat — die HoneyBar dagegen ist
überall. Naheliegend also: ein Knopf in der HoneyBar klappt dasselbe Widget als überall. Naheliegend also: ein Knopf in der HoneyBar klappt dasselbe Widget als
kleines Feld auf, ohne die App zu verlassen. kleines Feld auf, ohne die App zu verlassen.
Technisch ist das dieselbe Sache wie 1.6, nur ein zweites Zuhause für denselben Technisch ist das dieselbe Sache wie 1.5, nur ein zweites Zuhause für denselben
Inhalt: Der Rahmen muss dann drei Formen können — Fenster, Kachel, Aufklappfeld. Inhalt: Der Rahmen muss dann drei Formen können — Fenster, Kachel, Aufklappfeld.
Das ist beim **Bauen** von 1.6 zu bedenken, hinterher wird es teuer. Das ist beim **Bauen** von 1.5 zu bedenken, hinterher wird es teuer.
**Eine Einschränkung vorweg:** Die HoneyBar läuft in einer fremden App. Ein Für Widgets, die nur sich selbst brauchen (Wetter, Bild, Uhr), ist das
Aether-Widget in der HoneyBar **von InkNote aus** braucht deshalb dasselbe, was geschenkt — sie fragen HoneyOS, nicht die App.
1.4 für den Schreibtisch regelt, nur für einen weiteren Ursprung. In der App
selbst (Aether-Widget in Aethers eigener HoneyBar) ist es geschenkt.
→ Anfangen mit **letzte Dateien**. Wenn du danach merkst, dass du morgens
wirklich draufschaust, lohnt der Rest. Wenn nicht, war es ein Abend.
--- ---
@@ -508,6 +493,11 @@ Damit es nicht alle paar Monate neu diskutiert wird:
installierte PWA, wenn die Adresse in ihren Bereich fällt — das funktioniert installierte PWA, wenn die Adresse in ihren Bereich fällt — das funktioniert
heute und darf nicht durch JavaScript-Navigation oder Rahmen kaputtgemacht heute und darf nicht durch JavaScript-Navigation oder Rahmen kaputtgemacht
werden. werden.
- **Keine Widgets, die Daten aus Aether oder InkNote holen** (gestrichen
29.08.2026). Dafür standen einmal zwei Punkte im Fundament: CORS in Aether
und eine Cookie-Sitzung für InkNote. Beides ist nicht mehr gewollt — der Weg
über den HoneyBar-Proxy zeigt HoneyOS in den Apps, statt die Apps in HoneyOS
nachzubauen.
- **HoneyOS speichert keine Inhalte.** Keine Dateien, keine Notizen, keine - **HoneyOS speichert keine Inhalte.** Keine Dateien, keine Notizen, keine
Kopien. Es zeigt, was die Apps hergeben, und hört da auf. Kopien. Es zeigt, was die Apps hergeben, und hört da auf.
- **Keine Rechteverwaltung.** Die App-Liste gilt für alle Angemeldeten. Für eine - **Keine Rechteverwaltung.** Die App-Liste gilt für alle Angemeldeten. Für eine
+15
View File
@@ -114,6 +114,21 @@ Gespeichert wird die Liste als Ganzes; der Server prüft sie noch einmal und ant
dem, was er wirklich behalten hat. Eine Adresse ohne `https://` kommt als Fehlermeldung dem, was er wirklich behalten hat. Eine Adresse ohne `https://` kommt als Fehlermeldung
zurück, nicht als kaputter Eintrag. zurück, nicht als kaputter Eintrag.
## Die Schublade
Der Pfeil rechts in beiden Leisten klappt alle Apps als Raster auf: **Symbol,
Name, Untertitel.** Drei Spalten, am Handy dieselben drei.
Warum nicht nur Symbole? Weil acht geteilte Pixelglyphen nicht identifizieren —
zwei Apps können dieselbe Wolke tragen, und bei Homelab-Diensten ist das der
Normalfall. Dazu der Unterschied der beiden Orte: Den Streifen oben sieht man
im Vorbeigehen, da reicht ein Blick und die Symbole sind abschaltbar. Die
Schublade macht man auf, **weil man sucht** — Suchen heißt Lesen.
Der Untertitel aus der App-Liste steht damit endlich dort, wo er nützt: Er
beantwortet die Frage, die ein generisches Symbol offenlässt. Ist er leer,
fällt die Zeile weg.
## Ein Satz Symbole für alles ## Ein Satz Symbole für alles
Die Pixelraster stehen **an genau einer Stelle**: `web/glyphs.json`, 12×12 Die Pixelraster stehen **an genau einer Stelle**: `web/glyphs.json`, 12×12
+41
View File
@@ -831,6 +831,47 @@ body {
.startmenu button:hover { background: var(--p); color: var(--bg); text-shadow: none; } .startmenu button:hover { background: var(--p); color: var(--bg); text-shadow: none; }
.startmenu hr { border: 0; border-top: 1px solid var(--p-faint); margin: 3px 0; } .startmenu hr { border: 0; border-top: 1px solid var(--p-faint); margin: 3px 0; }
/* Die Schublade — der Zwilling der Schublade in honeybar.js. Symbol groß,
Name darunter, Untertitel als dritte Zeile: Wer sie aufmacht, sucht etwas,
und acht geteilte Pixelsymbole allein sagen dafür zu wenig. */
.appmenu { min-width: 318px; max-width: min(360px, calc(100vw - 12px)); }
/* minmax(0, 1fr): Ohne das darf eine lange Beschreibung ihre Spalte
auseinanderdrücken, und die Schublade wird breiter als der Schirm. */
.drawer { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 2px; }
.startmenu .drawer button.d-app {
display: flex;
flex-direction: column;
align-items: center;
gap: 5px;
padding: 9px 4px;
text-align: center;
border: 1px solid transparent;
min-width: 0;
}
.startmenu .drawer .d-name,
.startmenu .drawer .d-sub { max-width: 100%; }
.startmenu .drawer .d-name { overflow: hidden; text-overflow: ellipsis; }
.startmenu .drawer button.d-app:hover {
background: none;
color: var(--p);
border-color: var(--p-dim);
text-shadow: var(--glow);
}
.d-ico { width: 24px; height: 24px; }
.d-ico svg { width: 24px; height: 24px; display: block; }
.d-name { letter-spacing: 0.08em; }
/* Umbrechen darf er, wachsen nicht — sonst stehen die Kacheln unterschiedlich
hoch und das Raster franst aus. */
.d-sub {
font-size: 10px;
line-height: 1.25;
color: var(--p-dim);
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
@media (max-width: 620px) { @media (max-width: 620px) {
.task-btn { min-width: 0; } .task-btn { min-width: 0; }
.task-date { display: none; } .task-date { display: none; }
+45 -3
View File
@@ -188,6 +188,37 @@
color: var(--p); text-shadow: var(--glow); color: var(--p); text-shadow: var(--glow);
} }
.menu[data-open="1"] { display: flex; } .menu[data-open="1"] { display: flex; }
/* Die Schublade: Symbol, Name, Untertitel. Sie wird absichtlich
aufgemacht, weil man etwas sucht — also wird gelesen, nicht nur
wiedererkannt. Deshalb stehen hier immer Namen, anders als im
Streifen oben, wo ein Blick reichen muss. */
.menu.apps { min-width: 318px; max-width: min(360px, calc(100vw - 12px)); }
/* minmax(0, 1fr): Ohne das darf eine lange Beschreibung ihre Spalte
auseinanderdruecken, und die Schublade wird breiter als der Schirm. */
.drawer { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 2px; }
.d-app {
display: flex; flex-direction: column; align-items: center; gap: 5px;
padding: 9px 4px; text-align: center; color: var(--p-mid);
border: 1px solid transparent; min-width: 0;
}
/* Die Regel fuer a und button oben setzt nowrap — richtig fuer den
Streifen, falsch
hier: Der Untertitel soll umbrechen statt abgeschnitten zu werden. */
.d-name, .d-sub { max-width: 100%; }
.d-sub { white-space: normal; }
.d-name { overflow: hidden; text-overflow: ellipsis; }
.d-app:hover { border-color: var(--p-dim); color: var(--p); }
.d-app[aria-current="page"] { border-color: var(--p); color: var(--p); }
.d-app .ico { width: 24px; height: 24px; }
.d-app .ico svg { width: 24px; height: 24px; }
.d-name { letter-spacing: .08em; }
/* Der Untertitel darf umbrechen, aber nicht wachsen — sonst stehen die
Kacheln unterschiedlich hoch. */
.d-sub {
font-size: 10px; line-height: 1.25; color: var(--p-dim);
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
overflow: hidden;
}
.menu a, .menu button { text-align: left; padding: 6px 8px; color: var(--p-mid); } .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 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 hr { border: 0; border-top: 1px solid var(--p-faint); margin: 3px 0; }
@@ -219,9 +250,9 @@
<button id="hide" role="menuitem">HoneyBar einklappen</button> <button id="hide" role="menuitem">HoneyBar einklappen</button>
</div> </div>
<div class="menu" id="menu" role="menu"> <div class="menu apps" id="menu" role="menu">
<div class="head">wechseln zu</div> <div class="head">wechseln zu</div>
<div id="menuApps"></div> <div class="drawer" id="menuApps"></div>
</div>`; </div>`;
/* ── Aussehen ───────────────────────────────────────────────────────────── /* ── Aussehen ─────────────────────────────────────────────────────────────
@@ -287,11 +318,22 @@
nav.appendChild(a); nav.appendChild(a);
const m = document.createElement("a"); const m = document.createElement("a");
m.className = "d-app";
m.href = app.url; m.href = app.url;
m.setAttribute("role", "menuitem"); m.setAttribute("role", "menuitem");
const ico = symbol(app); const ico = symbol(app);
if (ico) m.appendChild(ico); if (ico) m.appendChild(ico);
m.appendChild(document.createTextNode((app.id === current ? "\u25b8 " : "") + app.name)); const name = document.createElement("span");
name.className = "d-name";
name.textContent = app.name;
m.appendChild(name);
if (app.subtitle) {
const sub = document.createElement("span");
sub.className = "d-sub";
sub.textContent = app.subtitle;
m.appendChild(sub);
}
if (app.id === current) m.setAttribute("aria-current", "page");
menuApps.appendChild(m); menuApps.appendChild(m);
}); });
} }
+13 -5
View File
@@ -840,17 +840,25 @@ function buildAppMenu() {
closeSystemMenu(); closeSystemMenu();
closeStartMenu(); closeStartMenu();
// Dieselbe Schublade wie in honeybar.js: Symbol, Name, Untertitel. Sie wird
// absichtlich aufgemacht, weil man etwas sucht — also wird gelesen, nicht
// nur wiedererkannt. Im Streifen oben reicht ein Blick, dort ist der Name
// abschaltbar; hier steht er immer.
menu.innerHTML = menu.innerHTML =
`<div class="sm-head">wechseln zu</div>` + `<div class="sm-head">wechseln zu</div>` +
(state.cfg.apps.length (state.cfg.apps.length
? state.cfg.apps ? `<div class="drawer">` +
state.cfg.apps
.map( .map(
(a) => (a) =>
// Im Menü stehen die Symbole immer — dort ist Platz, und dort `<button class="d-app" data-app="${escapeAttr(a.id)}">
// sucht man eine App, statt sie im Vorbeigehen zu erkennen. <span class="d-ico">${glyphSvg(a.glyph)}</span>
`<button data-app="${escapeAttr(a.id)}"><span class="sm-ico">${glyphSvg(a.glyph)}</span>${escapeHtml(a.name)}</button>` <span class="d-name">${escapeHtml(a.name)}</span>
${a.subtitle ? `<span class="d-sub">${escapeHtml(a.subtitle)}</span>` : ""}
</button>`
) )
.join("") .join("") +
`</div>`
: `<button data-settings="1">keine app eingetragen …</button>`); : `<button data-settings="1">keine app eingetragen …</button>`);
menu.querySelectorAll("[data-app]").forEach((b) => menu.querySelectorAll("[data-app]").forEach((b) =>