WIP Zentrale-Kachel nach VanVans Werktisch — NOCH NICHT FERTIG
Aufbau steht (Ring links, Titel mittig, Uhr rechts), aber pruef-start-ansicht meldet 3 Befunde am MAUS-LICHT der Kacheln. Gemessen: alter Stand 0 Befunde, dieser Stand 3 — kommt also von hier. Kein JS-Fehler (pageerror/console sind still), also Zeitverhalten: Die zusaetzliche Abfrage /api/zentrale verzoegert vermutlich den Aufbau der Kacheln ueber den Zeitpunkt hinaus, an dem kopf.js lichtFolgen ruft. Ausserdem offen: 2 Schriftgroessen unter 11,5 px (pruef-css-klassen). NICHT ausliefern.
This commit is contained in:
@@ -26,6 +26,7 @@ import { reportRouter } from "./workspace-reports.js";
|
|||||||
import { scoutRouter } from "./workspace-scouts.js";
|
import { scoutRouter } from "./workspace-scouts.js";
|
||||||
import { callRouter } from "./workspace-calls.js";
|
import { callRouter } from "./workspace-calls.js";
|
||||||
import { hinweisRouter } from "./workspace-hinweise.js";
|
import { hinweisRouter } from "./workspace-hinweise.js";
|
||||||
|
import { zentraleRouter } from "./workspace-zentrale.js";
|
||||||
import { sucheRouter } from "./workspace-suche.js";
|
import { sucheRouter } from "./workspace-suche.js";
|
||||||
import { startcheckRouter } from "./workspace-startcheck.js";
|
import { startcheckRouter } from "./workspace-startcheck.js";
|
||||||
import { wissenRouter } from "./workspace-wissen.js";
|
import { wissenRouter } from "./workspace-wissen.js";
|
||||||
@@ -216,6 +217,7 @@ app.use(reportRouter);
|
|||||||
app.use(scoutRouter);
|
app.use(scoutRouter);
|
||||||
app.use(callRouter);
|
app.use(callRouter);
|
||||||
app.use(hinweisRouter);
|
app.use(hinweisRouter);
|
||||||
|
app.use(zentraleRouter);
|
||||||
app.use(sucheRouter);
|
app.use(sucheRouter);
|
||||||
app.use(startcheckRouter);
|
app.use(startcheckRouter);
|
||||||
app.use(wissenRouter);
|
app.use(wissenRouter);
|
||||||
|
|||||||
@@ -0,0 +1,182 @@
|
|||||||
|
/* =====================================================================
|
||||||
|
workspace-zentrale.js — die Zahlen fuer den Ring auf der Startseite.
|
||||||
|
|
||||||
|
Wunsch Filipe (08.09.2026): die Begruessungskachel nach dem Vorbild
|
||||||
|
von VanVans Business Hub umbauen -- grosser Ring links, Text in der
|
||||||
|
Mitte, Uhr rechts. Dort zeigt der Ring "91 % deiner Produktakten":
|
||||||
|
ein Segment je Produkt, eingefaerbt nach Vollstaendigkeit.
|
||||||
|
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
WARUM ES DIESELBE ZAHL HIER NICHT GIBT
|
||||||
|
|
||||||
|
Nachgemessen an der echten Datenbank am 08.09.2026:
|
||||||
|
|
||||||
|
Termine 31 · Wissen 7 · Schulungen 4 · Personen 9 · AUFGABEN 1
|
||||||
|
Leistung, Leads, Profile, Content-Saeulen, Dateien: jeweils 0
|
||||||
|
|
||||||
|
VanVans Kranz funktioniert, weil 253 Produkte ein BILD ergeben. Ein
|
||||||
|
Kranz aus einer Aufgabe ergibt keins. Die naheliegende Uebertragung
|
||||||
|
("dann eben Aufgaben") haette eine leere Scheibe erzeugt, die aussieht
|
||||||
|
wie ein Ladefehler.
|
||||||
|
|
||||||
|
Filipe hat deshalb DAS TEAM gewaehlt: ein Segment je Person, gefaerbt
|
||||||
|
danach, wie es um sie steht. Neun Segmente sind wenige, aber sie sind
|
||||||
|
ECHT und aendern sich taeglich -- und die Zahl waechst mit dem Team.
|
||||||
|
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
UND WARUM DAS NICHT FUER JEDEN GEHT
|
||||||
|
|
||||||
|
Ein Creator darf die Teamliste nicht sehen. Das ist keine
|
||||||
|
Feinheit, sondern die Regel, die diesen ganzen Arbeitsplatz traegt
|
||||||
|
(Wunsch Filipe, 07.09.2026: "jeder soll und darf im kalender immer nur
|
||||||
|
seine eigenen eintraege nur sehen"). Ein Ring, der neun Namen
|
||||||
|
einfaerbt, waere fuer einen Creator ein Leck -- er koennte daran
|
||||||
|
ablesen, wer heute Termine hat und wer nicht.
|
||||||
|
|
||||||
|
Deshalb liefert diese Route ZWEI VERSCHIEDENE RINGE, je nach Rolle:
|
||||||
|
|
||||||
|
Leitung (DogFather, Manager, Scout, Spicy)
|
||||||
|
-> das Team: ein Segment je aktiver Person
|
||||||
|
Creator -> der eigene Tag: ein Segment je Stunde, plus die
|
||||||
|
eigenen Termine als Marken
|
||||||
|
|
||||||
|
Das ist keine Notloesung, sondern die richtige Antwort auf dieselbe
|
||||||
|
Frage: "Wie weit ist das, wofuer ich zustaendig bin?" Fuer DogFather
|
||||||
|
ist das sein Team, fuer eine Creatorin ihr Tag.
|
||||||
|
|
||||||
|
KEINE EIGENEN DATEN, wie bei den Hinweisen: Alles hier ist eine SICHT
|
||||||
|
auf Zeilen, die ohnehin existieren. Es gibt nichts zu pflegen und
|
||||||
|
nichts, was veralten kann.
|
||||||
|
===================================================================== */
|
||||||
|
|
||||||
|
import express from "express";
|
||||||
|
import { db, sitzungLesen, istLeitung, betreuteIds } from "./workspace.js";
|
||||||
|
|
||||||
|
export const zentraleRouter = express.Router();
|
||||||
|
|
||||||
|
function angemeldet(req, res, next) {
|
||||||
|
const person = sitzungLesen(req);
|
||||||
|
if (!person) return res.status(401).json({ fehler: "nicht_angemeldet" });
|
||||||
|
req.person = person;
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
zentraleRouter.use("/workspace/api/zentrale", angemeldet);
|
||||||
|
|
||||||
|
const p2 = (n) => String(n).padStart(2, "0");
|
||||||
|
/* ORTSZEIT, NICHT UTC. toISOString() liefert zwischen Mitternacht und
|
||||||
|
zwei Uhr noch den Vortag -- der Ring stuende dann auf den Terminen
|
||||||
|
von gestern. Derselbe Fehler ist mir am 08.09. zweimal an einem Abend
|
||||||
|
passiert; pruef-struktur.mjs sucht ihn inzwischen im ganzen Repo. */
|
||||||
|
function heuteLokal() {
|
||||||
|
const d = new Date();
|
||||||
|
return `${d.getFullYear()}-${p2(d.getMonth() + 1)}-${p2(d.getDate())}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
zentraleRouter.get("/workspace/api/zentrale", (req, res) => {
|
||||||
|
try {
|
||||||
|
const d = db();
|
||||||
|
const heute = heuteLokal();
|
||||||
|
const ich = req.person;
|
||||||
|
|
||||||
|
/* Wessen Lage wird gezeigt? Bei aktiver Fremdsicht die der Person,
|
||||||
|
in die man hineinsieht -- sonst zeigte die Kachel die eigene Lage
|
||||||
|
und alles darunter eine fremde. Genau diese Uneinheitlichkeit hat
|
||||||
|
auf der Startseite schon einmal zu "ist das jetzt meins oder
|
||||||
|
ihrs?" gefuehrt. */
|
||||||
|
const zeigt = req.person.sicht || req.person;
|
||||||
|
|
||||||
|
if (istLeitung(ich)) {
|
||||||
|
/* ---------- DAS TEAM ----------
|
||||||
|
Ein Segment je aktiver Person. Der Zustand einer Person ist
|
||||||
|
bewusst GROB in drei Stufen -- mehr taeuschte Genauigkeit vor,
|
||||||
|
die es nicht gibt (dieselbe Ueberlegung steht in VanVans Kranz).
|
||||||
|
|
||||||
|
frei - nichts Offenes, keine Termine heute -> ruhig
|
||||||
|
dran - hat heute Termine -> die sind versorgt
|
||||||
|
offen - hat unerledigte Termine aus der VERGANGENHEIT
|
||||||
|
-> das ist das, was liegen bleibt
|
||||||
|
*/
|
||||||
|
const leute = d.prepare(
|
||||||
|
`SELECT id, name, rolle FROM personen WHERE aktiv = 1 ORDER BY rolle, name`).all();
|
||||||
|
|
||||||
|
const heuteZaehler = d.prepare(
|
||||||
|
`SELECT COUNT(*) AS n FROM termine t
|
||||||
|
WHERE t.erledigt = 0 AND substr(t.beginn, 1, 10) = ?
|
||||||
|
AND (t.creator_id = ? OR t.erstellt_von = ?
|
||||||
|
OR EXISTS (SELECT 1 FROM termin_teilnehmer x
|
||||||
|
WHERE x.termin_id = t.id AND x.person_id = ?))`);
|
||||||
|
const altZaehler = d.prepare(
|
||||||
|
`SELECT COUNT(*) AS n FROM termine t
|
||||||
|
WHERE t.erledigt = 0 AND substr(t.beginn, 1, 10) < ?
|
||||||
|
AND (t.creator_id = ? OR t.erstellt_von = ?
|
||||||
|
OR EXISTS (SELECT 1 FROM termin_teilnehmer x
|
||||||
|
WHERE x.termin_id = t.id AND x.person_id = ?))`);
|
||||||
|
|
||||||
|
const segmente = leute.map((p) => {
|
||||||
|
const heuteN = heuteZaehler.get(heute, p.id, p.id, p.id).n;
|
||||||
|
const altN = altZaehler.get(heute, p.id, p.id, p.id).n;
|
||||||
|
const stufe = altN > 0 ? "offen" : (heuteN > 0 ? "dran" : "frei");
|
||||||
|
/* NUR DER VORNAME nach aussen. Der Ring braucht ein Kuerzel fuer
|
||||||
|
die Sprechblase, nicht den Datensatz einer Person. */
|
||||||
|
return { name: String(p.name || "").trim().split(/\s+/)[0] || "?",
|
||||||
|
rolle: p.rolle, stufe, heute: heuteN, alt: altN };
|
||||||
|
});
|
||||||
|
|
||||||
|
const versorgt = segmente.filter((s) => s.stufe !== "offen").length;
|
||||||
|
return res.json({
|
||||||
|
art: "team",
|
||||||
|
titel: "Team versorgt",
|
||||||
|
prozent: segmente.length ? Math.round((versorgt / segmente.length) * 100) : 100,
|
||||||
|
segmente,
|
||||||
|
zahlen: [
|
||||||
|
{ wert: segmente.length, schild: "im Team" },
|
||||||
|
{ wert: segmente.filter((s) => s.stufe === "dran").length, schild: "heute dran" },
|
||||||
|
{ wert: segmente.filter((s) => s.stufe === "offen").length, schild: "liegt liegen" },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- DER EIGENE TAG ----------
|
||||||
|
Fuer Creator. Ein Segment je Stunde von 6 bis 24 -- der Teil des
|
||||||
|
Tages, in dem gearbeitet wird. Nachts einen leeren Halbkreis zu
|
||||||
|
zeigen sagt nichts; 18 Segmente fuellen den Ring ordentlich.
|
||||||
|
|
||||||
|
Gefuellt sind die vergangenen Stunden, markiert die mit einem
|
||||||
|
eigenen Termin. Der Ring beantwortet damit "wie weit ist mein
|
||||||
|
Tag" -- dieselbe Frage wie bei VanVan, nur auf das bezogen,
|
||||||
|
wofuer eine Creatorin zustaendig ist. */
|
||||||
|
const VON = 6, BIS = 24;
|
||||||
|
const jetzt = new Date();
|
||||||
|
const stundeJetzt = jetzt.getHours();
|
||||||
|
|
||||||
|
const meine = d.prepare(
|
||||||
|
`SELECT t.beginn FROM termine t
|
||||||
|
WHERE substr(t.beginn, 1, 10) = ?
|
||||||
|
AND (t.creator_id = ? OR t.erstellt_von = ?
|
||||||
|
OR EXISTS (SELECT 1 FROM termin_teilnehmer x
|
||||||
|
WHERE x.termin_id = t.id AND x.person_id = ?))`)
|
||||||
|
.all(heute, zeigt.id, zeigt.id, zeigt.id);
|
||||||
|
const mitTermin = new Set(meine.map((t) => Number(String(t.beginn).slice(11, 13))));
|
||||||
|
|
||||||
|
const segmente = [];
|
||||||
|
for (let s = VON; s < BIS; s++) {
|
||||||
|
segmente.push({ name: `${p2(s)} Uhr`, rolle: "stunde",
|
||||||
|
stufe: mitTermin.has(s) ? "dran" : (s < stundeJetzt ? "frei" : "offen") });
|
||||||
|
}
|
||||||
|
const durch = Math.min(Math.max(stundeJetzt - VON, 0), BIS - VON);
|
||||||
|
return res.json({
|
||||||
|
art: "tag",
|
||||||
|
titel: "Tag geschafft",
|
||||||
|
prozent: Math.round((durch / (BIS - VON)) * 100),
|
||||||
|
segmente,
|
||||||
|
zahlen: [
|
||||||
|
{ wert: meine.length, schild: "heute" },
|
||||||
|
{ wert: [...mitTermin].filter((s) => s >= stundeJetzt).length, schild: "kommt noch" },
|
||||||
|
{ wert: betreuteIds(zeigt).length, schild: "betreut" },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
} catch (fehler) {
|
||||||
|
console.error("[workspace] Zentrale:", fehler?.message);
|
||||||
|
res.status(503).json({ fehler: "nicht_verfuegbar" });
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -346,11 +346,212 @@
|
|||||||
transparent 74%);
|
transparent 74%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* =====================================================================
|
||||||
|
DREI SPALTEN: RING — TEXT — UHR (08.09.2026)
|
||||||
|
|
||||||
|
Uebernommen von VanVans Werktisch im Business Hub, auf Wunsch Filipes
|
||||||
|
("das model da uebernehmen und es noch perfektionieren"). Vorher stand
|
||||||
|
hier eine FLEX-Zeile: Bild, Text, Zahlen, Uhr -- alles nebeneinander,
|
||||||
|
mit rund 300 px Leere in der Mitte. Das war eine Zeile mit einer
|
||||||
|
Luecke, keine Tafel.
|
||||||
|
|
||||||
|
`minmax(0, 1fr)` FUER DIE MITTE, nicht `1fr`. Das ist im Vorbild
|
||||||
|
ausdruecklich vermerkt, und der Grund ist nachlesenswert: `1fr` geht
|
||||||
|
nie unter die Mindestbreite seines Inhalts. Eine nicht umbrechende
|
||||||
|
Anrede und eine Zahlenreihe zwingen die Spalte damit auf 470 px -- auf
|
||||||
|
einem 390-px-Schirm. Die ganze Seite laesst sich dann seitlich
|
||||||
|
wegschieben. Mit `minmax(0, 1fr)` darf die Spalte schmaler werden als
|
||||||
|
ihr Inhalt, und der Inhalt bricht um, statt hinauszuragen.
|
||||||
|
|
||||||
|
Ich habe den Fehler nicht selbst gemacht, sondern die Begruendung
|
||||||
|
mituebernommen -- eine Loesung ohne ihren Grund haelt genau bis zum
|
||||||
|
naechsten Umbau. */
|
||||||
.willkommen__reihe {
|
.willkommen__reihe {
|
||||||
display: flex; align-items: center; gap: 16px;
|
display: grid;
|
||||||
flex-wrap: wrap;
|
grid-template-columns: minmax(180px, 232px) minmax(0, 1fr) minmax(180px, 232px);
|
||||||
|
gap: 26px; align-items: center;
|
||||||
|
}
|
||||||
|
.willkommen__text {
|
||||||
|
min-width: 0;
|
||||||
|
display: flex; flex-direction: column; align-items: center; gap: 9px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- Der Ring links ------------------------------------------------
|
||||||
|
Gleich gross wie die Uhr rechts. Im Vorbild steht dazu: "Beide Kreise
|
||||||
|
exakt gleich gross -- sie sind ein Paar, kein Haupt- und Nebenkreis."
|
||||||
|
Das ist der Grund, warum die Tafel ruhig wirkt: zwei gleiche Gewichte
|
||||||
|
links und rechts, dazwischen der Text. */
|
||||||
|
.zring {
|
||||||
|
position: relative; aspect-ratio: 1; width: 100%; max-width: 232px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
.zring__bild {
|
||||||
|
width: 100%; height: 100%; display: block;
|
||||||
|
/* Bei -90 Grad beginnt das erste Segment oben statt rechts -- so
|
||||||
|
liest man einen Fortschritt, seit es Uhren gibt. */
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
.zring__mitte {
|
||||||
|
position: absolute; inset: 0;
|
||||||
|
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
||||||
|
gap: 2px; pointer-events: none;
|
||||||
|
}
|
||||||
|
/* DAS SIEGEL IST RUND -- und das ist eine Reparatur, keine Stilfrage.
|
||||||
|
|
||||||
|
Erst stand hier dieselbe Maske wie in der Kopfleiste:
|
||||||
|
-webkit-mask: url("../img/marke-husky.webp") ...
|
||||||
|
Im Nahaufnahme-Bildschirmfoto war das Ergebnis ein KASTEN mit einem
|
||||||
|
Husky darin, kein freigestellter Husky.
|
||||||
|
|
||||||
|
Nachgemessen: Die Datei hat einen Alphakanal (VP8X mit ALPH-Chunk,
|
||||||
|
Alpha-Flag gesetzt) -- er ist nur RECHTECKIG. Das Bild ist nicht
|
||||||
|
freigestellt. Als Maske taugt es damit nicht, egal wie richtig die
|
||||||
|
CSS-Zeile ist.
|
||||||
|
|
||||||
|
BEFUND FUER SPAETER: Dasselbe gilt fuer `.kopfleiste .marke::before`
|
||||||
|
in start.css -- dort ist es bei 22 px nur nicht aufgefallen. Wer das
|
||||||
|
Logo einmal freistellt, repariert beide Stellen auf einmal.
|
||||||
|
|
||||||
|
Hier wird es deshalb als BILD gezeigt und rund beschnitten, mit
|
||||||
|
einem feinen Ring darum. Das ist naeher am Vorbild als die Maske es
|
||||||
|
je war: VanVans Werktisch traegt in der Mitte ein rundes Siegel, kein
|
||||||
|
ausgeschnittenes Zeichen. */
|
||||||
|
.zring__siegel {
|
||||||
|
width: 44px; height: 44px; margin-bottom: 5px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: url("../img/marke-husky.webp") center / 128% no-repeat, #0b1420;
|
||||||
|
box-shadow:
|
||||||
|
0 0 0 1px rgba(180, 210, 240, .28),
|
||||||
|
inset 0 0 12px rgba(0, 0, 0, .55);
|
||||||
|
/* Etwas entsaettigt und abgedunkelt: Das Siegel ist der ruhige Kern
|
||||||
|
des Rings, nicht sein hellster Punkt -- sonst zieht es den Blick von
|
||||||
|
der Zahl darunter ab, um die es geht. */
|
||||||
|
filter: saturate(.55) brightness(.92);
|
||||||
|
}
|
||||||
|
.zring__prozent {
|
||||||
|
font-size: 1.85rem; font-weight: 700; line-height: 1;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
color: #dfeaf6;
|
||||||
|
text-shadow: 0 0 16px rgba(127, 196, 242, .3);
|
||||||
|
}
|
||||||
|
/* ZWEIZEILIG, UND DAS IST GEWOLLT.
|
||||||
|
|
||||||
|
Erst stand hier `max-width: 78%` bei .68rem. In der Nahaufnahme lief
|
||||||
|
"DES TEAMS VERSORGT" als eine Zeile quer ueber die Segmentbahn -- der
|
||||||
|
Ring war dahinter durchgestrichen.
|
||||||
|
|
||||||
|
Der innere Segmentring liegt bei Radius 106 von 150, also auf 71 % der
|
||||||
|
Breite. Alles darunter muss schmaler bleiben als das, sonst kreuzt es
|
||||||
|
ihn. 58 % lassen dem Text Luft und zwingen ihn in zwei Zeilen -- genau
|
||||||
|
wie im Vorbild, wo "DEINER PRODUKTAKTEN" ebenfalls umbricht.
|
||||||
|
|
||||||
|
.72rem statt .68rem, weil 10,9 px unter meiner eigenen Untergrenze von
|
||||||
|
11,5 px lagen. Die Regel gilt auch fuer Text, den man nur ueberfliegt. */
|
||||||
|
.zring__unter {
|
||||||
|
font-size: .72rem; letter-spacing: .06em; text-transform: uppercase;
|
||||||
|
color: rgba(168, 192, 218, .66);
|
||||||
|
max-width: 58%; text-align: center; line-height: 1.25;
|
||||||
|
text-wrap: balance; /* zwei gleich lange Zeilen statt 4+1 Woertern */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- Die Anrede in eigener Fassung -------------------------------- */
|
||||||
|
.zgruss {
|
||||||
|
display: inline-flex; align-items: center; gap: 11px;
|
||||||
|
padding: 7px 15px 7px 8px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: linear-gradient(178deg, rgba(10, 18, 30, .62), rgba(6, 12, 21, .48));
|
||||||
|
box-shadow:
|
||||||
|
inset 0 1px 0 rgba(160, 195, 230, .13),
|
||||||
|
0 1px 10px rgba(0, 0, 0, .3);
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
.zgruss__bild {
|
||||||
|
width: 42px; height: 42px; flex: 0 0 auto;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-size: cover; background-position: center;
|
||||||
|
background-color: rgba(120, 160, 200, .16);
|
||||||
|
box-shadow: 0 0 0 1px rgba(180, 210, 240, .22), inset 0 0 14px rgba(0, 0, 0, .5);
|
||||||
|
display: grid; place-items: center;
|
||||||
|
font-weight: 700; color: #cfe2f5;
|
||||||
|
}
|
||||||
|
.zgruss__text { display: flex; flex-direction: column; gap: 1px; min-width: 0; text-align: left; }
|
||||||
|
.zgruss__datum { font-size: .78rem; color: rgba(168, 192, 218, .72); }
|
||||||
|
.zgruss__rolle {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
padding: 4px 11px; border-radius: 999px;
|
||||||
|
font-size: .66rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
|
||||||
|
color: #e6c88a;
|
||||||
|
border: 1px solid rgba(227, 179, 65, .34);
|
||||||
|
background: rgba(227, 179, 65, .09);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- Zierzeile und Titel ------------------------------------------ */
|
||||||
|
.zmarke {
|
||||||
|
display: inline-flex; align-items: center; gap: 11px;
|
||||||
|
font-size: .68rem; font-weight: 600; letter-spacing: .24em; text-transform: uppercase;
|
||||||
|
color: rgba(196, 214, 234, .6);
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
/* Die Raute ist ein ELEMENT, kein Schriftzeichen. Ein ◆ aus der
|
||||||
|
Schriftart sitzt nie auf der Grundlinie und sieht auf jedem Geraet
|
||||||
|
anders aus -- im Vorbild steht dieselbe Ueberlegung. */
|
||||||
|
.zraute {
|
||||||
|
width: 5px; height: 5px; flex: 0 0 auto;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
background: rgba(227, 179, 65, .62);
|
||||||
|
}
|
||||||
|
/* ZWEI STUFEN, wie im Vorbild -- nicht eine.
|
||||||
|
|
||||||
|
Bei mittlerer Breite fehlt zuerst der Platz fuer DREI Spalten, aber
|
||||||
|
noch lange nicht fuer zwei: Der Ring bleibt links neben dem Text, die
|
||||||
|
Uhr rutscht darunter und in die Mitte. Erst wenn auch das nicht mehr
|
||||||
|
reicht, steht alles untereinander.
|
||||||
|
|
||||||
|
Die Zahlen 1180 und 780 sind aus dem Vorbild uebernommen, wo sie an
|
||||||
|
echten Geraeten entstanden sind. Sie stehen hier zusammen mit dem,
|
||||||
|
was sie zaehlen -- wer eine vierte Spalte hinzufuegt, muss sie neu
|
||||||
|
messen. Genau das ist im September einmal vergessen worden, und der
|
||||||
|
Sicht-Umschalter lag danach ueber dem Chat-Knopf. */
|
||||||
|
@media (max-width: 1180px) {
|
||||||
|
.willkommen__reihe { grid-template-columns: minmax(170px, 220px) minmax(0, 1fr); }
|
||||||
|
.willkommen__rechts { grid-column: 1 / -1; justify-content: center; margin-left: 0; }
|
||||||
|
}
|
||||||
|
@media (max-width: 780px) {
|
||||||
|
.willkommen__reihe { grid-template-columns: minmax(0, 1fr); gap: 20px; }
|
||||||
|
.zring { max-width: 190px; }
|
||||||
|
.zgruss { flex-wrap: wrap; justify-content: center; }
|
||||||
|
.zgruss__text { text-align: center; align-items: center; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Der Satz unter dem Titel bekommt Fliesstextgroesse und darf umbrechen.
|
||||||
|
|
||||||
|
Im Vorbild stehen dort drei Zeilen ("Ich habe deine 253 Produkte
|
||||||
|
durchgesehen und 1561 von 1720 Angaben schon eingetragen ..."), und
|
||||||
|
genau die machen aus einer Anzeigetafel eine Ansprache. Bei mir ist
|
||||||
|
der Satz kuerzer -- er kommt aus derselben Zaehlung wie die Hinweise
|
||||||
|
darunter und wird nicht zweimal gerechnet -- aber er soll denselben
|
||||||
|
Raum bekommen statt als Kleingedrucktes am Titel zu kleben.
|
||||||
|
|
||||||
|
`text-wrap: balance` verteilt die Zeilen gleichmaessig, statt die
|
||||||
|
letzte mit einem einzelnen Wort enden zu lassen. */
|
||||||
|
.willkommen__reihe .unterzeile {
|
||||||
|
font-size: 1rem; line-height: 1.55;
|
||||||
|
max-width: 46ch; margin: 2px auto 0;
|
||||||
|
text-wrap: balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ztitel {
|
||||||
|
margin: 0;
|
||||||
|
font-size: clamp(1.9rem, 3.6vw, 2.9rem);
|
||||||
|
font-weight: 700; line-height: 1.06; letter-spacing: -.01em;
|
||||||
|
color: #dce9f6;
|
||||||
|
/* Ein Verlauf statt einer Volltonfarbe: Der Titel bekommt oben Licht
|
||||||
|
und unten Schatten, wie ein gefraester Schriftzug auf Metall. */
|
||||||
|
background: linear-gradient(178deg, #eef5fc 8%, #b9cee2 58%, #7f95ad 100%);
|
||||||
|
-webkit-background-clip: text; background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
}
|
}
|
||||||
.willkommen__text { min-width: 0; flex: 1 1 260px; }
|
|
||||||
|
|
||||||
/* Rechts: Glocke neben der Uhr, beide rechtsbündig. `margin-left: auto`
|
/* Rechts: Glocke neben der Uhr, beide rechtsbündig. `margin-left: auto`
|
||||||
statt `justify-content: space-between` am Elternteil -- so bleibt die
|
statt `justify-content: space-between` am Elternteil -- so bleibt die
|
||||||
|
|||||||
@@ -505,8 +505,37 @@
|
|||||||
$('rollentext').textContent = ich.sicht
|
$('rollentext').textContent = ich.sicht
|
||||||
? `Arbeitsplatz von ${ich.sicht.name} · ${ROLLENTEXT[zeigt.rolle] || zeigt.rolle}`
|
? `Arbeitsplatz von ${ich.sicht.name} · ${ROLLENTEXT[zeigt.rolle] || zeigt.rolle}`
|
||||||
: (ROLLENTEXT[ich.rolle] || ich.rolle);
|
: (ROLLENTEXT[ich.rolle] || ich.rolle);
|
||||||
|
|
||||||
|
/* Datum und Rolle in der Anrede -- wie im Vorbild, wo unter "Noch
|
||||||
|
wach, Dogi" das Datum steht und daneben "ADMIN & PARTNER".
|
||||||
|
|
||||||
|
Das Datum steht damit ZWEIMAL auf der Kachel: oben in der
|
||||||
|
Zierzeile mit KW, hier ohne. Das ist Absicht und keine Doppelung:
|
||||||
|
Oben gehoert es zur Tafel ("welcher Tag ist heute"), hier zur
|
||||||
|
Anrede ("wann begruesse ich dich"). Im Vorbild ist es genauso,
|
||||||
|
und es liest sich dort natuerlich. Faellt es Filipe als Doppelung
|
||||||
|
auf, kommt die Zierzeile oben weg -- nicht diese Zeile. */
|
||||||
|
const jetzt2 = new Date();
|
||||||
|
const dat = $('zgruss-datum');
|
||||||
|
if (dat) {
|
||||||
|
dat.textContent = `${WOCHENTAGE[jetzt2.getDay()]}, `
|
||||||
|
+ `${jetzt2.getDate()}. ${MONATE[jetzt2.getMonth()]}`;
|
||||||
|
}
|
||||||
|
const rolleEl = $('zgruss-rolle');
|
||||||
|
if (rolleEl) {
|
||||||
|
rolleEl.textContent = (ROLLEN_KURZ[zeigt.rolle] || zeigt.rolle || '').toUpperCase();
|
||||||
|
rolleEl.hidden = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Kurzform der Rolle fuer die Plakette neben dem Namen. Der lange
|
||||||
|
Text ("Gesamtuebersicht und Freigaben") steht schon darunter --
|
||||||
|
hier braucht es das Wort, nicht die Erklaerung. */
|
||||||
|
const ROLLEN_KURZ = {
|
||||||
|
admin: 'DogFather', manager: 'Manager', scout: 'Scout',
|
||||||
|
creator: 'Creator', spicy: 'Spicy Media',
|
||||||
|
};
|
||||||
|
|
||||||
/* Ein Satz zur Lage -- gerechnet aus denselben Hinweisen, die darunter
|
/* Ein Satz zur Lage -- gerechnet aus denselben Hinweisen, die darunter
|
||||||
stehen. Keine zweite Zählung, sonst gäbe es irgendwann zwei
|
stehen. Keine zweite Zählung, sonst gäbe es irgendwann zwei
|
||||||
Wahrheiten auf einem Bildschirm. */
|
Wahrheiten auf einem Bildschirm. */
|
||||||
@@ -534,6 +563,145 @@
|
|||||||
standSetzen('offen', gesamt === 0 ? '0' : String(gesamt), stufe);
|
standSetzen('offen', gesamt === 0 ? '0' : String(gesamt), stufe);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---------- Der Ring links ----------------------------------------------
|
||||||
|
Nach dem Vorbild von VanVans Werktisch. Zwei Bahnen:
|
||||||
|
|
||||||
|
INNEN eine feine Bahn mit EINEM Segment je Person (bzw. je
|
||||||
|
Stunde), eingefaerbt nach Lage -- dort sieht man jedes
|
||||||
|
Einzelne.
|
||||||
|
AUSSEN ein durchgehender Bogen, der GENAU auf der Prozentzahl in
|
||||||
|
der Mitte steht.
|
||||||
|
|
||||||
|
Die Trennung ist aus dem Vorbild uebernommen, samt Begruendung:
|
||||||
|
Dort zeigte der Ring erst die 162 Produkte je einzeln, und der
|
||||||
|
Anteil des Blauen entsprach dann der Zahl der fertigen AKTEN (44 %),
|
||||||
|
waehrend daneben die Zahl der erfuellten ANGABEN (91 %) stand. Zwei
|
||||||
|
Auskuenfte, die sich widersprechen, sind schlimmer als eine.
|
||||||
|
Deshalb: der Bogen sagt dasselbe wie die Zahl, immer. */
|
||||||
|
|
||||||
|
const RING_FARBE = {
|
||||||
|
frei: '#57b89b', /* nichts offen -- gedaempftes Petrol, kein Grasgruen */
|
||||||
|
dran: '#7fc4f2', /* heute versorgt */
|
||||||
|
offen: '#ff6b74', /* liegt liegen */
|
||||||
|
};
|
||||||
|
|
||||||
|
function bogen(cx, cy, r, von, bis) {
|
||||||
|
const x1 = cx + r * Math.cos(von), y1 = cy + r * Math.sin(von);
|
||||||
|
const x2 = cx + r * Math.cos(bis), y2 = cy + r * Math.sin(bis);
|
||||||
|
const gross = bis - von > Math.PI ? 1 : 0;
|
||||||
|
return `M ${x1.toFixed(2)} ${y1.toFixed(2)} A ${r} ${r} 0 ${gross} 1 ${x2.toFixed(2)} ${y2.toFixed(2)}`;
|
||||||
|
}
|
||||||
|
const svgEl = (name, attr) => {
|
||||||
|
const n = document.createElementNS('http://www.w3.org/2000/svg', name);
|
||||||
|
for (const [k, v] of Object.entries(attr)) n.setAttribute(k, v);
|
||||||
|
return n;
|
||||||
|
};
|
||||||
|
|
||||||
|
function ringZeichnen(daten) {
|
||||||
|
const svg = $('zring-bild');
|
||||||
|
if (!svg) return;
|
||||||
|
svg.replaceChildren();
|
||||||
|
const segmente = daten.segmente || [];
|
||||||
|
|
||||||
|
/* Der Verlauf fuer den Fortschrittsbogen -- eine Reise von Rot nach
|
||||||
|
Babyblau, dieselben zwei Farben wie in der Uhr daneben und im
|
||||||
|
Rahmen der Kachel. Keine dritte Handschrift. */
|
||||||
|
const defs = svgEl('defs', {});
|
||||||
|
const lauf = svgEl('linearGradient', { id: 'zring-lauf', x1: '0', y1: '0', x2: '1', y2: '1' });
|
||||||
|
for (const [o, f] of [['0%', '#ff5f6d'], ['46%', '#c07ad0'], ['100%', '#7fc4f2']]) {
|
||||||
|
lauf.appendChild(svgEl('stop', { offset: o, 'stop-color': f }));
|
||||||
|
}
|
||||||
|
defs.appendChild(lauf);
|
||||||
|
svg.appendChild(defs);
|
||||||
|
|
||||||
|
/* 1. Die leere Bahn zuerst -- damit der Ring auch bei 0 % ein Ring
|
||||||
|
ist und nicht ein Punkt. */
|
||||||
|
svg.appendChild(svgEl('path', {
|
||||||
|
d: bogen(150, 150, 128, 0, Math.PI * 1.9999),
|
||||||
|
stroke: 'rgba(120, 150, 185, .16)', 'stroke-width': '9',
|
||||||
|
fill: 'none', 'stroke-linecap': 'round',
|
||||||
|
}));
|
||||||
|
|
||||||
|
/* 2. Ein Segment je Person (oder Stunde), innen. Mit Luecke
|
||||||
|
dazwischen, sonst verschmelzen sie zu einem Ring und man
|
||||||
|
zaehlt nichts mehr. */
|
||||||
|
if (segmente.length) {
|
||||||
|
const schritt = (Math.PI * 2) / segmente.length;
|
||||||
|
const luecke = Math.min(schritt * 0.22, 0.06);
|
||||||
|
segmente.forEach((s, i) => {
|
||||||
|
const von = i * schritt + luecke / 2;
|
||||||
|
const bis = (i + 1) * schritt - luecke / 2;
|
||||||
|
const st = svgEl('path', {
|
||||||
|
d: bogen(150, 150, 106, von, bis),
|
||||||
|
stroke: RING_FARBE[s.stufe] || '#8fb3cf',
|
||||||
|
'stroke-width': '7', fill: 'none', 'stroke-linecap': 'round',
|
||||||
|
opacity: s.stufe === 'offen' ? '.95' : '.72',
|
||||||
|
});
|
||||||
|
/* Der Name als Sprechblase. Nur der Vorname, und nur das, was
|
||||||
|
der Server ohnehin geschickt hat -- der Browser erfaehrt
|
||||||
|
nichts, was er nicht sehen darf. */
|
||||||
|
const titel = document.createElementNS('http://www.w3.org/2000/svg', 'title');
|
||||||
|
titel.textContent = s.name || '';
|
||||||
|
st.appendChild(titel);
|
||||||
|
svg.appendChild(st);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3. Der Fortschrittsbogen aussen, genau auf der Prozentzahl. */
|
||||||
|
const anteil = Math.max(0, Math.min(100, Number(daten.prozent) || 0));
|
||||||
|
const bis = (anteil / 100) * Math.PI * 2;
|
||||||
|
if (bis > 0.01) {
|
||||||
|
const d = bogen(150, 150, 128, 0, Math.min(bis, Math.PI * 1.9999));
|
||||||
|
svg.appendChild(svgEl('path', {
|
||||||
|
d, stroke: 'url(#zring-lauf)', 'stroke-width': '9',
|
||||||
|
fill: 'none', 'stroke-linecap': 'round',
|
||||||
|
}));
|
||||||
|
/* Ein heller Punkt an der Spitze macht aus dem Bogen einen
|
||||||
|
Zeiger -- er markiert den Stand so genau, wie die Zahl es sagt. */
|
||||||
|
const px = 150 + 128 * Math.cos(bis), py = 150 + 128 * Math.sin(bis);
|
||||||
|
svg.appendChild(svgEl('circle', { cx: px, cy: py, r: '3.4', fill: '#eaf4ff' }));
|
||||||
|
}
|
||||||
|
|
||||||
|
$('zring-prozent').textContent = `${anteil} %`;
|
||||||
|
$('zring-unter').textContent = daten.titel || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
async function zentraleLaden() {
|
||||||
|
let daten;
|
||||||
|
try {
|
||||||
|
const antwort = await fetch('/workspace/api/zentrale', { credentials: 'same-origin' });
|
||||||
|
if (!antwort.ok) return;
|
||||||
|
daten = await antwort.json();
|
||||||
|
} catch { return; } /* Der Rest der Kachel steht trotzdem. */
|
||||||
|
|
||||||
|
ringZeichnen(daten);
|
||||||
|
|
||||||
|
/* Die drei Zahlen unter dem Titel kommen bei Leitung aus derselben
|
||||||
|
Antwort -- eine Abfrage, eine Wahrheit. Fuer die Tagesansicht
|
||||||
|
fuellen `lageZeigen` und `tagestermineLaden` sie weiter; deshalb
|
||||||
|
wird hier nur ueberschrieben, was der Server auch geschickt hat. */
|
||||||
|
const zahlen = daten.zahlen || [];
|
||||||
|
const felder = ['heute', 'naechster', 'offen'];
|
||||||
|
zahlen.slice(0, 3).forEach((z, i) => {
|
||||||
|
const wert = $('stand-' + felder[i]);
|
||||||
|
const schild = wert?.parentElement?.querySelector('.stand__schild');
|
||||||
|
if (!wert || !schild) return;
|
||||||
|
wert.textContent = String(z.wert);
|
||||||
|
schild.textContent = z.schild;
|
||||||
|
/* Die Farbe folgt der Bedeutung, nicht der Position: Was liegen
|
||||||
|
bleibt, ist rot -- egal an welcher Stelle es steht. */
|
||||||
|
const kasten = wert.closest('.stand');
|
||||||
|
if (kasten) {
|
||||||
|
kasten.dataset.stufe = /liegt|offen|fehlt/i.test(z.schild)
|
||||||
|
? (Number(z.wert) > 0 ? 'warnung' : 'ruhig') : '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (zahlen.length) {
|
||||||
|
standVonZentrale = true;
|
||||||
|
$('tagesstand').hidden = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ---------- Die drei Ablesungen in der Konsolenmitte --------------------- */
|
/* ---------- Die drei Ablesungen in der Konsolenmitte --------------------- */
|
||||||
|
|
||||||
/* EINE Funktion fuer alle drei, und sie wird von den STELLEN gerufen,
|
/* EINE Funktion fuer alle drei, und sie wird von den STELLEN gerufen,
|
||||||
@@ -546,7 +714,22 @@
|
|||||||
auf beide: Wer nichts Offenes hat, aber drei Calls, soll seinen Tag
|
auf beide: Wer nichts Offenes hat, aber drei Calls, soll seinen Tag
|
||||||
sehen, auch wenn die andere Abfrage haengt. Genau diesen Fehler hat
|
sehen, auch wenn die andere Abfrage haengt. Genau diesen Fehler hat
|
||||||
die Kachel darunter schon einmal gemacht. */
|
die Kachel darunter schon einmal gemacht. */
|
||||||
|
/* WER DIE FELDER BESETZT HAT, BEHAELT SIE (08.09.2026).
|
||||||
|
|
||||||
|
Seit der Ring da ist, schreiben ZWEI Quellen in dieselben drei
|
||||||
|
Felder: `zentraleLaden` (bei Leitung: im Team / heute dran / liegt
|
||||||
|
liegen) und `lageZeigen` + `tagestermineLaden` (Heute / Als
|
||||||
|
Naechstes / Offen). Beide laufen nebeneinander los -- wer zuletzt
|
||||||
|
ankommt, haette gewonnen, und das waere bei jedem Laden eine andere.
|
||||||
|
|
||||||
|
Ein Bildschirm, auf dem "heute dran: 2" steht und beim naechsten
|
||||||
|
Aufruf "Heute: 5", ist schlimmer als einer, der weniger zeigt.
|
||||||
|
Deshalb: Hat die Zentrale die Felder belegt, ruehrt sie niemand
|
||||||
|
mehr an. Die Reihenfolge des Eintreffens spielt dann keine Rolle. */
|
||||||
|
let standVonZentrale = false;
|
||||||
|
|
||||||
function standSetzen(welches, wert, stufe) {
|
function standSetzen(welches, wert, stufe) {
|
||||||
|
if (standVonZentrale) return;
|
||||||
const feld = $('stand-' + welches);
|
const feld = $('stand-' + welches);
|
||||||
if (!feld) return;
|
if (!feld) return;
|
||||||
feld.textContent = wert;
|
feld.textContent = wert;
|
||||||
@@ -579,8 +762,26 @@
|
|||||||
Die Tagestermine laufen daneben her: Sie sind die rechte Hälfte
|
Die Tagestermine laufen daneben her: Sie sind die rechte Hälfte
|
||||||
derselben Kachel, aber niemand soll auf sie warten. Scheitern
|
derselben Kachel, aber niemand soll auf sie warten. Scheitern
|
||||||
sie, steht die linke Hälfte trotzdem. */
|
sie, steht die linke Hälfte trotzdem. */
|
||||||
|
/* Der Ring laeuft daneben her, wie die Tagestermine: Er ist die
|
||||||
|
linke Spalte der Kachel, aber niemand soll auf ihn warten.
|
||||||
|
Scheitert er, steht der Rest trotzdem. */
|
||||||
|
const ringLaeuft = zentraleLaden();
|
||||||
|
|
||||||
const termineLaeuft = tagestermineLaden();
|
const termineLaeuft = tagestermineLaden();
|
||||||
await hinweiseLaden();
|
await hinweiseLaden();
|
||||||
|
/* KEIN `await ringLaeuft` HIER (08.09.2026).
|
||||||
|
|
||||||
|
Genau das stand kurz an dieser Stelle, und pruef-start-ansicht
|
||||||
|
wurde daraufhin dreimal rot -- nicht am Ring, sondern am
|
||||||
|
MAUS-LICHT auf den Kacheln weiter unten. Der Grund: Alles, was
|
||||||
|
nach diesem `await` kommt, wartet mit. Der Ring braucht eine
|
||||||
|
Server-Abfrage, und in der Zeit war das Licht noch nicht
|
||||||
|
eingehaengt, als die Pruefung mit dem Zeiger darueberfuhr.
|
||||||
|
|
||||||
|
Gemessen, nicht vermutet: derselbe Lauf am alten Stand meldete
|
||||||
|
null Befunde, mit dem `await` drei. Ein zusaetzliches `await` in
|
||||||
|
einer Ladefolge ist nie nur eine Verzoegerung fuer sich selbst --
|
||||||
|
es verzoegert alles dahinter. */
|
||||||
await termineLaeuft;
|
await termineLaeuft;
|
||||||
/* Erst jetzt steht fest, wie die Lage ist. */
|
/* Erst jetzt steht fest, wie die Lage ist. */
|
||||||
lageZeigen();
|
lageZeigen();
|
||||||
|
|||||||
+77
-20
@@ -47,33 +47,89 @@
|
|||||||
<span class="willkommen__marker" id="tagesmarker" hidden></span>
|
<span class="willkommen__marker" id="tagesmarker" hidden></span>
|
||||||
</p>
|
</p>
|
||||||
<div class="willkommen__reihe">
|
<div class="willkommen__reihe">
|
||||||
<span class="willkommen__plakette" id="plakette" aria-hidden="true"></span>
|
|
||||||
|
<!-- ==== LINKS: DER RING ======================================
|
||||||
|
Nach dem Vorbild von VanVans Werktisch (Business Hub), auf
|
||||||
|
Wunsch Filipes uebernommen und weitergebaut.
|
||||||
|
|
||||||
|
Dort steht "91 % deiner Produktakten" -- ein Segment je
|
||||||
|
Produkt. Diese Zahl gibt es hier nicht: Nachgemessen hat der
|
||||||
|
Workspace 31 Termine, 9 Personen und GENAU EINE Aufgabe. Ein
|
||||||
|
Kranz aus einer Aufgabe ist kein Bild, sondern sieht aus wie
|
||||||
|
ein Ladefehler.
|
||||||
|
|
||||||
|
Filipe hat DAS TEAM gewaehlt. Fuer Creator zeigt derselbe
|
||||||
|
Ring den eigenen Tag -- nicht als Notloesung, sondern weil
|
||||||
|
ein Creator die Teamliste nicht sehen darf und die Frage
|
||||||
|
dieselbe bleibt: "Wie weit ist das, wofuer ich zustaendig
|
||||||
|
bin?" Die Entscheidung faellt im Server
|
||||||
|
(workspace-zentrale.js), nicht hier: Was der Browser nicht
|
||||||
|
bekommt, kann er auch nicht verraten. -->
|
||||||
|
<div class="zring" id="zring">
|
||||||
|
<svg class="zring__bild" id="zring-bild" viewBox="0 0 300 300"
|
||||||
|
role="img" aria-labelledby="zring-titel zring-text">
|
||||||
|
<title id="zring-titel">Der Stand deiner Zentrale</title>
|
||||||
|
<desc id="zring-text">Ein Segment je Person, eingefärbt nach Lage.</desc>
|
||||||
|
</svg>
|
||||||
|
<!-- IN DER MITTE STEHT DAS SIEGEL, NICHT DAS PERSONENBILD.
|
||||||
|
|
||||||
|
Im Vorbild sitzt dort VanVans Firmenlogo, und das Bild von
|
||||||
|
Dogi steckt in der Anrede daneben. Das ist kein Zufall: Der
|
||||||
|
Ring gehoert dem BETRIEB, die Anrede der PERSON. Haette ich
|
||||||
|
das Personenbild in die Mitte gesetzt, staende dasselbe
|
||||||
|
Gesicht zweimal auf einer Kachel -- und der Ring saehe aus,
|
||||||
|
als messe er die Person. -->
|
||||||
|
<div class="zring__mitte">
|
||||||
|
<span class="zring__siegel" aria-hidden="true"></span>
|
||||||
|
<strong class="zring__prozent" id="zring-prozent">–</strong>
|
||||||
|
<span class="zring__unter" id="zring-unter">wird geladen</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ==== MITTE: WER, WO, WAS ================================== -->
|
||||||
<div class="willkommen__text">
|
<div class="willkommen__text">
|
||||||
<h1 class="titel" id="gruss">Willkommen</h1>
|
<!-- Die Anrede sitzt in einer eigenen Fassung, wie im Vorbild:
|
||||||
|
Bild, Name und Rolle gehoeren zusammen und heben sich
|
||||||
|
dadurch vom Titel darunter ab, statt mit ihm zu ringen. -->
|
||||||
|
<span class="zgruss">
|
||||||
|
<span class="zgruss__bild willkommen__plakette" id="plakette" aria-hidden="true"></span>
|
||||||
|
<span class="zgruss__text">
|
||||||
|
<h1 class="titel" id="gruss">Willkommen</h1>
|
||||||
|
<span class="zgruss__datum" id="zgruss-datum"></span>
|
||||||
|
</span>
|
||||||
|
<span class="zgruss__rolle" id="zgruss-rolle" hidden></span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<!-- Die Zierzeile traegt die Marke, wie "◆ VAN'S DIY ◆" im
|
||||||
|
Vorbild. Die Rauten sind eigene Elemente und kein Zeichen im
|
||||||
|
Text: Ein ◆ aus der Schriftart sitzt nie auf der Grundlinie
|
||||||
|
und sieht auf jedem Geraet anders aus. -->
|
||||||
|
<span class="zmarke">
|
||||||
|
<i class="zraute" aria-hidden="true"></i>
|
||||||
|
Dogfather Universe
|
||||||
|
<i class="zraute" aria-hidden="true"></i>
|
||||||
|
</span>
|
||||||
|
<p class="ztitel" id="ztitel">Die Zentrale</p>
|
||||||
<p class="unterzeile">
|
<p class="unterzeile">
|
||||||
<span id="rollentext">…</span>
|
<span id="rollentext">…</span>
|
||||||
<span class="willkommen__lage" id="lage" hidden></span>
|
<span class="willkommen__lage" id="lage" hidden></span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- ==== Die Mitte der Konsole: drei Ablesungen ================
|
<!-- ==== Die drei Ablesungen ==================================
|
||||||
Zwischen Text und Uhr standen rund 300 px Leere -- auf einem
|
Sie standen zuerst RECHTS, zwischen Text und Uhr -- dort
|
||||||
1440er Bildschirm nachgemessen, nicht geschaetzt. Eine
|
fuellten sie eine Luecke. Im Vorbild stehen sie unter dem
|
||||||
Konsole mit einem leeren Feld in der Mitte sieht nicht
|
Titel in der Mitte, und das ist der bessere Ort: Sie
|
||||||
aufgeraeumt aus, sondern unfertig.
|
gehoeren zum Satz darueber ("253 Produkte, 100 Akten
|
||||||
|
fertig, 159 Angaben offen" liest sich als Fortsetzung des
|
||||||
|
Textes, nicht als Anzeige am Rand).
|
||||||
|
|
||||||
Was hier steht, ist deshalb keine Deko, sondern das, was der
|
KEINE ZWEITE ZAEHLUNG. Die Zahlen kommen aus denselben
|
||||||
Lagesatz daneben NICHT sagt: wie viel heute ansteht, wann das
|
Quellen, die die Kacheln darunter fuellen. Zwei Rechenwege
|
||||||
Naechste losgeht, wie viel offen ist.
|
fuer dieselbe Zahl laufen auseinander, und dann stehen zwei
|
||||||
|
Wahrheiten auf einem Bildschirm.
|
||||||
|
|
||||||
KEINE ZWEITE ZAEHLUNG. Die Zahlen kommen aus denselben zwei
|
Versteckt, solange nichts geladen ist: Drei Striche in
|
||||||
Quellen, die die Kacheln darunter fuellen (`hinweise` und die
|
einer Fassung sehen aus wie ein Fehler. -->
|
||||||
Tagestermine). Zwei Rechenwege fuer dieselbe Zahl laufen
|
|
||||||
auseinander, und dann stehen zwei Wahrheiten auf einem
|
|
||||||
Bildschirm.
|
|
||||||
|
|
||||||
Versteckt, solange nichts geladen ist: Drei Striche in einer
|
|
||||||
Fassung sehen aus wie ein Fehler. -->
|
|
||||||
<div class="willkommen__stand" id="tagesstand" hidden>
|
<div class="willkommen__stand" id="tagesstand" hidden>
|
||||||
<div class="stand" data-stand="heute">
|
<div class="stand" data-stand="heute">
|
||||||
<span class="stand__wert" id="stand-heute">–</span>
|
<span class="stand__wert" id="stand-heute">–</span>
|
||||||
@@ -87,7 +143,8 @@
|
|||||||
<span class="stand__wert" id="stand-offen">–</span>
|
<span class="stand__wert" id="stand-offen">–</span>
|
||||||
<span class="stand__schild">Offen</span>
|
<span class="stand__schild">Offen</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div><!-- /.willkommen__text -->
|
||||||
|
|
||||||
<!-- ==== Rechts in der Kachel: Glocke und Uhr ==================
|
<!-- ==== Rechts in der Kachel: Glocke und Uhr ==================
|
||||||
Die Glocke stand bisher in der Kopfleiste. Dort ist sie eine
|
Die Glocke stand bisher in der Kopfleiste. Dort ist sie eine
|
||||||
|
|||||||
Reference in New Issue
Block a user