CSS-Verbesserung
All checks were successful
release-tag / release-image (push) Successful in 2m23s

This commit is contained in:
2026-08-05 21:37:04 +02:00
parent b3bd3d5ffd
commit 37377c79aa
6 changed files with 66 additions and 12 deletions

View File

@@ -51,16 +51,20 @@ GLPI_KB_LIMIT=500
GLPI_KB_SYNC_INTERVAL=10m
GLPI_KB_SOURCE=GLPI Knowledge Base
# Runtime controls. These defaults can later be changed live in the web UI.
# Empty category lists mean "all categories". Values are comma-separated.
# Runtime controls. Boolean/view/performance values are WebUI defaults.
# Source lists are initial WebUI defaults only; runtime-settings.json takes precedence afterwards.
# Empty lists mean unrestricted. Values must exactly match the KB JSON source field.
BRAIN_LEARNING_ENABLED=true
BRAIN_THINKING_ENABLED=true
BRAIN_LEARNING_CATEGORIES=
BRAIN_DISPLAY_CATEGORIES=
BRAIN_THINKING_CATEGORIES=
BRAIN_DEFAULT_VIEW=neural
# Initial exact source selections; empty = all sources.
BRAIN_LEARNING_SOURCES=
BRAIN_DISPLAY_SOURCES=
BRAIN_THINKING_SOURCES=
BRAIN_DEFAULT_VIEW=neural # neural | honeycomb | constellation
# 0 = unbegrenzt; Webinterface kann den Wert zur Laufzeit ändern
BRAIN_MAX_DISPLAY_NODES=0
# Browser-Rendering auf 30 FPS, geringere DPR und reduzierte Effektkosten optimieren.
BRAIN_LOW_POWER_MODE=false
# Sequential enrichment
BRAIN_AUTO_ENRICH=true

View File

@@ -0,0 +1,13 @@
# Filter panel scroll fix
## Änderung
Die Inhalte der Seitenleiste **FILTER / BRAIN CONTROL** liegen jetzt in einem eigenen vertikal scrollbaren Bereich.
- Kopfzeile und Schaltfläche **ÜBERNEHMEN** bleiben erreichbar.
- Betriebsmodi, Performance, SearXNG-Diagnose und alle Source-Filter können unabhängig von der Bildschirmhöhe erreicht werden.
- Mausrad, Touch-Scrollen und Tastaturfokus werden unterstützt.
- Eine schmale, zum UI passende Scrollbar ist in Firefox und Chromium sichtbar.
- Horizontales Überlaufen wird unterdrückt; das Scrollen bleibt auf die Seitenleiste begrenzt.
Es wurden keine Runtime-, Filter- oder Backend-Semantiken verändert.

View File

@@ -1,6 +1,7 @@
478e5158150ff119d661f1d9dcd02565ac9181db77b666289b860d45ed92b896 ./.env.example
8955cfbeff229e73f0cad664863ff21711c270a4233c3225680c89aa6268a901 ./ARCHITECTURE.md
2bc149241c2d25f755e4a0470dc517f646527ee3e98d3a6c2e7798639bd70866 ./CHANGELOG-CONSTELLATION-ECO-TRANSITIONS.md
933cdaeae7895e31d2281d591a75f23f07e7c41d356638654bac4f5e7a20a069 ./CHANGELOG-FILTER-PANEL-SCROLL.md
213ac897cd415bbeb9764a847843b9eff366983cf25bb3cbce4efa4c04b9e5f5 ./CHANGELOG-GLPI-POOL-PERSISTENCE.md
e2f1f0400999cb59b8be09bc2743e06e0a0b2ecdc44a583af7c9a08b70d8509e ./CHANGELOG-GPU-NODE-LIMIT.md
a317376127be1e47b9ec9f0781fcfebdcbf7fccfaeb7840d9241f9586048fadb ./CHANGELOG-GROUNDED-KNOWLEDGE-SYNTHESIS.md
@@ -80,8 +81,8 @@ e7138877303bcc07c429323c4792fed112d8c16d35fd44222fe144ab0b69344f ./internal/res
a46b953c22fb2aef112b11ba65c61bda1e1582903e39489c2d081d17519ebd9d ./internal/research/searxng.go
2f82e80ad91590f419b1bbb19647b5191596e97c4d765e8736c1867ad899d457 ./internal/research/searxng_test.go
500aa5830effdb248b08bf5e25d58920ab9a5bdb49ca8b18265f02435e2ccaf7 ./internal/web/server.go
e601277536f59c6064e643726a44cebaf67b2a8aad54039f45ff75dddd9b4a5d ./internal/web/server_test.go
5a1c81aa6e77e1408f3cfa86f9ad2c3dc6345b7d451a02e5c9524d0917bdc682 ./internal/web/static/app.css
12c30cf7d223e413abc69579eda36971a2d1f69a7e5973005ee31783fba9bf4b ./internal/web/server_test.go
752659210dcf681329c29dbb33a0c02a628b950c897d3dc88b9eb50afd343a8a ./internal/web/static/app.css
ecc55c4fad6d1b470ae5d546798339e1d1a63d47c1b21a311340b1458dee9e7e ./internal/web/static/app.js
4446cd59b91abb9e81b74ff66b1fb1aee63f891c36829c192c83308313653f94 ./internal/web/static/index.html
238d5fd766f9cb2e947d333251ba9e933aa66f81b792b1196fd138426f401ca9 ./internal/web/static/index.html
83aded814b6225395935e61fe957963c3c470f368fc9089f505b6de23e959115 ./preview.png

