docs: durchgaengig HoneyBar statt Leiste

Der Dienst im Beispiel heisst jetzt einsetzer — er ist nicht die HoneyBar,
er setzt sie ein. Zusammensetzungen wie Menueleiste, Taskleiste und
Statusleiste bleiben, die meinen etwas anderes.

Dazu in IDEAS notiert, dass HoneyBar und Menueleiste zwei getrennte Stilsaetze
sind und schon einmal auseinandergelaufen ist.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
marcandClaude Opus 5 committed 2026-08-29 16:57:01 +02:00
1 parent 3b7367944b
commit 9da6503837
6 files changed
+156 -131

No files matched your search

+68 -43
View File
@@ -14,10 +14,10 @@ wirklich hinschaut.
Ohne diese Stücke ist alles danach nicht möglich. Reihenfolge nach dem
Verhältnis von Aufwand zu spürbarer Wirkung.
### 1.1 Die Leiste trägt deine Röhre — ✅ erledigt (24.08.2026)
### 1.1 Die HoneyBar trägt deine Röhre — ✅ erledigt (24.08.2026)
Die Leiste liest ihre Farben nicht mehr fest, sondern aus derselben Antwort, mit
der sie die App-Liste holt. Röhre in HoneyOS auf grün → die Leiste in Aether ist
Die HoneyBar liest ihre Farben nicht mehr fest, sondern aus derselben Antwort, mit
der sie die App-Liste holt. Röhre in HoneyOS auf grün → die HoneyBar in Aether ist
grün, ohne dass Aether angefasst wird. `glow` und `scanlines` gelten dort ebenso.
**Ging entgegen der ersten Einschätzung auch über Site-Grenzen hinweg.** Ich
@@ -26,7 +26,7 @@ hatte notiert, das scheitere daran, dass der Browser die Sitzung nicht mitschick
das Aussehen gleich mit. Deshalb liefert `/api/apps` jetzt `{apps, settings}`
statt nur einer Liste.
Offen bleibt: Bei mehreren Nutzern trägt die Leiste die Farbe des
Offen bleibt: Bei mehreren Nutzern trägt die HoneyBar die Farbe des
Standardnutzers, weil ihr über die Site-Grenze niemand sagen kann, wer da
gerade schaut.
@@ -51,10 +51,10 @@ mit Symbolen — heute sind es Textknöpfe. Bei zwei Apps geht das noch, ab vier
wird es eng, am Handy sofort.
**Der eigentliche Punkt: die Symbole.** Das Pixelraster lebt in `os.js`
(`GLYPHS`), die Leiste kennt es nicht. Zwei Wege:
(`GLYPHS`), die HoneyBar kennt es nicht. Zwei Wege:
- **Pixelglyphen teilen** — `GLYPHS` + `glyphSvg()` in eine eigene Datei, die
Desktop und Leiste beide laden. Kein Upload, kein Speicher, passt zum Look.
Desktop und HoneyBar beide laden. Kein Upload, kein Speicher, passt zum Look.
Nachteil: nur die eingebauten Symbole.
- **Echte Bilder** — pro App eine Bildadresse oder ein Upload in HoneyOS.
Flexibler, aber: Speicher, Größenbegrenzungen, Auslieferung, und der
@@ -67,7 +67,7 @@ Bild in HoneyOS hinterlegen, statt nur aus den eingebauten Glyphen zu wählen.
Nicht als Ersatz für die Pixelglyphen, sondern daneben: Glyphe als Rückfall,
wenn kein Bild da ist.
**Das Logo gehört ausdrücklich auch in die Leiste**, nicht nur auf den
**Das Logo gehört ausdrücklich auch in die HoneyBar**, nicht nur auf den
Schreibtisch — dort ist die Unterscheidung am nötigsten, weil die Knöpfe klein
sind und nebeneinanderstehen. Damit ist die geteilte Symbolquelle aus 1.3
Voraussetzung: Beide Seiten müssen dasselbe Bild bekommen, sonst pflegt man es
@@ -82,18 +82,18 @@ Was daran zu bauen ist, in dieser Reihenfolge:
2. **Ausliefern** — unter einer Adresse je App, mit einem Versionsanteil, damit
ein Austausch nicht im Cache hängen bleibt (Aether macht das beim Logo
schon so).
3. **In der Leiste anzeigen** — über die Site-Grenze hinweg ein `<img>` von
3. **In der HoneyBar anzeigen** — über die Site-Grenze hinweg ein `<img>` von
HoneyOS. Das geht ohne Sitzung, Bilder unterliegen der CORS-Regel nicht.
**Vorher zu klären:** Sollen Bilder in den Retro-Look eingepasst werden
(auf wenige Farben reduziert, hart gerastert) oder bunt bleiben? Ein
Original-Logo mit Farbverlauf neben Pixelglyphen sieht schnell nach Fremdkörper
aus. Ein Filter in der Leiste wäre billig zu haben und ließe sich abschalten.
aus. Ein Filter in der HoneyBar wäre billig zu haben und ließe sich abschalten.
### 1.3b Reihenfolge der Apps
Heute stehen die Apps in der Reihenfolge, in der sie eingetragen wurden. Bei
zwei Stück ist das keine Frage; ab vier oder fünf schon, und in der Leiste
zwei Stück ist das keine Frage; ab vier oder fünf schon, und in der HoneyBar
zuerst — dort ist der Platz am knappsten und die Reihenfolge entscheidet, was
man am Handy noch sieht.
@@ -107,7 +107,7 @@ Möglichkeiten:
| feste Reihenfolge + Rest alphabetisch | mittel | Mischung |
→ **Vorschlag: von Hand sortieren**, dieselbe Reihenfolge auf Schreibtisch und
Leiste. Zählen, wie oft etwas benutzt wird, heißt Nutzungsdaten speichern —
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
dazukommt**, nicht vorher.
@@ -187,16 +187,16 @@ Eines bauen, benutzen, dann entscheiden.
- **Speicherplatz** (Aether) — eine Zahl, ein Balken, billig zu bauen
- **Letzte Notizen** (InkNote) — braucht 1.3, kommt also später
### Wetter in der Leiste, neben der Uhr — ✅ gebaut (25.08.2026)
### Wetter in der HoneyBar, neben der Uhr — ✅ gebaut (25.08.2026)
**Steht.** Zwei Schalter in den Einstellungen, unabhängig voneinander: auf dem
Schreibtisch, in der Leiste, beides oder keins. Die Stadt wird einmal gesucht
Schreibtisch, in der HoneyBar, beides oder keins. Die Stadt wird einmal gesucht
und mit ihren Koordinaten gespeichert; der Server holt das Wetter und legt es
zehn Minuten beiseite, die Oberflächen zeigen nur, was er hergibt.
Offen geblieben ist eines mit Absicht: **Die Stadt lässt sich nur auf dem
Schreibtisch ändern, nicht aus der Leiste heraus.** Ein Klick auf das Symbol
führt dorthin. Der Grund ist derselbe wie bei allem anderen in der Leiste: Sie
Schreibtisch ändern, nicht aus der HoneyBar heraus.** Ein Klick auf das Symbol
führt dorthin. Der Grund ist derselbe wie bei allem anderen in der HoneyBar: Sie
liest über den Schlüssel und darf nichts schreiben — und über eine Site-Grenze
wüsste sie nicht, für wen sie es täte. Liegt alles unter einer Domain, wäre es
nachrüstbar.
@@ -218,7 +218,7 @@ was sich noch ändern kann, und lässt sich an einem Abend fertig bauen. Damit
beantwortet es die eigentliche Frage — schaut man überhaupt hin? — ohne dass
vorher das halbe Fundament stehen muss.
Und es ist das erste Widget, das **in der Leiste** lebt statt auf dem
Und es ist das erste Widget, das **in der HoneyBar** lebt statt auf dem
Schreibtisch. Es ist damit zugleich der Probelauf für den Rahmen weiter unten.
**Die Abfrage gehört auf den Server, nicht in den Browser.** Open-Meteo braucht
@@ -241,10 +241,35 @@ Zu klären, wenn es soweit ist:
- **Kein Netz, kein Wetter.** Dann verschwindet das Symbol, statt eine Zahl von
gestern als heutige auszugeben.
### Die Leiste ohne `unsafe-inline`
### Zwei Leisten, zwei Stilsätze
Fremde Apps bekommen die Leiste über den Reverse Proxy (siehe README). Dabei
muss deren CSP heute `style-src 'unsafe-inline'` erlauben, weil die Leiste ihre
Die HoneyBar in fremden Apps (`honeybar.js`, eigenes CSS im Shadow DOM) und die
Menüleiste des Schreibtischs (`.menubar` in `style.css`) sehen gleich aus, sind
aber getrennter Code — rund 19 Regeln hier, 30 dort, alle von Hand
gleichgehalten.
**Das ist bereits einmal auseinandergelaufen:** Das Wetter stand zuerst nur in
`honeybar.js`, und der Schalter „in der honeybar" schien auf dem Schreibtisch
wirkungslos (25.08.2026). Es wird wieder passieren.
Zwei Auswege:
- **Die Schreibtisch-Menüleiste durch `honeybar.js` ersetzen.** Ein Stilsatz,
eine Anatomie, und was die HoneyBar kann, kann der Schreibtisch automatisch
auch. Kostet: Die Menüleiste hat Dinge, die die HoneyBar nicht hat
(Einstellungsknopf, Abmelden, Avatar) — die müssten hinein, und die HoneyBar
ist bewusst schlank.
- **Die Farb- und Maßangaben in eine gemeinsame Datei ziehen**, die beide
einbinden. Kleiner Eingriff, löst aber nur die Hälfte: Aufbau und Verhalten
bleiben doppelt.
→ Ersteres ist das Richtige, sobald die HoneyBar mehr kann als heute (Widgets,
Systemmenü). Vorher lohnt der Umbau nicht.
### Die HoneyBar ohne `unsafe-inline`
Fremde Apps bekommen die HoneyBar über den Reverse Proxy (siehe README). Dabei
muss deren CSP heute `style-src 'unsafe-inline'` erlauben, weil die HoneyBar ihre
Stile im Shadow DOM mitbringt — ohne das erscheint sie schwarz auf schwarz.
Gemessen am 28.08.2026 an einer nachgebauten fremden App.
@@ -253,25 +278,25 @@ Shadow DOM per `<link>` einbinden. Dann genügt `style-src 'self' https://honeyo
und die CSP der fremden App bleibt streng. Kostet eine zweite Anfrage, die
zwischengespeichert wird.
Zu prüfen ist dabei, was sonst noch inline gesetzt wird: die Lage der Leiste
Zu prüfen ist dabei, was sonst noch inline gesetzt wird: die Lage der HoneyBar
selbst und der Innenabstand, den sie der Seite verpasst. Über die CSSOM gesetzte
Stile (`el.style.x = …`) fallen nicht unter die CSP — was im Markup steht, schon.
### Widgets in der Leiste selbst
### Widgets in der HoneyBar selbst
Bisher sind Widgets als Fenster auf dem Schreibtisch gedacht. Der Schreibtisch
ist aber die Seite, die man am seltensten offen hat — die Leiste dagegen ist
überall. Naheliegend also: ein Knopf in der Leiste klappt dasselbe Widget als
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
kleines Feld auf, ohne die App zu verlassen.
Technisch ist das dieselbe Sache wie 1.6, nur ein zweites Zuhause für denselben
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.
**Eine Einschränkung vorweg:** Die Leiste läuft in einer fremden App. Ein
Aether-Widget in der Leiste **von InkNote aus** braucht deshalb dasselbe, was
**Eine Einschränkung vorweg:** Die HoneyBar läuft in einer fremden App. Ein
Aether-Widget in der HoneyBar **von InkNote aus** braucht deshalb dasselbe, was
1.4 für den Schreibtisch regelt, nur für einen weiteren Ursprung. In der App
selbst (Aether-Widget in Aethers eigener Leiste) ist es geschenkt.
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.
@@ -291,10 +316,10 @@ wirklich draufschaust, lohnt der Rest. Wenn nicht, war es ein Abend.
## Offene Entscheidungen
### Wie sichtbar darf die Leiste sein?
### Wie sichtbar darf die HoneyBar sein?
**Teilweise beantwortet:** „ausblenden" heißt seit dem 24.08. „einklappen" — es
bleibt ein 3 px hoher Strich am oberen Rand stehen, ein Klick holt die Leiste
bleibt ein 3 px hoher Strich am oberen Rand stehen, ein Klick holt die HoneyBar
zurück. Vorher war das eine Einbahnstraße: wer einmal ausgeblendet hatte, kam
nur über die Entwicklerkonsole wieder heran. `?honeybar=1` an der Adresse
funktioniert als Notausgang.
@@ -303,7 +328,7 @@ Damit ist der schmale Streifen technisch schon da. Offen bleibt, ob er am Handy
der **Standard** sein soll.
**Der Zwiespalt:** Die App lädt die Leiste bei *jedem* Aufruf nach, also ist sie
**Der Zwiespalt:** Die App lädt die HoneyBar bei *jedem* Aufruf nach, also ist sie
immer da — auch wenn man die Cloud einfach direkt öffnet und mit
HoneyOS gerade nichts zu tun hat. 32 px, dauerhaft, in einer App, die man auch
für sich allein benutzt. Am Handy in einer installierten PWA wiegt das schwerer
@@ -313,18 +338,18 @@ Möglichkeiten, von viel nach wenig Platz:
| | Platz | Gefühl |
|---|---|---|
| volle Leiste | 32 px immer | am ehesten „OS" |
| volle HoneyBar | 32 px immer | am ehesten „OS" |
| schmaler Streifen, klappt bei Berührung auf | 4 px | immer erreichbar, nie im Weg |
| nur ein Eckknopf | ~0 | praktisch, aber keine Leiste mehr |
| nur ein Eckknopf | ~0 | praktisch, aber keine HoneyBar mehr |
| `data-push="none"` (liegt darüber) | 0 im Layout | verdeckt die Kopfzeile der App |
| ganz aus | 0 | schon eingebaut („leiste ausblenden") |
| ganz aus | 0 | schon eingebaut („honeybar ausblenden") |
→ **Vorschlag: am Rechner die volle Leiste, am Handy der schmale Streifen.**
→ **Vorschlag: am Rechner die volle HoneyBar, am Handy der schmale Streifen.**
Als Einstellung, nicht fest verdrahtet — dann lässt sich die Meinung ändern,
ohne etwas neu zu bauen.
**Wichtig für die Entscheidung:** Das ist keine Einbahnstraße. In den Apps steht
nur ein Ursprung in der `.env`; das Verhalten der Leiste liegt zentral in HoneyOS. Aussehen,
nur ein Ursprung in der `.env`; das Verhalten der HoneyBar liegt zentral in HoneyOS. Aussehen,
Höhe, Auto-Verstecken, Abschaffen — alles eine Änderung an einer Stelle, ohne
Aether oder InkNote neu zu bauen.
@@ -335,13 +360,13 @@ in beide gleichzeitig.
**Empfehlung: löschen.** Gründe:
1. Er wirkt nur an einer von zwei Stellen — in der Leiste ja, auf dem Desktop
1. Er wirkt nur an einer von zwei Stellen — in der HoneyBar ja, auf dem Desktop
nie. Das ist schwer zu erklären und noch schwerer zu merken.
2. Er bringt allein die Namensanzeige. Kein Funktionsunterschied.
3. Sobald 1.3 gebaut ist, ist er ohnehin überflüssig.
4. **Scharfe Kante:** Das Feld „Wer-bin-ich" darf auch eine vollständige fremde
Adresse sein. Steht dort etwas Fremdes *und* ein Token-Schlüssel, schickt die
Leiste den InkNote-Token dorthin. Das setzt voraus, dass jemand Angemeldetes
HoneyBar den InkNote-Token dorthin. Das setzt voraus, dass jemand Angemeldetes
das selbst einträgt — bei einer Ein-Personen-Instanz also kein akuter
Notstand, aber eine Falle, die niemand braucht.
@@ -355,16 +380,16 @@ Heute gilt die App-Liste für alle — bewusst so, siehe „Bewusst nicht geplan
Denkbar wäre daneben eine kleine eigene Liste je Konto.
**Was dagegen spricht, ist nicht der Aufwand, sondern eine harte Grenze:** Auf
dem Schreibtisch ginge es sofort (dort ist man angemeldet). In der Leiste einer
dem Schreibtisch ginge es sofort (dort ist man angemeldet). In der HoneyBar einer
fremden App ginge es **nicht**, solange HoneyOS auf einer anderen Site liegt als
die App — der Browser schickt die HoneyOS-Sitzung dann nicht mit, und der
Schlüssel für die App-Liste weiß nicht, wer schaut. Die Leiste zeigte also die
Schlüssel für die App-Liste weiß nicht, wer schaut. Die HoneyBar zeigte also die
gemeinsamen Apps, der Schreibtisch zusätzlich die eigenen. Zwei verschiedene
Listen an zwei Stellen ist schlechter als eine.
**Liegt alles unter derselben Domain** (`os.beispiel.duckdns.org` +
`cloud.beispiel.duckdns.org`), fällt die Grenze weg: die Sitzung wird
mitgeschickt, die Leiste weiß, wer da ist. Seit dem Umzug auf
mitgeschickt, die HoneyBar weiß, wer da ist. Seit dem Umzug auf
`os.asianxpolish.duckdns.org` ist genau das der Fall — persönliche Apps sind
damit machbar geworden.
@@ -373,7 +398,7 @@ Person ist „persönlich" und „für alle" dasselbe. Der Weg ist aber offen un
sollte es bleiben: nichts einbauen, was von einer einzigen gemeinsamen Liste
ausgeht.
### Wie weit soll das Aussehen der Leiste einstellbar sein?
### Wie weit soll das Aussehen der HoneyBar einstellbar sein?
Röhre, Leuchten und Scanlines kommen schon aus HoneyOS (1.1). Offen ist, was
darüber hinaus in die Einstellungen gehört: Höhe, Schriftgröße, Position (oben
@@ -388,10 +413,10 @@ einmal ein und nie wieder — dann kann es auch gleich richtig fest stehen).
`honeyos.duckdns.org` als Dach, die Apps darunter (`cloud.honeyos.duckdns.org`
und so fort). Am 25.08.2026 gemessen: Dann schickt der Browser die
HoneyOS-Sitzung an die Leiste mit, über eine fremde Site hinweg nicht.
HoneyOS-Sitzung an die HoneyBar mit, über eine fremde Site hinweg nicht.
Damit möglich, was heute nicht geht: **mehrere Nutzer mit eigenem Aussehen**,
persönliche Apps, der Name in der Leiste. Und `HONEYBAR_KEY` samt CORS-Ausnahme
persönliche Apps, der Name in der HoneyBar. Und `HONEYBAR_KEY` samt CORS-Ausnahme
wird überflüssig — der Umzug räumt Komplexität weg, statt welche zu schaffen.
Kosten sind einmalig, aber real: Redirect-URIs in PocketID, `PUBLIC_URL` und
@@ -417,7 +442,7 @@ Damit es nicht alle paar Monate neu diskutiert wird:
(`helmet()`) verbieten es beide von sich aus, und das aus gutem Grund. Es
würde Clickjacking-Schutz, PWA-Installierbarkeit und InkNotes Offline-Betrieb
kosten. Widgets zeigen **Daten**, die Apps bleiben in ihrem eigenen Tab.
- **Nichts über die Leiste wird beim Bauen der Apps eingebacken.** Die Adresse
- **Nichts über die HoneyBar wird beim Bauen der Apps eingebacken.** Die Adresse
stand einmal fest in Aethers `index.html`. Das war aus zwei Gründen falsch:
Ein fertiges Abbild lässt sich dann nicht über die `.env` umziehen, und der
Service Worker der PWA hält die alte `index.html` im Cache, so dass eine
+38 -38
View File
@@ -1,11 +1,11 @@
# HoneyOS
Ein Retro-Schreibtisch vor den eigenen Apps. Amber-CRT, Boot-Log, zwei Betriebsarten,
Anmeldung über den eigenen OIDC-Anbieter — und dieselbe Leiste zum Einhängen in die Apps.
Anmeldung über den eigenen OIDC-Anbieter — und dieselbe HoneyBar zum Einhängen in die Apps.
**Was es ist:** eine Oberfläche davor. Jede App bleibt ihre eigene PWA auf ihrer eigenen
Domain mit ihrer eigenen Anmeldung. HoneyOS ist der Startpunkt, der Umschalter und die
gemeinsame Leiste — **kein Rahmen, der die Apps einsperrt** (kein iframe).
gemeinsame HoneyBar — **kein Rahmen, der die Apps einsperrt** (kein iframe).
**Wo der Zustand liegt:** im Server. Die App-Liste gilt für alle, die Einstellungen gehören
je Nutzer — deshalb sieht dein HoneyOS auf jedem Gerät gleich aus, an dem du angemeldet bist.
@@ -69,7 +69,7 @@ Der Browser behandelt `honeyos.duckdns.org` und `cloud.honeyy.duckdns.org` als
gemeinsame Endung zählt also nicht. Folge: Bei der Anfrage aus einer App heraus
schickt der Browser die HoneyOS-Sitzung **nicht** mit.
Damit die Leiste trotzdem eine App-Liste bekommt:
Damit die HoneyBar trotzdem eine App-Liste bekommt:
```dotenv
HONEYOS_APPS_KEY=… # openssl rand -hex 16
@@ -91,7 +91,7 @@ heraus, die **selbst als App eingetragen** sind. Eine fremde Seite scheitert
also an CORS, selbst mit richtigem Schlüssel.
**Was auf zwei Sites nicht geht:** der Anmeldestand auf den Kacheln des
Schreibtischs (fragt über die Domaingrenze). Der Name *in der Leiste* geht
Schreibtischs (fragt über die Domaingrenze). Der Name *in der HoneyBar* geht
weiterhin — den holt sie bei der App selbst, gleicher Ursprung.
Liegen alle Adressen unter derselben Domain (`os.honeyy…`, `cloud.honeyy…`),
@@ -104,7 +104,7 @@ entfällt der Schlüssel und alles funktioniert ohne Einschränkung.
| Feld | wofür |
|---|---|
| ID | klein, ohne Leerzeichen — muss zu `data-app` der Leiste passen |
| ID | klein, ohne Leerzeichen — muss zu `data-app` der HoneyBar passen |
| Name, Untertitel | Beschriftung auf Kachel und Symbol |
| Adresse | wohin der Start springt |
| Symbol | cloud · note · box · chip · folder · gear · globe · disk |
@@ -133,7 +133,7 @@ in beiden: Menüleiste, Palette, Einstellungen, App-Liste.
## Wetter
Ein Pixelsymbol mit der Temperatur — wahlweise auf dem Schreibtisch, in der
Leiste, in beidem oder nirgends. Zwei getrennte Schalter unter
HoneyBar, in beidem oder nirgends. Zwei getrennte Schalter unter
*Einstellungen → Wetter*, weil das zwei verschiedene Orte sind: Wer es beim
Arbeiten in einer App sehen will, will es nicht zwangsläufig auch auf einer
Seite, die er selten aufruft.
@@ -142,7 +142,7 @@ Die Stadt wird dort einmal gesucht und **mit ihren Koordinaten** gespeichert;
sonst müsste jede Abfrage den Ort erneut suchen — zwei Anfragen nach draußen
statt einer. Ohne Stadt bleibt das Wetter aus.
**Der Server holt es, nicht der Browser.** Die Leiste steht auf jeder Seite
**Der Server holt es, nicht der Browser.** Die HoneyBar steht auf jeder Seite
jeder App: Fragte sie selbst beim Wetterdienst an, ginge bei jedem Seitenaufruf
aus jeder App eine Anfrage samt IP dorthin, und die CSP jeder App müsste den
fremden Ursprung erlauben. So sieht der Dienst einen Server. Die Antwort gilt
@@ -153,10 +153,10 @@ Konto, nichts einzurichten. Ist der Dienst nicht erreichbar oder das Gerät
offline, verschwindet das Symbol — lieber keins als eine Zahl von gestern.
Ändern lässt sich die Stadt nur auf dem Schreibtisch; ein Klick auf das Symbol
in der Leiste führt dorthin. Die Leiste liest über den Schlüssel und darf nichts
in der HoneyBar führt dorthin. Die HoneyBar liest über den Schlüssel und darf nichts
schreiben.
## Die Leiste in deine Apps bringen
## Die HoneyBar in deine Apps bringen
Es gibt zwei Wege, und welcher gilt, hängt an einer einzigen Frage: **Kannst du
den Quelltext der App ändern?**
@@ -164,11 +164,11 @@ den Quelltext der App ändern?**
| | Weg 1 — selbst geschrieben | Weg 2 — fertig bezogen |
|---|---|---|
| Beispiele | Aether, InkNote | BentoPDF, Uptime Kuma, alles aus einem Image |
| Einbau | die App lädt die Leiste selbst | ein nginx davor setzt sie ein |
| Einbau | die App lädt die HoneyBar selbst | ein nginx davor setzt sie ein |
| Umstellen | eine Zeile in der `.env` | zwei Zeilen in der Proxy-Tabelle |
| Layout | passt sich an (`--honeybar-h`) | bleibt, wie die App es macht |
Beide Wege ergeben dieselbe Leiste; die App-Liste, die Farben und das Wetter
Beide Wege ergeben dieselbe HoneyBar; die App-Liste, die Farben und das Wetter
kommen ohnehin aus HoneyOS.
### Weg 1 — Apps, die du selbst schreibst
@@ -181,17 +181,17 @@ Eine Zeile im HTML der App:
```
`defer` ist nicht optional: ohne wartet der Seitenaufbau der App auf das Skript.
Ist HoneyOS langsam oder aus, soll die Leiste den Start von Aether nicht bremsen.
Ist HoneyOS langsam oder aus, soll die HoneyBar den Start von Aether nicht bremsen.
**Aether und InkNote machen es einen Schritt anders — und das ist die bessere
Art:** Sie laden die Leiste zur *Laufzeit*, die Adresse kommt aus ihrer eigenen
Art:** Sie laden die HoneyBar zur *Laufzeit*, die Adresse kommt aus ihrer eigenen
`.env` (`HONEYBAR_ORIGIN`) über einen kleinen Endpunkt der App. Der Grund ist
Erfahrung: Ein fertiges Abbild wird gezogen, nicht gebaut — was beim Bauen ins
HTML geschrieben wird, lässt sich hinterher nicht mehr ändern. Und der Service
Worker einer PWA hebt ganze Antworten auf, samt Kopfzeilen; eine ins HTML
eingefrorene Adresse überlebt dort jede Konfigurationsänderung.
`data-app` ist die ID aus der App-Liste. Die Liste holt sich die Leiste selbst von
`data-app` ist die ID aus der App-Liste. Die Liste holt sich die HoneyBar selbst von
`/api/apps` — mit deiner HoneyOS-Sitzung, weil alle Adressen unter derselben Domain liegen.
**Freigegeben sind nur die Ursprünge, die selbst als App eingetragen sind**: die App-Liste
ist zugleich ihre eigene CORS-Freigabe.
@@ -213,7 +213,7 @@ Für Werkzeuge, die man **nicht selbst geschrieben hat**, gibt es keinen
Seite durchreicht:
```
außen ──► Pangolin ──► leiste (nginx) ──► app:8080
außen ──► Pangolin ──► honeybar (nginx) ──► app:8080
TLS, Auth setzt eine Zeile ein, reicht sonst nur durch
```
@@ -244,20 +244,20 @@ location / {
Dazu muss der Ursprung dieser App **in HoneyOS als App eingetragen** sein — die
Liste ist zugleich die CORS-Freigabe. **Auf den Ursprung genau**: `localhost` und
`127.0.0.1` sind für den Browser zwei verschiedene, ebenso `http` und `https`
oder ein abweichender Port. Passt er nicht, erscheint die Leiste mit leerer
oder ein abweichender Port. Passt er nicht, erscheint die HoneyBar mit leerer
App-Liste und in der Konsole steht ein CORS-Fehler.
**Warum `style-src 'unsafe-inline'`:** Die Leiste bringt ihre Stile mit, im
Shadow DOM. Eine strenge CSP verbietet die — gemessen: die Leiste erscheint,
**Warum `style-src 'unsafe-inline'`:** Die HoneyBar bringt ihre Stile mit, im
Shadow DOM. Eine strenge CSP verbietet die — gemessen: die HoneyBar erscheint,
aber schwarz auf schwarz, ohne Röhre. Das ist eine echte Abschwächung der
CSP dieser App; viele fertige Werkzeuge brauchen `unsafe-inline` ohnehin für
sich selbst, aber wissen sollte man es. (Auflösbar, indem die Leiste ihre Stile
sich selbst, aber wissen sollte man es. (Auflösbar, indem die HoneyBar ihre Stile
als eigene Datei ausliefert — steht in [IDEAS.md](IDEAS.md).)
**Apps mit COEP** (alles mit WASM oder SharedArrayBuffer — BentoPDF etwa)
lehnen fremde Dateien ab, die sich nicht zur Einbettung bekennen. HoneyOS
liefert die Leiste deshalb mit `Cross-Origin-Resource-Policy: cross-origin`
aus. Ohne das erscheint dort keine Leiste, und in der Konsole steht nur
liefert die HoneyBar deshalb mit `Cross-Origin-Resource-Policy: cross-origin`
aus. Ohne das erscheint dort keine HoneyBar, und in der Konsole steht nur
`ERR_BLOCKED_BY_RESPONSE.NotSameOriginAfterDefaultedToSameOriginByCoep`.
Das COEP der App bleibt dabei unangetastet — ihre eigenen Fähigkeiten also auch.
@@ -273,7 +273,7 @@ schickt — und das tun die meisten:
| Aufwand | eine `sub_filter`-Zeile | drei `location`-Blöcke |
Bei der zweiten reicht der Einsetzer auch `/honeybar/` und die zwei Abfragen der
Leiste durch, unter *seiner* Adresse. Für den Browser ist damit alles derselbe
HoneyBar durch, unter *seiner* Adresse. Für den Browser ist damit alles derselbe
Ursprung, und die drei Hürden fallen auf einmal weg. Durchgereicht werden dabei
**nur** `/api/apps` und `/api/weather`, und nur lesend (`limit_except GET`) —
ein pauschales `/api/` hinge sonst die ganze HoneyOS-Schnittstelle unter die
@@ -314,42 +314,42 @@ Zwei Änderungen, mehr nicht:
Einsetzer spricht sie im Docker-Netz unter ihrem Namen an (`bentopdf:8080`;
die `8080` ist der Port *im* Behälter und bleibt, die `8888` war nur die
Klinke an der Außenseite). Ginge Pangolin weiter direkt auf die App, wäre der
Einsetzer umgangen und die Leiste fehlte. Zum Nachsehen darf ein `ports:`
ruhig stehen bleiben — dann hast du zwei Wege: direkt ohne Leiste, über
Einsetzer umgangen und die HoneyBar fehlte. Zum Nachsehen darf ein `ports:`
ruhig stehen bleiben — dann hast du zwei Wege: direkt ohne HoneyBar, über
Pangolin mit.
2. **Das Netz `honeybar` dazu.** Es entsteht im Einsetzer-Stapel; hier wird es
nur als `external` mitbenutzt. Deshalb jenen Stapel zuerst starten.
Dazu noch zwei Zeilen im Einsetzer (`$ziel` und `$appid`) und in Pangolin die
Ressource von der App auf `leiste:80` umstellen. Fertig.
Ressource von der App auf `honeybar:80` umstellen. Fertig.
#### Was es kostet
Nicht viel, aber nicht nichts:
- **Ein Ausfallpunkt mehr.** Ist der Einsetzer weg, sind die Apps dahinter weg —
nicht nur ihre Leiste. `restart: unless-stopped` ist deshalb Pflicht; ein
nicht nur ihre HoneyBar. `restart: unless-stopped` ist deshalb Pflicht; ein
nginx, der nur durchreicht, fällt praktisch nie aus.
- **Eine Stelle mehr zum Pflegen.** Je App zwei Zeilen, und beim Umbenennen
einer Adresse muss man daran denken.
- **Ein Sprung mehr im Netz.** Im selben Docker-Netz nicht messbar.
- **Nicht jede App muss dahinter.** Was ohne Leiste laufen soll, zeigt in
- **Nicht jede App muss dahinter.** Was ohne HoneyBar laufen soll, zeigt in
Pangolin weiter direkt auf die App. Das entscheidest du je App.
**Fertige Beispiele:**
- [`beispiele/bentopdf/`](beispiele/bentopdf/) — ein Dienst, alles über die
eigene Adresse. Geprüft mit `ghcr.io/alam00000/bentopdf-simple`, das eine
strenge CSP und COEP mitbringt: Leiste, Apps und Wetter erscheinen, ohne dass
strenge CSP und COEP mitbringt: HoneyBar, Apps und Wetter erscheinen, ohne dass
an dessen Kopfzeilen etwas geändert wird.
- [`beispiele/mehrere-apps/`](beispiele/mehrere-apps/) — **HoneyOS und ein
Einsetzer für beliebig viele Dienste in einem Stapel.** Zwei Tabellen oben in
der Datei sagen, welcher Name zu welchem Behälter gehört und welche App das
für HoneyOS ist; eine neue App sind zwei Zeilen. Die Leiste hebt die aktuelle
für HoneyOS ist; eine neue App sind zwei Zeilen. Die HoneyBar hebt die aktuelle
App hervor, sobald `$appid` der `ID` in der App-Liste entspricht — genau wie
in Aether und InkNote. Am Host erkennt nginx, welcher
Dienst gemeint ist; eine neue App sind zwei Zeilen in den Tabellen oben in
`leiste.conf`. Das ist der Aufbau, den man haben will, sobald es mehr als ein
`honeybar.conf`. Das ist der Aufbau, den man haben will, sobald es mehr als ein
Nicht ein Behälter je App, und nicht HoneyOS getrennt davon gepflegt.
Das Netz `honeybar` legt dieser Stapel selbst an, unter festem Namen. Die
@@ -365,10 +365,10 @@ dafür bräuchte es ein Plugin. Der kürzere Weg ist ein kleiner nginx *zwischen
Pangolin und der App, der nichts tut außer einsetzen:
```yaml
leiste:
honeybar:
image: nginx:alpine
restart: unless-stopped
volumes: [./leiste.conf:/etc/nginx/conf.d/default.conf:ro]
volumes: [./honeybar.conf:/etc/nginx/conf.d/default.conf:ro]
# Pangolin zeigt jetzt hierher statt direkt auf die App.
```
@@ -378,12 +378,12 @@ nur, wessen App selbst eine schickt.
**Was dabei zu erwarten ist:**
- **Das Layout der fremden App kennt die Leiste nicht.** Rechnet sie mit
- **Das Layout der fremden App kennt die HoneyBar nicht.** Rechnet sie mit
`100vh`, wird die Seite um 32 px zu hoch (Bildlaufleiste) — ihr CSS lässt
sich nicht anpassen wie das eigene. Dann hilft `data-push="none"`: Die Leiste
sich nicht anpassen wie das eigene. Dann hilft `data-push="none"`: Die HoneyBar
legt sich darüber, statt zu schieben. Verdeckt dafür die oberste Zeile.
- **Apps mit eigener Kopfleiste** sehen doppelt belegt aus. Geschmackssache.
- **Anmeldeseiten, iframes, Downloads** bekommen die Leiste ebenfalls, soweit
- **Anmeldeseiten, iframes, Downloads** bekommen die HoneyBar ebenfalls, soweit
sie HTML sind. `sub_filter` unterscheidet das nicht.
- **Andere Proxys:** Caddy braucht ein Zusatzmodul (`replace-response`),
Traefik ein Plugin für den Antwortkörper. nginx kann es ohne Erweiterung.
@@ -396,7 +396,7 @@ Das Feld **Wer-bin-ich** ist der Pfad, unter dem eine App „wer bin ich" beantw
Gelesen wird das an zwei Stellen, und die verhalten sich **unterschiedlich**:
1. **Die Leiste in der App** fragt ihre eigene App. Gleicher Ursprung → funktioniert
1. **Die HoneyBar in der App** fragt ihre eigene App. Gleicher Ursprung → funktioniert
sofort, ohne Änderung an Aether oder InkNote.
2. **Der Desktop auf `os.…`** fragt über die Domaingrenze. Dafür muss die App diesen
Ursprung erlauben:
@@ -463,11 +463,11 @@ Versionsnummer zu grob.
- **Die App-Liste ist für alle gleich.** Wer angemeldet ist, darf sie ändern — das ist für
eine Handvoll Konten gewollt und wäre für mehr Leute zu wenig.
- **Ein Angemeldeter kann jede Adresse eintragen.** Der Server prüft nur, dass es eine
http(s)-Adresse ist. Das ist zugleich die CORS-Freigabe der Leiste, also nicht
http(s)-Adresse ist. Das ist zugleich die CORS-Freigabe der HoneyBar, also nicht
gedankenlos etwas Fremdes eintragen.
## Was als Nächstes ansteht
1. **CORS in Aether** für `os.…`, damit der Desktop den Anmeldestand sehen kann.
2. **Überall abmelden** in der Leiste — braucht pro App den CSRF-Weg zum Logout.
2. **Überall abmelden** in der HoneyBar — braucht pro App den CSRF-Weg zum Logout.
3. **Fenster mit Inhalt** statt nur Verweisen: „letzte Dateien", „letzte Notizen".
+11 -11
View File
@@ -1,10 +1,10 @@
# ─────────────────────────────────────────────────────────────────────────────
# BentoPDF mit HoneyOS-Leiste — alles über den eigenen Ursprung.
# BentoPDF mit HoneyBar — alles über den eigenen Ursprung.
#
# Pangolin → leiste → bentopdf
# Pangolin → einsetzer → bentopdf
# ↘ honeyos (nur /honeybar/ und zwei Abfragen)
#
# Der Kniff: Die Leiste wird nicht von honeyos.… geladen, sondern über die
# Der Kniff: Die HoneyBar wird nicht von honeyos.… geladen, sondern über die
# Adresse der App selbst durchgereicht. Für den Browser ist sie damit eigener
# Ursprung — und alle drei Hürden fallen auf einmal weg:
#
@@ -16,7 +16,7 @@
# im Quelltext der Seite steht er nicht.
#
# docker compose up -d
# → in Pangolin die Ressource auf leiste:80 zeigen lassen,
# → in Pangolin die Ressource auf einsetzer:80 zeigen lassen,
# und in HoneyOS BentoPDF als App eintragen (ID: bentopdf, URL: die
# öffentliche Adresse, exakt so, wie du sie im Browser aufrufst).
# ─────────────────────────────────────────────────────────────────────────────
@@ -26,12 +26,12 @@ services:
container_name: bentopdf
restart: unless-stopped
# Kein ports: nötig — erreichbar ist nur noch der Einsetzer davor.
# (Zum direkten Nachsehen ohne Leiste ruhig eins lassen.)
# (Zum direkten Nachsehen ohne HoneyBar ruhig eins lassen.)
networks: [honeybar]
leiste:
einsetzer:
image: nginx:alpine
container_name: bentopdf-leiste
container_name: bentopdf-einsetzer
restart: unless-stopped
depends_on: [bentopdf]
ports:
@@ -39,15 +39,15 @@ services:
# Pangolin auf demselben Wirt im Host-Netz läuft — hängt es in einem
# eigenen Behälter oder auf einer anderen Maschine, kommt es dort nicht
# hin. Am saubersten: kein ports:, und Pangolin (bzw. sein Newt) tritt
# dem Netz `honeybar` bei und spricht `leiste:80` direkt an.
# dem Netz `honeybar` bei und spricht `einsetzer:80` direkt an.
- "${LEISTE_PORT:-8185}:80"
configs:
- source: leiste
- source: einsetzer
target: /etc/nginx/conf.d/default.conf
networks: [honeybar]
configs:
leiste:
einsetzer:
# `$$` ist hier ein einfaches `$` für nginx. Ein einzelnes `$` setzt
# dagegen Compose ein — genau das ist bei ${HONEYOS_APPS_KEY} gewollt:
# der Schlüssel kommt aus der .env und landet nur in der Konfiguration
@@ -64,7 +64,7 @@ configs:
# kaputt. Wieviel erlaubt ist, entscheidet die App dahinter.
client_max_body_size 0;
# 1. Die Leiste selbst, durchgereicht über diesen Ursprung.
# 1. Die HoneyBar selbst, durchgereicht über diesen Ursprung.
location /honeybar/ {
proxy_pass http://honeyos:8080/honeybar/;
}
+12 -12
View File
@@ -2,23 +2,23 @@
# HoneyOS und ein Einsetzer für beliebig viele fremde Dienste.
#
# außen ──► Pangolin ──► honeyos (der Schreibtisch)
# Pangolin ──► leiste ──► bentopdf:8080 (App mit Leiste)
# Pangolin ──► einsetzer ──► bentopdf:8080 (App mit HoneyBar)
# │ ──► uptime-kuma:3001
# └──► honeyos:8080 (Leiste + zwei Abfragen)
# └──► honeyos:8080 (HoneyBar + zwei Abfragen)
#
# Die fremden Dienste brauchen kein `ports:` mehr — erreichbar sind sie über
# ihren Namen im Netz `honeybar`, und nach außen führt nur der Einsetzer.
#
# Eine neue App hinzufügen heißt: zwei Zeilen in den Tabellen `$ziel` und
# `$appid`, dann `docker compose up -d --force-recreate leiste`.
# `$appid`, dann `docker compose up -d --force-recreate einsetzer`.
#
# cp ../../.env.example .env && ausfüllen (HONEYOS_APPS_KEY setzen!)
# mkdir -p daten && sudo chown 1000:1000 daten
# docker compose up -d
#
# Danach in Pangolin: honeyos.… → honeyos:8080, jede App → leiste:80.
# Danach in Pangolin: honeyos.… → honeyos:8080, jede App → einsetzer:80.
# Und in HoneyOS jede App eintragen — die `ID` dort muss dem `$appid` hier
# entsprechen, sonst weiß die Leiste nicht, in welcher App man gerade ist.
# entsprechen, sonst weiß die HoneyBar nicht, in welcher App man gerade ist.
# ─────────────────────────────────────────────────────────────────────────────
services:
@@ -45,21 +45,21 @@ services:
- HONEYOS_APPS_KEY=${HONEYOS_APPS_KEY:-}
networks: [honeybar]
leiste:
einsetzer:
image: nginx:alpine
container_name: honeybar-leiste
container_name: honeybar-einsetzer
restart: unless-stopped
ports:
- "${LEISTE_PORT:-8185}:80"
configs:
- source: leiste
- source: einsetzer
target: /etc/nginx/conf.d/default.conf
networks: [honeybar]
# Kein depends_on: Der Einsetzer reicht nur durch. Ist HoneyOS aus, fehlt
# die Leiste — die Apps laufen weiter.
# die HoneyBar — die Apps laufen weiter.
configs:
leiste:
einsetzer:
# `$$` ist hier ein einfaches `$` für nginx. Ein einzelnes `$` setzt
# dagegen Compose ein — genau das ist bei ${HONEYOS_APPS_KEY} gewollt: der
# Schlüssel steht damit nur in der nginx-Konfiguration, nie in der Seite.
@@ -74,7 +74,7 @@ configs:
}
# ── Und welche App das für HoneyOS ist ────────────────────────────────
# Muss der `ID` in der App-Liste entsprechen. Daran erkennt die Leiste,
# Muss der `ID` in der App-Liste entsprechen. Daran erkennt die HoneyBar,
# wo man gerade ist, und hebt den Eintrag hervor — wie in Aether.
map $$host $$appid {
default "";
@@ -101,7 +101,7 @@ configs:
# kaputt. Wieviel erlaubt ist, entscheidet die App dahinter.
client_max_body_size 0;
# ── Die Leiste, durchgereicht über DIESE Adresse ──────────────────
# ── Die HoneyBar, durchgereicht über DIESE Adresse ──────────────────
# Dadurch ist sie für den Browser eigener Ursprung: Die CSP der App
# bleibt unangetastet, CORS und COEP entfallen.
location /honeybar/ {
+19 -19
View File
@@ -1,28 +1,28 @@
/*
* HoneyBar — die HoneyOS-Leiste zum Einhängen in eine fremde App.
* HoneyBar — die HoneyBar zum Einhängen in eine fremde App.
*
* <script src="https://os.honeyy.duckdns.org/honeybar/honeybar.js"
* data-app="aether"></script>
*
* Eine Zeile, kein Build, keine Abhängigkeit. Die Leiste rendert in einem
* Eine Zeile, kein Build, keine Abhängigkeit. Die HoneyBar rendert in einem
* Shadow DOM — die Stile der Gastgeber-App kommen nicht rein, unsere nicht
* raus. Das ist der ganze Grund für die Konstruktion: Aether ist React +
* Tailwind, InkNote React + eigene Palette, und beide sollen von der Leiste
* Tailwind, InkNote React + eigene Palette, und beide sollen von der HoneyBar
* nichts merken außer den 32 Pixeln oben.
*
* data-Attribute am <script>:
* data-app (Pflicht) id der App, in der die Leiste steckt
* data-app (Pflicht) id der App, in der die HoneyBar steckt
* data-apps URL der App-Liste; ohne das /api/apps neben dem Skript
* data-key Schlüssel für die App-Liste. Nötig, wenn HoneyOS auf einer
* anderen Site liegt als die App: dann schickt der Browser die
* HoneyOS-Sitzung nicht mit, und ohne zweiten Ausweis bliebe die
* Leiste ohne Liste.
* HoneyBar ohne Liste.
* data-home URL des HoneyOS-Desktops
* data-push "body" (Standard) schiebt den Seiteninhalt nach unten,
* "none" legt die Leiste darüber
* "none" legt die HoneyBar darüber
*
* Wichtig zu wissen: localStorage ist pro Domain. Was auf os.honeyy… steht,
* sieht diese Leiste auf notes.honeyy… nicht — die Leiste ist ein Schalter,
* sieht diese HoneyBar auf notes.honeyy… nicht — die HoneyBar ist ein Schalter,
* kein geteilter Zustand. Gemeinsame Sitzung wäre echtes SSO und ist eine
* eigene Baustelle.
*/
@@ -46,7 +46,7 @@
// Ohne data-home führt der Weg zurück dorthin, wo dieses Skript herkommt.
const homeUrl = d("home", script ? new URL("/", script.src).href : "/");
const pushMode = d("push", "body");
// Ohne data-apps fragt die Leiste den HoneyOS-Server, von dem sie selbst
// Ohne data-apps fragt die HoneyBar den HoneyOS-Server, von dem sie selbst
// geladen wurde. Er gibt die Liste nur an angemeldete Browser heraus und
// nur an Ursprünge, die selbst als App eingetragen sind.
const appsUrl = d("apps", script ? new URL("../api/apps", script.src).href : "");
@@ -56,14 +56,14 @@
let apps = DEFAULT_APPS;
let settings = null;
// Was die Seite oben schon hatte, bevor die Leiste sie heruntergeschoben hat.
// Was die Seite oben schon hatte, bevor die HoneyBar sie heruntergeschoben hat.
let urspruenglichesPolster = null;
/* ── Aufbau ───────────────────────────────────────────────────────────── */
// Als installierte App liegt der Inhalt unter der Statusleiste des Geraets
// (die Apps setzen viewport-fit=cover, damit der Hintergrund bis an den Rand
// reicht). Eine Leiste, die stur bei 0 anfaengt, liegt dort unter Uhrzeit und
// reicht). Eine HoneyBar, die stur bei 0 anfaengt, liegt dort unter Uhrzeit und
// Akkustand. Deshalb waechst sie um die Aussparung und polstert sich selbst;
// im Browser ist env() null und alles bleibt bei 32 px.
const SAFE = "env(safe-area-inset-top, 0px)";
@@ -71,7 +71,7 @@
/* Wettersymbole als Pixelraster, dieselben Namen wie in weather.go.
Sie stehen auch in os.js — bis die geteilte Symbolquelle (1.3) gebaut ist,
ist das die kleinere Sünde: Die Leiste soll eine einzelne Datei bleiben,
ist das die kleinere Sünde: Die HoneyBar soll eine einzelne Datei bleiben,
die eine fremde App mit einer Zeile einbindet. */
const WX = {
sonne: "............;.....##.....;..#..##..#..;...#....#...;....####....;..##....##..;..##....##..;....####....;...#....#...;..#..##..#..;.....##.....;............",
@@ -133,7 +133,7 @@
user-select: none;
}
.bar::after {
/* Scanlines, damit die Leiste zum Desktop gehört */
/* Scanlines, damit die HoneyBar zum Desktop gehört */
content: ""; position: absolute; inset: 0; pointer-events: none;
background: repeating-linear-gradient(to bottom, var(--scan) 0 1px, transparent 1px 3px);
}
@@ -198,12 +198,12 @@
<div class="head">wechseln zu</div>
<div id="menuApps"></div>
<hr />
<button id="hide" role="menuitem">leiste einklappen</button>
<button id="hide" role="menuitem">honeybar 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
* bewusste Entscheidung: die HoneyBar soll ohne zweite Datei auskommen, damit
* sie in jeder fremden App mit einer Zeile funktioniert.
*/
const ROEHREN = {
@@ -280,7 +280,7 @@
}
/**
* Zeigt an, wer angemeldet ist. Die Leiste steckt in der App selbst, der
* Zeigt an, wer angemeldet ist. Die HoneyBar steckt in der App selbst, der
* Aufruf geht also an denselben Ursprung — kein CORS, keine Freigabe nötig.
* Antwortet die App nicht wie erwartet, bleibt das Feld leer und niemand
* merkt etwas: die Anzeige ist eine Zugabe, keine Zusicherung.
@@ -377,7 +377,7 @@
/**
* 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
* ist der Weg zurück. Ganz verschwinden darf die HoneyBar nicht: wer sie einmal
* weggeklickt hat, käme sonst nur noch über die Entwicklerkonsole an sie heran.
*/
let nub = null;
@@ -390,7 +390,7 @@
"top:" + SAFE,
"z-index:2147483000", "cursor:pointer", "display:block",
].join(";");
nub.title = "HoneyOS-Leiste einblenden";
nub.title = "HoneyBar einblenden";
const r = nub.attachShadow({ mode: "open" });
r.innerHTML = `
<style>
@@ -436,7 +436,7 @@
try {
hidden = localStorage.getItem(LS_HIDDEN) === "1";
} catch {
/* kein Speicher, Leiste bleibt sichtbar */
/* kein Speicher, HoneyBar bleibt sichtbar */
}
// ?honeybar=1 holt sie zurück, falls der Strich einmal übersehen wird.
if (hidden && new URLSearchParams(location.search).get("honeybar") === "1") {
@@ -467,7 +467,7 @@
}
} catch {
/* nicht angemeldet, kein CORS, kein Netz → eingebaute Liste;
die Leiste bleibt ein Umschalter, nur ohne frische Namen */
die HoneyBar bleibt ein Umschalter, nur ohne frische Namen */
}
}
+8 -8
View File
@@ -26,7 +26,7 @@ const DEFAULT_SETTINGS = {
flicker: "on",
glow: "on",
openIn: "tab", // tab | same
// Wetter. Zwei Schalter statt einem: Der Schreibtisch und die Leiste sind
// Wetter. Zwei Schalter statt einem: Der Schreibtisch und die HoneyBar sind
// zwei verschiedene Orte, und wer das Wetter beim Arbeiten in einer App will,
// will es nicht zwingend auch auf einer Seite, die er selten aufruft.
weatherBar: "off",
@@ -56,7 +56,7 @@ const isTouch = () => window.matchMedia("(pointer: coarse)").matches;
* im Retro-Raster statt aus einer Icon-Bibliothek zu kommen.
*/
const GLYPHS = {
// Wettersymbole. Dieselben Namen wie in weather.go (wmo) und in der Leiste —
// Wettersymbole. Dieselben Namen wie in weather.go (wmo) und in der HoneyBar —
// solange 1.3 (geteilte Symbolquelle) nicht gebaut ist, stehen sie zweimal da.
sonne: [
"............",
@@ -551,8 +551,8 @@ function renderWeather() {
desk.innerHTML = html;
}
// Und in der Leiste. Die Menüleiste hier ist zwar anderer Code als
// honeybar.js in den Apps, aber für den, der davorsitzt, dieselbe Leiste —
// Und in der HoneyBar. Die Menüleiste hier ist zwar anderer Code als
// honeybar.js in den Apps, aber für den, der davorsitzt, dieselbe HoneyBar —
// ein Schalter, der nur woanders wirkt, wäre nicht zu erklären.
const inLeiste = state.settings.weatherBar === "on" && w;
bar.hidden = !inLeiste;
@@ -1055,7 +1055,7 @@ function openSettings() {
<span class="label">Wetter</span>
${seg("weatherDesk", [["on", "auf dem schreibtisch"], ["off", "aus"]], s.weatherDesk)}
<div style="height:6px"></div>
${seg("weatherBar", [["on", "in der leiste"], ["off", "aus"]], s.weatherBar)}
${seg("weatherBar", [["on", "in der honeybar"], ["off", "aus"]], s.weatherBar)}
<div class="wx-city-row">
<input id="wxQuery" type="text" placeholder="Stadt suchen …" autocomplete="off" />
<button class="btn" id="btnWxSearch">suchen</button>
@@ -1169,7 +1169,7 @@ function openApps() {
<div class="ae-body">
<label class="ae-field"><span>ID</span>
<input data-i="${i}" data-f="id" value="${escapeAttr(a.id || "")}" placeholder="aether" spellcheck="false" /></label>
<p class="ae-hint">klein, ohne Leerzeichen — muss zu <code>data-app</code> der Leiste passen</p>
<p class="ae-hint">klein, ohne Leerzeichen — muss zu <code>data-app</code> der HoneyBar passen</p>
<label class="ae-field"><span>Name</span>
<input data-i="${i}" data-f="name" value="${escapeAttr(a.name || "")}" placeholder="AETHER" /></label>
<label class="ae-field"><span>Untertitel</span>
@@ -1261,9 +1261,9 @@ function openAbout() {
`<div class="about">
<p><b>HoneyOS ${escapeHtml(state.cfg.version)}</b> — eine Oberfläche für mehrere eigene Apps.
Jede App bleibt ihre eigene Seite auf ihrer eigenen Domain; HoneyOS ist der Schreibtisch
davor und die Leiste darin.</p>
davor und die HoneyBar darin.</p>
<p>Zwei Betriebsarten, ein Datenstand: <code>terminal</code> zeigt Kacheln,
<code>desktop</code> Symbole und Fenster. Die Leiste oben ist in beiden dieselbe —
<code>desktop</code> Symbole und Fenster. Die HoneyBar oben ist in beiden dieselbe —
und dieselbe steckt per <code>honeybar/honeybar.js</code> auch in Aether und InkNote.</p>
<dl class="keys">
${state.cfg.apps.map((a) => `<dt>${a.key || "·"}</dt><dd>${escapeHtml(a.name)} starten</dd>`).join("")}