Farbschema wie VVL-Tool, Dark Mode und lila Textmarkierung

- Farbwerte (hell/dunkel), IBM Plex Sans und Textmarkierung aus dem VVL-Tool übernommen
- Umschalter Hell/Dunkel in der Kopfzeile, Wahl wird gemerkt (Standard: Systemeinstellung)
- Kopfleiste <hi-topbar> folgt dem Farbschema des jeweiligen Tools

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
kerimatilganandClaude Opus 5.5 committed 2026-09-27 13:35:55 +02:00
1 parent cfe59e3652
commit 97acf2cb66
11 files changed
+221 -68

No files matched your search

+38 -16
View File
@@ -37,10 +37,14 @@ const PORTAL = (script?.dataset.portal || (script?.src ? new URL(script.src).ori
const css = `
:host { all: initial; display: block; position: relative; z-index: 2147483000; height: ${HEIGHT}px;
font-family: "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif; font-size: 14px; color: #fff; }
font-family: "IBM Plex Sans", "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif; font-size: 14px; color: #fff;
--p-bg: #ffffff; --p-text: #211a38; --p-text-3: #8a83a0; --p-border: #e5e0f0; --p-hover: #ede7fa; --p-current: #e3d9f8;
--p-accent: #5e35b1; --p-tile: transparent; --p-shadow: 0 8px 40px rgba(45,27,105,.18); }
:host([theme="dark"]) { --p-bg: #1c1436; --p-text: #ece8f6; --p-text-3: #7b7396; --p-border: #312551; --p-hover: #2a2048;
--p-current: #2f2452; --p-accent: #a88beb; --p-tile: #f4f0fc; --p-shadow: 0 12px 48px rgba(0,0,0,.55); }
:host([sticky]) { position: sticky; top: 0; }
* { box-sizing: border-box; }
.bar { display: flex; align-items: center; gap: 6px; height: ${HEIGHT}px; padding: 0 8px 0 4px; background: #2b0f71;
.bar { display: flex; align-items: center; gap: 6px; height: ${HEIGHT}px; padding: 0 8px 0 4px; background: #2d1b69;
box-shadow: 0 1px 0 rgba(0,0,0,.12); }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
a { color: inherit; text-decoration: none; }
@@ -54,29 +58,29 @@ a { color: inherit; text-decoration: none; }
.app-name { opacity: .85; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.sep { width: 1px; height: 18px; background: rgba(255,255,255,.3); margin: 0 4px; }
.spacer { flex: 1; }
.avatar { width: 30px; height: 30px; border-radius: 50%; background: #fff; color: #2b0f71; font-size: 12px; font-weight: 700;
.avatar { width: 30px; height: 30px; border-radius: 50%; background: #fff; color: #2d1b69; font-size: 12px; font-weight: 700;
display: grid; place-items: center; }
.panel { position: absolute; top: ${HEIGHT + 6}px; background: #fff; color: #1f2a52; border-radius: 12px;
border: 1px solid #e2e8f0; box-shadow: 0 12px 32px rgba(15,23,42,.18); overflow: hidden; }
.panel { position: absolute; top: ${HEIGHT + 6}px; background: var(--p-bg); color: var(--p-text); border-radius: 12px;
border: 1px solid var(--p-border); box-shadow: var(--p-shadow); overflow: hidden; }
.panel[hidden] { display: none; }
.apps { left: 6px; width: 344px; max-width: calc(100vw - 12px); max-height: calc(100vh - 60px); overflow-y: auto; padding: 12px; }
.apps h3 { margin: 4px 6px 8px; font-size: 12px; font-weight: 600; color: #64748b; text-transform: uppercase; letter-spacing: .04em; }
.apps h3 { margin: 4px 6px 8px; font-size: 12px; font-weight: 600; color: var(--p-text-3); text-transform: uppercase; letter-spacing: .04em; }
.grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 4px; margin-bottom: 8px; }
.tile { display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 10px 4px; border-radius: 10px;
text-align: center; font-size: 12.5px; font-weight: 500; line-height: 1.2; overflow-wrap: anywhere; hyphens: auto; }
.tile:hover { background: #f3f0fd; }
.tile[aria-current="page"] { background: #e6defb; }
.tile img { width: 36px; height: 36px; }
.footer { display: block; margin: 4px -12px -12px; padding: 12px 18px; border-top: 1px solid #f1f5f9; font-weight: 600; color: #5a2fd6; }
.footer:hover { background: #f3f0fd; }
.hint { margin: 6px; font-size: 13px; line-height: 1.45; color: #475569; }
.hint a { color: #5a2fd6; font-weight: 600; }
.tile:hover { background: var(--p-hover); }
.tile[aria-current="page"] { background: var(--p-current); }
.tile img { width: 36px; height: 36px; padding: 2px; border-radius: 8px; background: var(--p-tile); }
.footer { display: block; margin: 4px -12px -12px; padding: 12px 18px; border-top: 1px solid var(--p-border); font-weight: 600; color: var(--p-accent); }
.footer:hover { background: var(--p-hover); }
.hint { margin: 6px; font-size: 13px; line-height: 1.45; color: var(--p-text); }
.hint a { color: var(--p-accent); font-weight: 600; }
.user { right: 6px; width: 260px; }
.user .who { padding: 12px 16px; border-bottom: 1px solid #f1f5f9; }
.user .who { padding: 12px 16px; border-bottom: 1px solid var(--p-border); }
.user .who div:first-child { font-weight: 600; }
.user .who div:last-child { font-size: 13px; color: #64748b; overflow: hidden; text-overflow: ellipsis; }
.user .who div:last-child { font-size: 13px; color: var(--p-text-3); overflow: hidden; text-overflow: ellipsis; }
.user a { display: block; padding: 10px 16px; font-size: 14px; }
.user a:hover { background: #f3f0fd; }
.user a:hover { background: var(--p-hover); }
@media (max-width: 480px) { .brand span { display: none; } }
`;
@@ -112,8 +116,24 @@ class HiTopbar extends HTMLElement {
private nav: Navigation | null = null;
private open: 'apps' | 'user' | null = null;
private themeObserver?: MutationObserver;
private darkQuery = window.matchMedia('(prefers-color-scheme: dark)');
/** Folgt dem Farbschema des Tools: data-theme="dark" (VVL, Portal), Klasse "dark" (Tailwind) oder System. */
private syncTheme = () => {
const html = document.documentElement;
const attr = html.getAttribute('data-theme');
const dark = attr ? attr === 'dark' : html.classList.contains('dark') || this.darkQuery.matches;
if (dark) this.setAttribute('theme', 'dark');
else this.removeAttribute('theme');
};
connectedCallback(): void {
document.documentElement.style.setProperty('--hi-topbar-height', `${HEIGHT}px`);
this.syncTheme();
this.themeObserver = new MutationObserver(this.syncTheme);
this.themeObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme', 'class'] });
this.darkQuery.addEventListener('change', this.syncTheme);
this.nav = readCache();
this.render();
void this.load();
@@ -122,6 +142,8 @@ class HiTopbar extends HTMLElement {
}
disconnectedCallback(): void {
this.themeObserver?.disconnect();
this.darkQuery.removeEventListener('change', this.syncTheme);
document.removeEventListener('mousedown', this.onOutside);
document.removeEventListener('keydown', this.onKey);
}