View File

@@ -129,3 +129,37 @@ func TestResearchDiagnosticAPI(t *testing.T) {
t.Fatalf("unexpected status: %#v", status)
}
}
func TestSettingsPanelContentIsScrollable(t *testing.T) {
broker := activity.New(4)
h := (&Server{Broker: broker}).Handler()
res := httptest.NewRecorder()
h.ServeHTTP(res, httptest.NewRequest(http.MethodGet, "/", nil))
if res.Code != http.StatusOK {
t.Fatalf("GET / returned %d: %s", res.Code, res.Body.String())
}
body := res.Body.String()
if !strings.Contains(body, `class="settings-scroll"`) {
t.Fatal("settings panel is missing its scroll container")
}
if !strings.Contains(body, `class="settings-footer"`) {
t.Fatal("settings footer is missing")
}
res = httptest.NewRecorder()
h.ServeHTTP(res, httptest.NewRequest(http.MethodGet, "/app.css", nil))
if res.Code != http.StatusOK {
t.Fatalf("GET /app.css returned %d: %s", res.Code, res.Body.String())
}
css := res.Body.String()
for _, expected := range []string{
".settings-scroll{flex:1;min-height:0;overflow-y:auto",
"overscroll-behavior:contain",
".settings-footer{flex:0 0 auto",
} {
if !strings.Contains(css, expected) {
t.Fatalf("scroll CSS is missing %q", expected)
}
}
}

View File

