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:
1 parent
cfe59e3652
commit
97acf2cb66
11 files changed
+221
-68
No files matched your search
+38
-16
@@ -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);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user