@@ -36,13 +36,13 @@ html,body{margin:0;width:100%;height:100%;overflow:hidden;background:radial-grad
body.honeycomb-view .legend{opacity:.58}body.honeycomb-view .mode-status small:after{content:" · Honeycomb"}
.settings-backdrop{position:fixed;inset:0;z-index:20;background:rgba(0,3,9,.55);backdrop-filter:blur(3px)}
.settings-panel{position:fixed;z-index:21;right:18px;top:18px;bottom:18px;width:min(460px,calc(100vw - 36px));border-radius:20px;padding:16px;display:flex;flex-direction:column;overflow:hidden}
.settings-header{display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--line);padding:2px 2px 13px}.settings-header strong{display:block;font-size:12px;letter-spacing:.17em}.settings-header small{display:block;margin-top:4px;color:var(--muted);font-size:10px}.settings-header button{border:0;background:transparent;color:var(--muted);font-size:24px;cursor:pointer;padding:0 5px}
.settings-header{flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--line);padding:2px 2px 13px}.settings-header strong{display:block;font-size:12px;letter-spacing:.17em}.settings-header small{display:block;margin-top:4px;color:var(--muted);font-size:10px}.settings-header button{border:0;background:transparent;color:var(--muted);font-size:24px;cursor:pointer;padding:0 5px}
.settings-section{padding:14px 2px;border-bottom:1px solid var(--line)}.settings-section h2{font-size:10px;letter-spacing:.17em;text-transform:uppercase;color:#9eb5c6;margin:0 0 10px}.settings-section-title{display:flex;justify-content:space-between;align-items:center}.settings-section-title span{font-size:9px;color:#668094}
.switch-row{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:9px 10px;margin:7px 0;border:1px solid rgba(133,200,255,.1);border-radius:12px;background:rgba(255,255,255,.022);cursor:pointer}.switch-row b{display:block;font-size:11px}.switch-row small{display:block;margin-top:3px;color:#718b9e;font-size:9px;line-height:1.35}.switch-row input{appearance:none;width:38px;height:21px;border-radius:999px;background:rgba(119,146,168,.25);position:relative;cursor:pointer;flex:0 0 auto;outline:1px solid rgba(255,255,255,.06)}.switch-row input:after{content:"";position:absolute;width:15px;height:15px;left:3px;top:3px;border-radius:50%;background:#8196a7;transition:transform .2s,background .2s,box-shadow .2s}.switch-row input:checked{background:rgba(82,231,255,.19)}.switch-row input:checked:after{transform:translateX(17px);background:var(--cyan);box-shadow:0 0 10px rgba(82,231,255,.7)}
.view-selector{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;margin-top:10px}.view-selector button{border:1px solid rgba(133,200,255,.12);background:rgba(255,255,255,.025);color:#738da1;border-radius:10px;padding:9px;font-size:10px;font-weight:700;letter-spacing:.1em;cursor:pointer}.view-selector button.active{color:var(--green);border-color:rgba(93,255,189,.24);background:rgba(93,255,189,.07)}
.category-settings{flex:1;min-height:0;overflow:auto;padding-right:5px}.filter-search{display:block;margin-bottom:12px}.filter-search span{display:block;font-size:9px;color:#6d879a;margin-bottom:5px}.filter-search input{width:100%;border:1px solid rgba(133,200,255,.14);background:rgba(2,8,17,.6);color:var(--text);border-radius:10px;padding:9px 10px;outline:0}.filter-search input:focus{border-color:rgba(82,231,255,.38);box-shadow:0 0 0 3px rgba(82,231,255,.06)}
.settings-scroll{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;padding-right:7px;overscroll-behavior:contain;scrollbar-gutter:stable;scrollbar-width:thin;scrollbar-color:rgba(82,231,255,.28) transparent}.settings-scroll::-webkit-scrollbar{width:8px}.settings-scroll::-webkit-scrollbar-track{background:transparent}.settings-scroll::-webkit-scrollbar-thumb{border:2px solid transparent;border-radius:999px;background:rgba(82,231,255,.24);background-clip:padding-box}.settings-scroll::-webkit-scrollbar-thumb:hover{background:rgba(82,231,255,.42);background-clip:padding-box}.settings-scroll:focus-visible{outline:1px solid rgba(82,231,255,.28);outline-offset:3px;border-radius:10px}.settings-scroll .settings-section:last-child{border-bottom:0;padding-bottom:20px}.filter-search{display:block;margin-bottom:12px}.filter-search span{display:block;font-size:9px;color:#6d879a;margin-bottom:5px}.filter-search input{width:100%;border:1px solid rgba(133,200,255,.14);background:rgba(2,8,17,.6);color:var(--text);border-radius:10px;padding:9px 10px;outline:0}.filter-search input:focus{border-color:rgba(82,231,255,.38);box-shadow:0 0 0 3px rgba(82,231,255,.06)}
.filter-block{margin:12px 0 16px}.filter-heading{display:flex;align-items:center;justify-content:space-between;margin-bottom:7px}.filter-heading b{display:block;font-size:10px;color:#c8d9e4}.filter-heading small{display:block;margin-top:2px;color:#607b90;font-size:9px}.filter-heading button{border:1px solid rgba(82,231,255,.13);background:rgba(82,231,255,.04);color:#87a8bc;border-radius:8px;padding:5px 8px;font-size:8px;letter-spacing:.08em;cursor:pointer}.source-list{display:flex;flex-wrap:wrap;gap:5px;max-height:128px;overflow:auto;padding:1px}.source-option{position:relative}.source-option input{position:absolute;opacity:0;pointer-events:none}.source-option span{display:block;border:1px solid rgba(133,200,255,.12);background:rgba(255,255,255,.022);color:#7893a6;border-radius:999px;padding:5px 8px;font-size:9px;cursor:pointer;white-space:nowrap}.source-option input:checked+span{color:#dffaff;border-color:rgba(82,231,255,.32);background:rgba(82,231,255,.11);box-shadow:0 0 12px rgba(82,231,255,.05)}.source-option em{font-style:normal;opacity:.58;margin-left:4px}
.settings-footer{display:flex;align-items:center;justify-content:space-between;gap:12px;padding-top:13px}.settings-footer span{font-size:9px;color:#7f9aac;line-height:1.35}.settings-footer button{border:1px solid rgba(82,231,255,.3);background:rgba(82,231,255,.1);color:var(--cyan);border-radius:11px;padding:10px 13px;font-size:9px;font-weight:800;letter-spacing:.13em;cursor:pointer}.settings-footer button:disabled{opacity:.5;cursor:wait}
.settings-footer{flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:12px;padding-top:13px}.settings-footer span{font-size:9px;color:#7f9aac;line-height:1.35}.settings-footer button{border:1px solid rgba(82,231,255,.3);background:rgba(82,231,255,.1);color:var(--cyan);border-radius:11px;padding:10px 13px;font-size:9px;font-weight:800;letter-spacing:.13em;cursor:pointer}.settings-footer button:disabled{opacity:.5;cursor:wait}
@media(max-width:1100px){.dock{max-width:calc(100vw - 40px)}.settings-panel{right:10px;top:10px;bottom:10px}}
@media(max-width:780px){.settings-panel{left:10px;width:auto}.dock{max-width:calc(100vw - 20px)}.dock-separator{display:none}}

View File

@@ -79,6 +79,7 @@
<button id="closeSettings" title="Schließen">×</button>
</div>
<div class="settings-scroll" tabindex="0" aria-label="Scrollbarer Einstellungsinhalt">
<section class="settings-section">
<h2>Betriebsmodi</h2>
<label class="switch-row" for="settingsLearning">
@@ -148,6 +149,7 @@
<div id="thinkingSourceList" class="source-list"></div>
</div>
</section>
</div>
<div class="settings-footer">
<span id="settingsFeedback" aria-live="polite"></span>