Compare commits

..

2 Commits

Author SHA1 Message Date
devops 86ceb2bcce style: unify all views on Mission Control V2 design tokens
CI - Build & Test / Backend (.NET) (push) Successful in 31s
CI - Build & Test / Frontend (Vue/TS) (push) Successful in 16s
CI - Build & Test / Security Check (push) Successful in 3s
CI - Build & Test / Deploy Nexus (push) Has been skipped
- Map legacy v1 CSS variables (--nx-*, --panel, --text-*, --surface*) to V2 tokens in nexus-tokens.css
- Restyle global shell (main.css), AppSidebar, AppHeader to match V2 Sidebar/Topbar (glass, gradients, Space Grotesk)
- Add GalaxyBackground to the v1 shell in App.vue
- Replace hardcoded v1 hex colors with V2 tokens in all deviating views (Agents, Calendar, Docs, Incidents, Memory, Notifications, ProjectDetail, Security, Team, TaskDetail, Settings)
- Keep JS status colors as hex where alpha suffixes are concatenated (AgentsIndex, Team, Notifications)
- Add Settings nav item (System group) + gear icon to V2 sidebar so it shows on the dashboard
- No component or layout structure changes; LoginView and TaskBoardView untouched

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 08:05:52 +02:00
devops 706ff82ccd fix: harden Nexus runtime health and rollback 2026-07-10 00:37:24 +02:00
25 changed files with 629 additions and 533 deletions
+2 -2
View File
@@ -19,7 +19,7 @@ JWT_AUDIENCE=nexus-web
BOOTSTRAP_OWNER_EMAIL=*** BOOTSTRAP_OWNER_EMAIL=***
# ── OpenClaw Integration ──────────────────────────────── # ── OpenClaw Integration ────────────────────────────────
# Base URL of the OpenClaw gateway (host.docker.internal from inside container) # Internal Docker-DNS URL of the OpenClaw gateway
OPENCLAW_BASE_URL=http://host.docker.internal:18789 OPENCLAW_BASE_URL=http://openclaw-gateway-bao:18789
OPENCLAW_GATEWAY_TOKEN=*** OPENCLAW_GATEWAY_TOKEN=***
OPENCLAW_GATEWAY_PASSWORD=*** OPENCLAW_GATEWAY_PASSWORD=***
+10 -38
View File
@@ -60,7 +60,7 @@ JWT_KEY=${ENV_JWT_KEY}
JWT_ISSUER=nexus JWT_ISSUER=nexus
JWT_AUDIENCE=nexus-web JWT_AUDIENCE=nexus-web
BOOTSTRAP_OWNER_EMAIL=vmbao62@hotmail.de BOOTSTRAP_OWNER_EMAIL=vmbao62@hotmail.de
OPENCLAW_BASE_URL=http://host.docker.internal:18789 OPENCLAW_BASE_URL=http://openclaw-gateway-bao:18789
OPENCLAW_GATEWAY_TOKEN=${ENV_OPENCLAW_TOKEN:-} OPENCLAW_GATEWAY_TOKEN=${ENV_OPENCLAW_TOKEN:-}
OPENCLAW_GATEWAY_PASSWORD= OPENCLAW_GATEWAY_PASSWORD=
NEXUS_VERSION=${VERSION} NEXUS_VERSION=${VERSION}
@@ -105,40 +105,6 @@ git archive --format=tar HEAD | docker run --rm -i \
chown -R "$dest_owner" /dest chown -R "$dest_owner" /dest
' '
# ── Sanitized agents config for Nexus (no secrets) ──
echo "Generating sanitized agents config for Nexus (no secrets from openclaw.json)"
AGENTS_SANITIZED_PATH="/home/projekte_bao/openclaw/data/openclaw/agents-sanitized.json"
OPENCLAW_CONFIG="/home/projekte_bao/openclaw/data/openclaw/openclaw.json"
OPENCLAW_CONFIG_DIR="/home/projekte_bao/openclaw/data/openclaw"
# Use Docker to read openclaw.json (runner doesn't have direct host fs access)
if docker run --rm \
-v "$OPENCLAW_CONFIG:/input/openclaw.json:ro" \
-v "$OPENCLAW_CONFIG_DIR:/output" \
python:3.12-alpine \
python3 -c "
import json, sys, os
config_path = '/input/openclaw.json'
output_path = '/output/agents-sanitized.json'
if not os.path.isfile(config_path):
print(f'WARNING: openclaw.json not found at {config_path} — agents-sanitized.json NOT generated', file=sys.stderr)
sys.exit(1)
with open(config_path) as f:
data = json.load(f)
agents = data.get('agents')
if agents is None:
print('ERROR: \"agents\" key not found in openclaw.json', file=sys.stderr)
sys.exit(1)
with open(output_path, 'w') as f:
json.dump({'agents': agents}, f, indent=2)
f.write('\n')
print(f'Sanitized agents config written ({len(agents.get(\"list\", []))} agents)')
" 2>&1; then
echo "Sanitized agents config written to $AGENTS_SANITIZED_PATH"
else
echo "WARNING: Failed to generate agents-sanitized.json — Nexus will use fallback agent IDs" >&2
fi
echo "Building and starting Docker compose stack" echo "Building and starting Docker compose stack"
docker run --rm \ docker run --rm \
-v "$DEPLOY_PATH:/workspace/nexus" \ -v "$DEPLOY_PATH:/workspace/nexus" \
@@ -174,9 +140,15 @@ echo "Checking live health"
retry=0 retry=0
while [ "$retry" -lt 6 ]; do while [ "$retry" -lt 6 ]; do
retry=$((retry + 1)) retry=$((retry + 1))
if curl -fsS --max-time 10 "$BASE_URL/health" >/dev/null; then health_body="$(curl -fsS --max-time 10 "$BASE_URL/health" 2>/dev/null || true)"
echo "Health check passed" case "$health_body" in
break '{"status":"Healthy"'*)
echo "Health check passed"
break
;;
esac
if [ -n "$health_body" ]; then
echo "Health endpoint is reachable but not healthy: $health_body" >&2
fi fi
if [ "$retry" -eq 6 ]; then if [ "$retry" -eq 6 ]; then
echo "Health check failed" >&2 echo "Health check failed" >&2
+50 -23
View File
@@ -112,9 +112,11 @@ jobs:
JWT_ISSUER=nexus JWT_ISSUER=nexus
JWT_AUDIENCE=nexus-web JWT_AUDIENCE=nexus-web
BOOTSTRAP_OWNER_EMAIL=vmbao62@hotmail.de BOOTSTRAP_OWNER_EMAIL=vmbao62@hotmail.de
OPENCLAW_BASE_URL=http://host.docker.internal:18789 OPENCLAW_BASE_URL=http://openclaw-gateway-bao:18789
OPENCLAW_GATEWAY_TOKEN=${ENV_OPENCLAW_TOKEN} OPENCLAW_GATEWAY_TOKEN=${ENV_OPENCLAW_TOKEN}
OPENCLAW_GATEWAY_PASSWORD= OPENCLAW_GATEWAY_PASSWORD=
NEXUS_VERSION=$(tr -d '[:space:]' < VERSION)
NEXUS_GIT_SHA=$(git rev-parse HEAD)
EOF EOF
chmod 600 "${ENV_TMPFILE}" chmod 600 "${ENV_TMPFILE}"
@@ -127,18 +129,38 @@ jobs:
run: | run: |
set -euo pipefail set -euo pipefail
docker run --rm \ git archive --format=tar HEAD | docker run --rm -i \
-v "${{ gitea.workspace }}:/src:ro" \
-v "${DEPLOY_PATH}:/dest" \ -v "${DEPLOY_PATH}:/dest" \
alpine:latest \ alpine:latest \
sh -c " sh -c '
cd /src && \ set -eu
find . -mindepth 1 -maxdepth 1 \ dest_owner="$(stat -c "%u:%g" /dest)"
! -name .git \ mkdir -p /src-snapshot
-exec cp -r {} /dest/ \; && \ tar -xf - -C /src-snapshot
DEST_OWNER=\$(stat -c '%u:%g' /dest) && \
chown -R \"\$DEST_OWNER\" /dest is_protected_path() {
" case "$1" in
./.git|./.env|./.env.*|./data|./logs|./backups|./tmp|./uploads|./storage)
return 0
;;
*)
return 1
;;
esac
}
cd /dest
find . -mindepth 1 -maxdepth 1 | while IFS= read -r path; do
if ! is_protected_path "$path"; then rm -rf "$path"; fi
done
cd /src-snapshot
find . -mindepth 1 -maxdepth 1 | while IFS= read -r path; do
if ! is_protected_path "$path"; then cp -a "$path" /dest/; fi
done
chown -R "$dest_owner" /dest
'
echo "✅ Rollback code (${{ inputs.target_tag }}) synced to ${DEPLOY_PATH}" echo "✅ Rollback code (${{ inputs.target_tag }}) synced to ${DEPLOY_PATH}"
@@ -151,16 +173,18 @@ jobs:
docker run --rm \ docker run --rm \
-v "${DEPLOY_PATH}:/workspace/nexus" \ -v "${DEPLOY_PATH}:/workspace/nexus" \
-v "/tmp:/tmp-host:ro" \
-v /var/run/docker.sock:/var/run/docker.sock \ -v /var/run/docker.sock:/var/run/docker.sock \
-w /workspace/nexus \ -w /workspace/nexus \
-i \
docker:cli \ docker:cli \
sh -c " sh -c '
set -e set -eu
echo '🔙 Rolling back to ${{ inputs.target_tag }}' umask 077
docker compose --env-file /tmp-host/$(basename "${ENV_TMPFILE}") build --no-cache cat > /tmp/nexus-rollback-env
docker compose --env-file /tmp-host/$(basename "${ENV_TMPFILE}") up -d --wait --force-recreate trap '\''rm -f /tmp/nexus-rollback-env'\'' EXIT INT TERM
" docker compose --env-file /tmp/nexus-rollback-env build --no-cache
docker compose --env-file /tmp/nexus-rollback-env up -d --wait --force-recreate
' < "${ENV_TMPFILE}"
echo "✅ Rollback redeploy completed" echo "✅ Rollback redeploy completed"
@@ -186,11 +210,14 @@ jobs:
WAIT=1 WAIT=1
while [ $RETRY -lt $MAX ]; do while [ $RETRY -lt $MAX ]; do
RETRY=$((RETRY + 1)) RETRY=$((RETRY + 1))
if curl -sf --max-time 10 https://nexus.noveria.net/health; then HEALTH_BODY=$(curl -sf --max-time 10 https://nexus.noveria.net/health || true)
echo "" case "$HEALTH_BODY" in
echo "✅ Health check passed (attempt $RETRY/$MAX)" '{"status":"Healthy"'*)
exit 0 echo "✅ Health check passed (attempt $RETRY/$MAX)"
fi exit 0
;;
esac
[ -n "$HEALTH_BODY" ] && echo "⚠️ Health endpoint is degraded: $HEALTH_BODY"
echo "⏳ Attempt $RETRY/$MAX failed, waiting ${WAIT}s..." echo "⏳ Attempt $RETRY/$MAX failed, waiting ${WAIT}s..."
sleep $WAIT sleep $WAIT
NEXT=$((WAIT + RETRY)) NEXT=$((WAIT + RETRY))
+12 -3
View File
@@ -2,6 +2,15 @@ name: nexus
services: services:
postgres: postgres:
image: postgres:17-alpine image: postgres:17-alpine
# WAL-Archivierung bleibt deaktiviert, bis ein verwaltetes Off-Server-Ziel
# mit Retention und Restore-Test existiert. Ein lokales Endlosarchiv ist
# kein Backup und kann bei Fehlern pg_wal ungebremst wachsen lassen.
command:
- postgres
- -c
- archive_mode=off
- -c
- archive_command=
restart: always restart: always
deploy: deploy:
resources: resources:
@@ -50,7 +59,7 @@ services:
Jwt__Audience: ${JWT_AUDIENCE:-nexus-web} Jwt__Audience: ${JWT_AUDIENCE:-nexus-web}
Bootstrap__OwnerEmail: ${BOOTSTRAP_OWNER_EMAIL:?Set BOOTSTRAP_OWNER_EMAIL in .env} Bootstrap__OwnerEmail: ${BOOTSTRAP_OWNER_EMAIL:?Set BOOTSTRAP_OWNER_EMAIL in .env}
# Initial owner password is generated once at first seed and then lives only in the DB. # Initial owner password is generated once at first seed and then lives only in the DB.
Integrations__OpenClaw__BaseUrl: ${OPENCLAW_BASE_URL:-http://host.docker.internal:18789} Integrations__OpenClaw__BaseUrl: ${OPENCLAW_BASE_URL:-http://openclaw-gateway-bao:18789}
Integrations__OpenClaw__Token: ${OPENCLAW_GATEWAY_TOKEN:-} Integrations__OpenClaw__Token: ${OPENCLAW_GATEWAY_TOKEN:-}
Integrations__OpenClaw__Password: ${OPENCLAW_GATEWAY_PASSWORD:-} Integrations__OpenClaw__Password: ${OPENCLAW_GATEWAY_PASSWORD:-}
Admin__ResetToken: ${Admin__ResetToken:-} Admin__ResetToken: ${Admin__ResetToken:-}
@@ -59,7 +68,7 @@ services:
- host.docker.internal:host-gateway - host.docker.internal:host-gateway
depends_on: depends_on:
postgres: postgres:
condition: service_started condition: service_healthy
restart: true restart: true
healthcheck: healthcheck:
test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:8080/health/live || exit 1"] test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:8080/health/live || exit 1"]
@@ -106,7 +115,7 @@ services:
- "127.0.0.1:18880:80" - "127.0.0.1:18880:80"
depends_on: depends_on:
api: api:
condition: service_started condition: service_healthy
restart: true restart: true
healthcheck: healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:80/ || exit 1"] test: ["CMD-SHELL", "curl -f http://localhost:80/ || exit 1"]
+16 -21
View File
@@ -68,8 +68,8 @@ Ansatz. Das Backend fungiert bereits als sichere Schicht zwischen allen Akteuren
│ │ │ │
│ ALLE Gateway-Calls → Authorization: Bearer <Gateway-Password> │ │ ALLE Gateway-Calls → Authorization: Bearer <Gateway-Password> │
└──────────────┬──────────────────────────────┬────────────────────┘ └──────────────┬──────────────────────────────┬────────────────────┘
host.docker.internal:18789 │ openclaw-gateway-bao:18789 │
│ (Gateway loopback/lan) │ (internes Docker-DNS)
▼ │ ▼ │
┌──────────────────────────────┐ │ ┌──────────────────────────────┐ │
│ OpenClaw Gateway Container │ │ │ OpenClaw Gateway Container │ │
@@ -199,7 +199,7 @@ Ebene 4: X-Agent-Id Header (Agent-Identität für Task-State-Enforcement)
``` ```
POST /api/v1/operations/snapshot POST /api/v1/operations/snapshot
→ DashboardService → OpenClawGatewayClient.InvokeToolAsync() → DashboardService → OpenClawGatewayClient.InvokeToolAsync()
→ POST http://host.docker.internal:18789/tools/invoke → POST http://openclaw-gateway-bao:18789/tools/invoke
Authorization: Bearer <Gateway-Password> Authorization: Bearer <Gateway-Password>
``` ```
@@ -220,7 +220,7 @@ POST /api/v1/operations/snapshot
### 5.2 Docker-Netzwerk & Gateway-Bind ### 5.2 Docker-Netzwerk & Gateway-Bind
**Aktuelles Problem:** **Aktueller Stand (2026-07-09):**
``` ```
compose.yaml: compose.yaml:
api: api:
@@ -228,32 +228,27 @@ compose.yaml:
- host.docker.internal:host-gateway - host.docker.internal:host-gateway
networks: networks:
- nexus - nexus
- openclaw_default ← API-Container ist im Gateway-Netzwerk - openclaw_default
Gateway-Konfiguration: Gateway-Konfiguration:
gateway.bind: "loopback" ← Bindet nur 127.0.0.1 IM GATEWAY-CONTAINER gateway.bind: "lan"
Nexus-Konfiguration:
OPENCLAW_BASE_URL=http://openclaw-gateway-bao:18789
``` ```
**Ergebnis:** **Ergebnis:**
- `host.docker.internal:18789` funktioniert, weil `extra_hosts` auf den Docker-Host zeigt - Nexus erreicht das Gateway direkt über Docker-DNS im gemeinsamen `openclaw_default`-Netz.
- ABER: Docker-Port-Forward (wenn vorhanden) sendet an Container-IP, nicht loopback - Der Umweg über einen nicht veröffentlichten Host-Port entfällt.
- Die `openclaw_default` Netzwerk-Mitgliedschaft des API-Containers wird NICHT genutzt - Der produktive Aggregat-Healthcheck prüft neben PostgreSQL auch die Runtime-Verbindung.
**Empfehlung (siehe gateway-api-research.md, Abschnitt 6):** Der frühere Pfad `host.docker.internal:18789` war auf dem VPS nicht erreichbar und ist obsolet.
```json5
// openclaw.json
{
gateway: {
bind: "lan" // war "loopback"
}
}
```
Alternativ: API-Container über Gateway-Container-Namen ansprechen: Produktive Einstellung:
```yaml ```yaml
Integrations__OpenClaw__BaseUrl: http://openclaw_gateway:18789 Integrations__OpenClaw__BaseUrl: http://openclaw-gateway-bao:18789
``` ```
(Vorausgesetzt der Gateway-Container heißt `openclaw_gateway` und ist im `openclaw_default` Netzwerk) Beide Container müssen Mitglied im `openclaw_default`-Netzwerk sein.
### 5.3 MCP-artige Integration: Bewertung ### 5.3 MCP-artige Integration: Bewertung
+13 -13
View File
@@ -290,30 +290,30 @@ The Nexus compose.yaml already includes the full integration infrastructure:
```yaml ```yaml
api: api:
extra_hosts:
- host.docker.internal:host-gateway
environment: environment:
Integrations__OpenClaw__BaseUrl: ${OPENCLAW_BASE_URL:-http://host.docker.internal:18789} Integrations__OpenClaw__BaseUrl: ${OPENCLAW_BASE_URL:-http://openclaw-gateway-bao:18789}
Integrations__OpenClaw__Token: ${OPENCLAW_GATEWAY_TOKEN:-} Integrations__OpenClaw__Token: ${OPENCLAW_GATEWAY_TOKEN:-}
Integrations__OpenClaw__Password: ${OPENCLAW_GATEWAY_PASSWORD:-} Integrations__OpenClaw__Password: ${OPENCLAW_GATEWAY_PASSWORD:-}
networks:
- nexus
- openclaw_default
``` ```
The API container: The API container:
- Uses `host.docker.internal:18789` to reach the Gateway via the Docker host - Uses Docker DNS (`openclaw-gateway-bao:18789`) in the shared `openclaw_default` network
- Has `extra_hosts` configured for `host.docker.internal` - Does not depend on a published host port for the Gateway
- Reads token/password from `.env` via `OPENCLAW_GATEWAY_PASSWORD` - Reads token/password from `.env` via `OPENCLAW_GATEWAY_PASSWORD`
### Known Issue: Gateway Bind = loopback ### Resolved Routing Issue (2026-07-09)
The Gateway binds to `127.0.0.1` (`gateway.bind: "loopback"`). This means it only listens inside the gateway container's loopback interface. The old `host.docker.internal:18789` route was unreachable because no usable host port was published. The Gateway is now reached directly by its container DNS name.
| Scenario | Works? | Why | | Scenario | Works? | Why |
|----------|--------|-----| |----------|--------|-----|
| Gateway with `--network host` | ✅ Yes | Process sees host's 127.0.0.1 directly | | `host.docker.internal:18789` | ❌ No | No reachable host listener on the VPS |
| Gateway with `-p 18789:18789` + loopback bind | ❌ No | Port forward sends to container IP, not loopback | | `openclaw-gateway-bao:18789` in `openclaw_default` | ✅ Yes | Direct container-to-container routing via Docker DNS |
| Gateway with `-p 18789:18789` + lan bind | ✅ Yes | Listens on all interfaces including container IP |
**Fix**: Change `gateway.bind` from `"loopback"` to `"lan"` (binds `0.0.0.0`): The Gateway must listen on its container interface (`gateway.bind: "lan"`):
```json5 ```json5
{ {
@@ -325,8 +325,8 @@ The Gateway binds to `127.0.0.1` (`gateway.bind: "loopback"`). This means it onl
**Test command (from Nexus API container):** **Test command (from Nexus API container):**
```bash ```bash
curl -s http://host.docker.internal:18789/health curl -s http://openclaw-gateway-bao:18789/
# Expected: 200 if gateway bind is lan/container IP is reachable # Expected: HTTP 200 from inside nexus-api-1
``` ```
### Required .env Vars for Nexus ### Required .env Vars for Nexus
+4
View File
@@ -6,6 +6,7 @@ import { useOperationsStore } from './stores/operations'
import { useAuthStore } from './stores/auth' import { useAuthStore } from './stores/auth'
import AppSidebar from './components/layout/AppSidebar.vue' import AppSidebar from './components/layout/AppSidebar.vue'
import AppHeader from './components/layout/AppHeader.vue' import AppHeader from './components/layout/AppHeader.vue'
import GalaxyBackground from './components/background/GalaxyBackground.vue'
import ModuleView from './components/ModuleView.vue' import ModuleView from './components/ModuleView.vue'
import ToastContainer from './components/ui/ToastContainer.vue' import ToastContainer from './components/ui/ToastContainer.vue'
@@ -46,6 +47,7 @@ onMounted(() => {
<template> <template>
<RouterView v-if="route.name === 'Login' || route.name === 'Dashboard'" /> <RouterView v-if="route.name === 'Login' || route.name === 'Dashboard'" />
<div v-else class="shell"> <div v-else class="shell">
<GalaxyBackground />
<AppSidebar <AppSidebar
:active-view="activeView" :active-view="activeView"
:mobile-nav-open="mobileNavOpen" :mobile-nav-open="mobileNavOpen"
@@ -103,6 +105,8 @@ main {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-width: 0; min-width: 0;
position: relative;
z-index: 1;
} }
.content { .content {
+108 -80
View File
@@ -83,8 +83,11 @@
} }
body { body {
background: hsl(var(--background)); background:
color: hsl(var(--foreground)); radial-gradient(1100px 700px at 12% -10%, rgba(79, 124, 255, 0.10), transparent 60%),
radial-gradient(1000px 700px at 95% 8%, rgba(181, 87, 246, 0.09), transparent 60%),
var(--space-0, #050410);
color: var(--tx, #ece9ff);
font-family: 'Manrope', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, font-family: 'Manrope', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
'Segoe UI', sans-serif; 'Segoe UI', sans-serif;
margin: 0; margin: 0;
@@ -92,6 +95,10 @@ body {
min-height: 100vh; min-height: 100vh;
} }
h1, h2, h3, .font-display {
font-family: 'Space Grotesk', 'Manrope', sans-serif;
}
/* Nexus overrides for existing CSS variables used in dashboard */ /* Nexus overrides for existing CSS variables used in dashboard */
:root { :root {
--nx-bg: #080a0f; --nx-bg: #080a0f;
@@ -126,9 +133,9 @@ body {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: 22px 14px 14px; padding: 22px 14px 14px;
border-right: 1px solid #1a1e27; border-right: 1px solid var(--line);
background: rgba(9, 11, 16, 0.94); background: linear-gradient(180deg, rgba(14, 12, 32, 0.92), rgba(8, 6, 20, 0.92));
backdrop-filter: blur(18px); backdrop-filter: blur(14px);
} }
.brand { .brand {
@@ -143,15 +150,16 @@ body {
height: 35px; height: 35px;
display: grid; display: grid;
place-items: center; place-items: center;
border: 1px solid #443d7c; border: none;
border-radius: 10px; border-radius: 11px;
background: linear-gradient(145deg, #241f44, #12121f); background: var(--grad);
color: #b8adff; color: #fff;
box-shadow: 0 0 24px rgba(139, 124, 246, 0.13); box-shadow: var(--glow-purple);
} }
.brand strong { .brand strong {
display: block; display: block;
font-family: 'Space Grotesk', sans-serif;
font-size: 13px; font-size: 13px;
letter-spacing: 0.14em; letter-spacing: 0.14em;
} }
@@ -178,36 +186,38 @@ body {
gap: 10px; gap: 10px;
border: 0; border: 0;
padding: 9px 10px; padding: 9px 10px;
border-radius: 7px; border-radius: 10px;
background: transparent; background: transparent;
color: #8991a1; color: var(--tx-2);
font-size: 12px; font-size: 12px;
text-align: left; text-align: left;
cursor: pointer; cursor: pointer;
} }
.nav button:hover, .nav button:hover {
.nav button.active { color: var(--tx);
color: #ececf5; background: rgba(124, 108, 255, 0.08);
background: var(--nx-accent-soft);
} }
.nav button.active { .nav button.active {
box-shadow: inset 2px 0 var(--nx-accent); color: #fff;
background: linear-gradient(90deg, rgba(124, 108, 255, 0.22), rgba(124, 108, 255, 0.04));
box-shadow: inset 0 0 0 1px rgba(124, 108, 255, 0.25);
} }
.nav button i { .nav button i {
margin-left: auto; margin-left: auto;
padding: 1px 6px; padding: 1px 6px;
border: 1px solid #343947; border: 1px solid var(--line-2);
border-radius: 8px; border-radius: 8px;
background: rgba(124, 108, 255, 0.10);
font-size: 9px; font-size: 9px;
font-style: normal; font-style: normal;
} }
.sidebar-bottom { .sidebar-bottom {
margin-top: auto; margin-top: auto;
border-top: 1px solid #1b1f28; border-top: 1px solid var(--line);
padding-top: 10px; padding-top: 10px;
} }
@@ -240,10 +250,12 @@ body {
height: 31px; height: 31px;
display: grid; display: grid;
place-items: center; place-items: center;
border-radius: 50%; border-radius: 10px;
background: #28243f; background: var(--grad-soft);
color: #bcb3ff; border: 1px solid var(--line-2);
color: var(--tx);
font-size: 10px; font-size: 10px;
font-weight: 700;
} }
main { main {
@@ -256,9 +268,9 @@ main {
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
padding: 0 30px; padding: 0 30px;
border-bottom: 1px solid #191d25; border-bottom: 1px solid var(--line);
background: rgba(8, 10, 15, 0.68); background: rgba(8, 6, 20, 0.5);
backdrop-filter: blur(16px); backdrop-filter: blur(14px);
} }
.search { .search {
@@ -266,19 +278,20 @@ main {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 9px; gap: 9px;
padding: 8px 10px; padding: 8px 12px;
border: 1px solid #202530; border: 1px solid var(--line);
border-radius: 7px; border-radius: 11px;
color: #6f7889; background: rgba(124, 108, 255, 0.06);
color: var(--tx-3);
font-size: 11px; font-size: 11px;
} }
.search kbd { .search kbd {
margin-left: auto; margin-left: auto;
padding: 2px 5px; padding: 2px 5px;
border: 1px solid #2c313d; border: 1px solid var(--line-2);
border-radius: 4px; border-radius: 4px;
color: #606979; color: var(--tx-3);
font-size: 9px; font-size: 9px;
} }
@@ -293,15 +306,20 @@ main {
gap: 6px; gap: 6px;
align-items: center; align-items: center;
font-size: 10px; font-size: 10px;
color: #8c95a5; font-weight: 600;
color: var(--tx-2);
border: 1px solid var(--line-2);
background: rgba(124, 108, 255, 0.07);
border-radius: 20px;
padding: 4px 11px;
} }
.connection.live { .connection.live {
color: var(--nx-green); color: var(--st-work);
} }
.connection.preview { .connection.preview {
color: #e6b75d; color: var(--st-queue);
} }
.ask, .ask,
@@ -309,13 +327,20 @@ main {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 7px; gap: 7px;
padding: 8px 11px; padding: 8px 13px;
border: 1px solid #37315e; border: none;
border-radius: 7px; border-radius: 10px;
background: #18152a; background: var(--grad);
color: #c4bbff; color: #fff;
font-weight: 600;
box-shadow: var(--glow-purple);
font-size: 10px; font-size: 10px;
cursor: pointer; cursor: pointer;
transition: filter .16s;
}
.ask:hover {
filter: brightness(1.08);
} }
.content { .content {
@@ -331,7 +356,7 @@ main {
.eyebrow, .eyebrow,
.kicker { .kicker {
color: #7065c8; color: var(--a-mid);
font-size: 9px; font-size: 9px;
font-weight: 700; font-weight: 700;
letter-spacing: 0.18em; letter-spacing: 0.18em;
@@ -351,9 +376,10 @@ h1 {
} }
.refresh-btn { .refresh-btn {
border-color: var(--nx-line); background: rgba(124, 108, 255, 0.07);
background: var(--nx-panel); border: 1px solid var(--line-2);
color: #a5adba; box-shadow: none;
color: var(--tx-2);
} }
.spin { .spin {
@@ -370,7 +396,7 @@ h1 {
display: none; display: none;
border: 0; border: 0;
background: transparent; background: transparent;
color: #aaa4e7; color: var(--tx-2);
} }
/* ── Keep existing module/layout styles for non-dashboard pages ── */ /* ── Keep existing module/layout styles for non-dashboard pages ── */
@@ -383,9 +409,10 @@ h1 {
.metrics article, .metrics article,
.panel { .panel {
border: 1px solid var(--nx-line); border: 1px solid var(--line);
background: linear-gradient(145deg, rgba(18, 21, 29, 0.96), rgba(12, 15, 21, 0.96)); background: var(--glass);
border-radius: 9px; border-radius: var(--r);
backdrop-filter: blur(12px);
} }
.metrics article { .metrics article {
@@ -393,7 +420,7 @@ h1 {
} }
.metrics span { .metrics span {
color: #717a8a; color: var(--tx-3);
font-size: 8px; font-size: 8px;
font-weight: 700; font-weight: 700;
letter-spacing: 0.14em; letter-spacing: 0.14em;
@@ -407,12 +434,12 @@ h1 {
} }
.metrics small { .metrics small {
color: #687181; color: var(--tx-3);
font-size: 9px; font-size: 9px;
} }
.metrics small.up { .metrics small.up {
color: #55c995; color: var(--st-work);
} }
.dashboard-grid { .dashboard-grid {
@@ -435,7 +462,7 @@ h1 {
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
padding-bottom: 15px; padding-bottom: 15px;
border-bottom: 1px solid #1d222c; border-bottom: 1px solid var(--line);
} }
.panel-head h2 { .panel-head h2 {
@@ -446,7 +473,7 @@ h1 {
.panel-head button { .panel-head button {
border: 0; border: 0;
background: transparent; background: transparent;
color: #8e96a5; color: var(--tx-2);
font-size: 9px; font-size: 9px;
} }
@@ -457,18 +484,18 @@ h1 {
} }
.badge.positive { .badge.positive {
color: var(--nx-green); color: var(--st-work);
background: rgba(81, 212, 154, 0.1); background: rgba(61, 220, 151, 0.12);
} }
.badge.warning { .badge.warning {
color: #e7b660; color: var(--st-queue);
background: rgba(231, 182, 96, 0.1); background: rgba(251, 191, 36, 0.12);
} }
.badge.negative { .badge.negative {
color: #e16e75; color: var(--st-block);
background: rgba(225, 110, 117, 0.1); background: rgba(251, 113, 133, 0.12);
} }
.runtime-row { .runtime-row {
@@ -483,9 +510,10 @@ h1 {
height: 45px; height: 45px;
display: grid; display: grid;
place-items: center; place-items: center;
border-radius: 9px; border-radius: var(--r-sm);
color: #ad9fff; color: var(--a-mid);
background: var(--nx-accent-soft); background: var(--grad-soft);
border: 1px solid var(--line-2);
} }
.runtime-main strong, .runtime-main strong,
@@ -517,7 +545,7 @@ h1 {
width: 3px; width: 3px;
min-height: 5px; min-height: 5px;
border-radius: 3px; border-radius: 3px;
background: linear-gradient(#927fff, #443b7c); background: linear-gradient(var(--a-mid), rgba(124, 108, 255, 0.35));
} }
.model { .model {
@@ -526,11 +554,11 @@ h1 {
align-items: center; align-items: center;
gap: 9px; gap: 9px;
padding: 12px 2px; padding: 12px 2px;
border-bottom: 1px solid #1b2029; border-bottom: 1px solid var(--line);
} }
.model > span:last-child { .model > span:last-child {
color: #687181; color: var(--tx-3);
font-size: 8px; font-size: 8px;
} }
@@ -538,16 +566,16 @@ h1 {
width: 6px; width: 6px;
height: 6px; height: 6px;
border-radius: 50%; border-radius: 50%;
background: #657083; background: var(--st-idle);
} }
.status-dot.online { .status-dot.online {
background: var(--nx-green); background: var(--st-work);
box-shadow: 0 0 7px rgba(81, 212, 154, 0.4); box-shadow: 0 0 7px rgba(61, 220, 151, 0.4);
} }
.status-dot.offline { .status-dot.offline {
background: #e16e75; background: var(--st-block);
} }
.project { .project {
@@ -556,7 +584,7 @@ h1 {
align-items: center; align-items: center;
gap: 11px; gap: 11px;
padding: 12px 0; padding: 12px 0;
border-bottom: 1px solid #1b2029; border-bottom: 1px solid var(--line);
} }
.project-letter { .project-letter {
@@ -564,9 +592,9 @@ h1 {
height: 31px; height: 31px;
display: grid; display: grid;
place-items: center; place-items: center;
border: 1px solid #353047; border: 1px solid var(--line-2);
border-radius: 7px; border-radius: 7px;
color: #a99cf5; color: var(--a-mid);
font-size: 10px; font-size: 10px;
} }
@@ -581,7 +609,7 @@ h1 {
} }
.project b { .project b {
color: #838c9c; color: var(--tx-2);
font-size: 9px; font-size: 9px;
} }
@@ -590,14 +618,14 @@ h1 {
margin-top: 8px; margin-top: 8px;
overflow: hidden; overflow: hidden;
border-radius: 4px; border-radius: 4px;
background: #242936; background: var(--space-3);
} }
.progress i { .progress i {
display: block; display: block;
height: 100%; height: 100%;
border-radius: inherit; border-radius: inherit;
background: linear-gradient(90deg, #685ac8, #a091ff); background: var(--grad);
} }
.event { .event {
@@ -605,7 +633,7 @@ h1 {
grid-template-columns: auto 1fr; grid-template-columns: auto 1fr;
gap: 10px; gap: 10px;
padding: 12px 0; padding: 12px 0;
border-bottom: 1px solid #1b2029; border-bottom: 1px solid var(--line);
} }
.event > span { .event > span {
@@ -613,19 +641,19 @@ h1 {
height: 6px; height: 6px;
margin-top: 4px; margin-top: 4px;
border-radius: 50%; border-radius: 50%;
background: #657083; background: var(--st-idle);
} }
.event > span.runtime { .event > span.runtime {
background: var(--nx-green); background: var(--st-work);
} }
.event > span.deploy { .event > span.deploy {
background: #8b7cf6; background: var(--a-mid);
} }
.event > span.security { .event > span.security {
background: #e5ad52; background: var(--st-queue);
} }
.placeholder { .placeholder {
@@ -639,7 +667,7 @@ h1 {
.placeholder svg { .placeholder svg {
margin-bottom: 18px; margin-bottom: 18px;
color: #8074d8; color: var(--a-mid);
} }
.placeholder h2 { .placeholder h2 {
+25
View File
@@ -53,6 +53,31 @@
--sidebar-w: 248px; --sidebar-w: 248px;
--topbar-h: 62px; --topbar-h: 62px;
--rail-w: 360px; --rail-w: 360px;
/* ── Legacy-Aliasse (v1-Views) → V2-Tokens ────────────
Ältere Views konsumieren noch die v1-Variablennamen.
Nicht anfassen: --border/--accent (shadcn-HSL-Tripel,
werden als hsl(var(--…)) konsumiert). */
--nx-bg: var(--space-1);
--nx-panel: var(--glass);
--nx-panel-soft: var(--glass-2);
--nx-line: var(--line);
--nx-muted: var(--tx-3);
--nx-accent: var(--a-mid);
--nx-accent-soft: rgba(124, 108, 255, 0.10);
--nx-green: var(--st-work);
--nx-text: var(--tx);
--nx-text-dim: var(--tx-2);
--panel: var(--glass);
--card-color: var(--glass);
--surface: var(--space-2);
--surface-raised: var(--space-3);
--accent-soft: rgba(124, 108, 255, 0.10);
--accent-secondary: var(--a-purple);
--text-primary: var(--tx);
--text-secondary: var(--tx-2);
--text-muted: var(--tx-3);
--text-dim: var(--tx-3);
} }
/* ── Glass card utility ────────────────────────────── */ /* ── Glass card utility ────────────────────────────── */
+28 -17
View File
@@ -35,9 +35,10 @@ defineEmits<{
display: flex; display: flex;
align-items: center; align-items: center;
gap: 12px; gap: 12px;
padding: 10px 20px; padding: 12px 22px;
border-bottom: 1px solid var(--nx-line, #1f2330); border-bottom: 1px solid var(--line);
background: var(--nx-panel, #11141b); background: rgba(8, 6, 20, 0.5);
backdrop-filter: blur(14px);
} }
.mobile-menu { display: none; } .mobile-menu { display: none; }
.search { .search {
@@ -45,24 +46,27 @@ defineEmits<{
align-items: center; align-items: center;
gap: 8px; gap: 8px;
flex: 1; flex: 1;
padding: 6px 12px; max-width: 560px;
border: 1px solid var(--nx-line, #1f2330); padding: 8px 14px;
border-radius: 7px; border: 1px solid var(--line);
color: var(--nx-text-dim, #6f7889); border-radius: 11px;
background: rgba(124, 108, 255, 0.06);
color: var(--tx-3);
font-size: 11px; font-size: 11px;
} }
.search kbd { .search kbd {
margin-left: auto; margin-left: auto;
padding: 1px 4px; padding: 1px 4px;
border: 1px solid #2a2f3d; border: 1px solid var(--line-2);
border-radius: 4px; border-radius: 4px;
font-size: 8px; font-size: 8px;
color: #4a5266; color: var(--tx-3);
} }
.top-actions { .top-actions {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 10px;
margin-left: auto;
} }
.connection { .connection {
display: flex; display: flex;
@@ -70,25 +74,32 @@ defineEmits<{
gap: 5px; gap: 5px;
font-size: 9px; font-size: 9px;
font-weight: 600; font-weight: 600;
padding: 4px 9px; padding: 4px 11px;
border-radius: 6px; border-radius: 20px;
border: 1px solid var(--line-2);
background: rgba(124, 108, 255, 0.07);
color: var(--tx-2);
} }
.connection.live { color: #27ae60; background: rgba(39,174,96,.1); } .connection.live { color: var(--st-work); }
.connection.preview { color: #e67e22; background: rgba(230,126,34,.1); } .connection.preview { color: var(--st-queue); }
.ask { .ask {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 5px; gap: 5px;
padding: 5px 10px; padding: 6px 12px;
border: none; border: none;
border-radius: 6px; border-radius: 10px;
background: var(--nx-accent, #7b6ef2); background: var(--grad);
box-shadow: var(--glow-purple);
color: #fff; color: #fff;
font-size: 10px; font-size: 10px;
font-weight: 600;
cursor: pointer; cursor: pointer;
transition: filter .16s;
} }
.ask:hover { filter: brightness(1.08); }
@media (max-width: 860px) { @media (max-width: 860px) {
.mobile-menu { display: flex; align-items: center; justify-content: center; padding: 6px; border: 1px solid var(--nx-line, #1f2330); border-radius: 6px; background: transparent; color: var(--nx-accent, #7b6ef2); cursor: pointer; } .mobile-menu { display: flex; align-items: center; justify-content: center; padding: 6px; border: 1px solid var(--line-2); border-radius: 9px; background: transparent; color: var(--tx-2); cursor: pointer; }
} }
</style> </style>
+43 -26
View File
@@ -104,8 +104,9 @@ async function logout() {
width: 210px; width: 210px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background: var(--panel, #11141b); background: linear-gradient(180deg, rgba(14, 12, 32, 0.92), rgba(8, 6, 20, 0.92));
border-right: 1px solid var(--line, #1f2330); border-right: 1px solid var(--line);
backdrop-filter: blur(14px);
flex-shrink: 0; flex-shrink: 0;
padding: 0 8px; padding: 0 8px;
} }
@@ -120,12 +121,13 @@ async function logout() {
height: 30px; height: 30px;
display: grid; display: grid;
place-items: center; place-items: center;
border-radius: 7px; border-radius: 9px;
background: var(--accent, #7b6ef2); background: var(--grad);
box-shadow: var(--glow-purple);
color: #fff; color: #fff;
} }
.brand div strong { display: block; font-size: 10px; letter-spacing: .08em; } .brand div strong { display: block; font-family: 'Space Grotesk', sans-serif; font-size: 10px; letter-spacing: .12em; }
.brand div span { font-size: 8px; color: var(--text-dim, #6f7889); } .brand div span { font-size: 8px; color: var(--tx-3); }
.nav { .nav {
flex: 1; flex: 1;
display: flex; display: flex;
@@ -141,36 +143,45 @@ async function logout() {
width: 100%; width: 100%;
padding: 8px 10px; padding: 8px 10px;
border: none; border: none;
border-radius: 6px; border-radius: 10px;
background: transparent; background: transparent;
color: #9ea5b3; color: var(--tx-2);
font-size: 10.5px; font-size: 10.5px;
text-align: left; text-align: left;
cursor: pointer; cursor: pointer;
transition: background .15s, color .15s; transition: background .15s, color .15s;
} }
.nav button:hover { background: var(--accent-soft, rgba(123,110,242,.08)); color: #d8dbe3; } .nav button:hover { background: rgba(124,108,255,.08); color: var(--tx); }
.nav button.active { background: var(--accent-soft, rgba(123,110,242,.08)); color: var(--accent, #7b6ef2); font-weight: 600; } .nav button.active {
background: linear-gradient(90deg, rgba(124,108,255,.22), rgba(124,108,255,.04));
box-shadow: inset 0 0 0 1px rgba(124,108,255,.25);
color: #fff;
font-weight: 600;
}
.nav button i { .nav button i {
margin-left: auto; margin-left: auto;
background: var(--accent, #7b6ef2); background: rgba(124,108,255,.14);
color: #fff; border: 1px solid var(--line-2);
color: var(--tx);
font-family: 'JetBrains Mono', monospace;
font-style: normal; font-style: normal;
font-size: 8px; font-size: 8px;
font-weight: 700; font-weight: 700;
padding: 1px 5px; padding: 1px 6px;
border-radius: 5px; border-radius: 20px;
line-height: 1.4; line-height: 1.4;
} }
.nav button i.badge-red { .nav button i.badge-red {
background: #e16e75; background: rgba(251,113,133,.18);
border-color: rgba(251,113,133,.4);
color: var(--st-block);
} }
.nav-separator { .nav-separator {
height: 1px; height: 1px;
margin: 6px 10px; margin: 6px 10px;
background: var(--nx-line, #1f2330); background: var(--line);
} }
.sidebar-bottom { padding: 8px 0; border-top: 1px solid var(--nx-line, #1f2330); } .sidebar-bottom { padding: 8px 0; border-top: 1px solid var(--line); }
.sidebar-bottom > button { .sidebar-bottom > button {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -178,33 +189,39 @@ async function logout() {
width: 100%; width: 100%;
padding: 8px 10px; padding: 8px 10px;
border: none; border: none;
border-radius: 6px; border-radius: 10px;
background: transparent; background: transparent;
color: #9ea5b3; color: var(--tx-2);
font-size: 10.5px; font-size: 10.5px;
cursor: pointer; cursor: pointer;
transition: background .15s, color .15s; transition: background .15s, color .15s;
} }
.sidebar-bottom > button:hover { background: var(--nx-accent-soft, rgba(123,110,242,.08)); color: #d8dbe3; } .sidebar-bottom > button:hover { background: rgba(124,108,255,.08); color: var(--tx); }
.sidebar-bottom > button.active { background: var(--nx-accent-soft, rgba(123,110,242,.08)); color: var(--nx-accent, #7b6ef2); font-weight: 600; } .sidebar-bottom > button.active {
background: linear-gradient(90deg, rgba(124,108,255,.22), rgba(124,108,255,.04));
box-shadow: inset 0 0 0 1px rgba(124,108,255,.25);
color: #fff;
font-weight: 600;
}
.owner { .owner {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: 8px;
margin-top: 6px; margin-top: 6px;
} }
.owner div strong { display: block; font-size: 9px; } .owner div strong { display: block; font-size: 9px; color: var(--tx); }
.owner div span { font-size: 7.5px; color: var(--text-dim, #6f7889); text-transform: capitalize; } .owner div span { font-size: 7.5px; color: var(--tx-3); text-transform: capitalize; }
.owner > svg:last-child { margin-left: auto; opacity: .4; transition: opacity .15s; } .owner > svg:last-child { margin-left: auto; opacity: .4; transition: opacity .15s; }
.owner:hover > svg:last-child { opacity: 1; } .owner:hover > svg:last-child { opacity: 1; }
.avatar { .avatar {
width: 26px; width: 26px;
height: 26px; height: 26px;
border-radius: 6px; border-radius: 8px;
display: grid; display: grid;
place-items: center; place-items: center;
background: var(--accent, #7b6ef2); background: var(--grad-soft);
color: #fff; border: 1px solid var(--line-2);
color: var(--tx);
font-size: 9px; font-size: 9px;
font-weight: 700; font-weight: 700;
} }
+7
View File
@@ -25,6 +25,7 @@ export const icons: Record<string, string> = {
arrow: `<path d="M5 12h14M13 6l6 6-6 6"/>`, arrow: `<path d="M5 12h14M13 6l6 6-6 6"/>`,
plus: `<path d="M12 5v14M5 12h14"/>`, plus: `<path d="M12 5v14M5 12h14"/>`,
command: `<path d="M7 4a3 3 0 0 0-3 3v10a3 3 0 0 0 3 3h10a3 3 0 0 0 3-3V7a3 3 0 0 0-3-3H7z"/><path d="M12 8v8M8 12h8"/>`, command: `<path d="M7 4a3 3 0 0 0-3 3v10a3 3 0 0 0 3 3h10a3 3 0 0 0 3-3V7a3 3 0 0 0-3-3H7z"/><path d="M12 8v8M8 12h8"/>`,
gear: `<circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.7 1.7 0 0 0 .34 1.87l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.7 1.7 0 0 0-1.87-.34 1.7 1.7 0 0 0-1.03 1.56V21a2 2 0 1 1-4 0v-.09a1.7 1.7 0 0 0-1.11-1.56 1.7 1.7 0 0 0-1.87.34l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.7 1.7 0 0 0 .34-1.87 1.7 1.7 0 0 0-1.56-1.03H3a2 2 0 1 1 0-4h.09a1.7 1.7 0 0 0 1.56-1.11 1.7 1.7 0 0 0-.34-1.87l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.7 1.7 0 0 0 1.87.34h.09a1.7 1.7 0 0 0 1.03-1.56V3a2 2 0 1 1 4 0v.09a1.7 1.7 0 0 0 1.03 1.56 1.7 1.7 0 0 0 1.87-.34l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.7 1.7 0 0 0-.34 1.87v.09a1.7 1.7 0 0 0 1.56 1.03H21a2 2 0 1 1 0 4h-.09a1.7 1.7 0 0 0-1.51 1.87Z"/>`,
chevron_left: `<path d="m15 18-6-6 6-6"/>`, chevron_left: `<path d="m15 18-6-6 6-6"/>`,
chevron_right: `<path d="m9 18 6-6-6-6"/>`, chevron_right: `<path d="m9 18 6-6-6-6"/>`,
dots: `<circle cx="12" cy="12" r="1.5"/><circle cx="19" cy="12" r="1.5"/><circle cx="5" cy="12" r="1.5"/>`, dots: `<circle cx="12" cy="12" r="1.5"/><circle cx="19" cy="12" r="1.5"/><circle cx="5" cy="12" r="1.5"/>`,
@@ -86,4 +87,10 @@ export const navigation: NavGroupDef[] = [
{ icon: 'alert', label: 'Incidents', route: '/incidents' }, { icon: 'alert', label: 'Incidents', route: '/incidents' },
], ],
}, },
{
group: 'System',
items: [
{ icon: 'gear', label: 'Settings', route: '/settings' },
],
},
] ]
+34 -34
View File
@@ -143,10 +143,10 @@ function formatModifiedAt(dateStr: string): string {
const statusColor = (status: string): string => { const statusColor = (status: string): string => {
switch (status) { switch (status) {
case 'Online': return '#51d49a' case 'Online': return 'var(--st-work)'
case 'Degraded': return '#e5b05e' case 'Degraded': return 'var(--st-queue)'
case 'Offline': return '#e16e75' case 'Offline': return 'var(--st-block)'
default: return '#7e8799' default: return 'var(--tx-3)'
} }
} }
@@ -612,15 +612,15 @@ onUnmounted(() => {
border: 1px solid var(--line); border: 1px solid var(--line);
border-radius: 7px; border-radius: 7px;
background: var(--panel); background: var(--panel);
color: #7e8799; color: var(--tx-3);
font-size: 10.5px; font-size: 10.5px;
cursor: pointer; cursor: pointer;
margin-bottom: 20px; margin-bottom: 20px;
transition: border-color 0.15s, color 0.15s; transition: border-color 0.15s, color 0.15s;
} }
.back-link:hover { .back-link:hover {
border-color: #443d7c; border-color: var(--line-3);
color: #d8dbe3; color: var(--tx);
} }
.status-message { .status-message {
@@ -629,11 +629,11 @@ onUnmounted(() => {
justify-content: center; justify-content: center;
gap: 8px; gap: 8px;
padding: 48px; padding: 48px;
color: #7e8799; color: var(--tx-3);
font-size: 12px; font-size: 12px;
} }
.status-message.error { .status-message.error {
color: #e16e75; color: var(--st-block);
} }
.status-message.compact { .status-message.compact {
padding: 20px; padding: 20px;
@@ -660,15 +660,15 @@ onUnmounted(() => {
place-items: center; place-items: center;
border-radius: 12px; border-radius: 12px;
background: rgba(139,124,246,.1); background: rgba(139,124,246,.1);
color: #8b7cf6; color: var(--a-mid);
flex-shrink: 0; flex-shrink: 0;
} }
.agent-avatar.iris { background: rgba(139,124,246,.15); color: #8b7cf6; } .agent-avatar.iris { background: rgba(139,124,246,.15); color: var(--a-mid); }
.agent-avatar.programmer { background: rgba(77,140,246,.15); color: #4d8cf6; } .agent-avatar.programmer { background: rgba(77,140,246,.15); color: var(--a-blue); }
.agent-avatar.architekt { background: rgba(77,168,246,.15); color: #4da8f6; } .agent-avatar.architekt { background: rgba(77,168,246,.15); color: var(--a-blue); }
.agent-avatar.reviewer { background: rgba(246,168,77,.15); color: #f6a84d; } .agent-avatar.reviewer { background: rgba(246,168,77,.15); color: var(--st-queue); }
.agent-avatar.researcher { background: rgba(139,77,246,.15); color: #8b4df6; } .agent-avatar.researcher { background: rgba(139,77,246,.15); color: var(--a-purple); }
.agent-avatar.executor { background: rgba(77,246,212,.15); color: #4df6d4; } .agent-avatar.executor { background: rgba(77,246,212,.15); color: var(--st-think); }
.agent-header-info { .agent-header-info {
flex: 1; flex: 1;
@@ -678,7 +678,7 @@ onUnmounted(() => {
font-size: 8.5px; font-size: 8.5px;
font-weight: 700; font-weight: 700;
letter-spacing: .12em; letter-spacing: .12em;
color: var(--accent, #7b6ef2); color: var(--a-mid);
text-transform: uppercase; text-transform: uppercase;
margin-bottom: 2px; margin-bottom: 2px;
} }
@@ -686,7 +686,7 @@ onUnmounted(() => {
margin: 0 0 4px; margin: 0 0 4px;
font-size: 20px; font-size: 20px;
font-weight: 600; font-weight: 600;
color: #e8eaf0; color: var(--tx);
} }
.agent-status-row { .agent-status-row {
display: flex; display: flex;
@@ -702,18 +702,18 @@ onUnmounted(() => {
} }
.status-label { .status-label {
font-size: 11px; font-size: 11px;
color: #7e8799; color: var(--tx-3);
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
gap: 4px; gap: 4px;
} }
.status-label.muted { color: #6b7385; } .status-label.muted { color: var(--tx-3); }
.status-label.mono { font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace; } .status-label.mono { font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace; }
.status-sep { color: #3d4152; font-size: 11px; } .status-sep { color: var(--line-2); font-size: 11px; }
.thinking-section { .thinking-section {
border: 1px solid var(--line); border: 1px solid var(--line);
border-radius: 9px; border-radius: var(--r);
background: var(--panel); background: var(--panel);
margin-bottom: 16px; margin-bottom: 16px;
overflow: hidden; overflow: hidden;
@@ -731,11 +731,11 @@ onUnmounted(() => {
font-size: 8.5px; font-size: 8.5px;
font-weight: 700; font-weight: 700;
letter-spacing: .12em; letter-spacing: .12em;
color: var(--accent, #7b6ef2); color: var(--a-mid);
} }
.section-head h2 { .section-head h2 {
margin: 2px 0 0; margin: 2px 0 0;
color: #e8eaf0; color: var(--tx);
font-size: 13px; font-size: 13px;
font-weight: 600; font-weight: 600;
display: inline-flex; display: inline-flex;
@@ -744,7 +744,7 @@ onUnmounted(() => {
} }
.section-note { .section-note {
margin: 6px 0 0; margin: 6px 0 0;
color: #6f788b; color: var(--tx-3);
font-size: 10px; font-size: 10px;
line-height: 1.45; line-height: 1.45;
max-width: 560px; max-width: 560px;
@@ -753,10 +753,10 @@ onUnmounted(() => {
width: 6px; width: 6px;
height: 6px; height: 6px;
border-radius: 999px; border-radius: 999px;
background: #6b7385; background: var(--tx-3);
} }
.live-dot.on { .live-dot.on {
background: #51d49a; background: var(--st-work);
} }
.icon-button { .icon-button {
width: 30px; width: 30px;
@@ -764,7 +764,7 @@ onUnmounted(() => {
border: 1px solid var(--line); border: 1px solid var(--line);
border-radius: 7px; border-radius: 7px;
background: rgba(255,255,255,.03); background: rgba(255,255,255,.03);
color: #9ba3b5; color: var(--tx-2);
display: grid; display: grid;
place-items: center; place-items: center;
cursor: pointer; cursor: pointer;
@@ -790,13 +790,13 @@ onUnmounted(() => {
.summary-card small { .summary-card small {
display: block; display: block;
margin-top: 7px; margin-top: 7px;
color: #6f788b; color: var(--tx-3);
font-size: 9.5px; font-size: 9.5px;
line-height: 1.4; line-height: 1.4;
} }
.summary-row span { .summary-row span {
display: block; display: block;
color: #6f788b; color: var(--tx-3);
font-size: 9px; font-size: 9px;
font-weight: 700; font-weight: 700;
text-transform: uppercase; text-transform: uppercase;
@@ -804,7 +804,7 @@ onUnmounted(() => {
} }
.summary-row p { .summary-row p {
margin: 0; margin: 0;
color: #cbd0dc; color: var(--tx-2);
font-size: 11px; font-size: 11px;
line-height: 1.5; line-height: 1.5;
overflow-wrap: anywhere; overflow-wrap: anywhere;
@@ -821,20 +821,20 @@ onUnmounted(() => {
align-items: center; align-items: center;
gap: 8px; gap: 8px;
margin-bottom: 6px; margin-bottom: 6px;
color: #6f788b; color: var(--tx-3);
font-size: 10px; font-size: 10px;
} }
.type-pill { .type-pill {
padding: 2px 6px; padding: 2px 6px;
border-radius: 999px; border-radius: 999px;
border: 1px solid rgba(123,110,242,.24); border: 1px solid rgba(123,110,242,.24);
color: #aaa1ff; color: var(--a-mid);
background: rgba(123,110,242,.08); background: rgba(123,110,242,.08);
font-size: 9px; font-size: 9px;
} }
.thinking-item p { .thinking-item p {
margin: 0; margin: 0;
color: #cbd0dc; color: var(--tx-2);
font-size: 11px; font-size: 11px;
line-height: 1.55; line-height: 1.55;
overflow-wrap: anywhere; overflow-wrap: anywhere;
+35 -35
View File
@@ -41,7 +41,7 @@ const fallbackAgents: AgentCard[] = [
role: 'Chief of Staff', role: 'Chief of Staff',
description: 'Koordiniert, delegiert, hält das Team tight. Die erste Anlaufstelle zwischen Boss und Maschine.', description: 'Koordiniert, delegiert, hält das Team tight. Die erste Anlaufstelle zwischen Boss und Maschine.',
tags: ['Orchestration', 'Delegation', 'Approval'], tags: ['Orchestration', 'Delegation', 'Approval'],
color: '#8b7cf6', color: '#7c6cff',
icon: 'bot', icon: 'bot',
}, },
{ {
@@ -50,7 +50,7 @@ const fallbackAgents: AgentCard[] = [
role: 'Lead Developer', role: 'Lead Developer',
description: 'Implementiert Features, schreibt Code, führt Builds und Tests aus. Arbeitet autonom im Scope.', description: 'Implementiert Features, schreibt Code, führt Builds und Tests aus. Arbeitet autonom im Scope.',
tags: ['Coding', 'Development', 'Builds'], tags: ['Coding', 'Development', 'Builds'],
color: '#4d8cf6', color: '#4f7cff',
icon: 'code', icon: 'code',
}, },
{ {
@@ -59,7 +59,7 @@ const fallbackAgents: AgentCard[] = [
role: 'Infrastructure Engineer', role: 'Infrastructure Engineer',
description: 'Verantwortlich für Docker, Nginx, Deployment und VPS-Infrastruktur.', description: 'Verantwortlich für Docker, Nginx, Deployment und VPS-Infrastruktur.',
tags: ['Infrastructure', 'Deployment', 'Docker'], tags: ['Infrastructure', 'Deployment', 'Docker'],
color: '#4da8f6', color: '#4f7cff',
icon: 'server', icon: 'server',
}, },
{ {
@@ -68,7 +68,7 @@ const fallbackAgents: AgentCard[] = [
role: 'Code QA', role: 'Code QA',
description: 'Prüft Code auf Bugs, Sicherheit und Wartbarkeit. Fixt Probleme eigenständig.', description: 'Prüft Code auf Bugs, Sicherheit und Wartbarkeit. Fixt Probleme eigenständig.',
tags: ['QA', 'Security', 'Code Review'], tags: ['QA', 'Security', 'Code Review'],
color: '#f6a84d', color: '#fbbf24',
icon: 'shield', icon: 'shield',
}, },
{ {
@@ -77,7 +77,7 @@ const fallbackAgents: AgentCard[] = [
role: 'Research Analyst', role: 'Research Analyst',
description: 'Recherchiert, analysiert Quellen, prüft Fakten. Nur Lese-Rechte, keine Aktionen.', description: 'Recherchiert, analysiert Quellen, prüft Fakten. Nur Lese-Rechte, keine Aktionen.',
tags: ['Research', 'Analysis', 'Fact-Checking'], tags: ['Research', 'Analysis', 'Fact-Checking'],
color: '#8b4df6', color: '#b557f6',
icon: 'search', icon: 'search',
}, },
{ {
@@ -86,7 +86,7 @@ const fallbackAgents: AgentCard[] = [
role: 'Host Executor', role: 'Host Executor',
description: 'Führt Host-Kommandos auf dem VPS aus. Nur auf Iris-Befehl, niemals eigeninitiativ.', description: 'Führt Host-Kommandos auf dem VPS aus. Nur auf Iris-Befehl, niemals eigeninitiativ.',
tags: ['Execution', 'Docker', 'VPS'], tags: ['Execution', 'Docker', 'VPS'],
color: '#4df6d4', color: '#34d6f5',
icon: 'terminal', icon: 'terminal',
}, },
] ]
@@ -161,7 +161,7 @@ function enrichAgent(item: any): AgentCard {
role: item.role || fallback?.role || 'Agent', role: item.role || fallback?.role || 'Agent',
description: item.description || fallback?.description || 'OpenClaw agent', description: item.description || fallback?.description || 'OpenClaw agent',
tags: item.tags?.length ? item.tags : fallback?.tags ?? [], tags: item.tags?.length ? item.tags : fallback?.tags ?? [],
color: fallback?.color ?? '#7e8799', color: fallback?.color ?? '#6f6aa0',
icon: fallback?.icon ?? 'bot', icon: fallback?.icon ?? 'bot',
model: item.model, model: item.model,
statusLabel: item.statusLabel, statusLabel: item.statusLabel,
@@ -327,19 +327,19 @@ onMounted(loadMissionControl)
place-items: center; place-items: center;
border-radius: 11px; border-radius: 11px;
background: rgba(139, 124, 246, 0.1); background: rgba(139, 124, 246, 0.1);
color: #8b7cf6; color: var(--a-mid);
flex-shrink: 0; flex-shrink: 0;
} }
.header-text h1 { .header-text h1 {
margin: 0 0 2px; margin: 0 0 2px;
font-size: 22px; font-size: 22px;
font-weight: 600; font-weight: 600;
color: #e8eaf0; color: var(--tx);
} }
.header-subtitle { .header-subtitle {
margin: 0; margin: 0;
font-size: 11px; font-size: 11px;
color: #7e8799; color: var(--tx-3);
} }
.gateway-chip { .gateway-chip {
margin-left: auto; margin-left: auto;
@@ -349,24 +349,24 @@ onMounted(loadMissionControl)
padding: 6px 9px; padding: 6px 9px;
border: 1px solid var(--line); border: 1px solid var(--line);
border-radius: 7px; border-radius: 7px;
color: #9ba3b5; color: var(--tx-2);
font-size: 10px; font-size: 10px;
} }
.gateway-chip.ok { .gateway-chip.ok {
color: #51d49a; color: var(--st-work);
border-color: rgba(81, 212, 154, .25); border-color: rgba(81, 212, 154, .25);
} }
.gateway-chip.warn { .gateway-chip.warn {
color: #e5b05e; color: var(--st-queue);
border-color: rgba(229, 176, 94, .28); border-color: rgba(229, 176, 94, .28);
} }
.gateway-chip.error { .gateway-chip.error {
color: #f29b9b; color: var(--st-block);
border-color: rgba(242, 155, 155, .3); border-color: rgba(242, 155, 155, .3);
} }
.load-error { .load-error {
margin-bottom: 14px; margin-bottom: 14px;
color: #e5b05e; color: var(--st-queue);
font-size: 11px; font-size: 11px;
} }
.gateway-warning, .gateway-warning,
@@ -376,19 +376,19 @@ onMounted(loadMissionControl)
border-radius: 11px; border-radius: 11px;
border: 1px solid rgba(229, 176, 94, .24); border: 1px solid rgba(229, 176, 94, .24);
background: rgba(229, 176, 94, .08); background: rgba(229, 176, 94, .08);
color: #f1d7aa; color: var(--st-queue);
font-size: 11px; font-size: 11px;
line-height: 1.5; line-height: 1.5;
} }
.empty-state { .empty-state {
border-color: var(--line); border-color: var(--line);
background: rgba(255,255,255,.03); background: rgba(255,255,255,.03);
color: #aab2c3; color: var(--tx-2);
} }
.empty-state h3 { .empty-state h3 {
margin: 0 0 6px; margin: 0 0 6px;
font-size: 14px; font-size: 14px;
color: #e8eaf0; color: var(--tx);
} }
.empty-state p { .empty-state p {
margin: 0; margin: 0;
@@ -451,7 +451,7 @@ onMounted(loadMissionControl)
height: 36px; height: 36px;
display: grid; display: grid;
place-items: center; place-items: center;
border-radius: 9px; border-radius: var(--r);
flex-shrink: 0; flex-shrink: 0;
} }
@@ -464,19 +464,19 @@ onMounted(loadMissionControl)
margin: 0 0 1px; margin: 0 0 1px;
font-size: 13px; font-size: 13px;
font-weight: 600; font-weight: 600;
color: #e8eaf0; color: var(--tx);
} }
.card-role { .card-role {
display: block; display: block;
font-size: 9px; font-size: 9px;
color: #7e8799; color: var(--tx-3);
letter-spacing: 0.02em; letter-spacing: 0.02em;
} }
.card-desc { .card-desc {
font-size: 10.5px; font-size: 10.5px;
color: #7e8799; color: var(--tx-3);
line-height: 1.5; line-height: 1.5;
margin: 0 0 10px; margin: 0 0 10px;
flex: 1; flex: 1;
@@ -486,7 +486,7 @@ onMounted(loadMissionControl)
align-items: center; align-items: center;
gap: 6px; gap: 6px;
margin-bottom: 8px; margin-bottom: 8px;
color: #8a92a5; color: var(--tx-2);
font-size: 9.5px; font-size: 9.5px;
min-width: 0; min-width: 0;
} }
@@ -494,19 +494,19 @@ onMounted(loadMissionControl)
width: 7px; width: 7px;
height: 7px; height: 7px;
border-radius: 999px; border-radius: 999px;
background: #6b7385; background: var(--tx-3);
flex-shrink: 0; flex-shrink: 0;
} }
.runtime-dot.on { .runtime-dot.on {
background: #51d49a; background: var(--st-work);
} }
.runtime-dot.connected { background: #51d49a; } .runtime-dot.connected { background: var(--st-work); }
.runtime-dot.thinking { background: #79aaff; } .runtime-dot.thinking { background: var(--a-blue); }
.runtime-dot.blocked { background: #f87171; } .runtime-dot.blocked { background: var(--st-block); }
.runtime-dot.stale { background: #f59e0b; } .runtime-dot.stale { background: var(--st-queue); }
.runtime-dot.error { background: #f29b9b; } .runtime-dot.error { background: var(--st-block); }
.runtime-dot.unsupported { background: #e5b05e; } .runtime-dot.unsupported { background: var(--st-queue); }
.runtime-dot.ready { background: #6b7385; } .runtime-dot.ready { background: var(--tx-3); }
.runtime-model { .runtime-model {
margin-left: auto; margin-left: auto;
max-width: 46%; max-width: 46%;
@@ -514,12 +514,12 @@ onMounted(loadMissionControl)
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace; font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
color: #6f788b; color: var(--tx-3);
} }
.runtime-detail { .runtime-detail {
margin: 0 0 10px; margin: 0 0 10px;
min-height: 28px; min-height: 28px;
color: #7e8799; color: var(--tx-3);
font-size: 10px; font-size: 10px;
line-height: 1.4; line-height: 1.4;
} }
@@ -561,7 +561,7 @@ onMounted(loadMissionControl)
border-top: 1px solid var(--line); border-top: 1px solid var(--line);
font-size: 9px; font-size: 9px;
font-weight: 600; font-weight: 600;
color: #6b7385; color: var(--tx-3);
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.06em; letter-spacing: 0.06em;
transition: color 0.15s; transition: color 0.15s;
+20 -20
View File
@@ -219,7 +219,7 @@ onMounted(() => {
} }
.calendar-panel { .calendar-panel {
border: 1px solid var(--line); border: 1px solid var(--line);
border-radius: 9px; border-radius: var(--r);
background: var(--panel); background: var(--panel);
padding: 16px; padding: 16px;
} }
@@ -235,7 +235,7 @@ onMounted(() => {
margin: 0; margin: 0;
font-size: 13px; font-size: 13px;
font-weight: 600; font-weight: 600;
color: #e8eaf0; color: var(--tx);
} }
.calendar-status { .calendar-status {
display: flex; display: flex;
@@ -243,11 +243,11 @@ onMounted(() => {
justify-content: center; justify-content: center;
gap: 8px; gap: 8px;
padding: 32px; padding: 32px;
color: #7e8799; color: var(--tx-3);
font-size: 11px; font-size: 11px;
} }
.calendar-status.error { .calendar-status.error {
color: #e16e75; color: var(--st-block);
} }
/* Upcoming jobs */ /* Upcoming jobs */
@@ -268,25 +268,25 @@ onMounted(() => {
display: grid; display: grid;
place-items: center; place-items: center;
border-radius: 6px; border-radius: 6px;
color: #a99cf5; color: var(--a-mid);
background: rgba(139,124,246,.1); background: rgba(139,124,246,.1);
} }
.upcoming-item-info strong { .upcoming-item-info strong {
display: block; display: block;
font-size: 11px; font-size: 11px;
margin-bottom: 2px; margin-bottom: 2px;
color: #e8eaf0; color: var(--tx);
} }
.upcoming-item-schedule { .upcoming-item-schedule {
display: block; display: block;
font-size: 9px; font-size: 9px;
color: #7e8799; color: var(--tx-3);
margin-bottom: 2px; margin-bottom: 2px;
} }
.upcoming-item-next { .upcoming-item-next {
display: block; display: block;
font-size: 9px; font-size: 9px;
color: #a99cf5; color: var(--a-mid);
font-weight: 600; font-weight: 600;
} }
@@ -310,19 +310,19 @@ onMounted(() => {
border-radius: 6px; border-radius: 6px;
} }
.job-item-icon.status-completed { .job-item-icon.status-completed {
color: #27ae60; color: var(--st-work);
background: rgba(39, 174, 96, 0.12); background: rgba(39, 174, 96, 0.12);
} }
.job-item-icon.status-running { .job-item-icon.status-running {
color: #3498db; color: var(--a-blue);
background: rgba(52, 152, 219, 0.12); background: rgba(52, 152, 219, 0.12);
} }
.job-item-icon.status-failed { .job-item-icon.status-failed {
color: #e74c3c; color: var(--st-block);
background: rgba(231, 76, 60, 0.12); background: rgba(231, 76, 60, 0.12);
} }
.job-item-icon.status-idle { .job-item-icon.status-idle {
color: #7e8799; color: var(--tx-3);
background: rgba(126, 135, 153, 0.12); background: rgba(126, 135, 153, 0.12);
} }
.job-item-info { .job-item-info {
@@ -332,19 +332,19 @@ onMounted(() => {
display: block; display: block;
font-size: 11px; font-size: 11px;
margin-bottom: 2px; margin-bottom: 2px;
color: #e8eaf0; color: var(--tx);
} }
.job-item-id { .job-item-id {
display: block; display: block;
font-size: 9px; font-size: 9px;
color: #6b7385; color: var(--tx-3);
margin-bottom: 2px; margin-bottom: 2px;
font-family: monospace; font-family: monospace;
} }
.job-item-schedule { .job-item-schedule {
display: block; display: block;
font-size: 9px; font-size: 9px;
color: #7e8799; color: var(--tx-3);
} }
.job-item-meta { .job-item-meta {
display: flex; display: flex;
@@ -355,7 +355,7 @@ onMounted(() => {
} }
.job-item-meta small { .job-item-meta small {
font-size: 8px; font-size: 8px;
color: #6b7385; color: var(--tx-3);
text-align: right; text-align: right;
} }
.job-status-badge { .job-status-badge {
@@ -368,19 +368,19 @@ onMounted(() => {
} }
.job-status-badge.status-completed { .job-status-badge.status-completed {
background: rgba(39, 174, 96, 0.15); background: rgba(39, 174, 96, 0.15);
color: #27ae60; color: var(--st-work);
} }
.job-status-badge.status-running { .job-status-badge.status-running {
background: rgba(52, 152, 219, 0.15); background: rgba(52, 152, 219, 0.15);
color: #3498db; color: var(--a-blue);
} }
.job-status-badge.status-failed { .job-status-badge.status-failed {
background: rgba(231, 76, 60, 0.15); background: rgba(231, 76, 60, 0.15);
color: #e74c3c; color: var(--st-block);
} }
.job-status-badge.status-idle { .job-status-badge.status-idle {
background: rgba(126, 135, 153, 0.15); background: rgba(126, 135, 153, 0.15);
color: #7e8799; color: var(--tx-3);
} }
.spin { .spin {
animation: spin 1s linear infinite; animation: spin 1s linear infinite;
+32 -32
View File
@@ -203,14 +203,14 @@ onMounted(loadDocs)
border: 1px solid var(--line); border: 1px solid var(--line);
border-radius: 8px; border-radius: 8px;
background: var(--panel); background: var(--panel);
color: #6f7889; color: var(--tx-3);
} }
.docs-search-bar input { .docs-search-bar input {
flex: 1; flex: 1;
border: none; border: none;
outline: none; outline: none;
background: transparent; background: transparent;
color: #e8eaf0; color: var(--tx);
font: inherit; font: inherit;
font-size: 13px; font-size: 13px;
} }
@@ -222,13 +222,13 @@ onMounted(loadDocs)
border: 1px solid var(--line); border: 1px solid var(--line);
border-radius: 8px; border-radius: 8px;
background: var(--panel); background: var(--panel);
color: #8991a1; color: var(--tx-2);
} }
.docs-filter-group select { .docs-filter-group select {
border: none; border: none;
outline: none; outline: none;
background: transparent; background: transparent;
color: #e8eaf0; color: var(--tx);
font: inherit; font: inherit;
font-size: 12px; font-size: 12px;
cursor: pointer; cursor: pointer;
@@ -241,7 +241,7 @@ onMounted(loadDocs)
} }
.memory-sidebar { .memory-sidebar {
border: 1px solid var(--line); border: 1px solid var(--line);
border-radius: 9px; border-radius: var(--r);
background: var(--panel); background: var(--panel);
padding: 8px; padding: 8px;
max-height: 640px; max-height: 640px;
@@ -250,7 +250,7 @@ onMounted(loadDocs)
.memory-list-header { .memory-list-header {
font-size: 9px; font-size: 9px;
font-weight: 700; font-weight: 700;
color: #7065c8; color: var(--a-mid);
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.14em; letter-spacing: 0.14em;
padding: 10px 8px 6px; padding: 10px 8px 6px;
@@ -264,7 +264,7 @@ onMounted(loadDocs)
border: none; border: none;
border-radius: 7px; border-radius: 7px;
background: transparent; background: transparent;
color: #e8eaf0; color: var(--tx);
text-align: left; text-align: left;
cursor: pointer; cursor: pointer;
font: inherit; font: inherit;
@@ -280,7 +280,7 @@ onMounted(loadDocs)
display: grid; display: grid;
place-items: center; place-items: center;
border-radius: 6px; border-radius: 6px;
color: #a99cf5; color: var(--a-mid);
background: rgba(139,124,246,.1); background: rgba(139,124,246,.1);
} }
.memory-file-info strong { .memory-file-info strong {
@@ -305,41 +305,41 @@ onMounted(loadDocs)
} }
.doc-category-badge.cat-phases { .doc-category-badge.cat-phases {
background: rgba(139,124,246,.12); background: rgba(139,124,246,.12);
color: #a99cf5; color: var(--a-mid);
} }
.doc-category-badge.cat-skills { .doc-category-badge.cat-skills {
background: rgba(81,212,154,.1); background: rgba(81,212,154,.1);
color: #51d49a; color: var(--st-work);
} }
.doc-category-badge.cat-workspace { .doc-category-badge.cat-workspace {
background: rgba(229,176,94,.1); background: rgba(229,176,94,.1);
color: #e5b05e; color: var(--st-queue);
} }
.doc-category-badge.cat-nexus { .doc-category-badge.cat-nexus {
background: rgba(109,159,230,.1); background: rgba(109,159,230,.1);
color: #6d9fe6; color: var(--a-blue);
} }
.doc-category-badge.cat-nexus-phases { .doc-category-badge.cat-nexus-phases {
background: rgba(225,110,117,.1); background: rgba(225,110,117,.1);
color: #e16e75; color: var(--st-block);
} }
.doc-type-tag { .doc-type-tag {
font-size: 8px; font-size: 8px;
padding: 1px 5px; padding: 1px 5px;
border: 1px solid #343947; border: 1px solid var(--line-2);
border-radius: 4px; border-radius: 4px;
color: #8991a1; color: var(--tx-2);
} }
.memory-file-meta { .memory-file-meta {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 4px; gap: 4px;
font-size: 9px; font-size: 9px;
color: #7e8799; color: var(--tx-3);
} }
.memory-content { .memory-content {
border: 1px solid var(--line); border: 1px solid var(--line);
border-radius: 9px; border-radius: var(--r);
background: var(--panel); background: var(--panel);
padding: 24px; padding: 24px;
min-height: 480px; min-height: 480px;
@@ -363,7 +363,7 @@ onMounted(loadDocs)
align-items: center; align-items: center;
gap: 4px; gap: 4px;
font-size: 9px; font-size: 9px;
color: #7e8799; color: var(--tx-3);
margin-top: 4px; margin-top: 4px;
} }
.memory-back-btn { .memory-back-btn {
@@ -374,13 +374,13 @@ onMounted(loadDocs)
border: 1px solid var(--line); border: 1px solid var(--line);
border-radius: 6px; border-radius: 6px;
background: transparent; background: transparent;
color: #8991a1; color: var(--tx-2);
font-size: 10px; font-size: 10px;
cursor: pointer; cursor: pointer;
flex-shrink: 0; flex-shrink: 0;
} }
.memory-back-btn:hover { .memory-back-btn:hover {
color: #e8eaf0; color: var(--tx);
background: var(--accent-soft); background: var(--accent-soft);
} }
.memory-status { .memory-status {
@@ -389,11 +389,11 @@ onMounted(loadDocs)
justify-content: center; justify-content: center;
gap: 8px; gap: 8px;
padding: 32px; padding: 32px;
color: #7e8799; color: var(--tx-3);
font-size: 11px; font-size: 11px;
} }
.memory-status.error { .memory-status.error {
color: #e16e75; color: var(--st-block);
} }
.memory-empty-state { .memory-empty-state {
display: flex; display: flex;
@@ -402,27 +402,27 @@ onMounted(loadDocs)
justify-content: center; justify-content: center;
text-align: center; text-align: center;
min-height: 360px; min-height: 360px;
color: #6b7385; color: var(--tx-3);
} }
.memory-empty-state h3 { .memory-empty-state h3 {
margin: 12px 0 6px; margin: 12px 0 6px;
font-size: 14px; font-size: 14px;
color: #a5adba; color: var(--tx-2);
} }
.memory-empty-state p { .memory-empty-state p {
margin: 0; margin: 0;
font-size: 10px; font-size: 10px;
color: #7e8799; color: var(--tx-3);
} }
.memory-rendered { .memory-rendered {
font-size: 12px; font-size: 12px;
line-height: 1.7; line-height: 1.7;
color: #d0d4dd; color: var(--tx-2);
} }
.memory-rendered :deep(h1), .memory-rendered :deep(h1),
.memory-rendered :deep(h2), .memory-rendered :deep(h2),
.memory-rendered :deep(h3) { .memory-rendered :deep(h3) {
color: #e8eaf0; color: var(--tx);
margin: 1.2em 0 0.5em; margin: 1.2em 0 0.5em;
} }
.memory-rendered :deep(h1) { font-size: 1.3rem; } .memory-rendered :deep(h1) { font-size: 1.3rem; }
@@ -438,8 +438,8 @@ onMounted(loadDocs)
.memory-rendered :deep(pre) { .memory-rendered :deep(pre) {
padding: 12px; padding: 12px;
border-radius: 8px; border-radius: 8px;
background: #0d1016; background: var(--space-2);
border: 1px solid var(--nx-line); border: 1px solid var(--line);
overflow-x: auto; overflow-x: auto;
} }
.memory-rendered :deep(pre code) { .memory-rendered :deep(pre code) {
@@ -447,7 +447,7 @@ onMounted(loadDocs)
padding: 0; padding: 0;
} }
.memory-rendered :deep(a) { .memory-rendered :deep(a) {
color: #a99cf5; color: var(--a-mid);
text-decoration: none; text-decoration: none;
} }
.memory-rendered :deep(a:hover) { .memory-rendered :deep(a:hover) {
@@ -461,11 +461,11 @@ onMounted(loadDocs)
} }
.memory-rendered :deep(hr) { .memory-rendered :deep(hr) {
border: none; border: none;
border-top: 1px solid var(--nx-line); border-top: 1px solid var(--line);
margin: 1.2em 0; margin: 1.2em 0;
} }
.memory-rendered :deep(strong) { .memory-rendered :deep(strong) {
color: #e8eaf0; color: var(--tx);
} }
.spin { .spin {
animation: spin 1s linear infinite; animation: spin 1s linear infinite;
+29 -29
View File
@@ -202,7 +202,7 @@ onMounted(loadIncidents)
} }
.incident-sidebar { .incident-sidebar {
border: 1px solid var(--line); border: 1px solid var(--line);
border-radius: 9px; border-radius: var(--r);
background: var(--panel); background: var(--panel);
padding: 8px; padding: 8px;
max-height: 640px; max-height: 640px;
@@ -211,7 +211,7 @@ onMounted(loadIncidents)
.incident-list-header { .incident-list-header {
font-size: 9px; font-size: 9px;
font-weight: 700; font-weight: 700;
color: #7065c8; color: var(--a-mid);
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.14em; letter-spacing: 0.14em;
padding: 10px 8px 6px; padding: 10px 8px 6px;
@@ -225,7 +225,7 @@ onMounted(loadIncidents)
border: none; border: none;
border-radius: 7px; border-radius: 7px;
background: transparent; background: transparent;
color: #e8eaf0; color: var(--tx);
text-align: left; text-align: left;
cursor: pointer; cursor: pointer;
font: inherit; font: inherit;
@@ -243,19 +243,19 @@ onMounted(loadIncidents)
border-radius: 6px; border-radius: 6px;
} }
.incident-file-icon.sev-critical { .incident-file-icon.sev-critical {
color: #e74c3c; color: var(--st-block);
background: rgba(231, 76, 60, 0.12); background: rgba(231, 76, 60, 0.12);
} }
.incident-file-icon.sev-major { .incident-file-icon.sev-major {
color: #e67e22; color: var(--st-queue);
background: rgba(230, 126, 34, 0.12); background: rgba(230, 126, 34, 0.12);
} }
.incident-file-icon.sev-minor { .incident-file-icon.sev-minor {
color: #f1c40f; color: var(--st-queue);
background: rgba(241, 196, 15, 0.12); background: rgba(241, 196, 15, 0.12);
} }
.incident-file-icon.sev-unknown { .incident-file-icon.sev-unknown {
color: #7e8799; color: var(--tx-3);
background: rgba(126, 135, 153, 0.12); background: rgba(126, 135, 153, 0.12);
} }
.incident-file-info strong { .incident-file-info strong {
@@ -269,7 +269,7 @@ onMounted(loadIncidents)
align-items: center; align-items: center;
gap: 4px; gap: 4px;
font-size: 9px; font-size: 9px;
color: #7e8799; color: var(--tx-3);
margin-bottom: 4px; margin-bottom: 4px;
} }
.incident-file-excerpt { .incident-file-excerpt {
@@ -278,7 +278,7 @@ onMounted(loadIncidents)
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
overflow: hidden; overflow: hidden;
font-size: 9px; font-size: 9px;
color: #6b7385; color: var(--tx-3);
line-height: 1.5; line-height: 1.5;
} }
.severity-badge { .severity-badge {
@@ -291,23 +291,23 @@ onMounted(loadIncidents)
} }
.severity-badge.sev-critical { .severity-badge.sev-critical {
background: rgba(231, 76, 60, 0.15); background: rgba(231, 76, 60, 0.15);
color: #e74c3c; color: var(--st-block);
} }
.severity-badge.sev-major { .severity-badge.sev-major {
background: rgba(230, 126, 34, 0.15); background: rgba(230, 126, 34, 0.15);
color: #e67e22; color: var(--st-queue);
} }
.severity-badge.sev-minor { .severity-badge.sev-minor {
background: rgba(241, 196, 15, 0.15); background: rgba(241, 196, 15, 0.15);
color: #f1c40f; color: var(--st-queue);
} }
.severity-badge.sev-unknown { .severity-badge.sev-unknown {
background: rgba(126, 135, 153, 0.15); background: rgba(126, 135, 153, 0.15);
color: #7e8799; color: var(--tx-3);
} }
.incident-content { .incident-content {
border: 1px solid var(--line); border: 1px solid var(--line);
border-radius: 9px; border-radius: var(--r);
background: var(--panel); background: var(--panel);
padding: 24px; padding: 24px;
min-height: 480px; min-height: 480px;
@@ -335,7 +335,7 @@ onMounted(loadIncidents)
align-items: center; align-items: center;
gap: 4px; gap: 4px;
font-size: 9px; font-size: 9px;
color: #7e8799; color: var(--tx-3);
} }
.incident-back-btn { .incident-back-btn {
display: flex; display: flex;
@@ -345,13 +345,13 @@ onMounted(loadIncidents)
border: 1px solid var(--line); border: 1px solid var(--line);
border-radius: 6px; border-radius: 6px;
background: transparent; background: transparent;
color: #8991a1; color: var(--tx-2);
font-size: 10px; font-size: 10px;
cursor: pointer; cursor: pointer;
flex-shrink: 0; flex-shrink: 0;
} }
.incident-back-btn:hover { .incident-back-btn:hover {
color: #e8eaf0; color: var(--tx);
background: var(--accent-soft); background: var(--accent-soft);
} }
.incident-status { .incident-status {
@@ -360,11 +360,11 @@ onMounted(loadIncidents)
justify-content: center; justify-content: center;
gap: 8px; gap: 8px;
padding: 32px; padding: 32px;
color: #7e8799; color: var(--tx-3);
font-size: 11px; font-size: 11px;
} }
.incident-status.error { .incident-status.error {
color: #e16e75; color: var(--st-block);
} }
.incident-empty-state { .incident-empty-state {
display: flex; display: flex;
@@ -373,27 +373,27 @@ onMounted(loadIncidents)
justify-content: center; justify-content: center;
text-align: center; text-align: center;
min-height: 360px; min-height: 360px;
color: #6b7385; color: var(--tx-3);
} }
.incident-empty-state h3 { .incident-empty-state h3 {
margin: 12px 0 6px; margin: 12px 0 6px;
font-size: 14px; font-size: 14px;
color: #a5adba; color: var(--tx-2);
} }
.incident-empty-state p { .incident-empty-state p {
margin: 0; margin: 0;
font-size: 10px; font-size: 10px;
color: #7e8799; color: var(--tx-3);
} }
.incident-rendered { .incident-rendered {
font-size: 12px; font-size: 12px;
line-height: 1.7; line-height: 1.7;
color: #d0d4dd; color: var(--tx-2);
} }
.incident-rendered :deep(h1), .incident-rendered :deep(h1),
.incident-rendered :deep(h2), .incident-rendered :deep(h2),
.incident-rendered :deep(h3) { .incident-rendered :deep(h3) {
color: #e8eaf0; color: var(--tx);
margin: 1.2em 0 0.5em; margin: 1.2em 0 0.5em;
} }
.incident-rendered :deep(h1) { font-size: 1.3rem; } .incident-rendered :deep(h1) { font-size: 1.3rem; }
@@ -409,8 +409,8 @@ onMounted(loadIncidents)
.incident-rendered :deep(pre) { .incident-rendered :deep(pre) {
padding: 12px; padding: 12px;
border-radius: 8px; border-radius: 8px;
background: #0d1016; background: var(--space-2);
border: 1px solid var(--nx-line); border: 1px solid var(--line);
overflow-x: auto; overflow-x: auto;
} }
.incident-rendered :deep(pre code) { .incident-rendered :deep(pre code) {
@@ -418,7 +418,7 @@ onMounted(loadIncidents)
padding: 0; padding: 0;
} }
.incident-rendered :deep(a) { .incident-rendered :deep(a) {
color: #a99cf5; color: var(--a-mid);
text-decoration: none; text-decoration: none;
} }
.incident-rendered :deep(a:hover) { .incident-rendered :deep(a:hover) {
@@ -432,11 +432,11 @@ onMounted(loadIncidents)
} }
.incident-rendered :deep(hr) { .incident-rendered :deep(hr) {
border: none; border: none;
border-top: 1px solid var(--nx-line); border-top: 1px solid var(--line);
margin: 1.2em 0; margin: 1.2em 0;
} }
.incident-rendered :deep(strong) { .incident-rendered :deep(strong) {
color: #e8eaf0; color: var(--tx);
} }
.spin { .spin {
animation: spin 1s linear infinite; animation: spin 1s linear infinite;
+25 -25
View File
@@ -227,22 +227,22 @@ onMounted(loadMemories)
border-radius: 8px; border-radius: 8px;
background: var(--panel); background: var(--panel);
margin-bottom: 16px; margin-bottom: 16px;
color: #6f7889; color: var(--tx-3);
} }
.memory-search-bar input { .memory-search-bar input {
flex: 1; flex: 1;
border: none; border: none;
outline: none; outline: none;
background: transparent; background: transparent;
color: #e8eaf0; color: var(--tx);
font: inherit; font: inherit;
font-size: 13px; font-size: 13px;
} }
.memory-search-bar kbd { .memory-search-bar kbd {
padding: 2px 5px; padding: 2px 5px;
border: 1px solid #2c313d; border: 1px solid var(--line-2);
border-radius: 4px; border-radius: 4px;
color: #606979; color: var(--tx-3);
font-size: 9px; font-size: 9px;
} }
.memory-layout { .memory-layout {
@@ -253,7 +253,7 @@ onMounted(loadMemories)
} }
.memory-sidebar { .memory-sidebar {
border: 1px solid var(--line); border: 1px solid var(--line);
border-radius: 9px; border-radius: var(--r);
background: var(--panel); background: var(--panel);
padding: 8px; padding: 8px;
max-height: 640px; max-height: 640px;
@@ -262,7 +262,7 @@ onMounted(loadMemories)
.memory-list-header { .memory-list-header {
font-size: 9px; font-size: 9px;
font-weight: 700; font-weight: 700;
color: #7065c8; color: var(--a-mid);
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.14em; letter-spacing: 0.14em;
padding: 10px 8px 6px; padding: 10px 8px 6px;
@@ -276,7 +276,7 @@ onMounted(loadMemories)
border: none; border: none;
border-radius: 7px; border-radius: 7px;
background: transparent; background: transparent;
color: #e8eaf0; color: var(--tx);
text-align: left; text-align: left;
cursor: pointer; cursor: pointer;
font: inherit; font: inherit;
@@ -292,7 +292,7 @@ onMounted(loadMemories)
display: grid; display: grid;
place-items: center; place-items: center;
border-radius: 6px; border-radius: 6px;
color: #a99cf5; color: var(--a-mid);
background: rgba(139,124,246,.1); background: rgba(139,124,246,.1);
} }
.memory-file-info strong { .memory-file-info strong {
@@ -307,7 +307,7 @@ onMounted(loadMemories)
align-items: center; align-items: center;
gap: 4px; gap: 4px;
font-size: 9px; font-size: 9px;
color: #7e8799; color: var(--tx-3);
line-height: 1.5; line-height: 1.5;
} }
.memory-file-excerpt { .memory-file-excerpt {
@@ -318,7 +318,7 @@ onMounted(loadMemories)
} }
.memory-content { .memory-content {
border: 1px solid var(--line); border: 1px solid var(--line);
border-radius: 9px; border-radius: var(--r);
background: var(--panel); background: var(--panel);
padding: 24px; padding: 24px;
min-height: 480px; min-height: 480px;
@@ -342,7 +342,7 @@ onMounted(loadMemories)
align-items: center; align-items: center;
gap: 4px; gap: 4px;
font-size: 9px; font-size: 9px;
color: #7e8799; color: var(--tx-3);
} }
.memory-back-btn { .memory-back-btn {
display: flex; display: flex;
@@ -352,13 +352,13 @@ onMounted(loadMemories)
border: 1px solid var(--line); border: 1px solid var(--line);
border-radius: 6px; border-radius: 6px;
background: transparent; background: transparent;
color: #8991a1; color: var(--tx-2);
font-size: 10px; font-size: 10px;
cursor: pointer; cursor: pointer;
flex-shrink: 0; flex-shrink: 0;
} }
.memory-back-btn:hover { .memory-back-btn:hover {
color: #e8eaf0; color: var(--tx);
background: var(--accent-soft); background: var(--accent-soft);
} }
.memory-status { .memory-status {
@@ -367,11 +367,11 @@ onMounted(loadMemories)
justify-content: center; justify-content: center;
gap: 8px; gap: 8px;
padding: 32px; padding: 32px;
color: #7e8799; color: var(--tx-3);
font-size: 11px; font-size: 11px;
} }
.memory-status.error { .memory-status.error {
color: #e16e75; color: var(--st-block);
} }
.memory-empty-state { .memory-empty-state {
display: flex; display: flex;
@@ -380,27 +380,27 @@ onMounted(loadMemories)
justify-content: center; justify-content: center;
text-align: center; text-align: center;
min-height: 360px; min-height: 360px;
color: #6b7385; color: var(--tx-3);
} }
.memory-empty-state h3 { .memory-empty-state h3 {
margin: 12px 0 6px; margin: 12px 0 6px;
font-size: 14px; font-size: 14px;
color: #a5adba; color: var(--tx-2);
} }
.memory-empty-state p { .memory-empty-state p {
margin: 0; margin: 0;
font-size: 10px; font-size: 10px;
color: #7e8799; color: var(--tx-3);
} }
.memory-rendered { .memory-rendered {
font-size: 12px; font-size: 12px;
line-height: 1.7; line-height: 1.7;
color: #d0d4dd; color: var(--tx-2);
} }
.memory-rendered :deep(h1), .memory-rendered :deep(h1),
.memory-rendered :deep(h2), .memory-rendered :deep(h2),
.memory-rendered :deep(h3) { .memory-rendered :deep(h3) {
color: #e8eaf0; color: var(--tx);
margin: 1.2em 0 0.5em; margin: 1.2em 0 0.5em;
} }
.memory-rendered :deep(h1) { font-size: 1.3rem; } .memory-rendered :deep(h1) { font-size: 1.3rem; }
@@ -416,8 +416,8 @@ onMounted(loadMemories)
.memory-rendered :deep(pre) { .memory-rendered :deep(pre) {
padding: 12px; padding: 12px;
border-radius: 8px; border-radius: 8px;
background: #0d1016; background: var(--space-2);
border: 1px solid var(--nx-line); border: 1px solid var(--line);
overflow-x: auto; overflow-x: auto;
} }
.memory-rendered :deep(pre code) { .memory-rendered :deep(pre code) {
@@ -425,7 +425,7 @@ onMounted(loadMemories)
padding: 0; padding: 0;
} }
.memory-rendered :deep(a) { .memory-rendered :deep(a) {
color: #a99cf5; color: var(--a-mid);
text-decoration: none; text-decoration: none;
} }
.memory-rendered :deep(a:hover) { .memory-rendered :deep(a:hover) {
@@ -439,11 +439,11 @@ onMounted(loadMemories)
} }
.memory-rendered :deep(hr) { .memory-rendered :deep(hr) {
border: none; border: none;
border-top: 1px solid var(--nx-line); border-top: 1px solid var(--line);
margin: 1.2em 0; margin: 1.2em 0;
} }
.memory-rendered :deep(strong) { .memory-rendered :deep(strong) {
color: #e8eaf0; color: var(--tx);
} }
.spin { .spin {
animation: spin 1s linear infinite; animation: spin 1s linear infinite;
+14 -14
View File
@@ -26,10 +26,10 @@ function typeIcon(type: string): string {
function typeColor(type: string): string { function typeColor(type: string): string {
switch (type) { switch (type) {
case 'task_assigned': return '#4d8cf6' case 'task_assigned': return '#4f7cff'
case 'task_review': return '#f6a84d' case 'task_review': return '#fbbf24'
case 'task_blocked': return '#e16e75' case 'task_blocked': return '#fb7185'
default: return '#7b6ef2' default: return '#7c6cff'
} }
} }
@@ -137,18 +137,18 @@ onUnmounted(() => {
align-items: center; align-items: center;
gap: 6px; gap: 6px;
padding: 6px 12px; padding: 6px 12px;
border: 1px solid var(--nx-line, #1f2330); border: 1px solid var(--line);
border-radius: 6px; border-radius: 6px;
background: transparent; background: transparent;
color: var(--nx-text-dim, #6f7889); color: var(--tx-3);
font-size: 10.5px; font-size: 10.5px;
cursor: pointer; cursor: pointer;
transition: background .15s, color .15s; transition: background .15s, color .15s;
} }
.mark-all-btn:hover { .mark-all-btn:hover {
background: var(--nx-accent-soft, rgba(123, 110, 242, .08)); background: rgba(124, 108, 255, 0.08);
color: #d8dbe3; color: var(--tx);
} }
/* ── Empty State ── */ /* ── Empty State ── */
@@ -158,7 +158,7 @@ onUnmounted(() => {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 80px 0; padding: 80px 0;
color: var(--nx-text-dim, #6f7889); color: var(--tx-3);
gap: 16px; gap: 16px;
} }
@@ -186,7 +186,7 @@ onUnmounted(() => {
} }
.notification-card:hover { .notification-card:hover {
background: var(--nx-accent-soft, rgba(123, 110, 242, .06)); background: rgba(124, 108, 255, 0.06);
} }
.notification-card.unread { .notification-card.unread {
@@ -215,7 +215,7 @@ onUnmounted(() => {
.card-title { .card-title {
font-size: 12.5px; font-size: 12.5px;
color: #d8dbe3; color: var(--tx);
line-height: 1.4; line-height: 1.4;
} }
@@ -226,7 +226,7 @@ onUnmounted(() => {
.card-message { .card-message {
font-size: 10.5px; font-size: 10.5px;
color: var(--nx-text-dim, #6f7889); color: var(--tx-3);
margin-top: 3px; margin-top: 3px;
line-height: 1.3; line-height: 1.3;
} }
@@ -242,12 +242,12 @@ onUnmounted(() => {
.timestamp { .timestamp {
font-size: 9px; font-size: 9px;
color: var(--nx-text-dim, #6f7889); color: var(--tx-3);
white-space: nowrap; white-space: nowrap;
} }
.arrow { .arrow {
color: var(--nx-text-dim, #6f7889); color: var(--tx-3);
opacity: .5; opacity: .5;
} }
</style> </style>
+15 -15
View File
@@ -221,7 +221,7 @@ onMounted(loadProject)
} }
.project-detail-card { .project-detail-card {
background: var(--surface); background: var(--surface);
border: 1px solid var(--border); border: 1px solid var(--line-2);
border-radius: 12px; border-radius: 12px;
padding: 1.5rem; padding: 1.5rem;
} }
@@ -234,7 +234,7 @@ onMounted(loadProject)
width: 48px; width: 48px;
height: 48px; height: 48px;
border-radius: 10px; border-radius: 10px;
background: linear-gradient(135deg, var(--accent), var(--accent-secondary)); background: linear-gradient(135deg, var(--a-mid), var(--accent-secondary));
color: #fff; color: #fff;
font-size: 1.25rem; font-size: 1.25rem;
font-weight: 600; font-weight: 600;
@@ -273,7 +273,7 @@ onMounted(loadProject)
} }
.btn-icon { .btn-icon {
background: var(--surface-raised); background: var(--surface-raised);
border: 1px solid var(--border); border: 1px solid var(--line-2);
border-radius: 8px; border-radius: 8px;
padding: 0.5rem; padding: 0.5rem;
cursor: pointer; cursor: pointer;
@@ -282,8 +282,8 @@ onMounted(loadProject)
transition: all 0.15s; transition: all 0.15s;
} }
.btn-icon:hover { .btn-icon:hover {
background: var(--nx-accent-soft); background: rgba(124, 108, 255, 0.10);
color: var(--nx-accent); color: var(--a-mid);
} }
.btn-icon.btn-danger:hover { .btn-icon.btn-danger:hover {
background: rgba(239, 68, 68, 0.1); background: rgba(239, 68, 68, 0.1);
@@ -294,7 +294,7 @@ onMounted(loadProject)
width: 100%; width: 100%;
padding: 0.5rem 0.75rem; padding: 0.5rem 0.75rem;
background: var(--surface-raised); background: var(--surface-raised);
border: 1px solid var(--border); border: 1px solid var(--line-2);
border-radius: 8px; border-radius: 8px;
font-size: 1.1rem; font-size: 1.1rem;
color: var(--text-primary); color: var(--text-primary);
@@ -304,7 +304,7 @@ onMounted(loadProject)
width: 100%; width: 100%;
padding: 0.5rem 0.75rem; padding: 0.5rem 0.75rem;
background: var(--surface-raised); background: var(--surface-raised);
border: 1px solid var(--border); border: 1px solid var(--line-2);
border-radius: 8px; border-radius: 8px;
font-size: 0.9rem; font-size: 0.9rem;
color: var(--text-primary); color: var(--text-primary);
@@ -321,7 +321,7 @@ onMounted(loadProject)
align-items: center; align-items: center;
gap: 0.35rem; gap: 0.35rem;
padding: 0.4rem 0.8rem; padding: 0.4rem 0.8rem;
background: var(--nx-accent); background: var(--a-mid);
color: #fff; color: #fff;
border: none; border: none;
border-radius: 6px; border-radius: 6px;
@@ -335,7 +335,7 @@ onMounted(loadProject)
padding: 0.4rem 0.8rem; padding: 0.4rem 0.8rem;
background: var(--surface-raised); background: var(--surface-raised);
color: var(--text-secondary); color: var(--text-secondary);
border: 1px solid var(--border); border: 1px solid var(--line-2);
border-radius: 6px; border-radius: 6px;
font-size: 0.85rem; font-size: 0.85rem;
cursor: pointer; cursor: pointer;
@@ -343,7 +343,7 @@ onMounted(loadProject)
.progress-section { .progress-section {
margin-top: 1.25rem; margin-top: 1.25rem;
padding-top: 1rem; padding-top: 1rem;
border-top: 1px solid var(--border); border-top: 1px solid var(--line-2);
} }
.progress-header { .progress-header {
display: flex; display: flex;
@@ -361,7 +361,7 @@ onMounted(loadProject)
.progress-bar i { .progress-bar i {
display: block; display: block;
height: 100%; height: 100%;
background: linear-gradient(90deg, var(--nx-accent), var(--accent-secondary)); background: linear-gradient(90deg, var(--a-mid), var(--accent-secondary));
border-radius: 4px; border-radius: 4px;
transition: width 0.3s; transition: width 0.3s;
} }
@@ -380,7 +380,7 @@ onMounted(loadProject)
padding: 1.5rem; padding: 1.5rem;
text-align: center; text-align: center;
background: var(--surface); background: var(--surface);
border: 1px dashed var(--border); border: 1px dashed var(--line-2);
border-radius: 8px; border-radius: 8px;
} }
.task-list { .task-list {
@@ -394,7 +394,7 @@ onMounted(loadProject)
gap: 0.75rem; gap: 0.75rem;
padding: 0.75rem 1rem; padding: 0.75rem 1rem;
background: var(--surface); background: var(--surface);
border: 1px solid var(--border); border: 1px solid var(--line-2);
border-radius: 8px; border-radius: 8px;
} }
.task-icon { .task-icon {
@@ -403,7 +403,7 @@ onMounted(loadProject)
.task-icon.done { color: rgb(34, 197, 94); } .task-icon.done { color: rgb(34, 197, 94); }
.task-icon.blocked { color: rgb(239, 68, 68); } .task-icon.blocked { color: rgb(239, 68, 68); }
.task-icon.backlog { color: var(--text-muted); } .task-icon.backlog { color: var(--text-muted); }
.task-icon.in-progress { color: var(--nx-accent); } .task-icon.in-progress { color: var(--a-mid); }
.task-info { .task-info {
flex: 1; flex: 1;
} }
@@ -441,7 +441,7 @@ onMounted(loadProject)
} }
.modal { .modal {
background: var(--surface); background: var(--surface);
border: 1px solid var(--border); border: 1px solid var(--line-2);
border-radius: 12px; border-radius: 12px;
padding: 1.5rem; padding: 1.5rem;
max-width: 420px; max-width: 420px;
+18 -18
View File
@@ -192,7 +192,7 @@ onMounted(loadStatus)
} }
.security-card { .security-card {
border: 1px solid var(--line); border: 1px solid var(--line);
border-radius: 9px; border-radius: var(--r);
background: var(--panel); background: var(--panel);
padding: 20px; padding: 20px;
display: flex; display: flex;
@@ -204,27 +204,27 @@ onMounted(loadStatus)
height: 40px; height: 40px;
display: grid; display: grid;
place-items: center; place-items: center;
border-radius: 9px; border-radius: var(--r);
color: #a99cff; color: var(--a-mid);
background: var(--accent-soft); background: var(--accent-soft);
} }
.security-card-icon.twofa-icon { .security-card-icon.twofa-icon {
color: #e5b05e; color: var(--st-queue);
background: rgba(229,176,94,.1); background: rgba(229,176,94,.1);
} }
.security-card-icon.passkey-icon { .security-card-icon.passkey-icon {
color: #6d9fe6; color: var(--a-blue);
background: rgba(109,159,230,.1); background: rgba(109,159,230,.1);
} }
.security-card h3 { .security-card h3 {
margin: 0; margin: 0;
font-size: 13px; font-size: 13px;
color: #e8eaf0; color: var(--tx);
} }
.security-value { .security-value {
font-size: 13px; font-size: 13px;
font-weight: 600; font-weight: 600;
color: #e8eaf0; color: var(--tx);
} }
.policy-text { .policy-text {
font-size: 11px; font-size: 11px;
@@ -234,7 +234,7 @@ onMounted(loadStatus)
.security-desc { .security-desc {
margin: 0; margin: 0;
font-size: 10px; font-size: 10px;
color: #7e8799; color: var(--tx-3);
line-height: 1.5; line-height: 1.5;
} }
.security-detail-list { .security-detail-list {
@@ -250,14 +250,14 @@ onMounted(loadStatus)
} }
.security-detail-label { .security-detail-label {
font-size: 10px; font-size: 10px;
color: #8991a1; color: var(--tx-2);
font-weight: 500; font-weight: 500;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.03em; letter-spacing: 0.03em;
} }
.security-detail-value { .security-detail-value {
font-size: 10px; font-size: 10px;
color: #e8eaf0; color: var(--tx);
font-weight: 500; font-weight: 500;
text-align: right; text-align: right;
word-break: break-word; word-break: break-word;
@@ -281,11 +281,11 @@ code.security-detail-value {
} }
.status-bool.enabled { .status-bool.enabled {
background: rgba(81,212,154,.1); background: rgba(81,212,154,.1);
color: #51d49a; color: var(--st-work);
} }
.status-bool.disabled { .status-bool.disabled {
background: rgba(225,110,117,.08); background: rgba(225,110,117,.08);
color: #e16e75; color: var(--st-block);
} }
.security-status-row { .security-status-row {
display: flex; display: flex;
@@ -293,16 +293,16 @@ code.security-detail-value {
gap: 6px; gap: 6px;
} }
.check-icon { .check-icon {
color: #51d49a; color: var(--st-work);
} }
.x-icon { .x-icon {
color: #e16e75; color: var(--st-block);
} }
.enabled-text { .enabled-text {
color: #51d49a; color: var(--st-work);
} }
.disabled-text { .disabled-text {
color: #e16e75; color: var(--st-block);
} }
.memory-status { .memory-status {
@@ -311,11 +311,11 @@ code.security-detail-value {
justify-content: center; justify-content: center;
gap: 8px; gap: 8px;
padding: 48px; padding: 48px;
color: #7e8799; color: var(--tx-3);
font-size: 12px; font-size: 12px;
} }
.memory-status.error { .memory-status.error {
color: #e16e75; color: var(--st-block);
} }
.spin { .spin {
animation: spin 1s linear infinite; animation: spin 1s linear infinite;
+29 -29
View File
@@ -409,7 +409,7 @@ onMounted(() => {
} }
.grad-text { .grad-text {
background: linear-gradient(135deg, #4f7cff, #b557f6); background: linear-gradient(135deg, var(--a-blue), var(--a-purple));
-webkit-background-clip: text; -webkit-background-clip: text;
background-clip: text; background-clip: text;
color: transparent; color: transparent;
@@ -418,7 +418,7 @@ onMounted(() => {
.settings-subtitle { .settings-subtitle {
margin: 4px 0 0; margin: 4px 0 0;
font-size: 11px; font-size: 11px;
color: #6f6aa0; color: var(--tx-3);
font-family: 'Manrope', sans-serif; font-family: 'Manrope', sans-serif;
} }
@@ -444,7 +444,7 @@ onMounted(() => {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 10px;
color: #ece9ff; color: var(--tx);
padding-bottom: 14px; padding-bottom: 14px;
border-bottom: 1px solid rgba(150, 140, 255, 0.08); border-bottom: 1px solid rgba(150, 140, 255, 0.08);
} }
@@ -470,7 +470,7 @@ onMounted(() => {
.field label { .field label {
font-size: 10px; font-size: 10px;
font-weight: 600; font-weight: 600;
color: #a8a3d6; color: var(--tx-2);
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.05em; letter-spacing: 0.05em;
} }
@@ -490,7 +490,7 @@ onMounted(() => {
border: 1px solid rgba(150, 140, 255, 0.12); border: 1px solid rgba(150, 140, 255, 0.12);
border-radius: 11px; border-radius: 11px;
background: rgba(10, 9, 24, 0.55); background: rgba(10, 9, 24, 0.55);
color: #ece9ff; color: var(--tx);
font-size: 13.5px; font-size: 13.5px;
font-family: 'Manrope', sans-serif; font-family: 'Manrope', sans-serif;
outline: none; outline: none;
@@ -513,13 +513,13 @@ onMounted(() => {
} }
.galaxy-select option { .galaxy-select option {
background: #141130; background: var(--space-3);
color: #ece9ff; color: var(--tx);
} }
.value-tag { .value-tag {
font-size: 14px; font-size: 14px;
color: #ece9ff; color: var(--tx);
font-weight: 500; font-weight: 500;
} }
@@ -538,7 +538,7 @@ onMounted(() => {
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.05em; letter-spacing: 0.05em;
background: linear-gradient(135deg, rgba(79, 124, 255, 0.15), rgba(181, 87, 246, 0.15)); background: linear-gradient(135deg, rgba(79, 124, 255, 0.15), rgba(181, 87, 246, 0.15));
color: #b8adff; color: var(--a-mid);
border: 1px solid rgba(124, 108, 255, 0.15); border: 1px solid rgba(124, 108, 255, 0.15);
width: fit-content; width: fit-content;
} }
@@ -589,14 +589,14 @@ onMounted(() => {
border: none; border: none;
border-radius: 8px; border-radius: 8px;
background: transparent; background: transparent;
color: #6f6aa0; color: var(--tx-3);
cursor: pointer; cursor: pointer;
transition: background 0.15s, color 0.15s; transition: background 0.15s, color 0.15s;
} }
.pw-toggle:hover { .pw-toggle:hover {
background: rgba(124, 108, 255, 0.08); background: rgba(124, 108, 255, 0.08);
color: #a8a3d6; color: var(--tx-2);
} }
/* ── Messages ──────────────────────────────────── */ /* ── Messages ──────────────────────────────────── */
@@ -613,13 +613,13 @@ onMounted(() => {
.msg.error { .msg.error {
background: rgba(244, 63, 94, 0.1); background: rgba(244, 63, 94, 0.1);
border: 1px solid rgba(244, 63, 94, 0.2); border: 1px solid rgba(244, 63, 94, 0.2);
color: #fda4af; color: var(--st-block);
} }
.msg.success { .msg.success {
background: rgba(34, 197, 94, 0.1); background: rgba(34, 197, 94, 0.1);
border: 1px solid rgba(34, 197, 94, 0.2); border: 1px solid rgba(34, 197, 94, 0.2);
color: #86efac; color: var(--st-work);
} }
/* ── Buttons ──────────────────────────────────── */ /* ── Buttons ──────────────────────────────────── */
@@ -630,7 +630,7 @@ onMounted(() => {
padding: 9px 16px; padding: 9px 16px;
border: none; border: none;
border-radius: 10px; border-radius: 10px;
background: linear-gradient(135deg, #4f7cff, #7c6cff, #b557f6); background: linear-gradient(135deg, var(--a-blue), var(--a-mid), var(--a-purple));
color: #fff; color: #fff;
font-size: 12.5px; font-size: 12.5px;
font-weight: 600; font-weight: 600;
@@ -665,7 +665,7 @@ onMounted(() => {
font-family: 'Manrope', sans-serif; font-family: 'Manrope', sans-serif;
background: transparent; background: transparent;
border: 1px solid rgba(150, 140, 255, 0.12); border: 1px solid rgba(150, 140, 255, 0.12);
color: #a8a3d6; color: var(--tx-2);
border-radius: 8px; border-radius: 8px;
cursor: pointer; cursor: pointer;
transition: background 0.15s, color 0.15s; transition: background 0.15s, color 0.15s;
@@ -673,7 +673,7 @@ onMounted(() => {
.btn-ghost:hover { .btn-ghost:hover {
background: rgba(124, 108, 255, 0.08); background: rgba(124, 108, 255, 0.08);
color: #ece9ff; color: var(--tx);
} }
/* ── Admin User Management ───────────────────── */ /* ── Admin User Management ───────────────────── */
@@ -711,7 +711,7 @@ onMounted(() => {
place-items: center; place-items: center;
background: linear-gradient(135deg, rgba(79, 124, 255, 0.2), rgba(181, 87, 246, 0.2)); background: linear-gradient(135deg, rgba(79, 124, 255, 0.2), rgba(181, 87, 246, 0.2));
border: 1px solid rgba(124, 108, 255, 0.15); border: 1px solid rgba(124, 108, 255, 0.15);
color: #b8adff; color: var(--a-mid);
font-weight: 700; font-weight: 700;
font-size: 14px; font-size: 14px;
flex-shrink: 0; flex-shrink: 0;
@@ -725,12 +725,12 @@ onMounted(() => {
.user-name { .user-name {
font-size: 13px; font-size: 13px;
font-weight: 600; font-weight: 600;
color: #ece9ff; color: var(--tx);
} }
.user-email { .user-email {
font-size: 11px; font-size: 11px;
color: #6f6aa0; color: var(--tx-3);
display: flex; display: flex;
align-items: center; align-items: center;
gap: 4px; gap: 4px;
@@ -754,31 +754,31 @@ onMounted(() => {
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.04em; letter-spacing: 0.04em;
background: rgba(124, 108, 255, 0.1); background: rgba(124, 108, 255, 0.1);
color: #b8adff; color: var(--a-mid);
border: 1px solid rgba(124, 108, 255, 0.1); border: 1px solid rgba(124, 108, 255, 0.1);
} }
.role-tag.owner { .role-tag.owner {
background: linear-gradient(135deg, rgba(244, 63, 94, 0.15), rgba(251, 191, 36, 0.15)); background: linear-gradient(135deg, rgba(244, 63, 94, 0.15), rgba(251, 191, 36, 0.15));
color: #fde68a; color: var(--st-queue);
border-color: rgba(251, 191, 36, 0.2); border-color: rgba(251, 191, 36, 0.2);
} }
.role-tag.admin { .role-tag.admin {
background: rgba(79, 124, 255, 0.12); background: rgba(79, 124, 255, 0.12);
color: #93c5fd; color: var(--a-blue);
border-color: rgba(79, 124, 255, 0.2); border-color: rgba(79, 124, 255, 0.2);
} }
.role-tag.viewer { .role-tag.viewer {
background: rgba(107, 103, 150, 0.15); background: rgba(107, 103, 150, 0.15);
color: #a8a3d6; color: var(--tx-2);
border-color: rgba(107, 103, 150, 0.2); border-color: rgba(107, 103, 150, 0.2);
} }
.user-date { .user-date {
font-size: 10px; font-size: 10px;
color: #6f6aa0; color: var(--tx-3);
} }
.loading-pulse { .loading-pulse {
@@ -806,7 +806,7 @@ onMounted(() => {
align-items: center; align-items: center;
gap: 12px; gap: 12px;
padding: 32px; padding: 32px;
color: #6f6aa0; color: var(--tx-3);
} }
.empty-state p { .empty-state p {
@@ -849,7 +849,7 @@ onMounted(() => {
margin: 0; margin: 0;
font-size: 16px; font-size: 16px;
font-weight: 700; font-weight: 700;
color: #ece9ff; color: var(--tx);
font-family: 'Space Grotesk', sans-serif; font-family: 'Space Grotesk', sans-serif;
} }
@@ -861,7 +861,7 @@ onMounted(() => {
justify-content: center; justify-content: center;
border: none; border: none;
background: transparent; background: transparent;
color: #6f6aa0; color: var(--tx-3);
cursor: pointer; cursor: pointer;
border-radius: 6px; border-radius: 6px;
font-size: 20px; font-size: 20px;
@@ -870,11 +870,11 @@ onMounted(() => {
.modal-close:hover { .modal-close:hover {
background: rgba(124, 108, 255, 0.08); background: rgba(124, 108, 255, 0.08);
color: #ece9ff; color: var(--tx);
} }
.req { .req {
color: #fb7185; color: var(--st-block);
} }
.modal-form { .modal-form {
+45 -45
View File
@@ -111,9 +111,9 @@ function statusClass(state: string): string {
function priorityColor(p: string): string { function priorityColor(p: string): string {
const lower = p.toLowerCase() const lower = p.toLowerCase()
if (lower === 'high') return '#f87171' if (lower === 'high') return 'var(--st-block)'
if (lower === 'low') return '#60a5fa' if (lower === 'low') return 'var(--a-blue)'
return '#facc15' return 'var(--st-queue)'
} }
function priorityLabel(p: string): string { function priorityLabel(p: string): string {
@@ -638,7 +638,7 @@ function handleKeydown(e: KeyboardEvent) {
border: 1px solid rgba(150, 140, 255, 0.12); border: 1px solid rgba(150, 140, 255, 0.12);
border-radius: 10px; border-radius: 10px;
background: transparent; background: transparent;
color: #a8a3d6; color: var(--tx-2);
font-size: 12px; font-size: 12px;
font-family: 'Manrope', sans-serif; font-family: 'Manrope', sans-serif;
cursor: pointer; cursor: pointer;
@@ -648,7 +648,7 @@ function handleKeydown(e: KeyboardEvent) {
.back-btn:hover { .back-btn:hover {
background: rgba(124, 108, 255, 0.08); background: rgba(124, 108, 255, 0.08);
color: #ece9ff; color: var(--tx);
} }
/* ── Loading / Error ────────────────────────── */ /* ── Loading / Error ────────────────────────── */
@@ -659,14 +659,14 @@ function handleKeydown(e: KeyboardEvent) {
justify-content: center; justify-content: center;
gap: 16px; gap: 16px;
padding: 80px 20px; padding: 80px 20px;
color: #6f6aa0; color: var(--tx-3);
} }
.spinner { .spinner {
width: 24px; width: 24px;
height: 24px; height: 24px;
border: 2.5px solid rgba(150, 140, 255, 0.15); border: 2.5px solid rgba(150, 140, 255, 0.15);
border-top-color: #7c6cff; border-top-color: var(--a-mid);
border-radius: 50%; border-radius: 50%;
animation: spin 0.6s linear infinite; animation: spin 0.6s linear infinite;
} }
@@ -675,7 +675,7 @@ function handleKeydown(e: KeyboardEvent) {
width: 16px; width: 16px;
height: 16px; height: 16px;
border: 2px solid rgba(150, 140, 255, 0.15); border: 2px solid rgba(150, 140, 255, 0.15);
border-top-color: #7c6cff; border-top-color: var(--a-mid);
border-radius: 50%; border-radius: 50%;
animation: spin 0.6s linear infinite; animation: spin 0.6s linear infinite;
flex-shrink: 0; flex-shrink: 0;
@@ -686,7 +686,7 @@ function handleKeydown(e: KeyboardEvent) {
.error-state p { .error-state p {
font-size: 14px; font-size: 14px;
margin: 0; margin: 0;
color: #fda4af; color: var(--st-block);
} }
/* ── Detail Header ──────────────────────────── */ /* ── Detail Header ──────────────────────────── */
@@ -711,15 +711,15 @@ function handleKeydown(e: KeyboardEvent) {
border: 1px solid transparent; border: 1px solid transparent;
} }
.state-badge.is-backlog { color: #fde68a; background: rgba(251,191,36,.12); border-color: rgba(251,191,36,.25); } .state-badge.is-backlog { color: var(--st-queue); background: rgba(251,191,36,.12); border-color: rgba(251,191,36,.25); }
.state-badge.is-progress { color: #86efac; background: rgba(34,197,94,.12); border-color: rgba(34,197,94,.25); } .state-badge.is-progress { color: var(--st-work); background: rgba(34,197,94,.12); border-color: rgba(34,197,94,.25); }
.state-badge.is-review { color: #fdba74; background: rgba(249,115,22,.12); border-color: rgba(249,115,22,.25); } .state-badge.is-review { color: var(--st-queue); background: rgba(249,115,22,.12); border-color: rgba(249,115,22,.25); }
.state-badge.is-blocked { color: #fda4af; background: rgba(244,63,94,.12); border-color: rgba(244,63,94,.25); } .state-badge.is-blocked { color: var(--st-block); background: rgba(244,63,94,.12); border-color: rgba(244,63,94,.25); }
.state-badge.is-done { color: #86efac; background: rgba(34,197,94,.12); border-color: rgba(34,197,94,.25); } .state-badge.is-done { color: var(--st-work); background: rgba(34,197,94,.12); border-color: rgba(34,197,94,.25); }
.meta-chip { .meta-chip {
font-size: 10px; font-size: 10px;
color: #6f6aa0; color: var(--tx-3);
background: rgba(10, 9, 24, 0.35); background: rgba(10, 9, 24, 0.35);
padding: 3px 10px; padding: 3px 10px;
border-radius: 6px; border-radius: 6px;
@@ -735,7 +735,7 @@ function handleKeydown(e: KeyboardEvent) {
border-radius: 10px; border-radius: 10px;
background: rgba(147,51,234,.08); background: rgba(147,51,234,.08);
border: 1px solid rgba(147,51,234,.18); border: 1px solid rgba(147,51,234,.18);
color: #c084fc; color: var(--a-purple);
font-size: 12px; font-size: 12px;
} }
@@ -759,7 +759,7 @@ function handleKeydown(e: KeyboardEvent) {
border: none; border: none;
border-bottom: 2px solid transparent; border-bottom: 2px solid transparent;
padding: 4px 0; padding: 4px 0;
color: #ece9ff; color: var(--tx);
font-family: 'Space Grotesk', sans-serif; font-family: 'Space Grotesk', sans-serif;
font-size: 28px; font-size: 28px;
font-weight: 700; font-weight: 700;
@@ -777,7 +777,7 @@ function handleKeydown(e: KeyboardEvent) {
flex-wrap: wrap; flex-wrap: wrap;
gap: 16px; gap: 16px;
font-size: 12px; font-size: 12px;
color: #6f6aa0; color: var(--tx-3);
} }
.meta-row span { .meta-row span {
@@ -791,7 +791,7 @@ function handleKeydown(e: KeyboardEvent) {
border-radius: 12px; border-radius: 12px;
background: rgba(124, 108, 255, 0.08); background: rgba(124, 108, 255, 0.08);
border: 1px solid rgba(124, 108, 255, 0.14); border: 1px solid rgba(124, 108, 255, 0.14);
color: #a8a3d6; color: var(--tx-2);
font-size: 12px; font-size: 12px;
} }
@@ -808,7 +808,7 @@ function handleKeydown(e: KeyboardEvent) {
align-items: center; align-items: center;
gap: 8px; gap: 8px;
margin-bottom: 14px; margin-bottom: 14px;
color: #a8a3d6; color: var(--tx-2);
font-size: 11px; font-size: 11px;
font-weight: 700; font-weight: 700;
text-transform: uppercase; text-transform: uppercase;
@@ -826,7 +826,7 @@ function handleKeydown(e: KeyboardEvent) {
border: 1px solid rgba(150, 140, 255, 0.10); border: 1px solid rgba(150, 140, 255, 0.10);
border-radius: 12px; border-radius: 12px;
background: rgba(10, 9, 24, 0.45); background: rgba(10, 9, 24, 0.45);
color: #ece9ff; color: var(--tx);
font-size: 14px; font-size: 14px;
line-height: 1.6; line-height: 1.6;
font-family: 'Manrope', sans-serif; font-family: 'Manrope', sans-serif;
@@ -897,13 +897,13 @@ function handleKeydown(e: KeyboardEvent) {
.subtask-title { .subtask-title {
font-size: 13px; font-size: 13px;
font-weight: 600; font-weight: 600;
color: #ece9ff; color: var(--tx);
} }
.subtask-detail { .subtask-detail {
margin: 4px 0 0; margin: 4px 0 0;
font-size: 11.5px; font-size: 11.5px;
color: #6f6aa0; color: var(--tx-3);
line-height: 1.4; line-height: 1.4;
} }
@@ -919,7 +919,7 @@ function handleKeydown(e: KeyboardEvent) {
border: 1px solid rgba(150, 140, 255, 0.12); border: 1px solid rgba(150, 140, 255, 0.12);
border-radius: 6px; border-radius: 6px;
background: rgba(10, 9, 24, 0.5); background: rgba(10, 9, 24, 0.5);
color: #a8a3d6; color: var(--tx-2);
font-size: 10px; font-size: 10px;
font-family: 'Manrope', sans-serif; font-family: 'Manrope', sans-serif;
cursor: pointer; cursor: pointer;
@@ -927,8 +927,8 @@ function handleKeydown(e: KeyboardEvent) {
} }
.state-select-mini option { .state-select-mini option {
background: #141130; background: var(--space-3);
color: #ece9ff; color: var(--tx);
} }
.state-select-mini:disabled { .state-select-mini:disabled {
@@ -941,14 +941,14 @@ function handleKeydown(e: KeyboardEvent) {
align-items: center; align-items: center;
gap: 8px; gap: 8px;
padding: 16px; padding: 16px;
color: #6f6aa0; color: var(--tx-3);
font-size: 12px; font-size: 12px;
} }
.empty-section { .empty-section {
padding: 20px; padding: 20px;
text-align: center; text-align: center;
color: #6f6aa0; color: var(--tx-3);
font-size: 12px; font-size: 12px;
} }
@@ -996,7 +996,7 @@ function handleKeydown(e: KeyboardEvent) {
display: grid; display: grid;
place-items: center; place-items: center;
background: rgba(124, 108, 255, 0.08); background: rgba(124, 108, 255, 0.08);
color: #7c6cff; color: var(--a-mid);
flex-shrink: 0; flex-shrink: 0;
} }
@@ -1007,13 +1007,13 @@ function handleKeydown(e: KeyboardEvent) {
.activity-msg { .activity-msg {
font-size: 12.5px; font-size: 12.5px;
color: #a8a3d6; color: var(--tx-2);
line-height: 1.4; line-height: 1.4;
} }
.activity-time { .activity-time {
font-size: 10px; font-size: 10px;
color: #6f6aa0; color: var(--tx-3);
margin-top: 3px; margin-top: 3px;
} }
@@ -1042,7 +1042,7 @@ function handleKeydown(e: KeyboardEvent) {
font-weight: 700; font-weight: 700;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.06em; letter-spacing: 0.06em;
color: #a8a3d6; color: var(--tx-2);
margin-bottom: 14px; margin-bottom: 14px;
} }
@@ -1060,7 +1060,7 @@ function handleKeydown(e: KeyboardEvent) {
.sidebar-field span { .sidebar-field span {
font-size: 10px; font-size: 10px;
font-weight: 600; font-weight: 600;
color: #6f6aa0; color: var(--tx-3);
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.04em; letter-spacing: 0.04em;
} }
@@ -1079,13 +1079,13 @@ function handleKeydown(e: KeyboardEvent) {
} }
.info-list dt { .info-list dt {
color: #6f6aa0; color: var(--tx-3);
font-size: 11px; font-size: 11px;
} }
.info-list dd { .info-list dd {
margin: 0; margin: 0;
color: #a8a3d6; color: var(--tx-2);
font-size: 11.5px; font-size: 11.5px;
text-align: right; text-align: right;
} }
@@ -1104,7 +1104,7 @@ function handleKeydown(e: KeyboardEvent) {
border: 1px solid rgba(150, 140, 255, 0.12); border: 1px solid rgba(150, 140, 255, 0.12);
border-radius: 10px; border-radius: 10px;
background: rgba(10, 9, 24, 0.55); background: rgba(10, 9, 24, 0.55);
color: #ece9ff; color: var(--tx);
font-size: 13.5px; font-size: 13.5px;
font-family: 'Manrope', sans-serif; font-family: 'Manrope', sans-serif;
outline: none; outline: none;
@@ -1127,8 +1127,8 @@ function handleKeydown(e: KeyboardEvent) {
} }
.galaxy-select option { .galaxy-select option {
background: #141130; background: var(--space-3);
color: #ece9ff; color: var(--tx);
} }
.galaxy-select:disabled { .galaxy-select:disabled {
@@ -1143,7 +1143,7 @@ function handleKeydown(e: KeyboardEvent) {
padding: 9px 16px; padding: 9px 16px;
border: none; border: none;
border-radius: 10px; border-radius: 10px;
background: linear-gradient(135deg, #4f7cff, #7c6cff, #b557f6); background: linear-gradient(135deg, var(--a-blue), var(--a-mid), var(--a-purple));
color: #fff; color: #fff;
font-size: 12.5px; font-size: 12.5px;
font-weight: 600; font-weight: 600;
@@ -1169,7 +1169,7 @@ function handleKeydown(e: KeyboardEvent) {
border: 1px solid rgba(150, 140, 255, 0.12); border: 1px solid rgba(150, 140, 255, 0.12);
border-radius: 8px; border-radius: 8px;
background: transparent; background: transparent;
color: #a8a3d6; color: var(--tx-2);
font-size: 11px; font-size: 11px;
font-family: 'Manrope', sans-serif; font-family: 'Manrope', sans-serif;
cursor: pointer; cursor: pointer;
@@ -1186,13 +1186,13 @@ function handleKeydown(e: KeyboardEvent) {
border: none; border: none;
border-radius: 7px; border-radius: 7px;
background: rgba(124, 108, 255, 0.06); background: rgba(124, 108, 255, 0.06);
color: #a8a3d6; color: var(--tx-2);
cursor: pointer; cursor: pointer;
transition: background 0.15s, color 0.15s; transition: background 0.15s, color 0.15s;
} }
.btn-icon-sm:hover { background: rgba(124, 108, 255, 0.12); color: #ece9ff; } .btn-icon-sm:hover { background: rgba(124, 108, 255, 0.12); color: var(--tx); }
.btn-icon-sm.danger:hover { background: rgba(244, 63, 94, 0.12); color: #fda4af; } .btn-icon-sm.danger:hover { background: rgba(244, 63, 94, 0.12); color: var(--st-block); }
.btn-icon-sm:disabled { opacity: 0.4; cursor: not-allowed; } .btn-icon-sm:disabled { opacity: 0.4; cursor: not-allowed; }
.msg { .msg {
@@ -1202,8 +1202,8 @@ function handleKeydown(e: KeyboardEvent) {
border-radius: 8px; border-radius: 8px;
} }
.msg.error { background: rgba(244, 63, 94, 0.08); border: 1px solid rgba(244, 63, 94, 0.15); color: #fda4af; } .msg.error { background: rgba(244, 63, 94, 0.08); border: 1px solid rgba(244, 63, 94, 0.15); color: var(--st-block); }
.msg.success { background: rgba(34, 197, 94, 0.08); border: 1px solid rgba(34, 197, 94, 0.15); color: #86efac; display: flex; align-items: center; gap: 6px; } .msg.success { background: rgba(34, 197, 94, 0.08); border: 1px solid rgba(34, 197, 94, 0.15); color: var(--st-work); display: flex; align-items: center; gap: 6px; }
/* ── Responsive ──────────────────────────────── */ /* ── Responsive ──────────────────────────────── */
@media (max-width: 860px) { @media (max-width: 860px) {
+12 -12
View File
@@ -23,7 +23,7 @@ const agents: AgentCardData[] = [
role: 'Chief of Staff', role: 'Chief of Staff',
description: 'Koordiniert, delegiert, hält das Team tight. Die erste Anlaufstelle zwischen Boss und Maschine.', description: 'Koordiniert, delegiert, hält das Team tight. Die erste Anlaufstelle zwischen Boss und Maschine.',
tags: ['Orchestration', 'Delegation', 'Approval'], tags: ['Orchestration', 'Delegation', 'Approval'],
color: '#8b7cf6', color: '#7c6cff',
icon: 'bot', icon: 'bot',
hero: true, hero: true,
}, },
@@ -33,7 +33,7 @@ const agents: AgentCardData[] = [
role: 'Lead Developer', role: 'Lead Developer',
description: 'Implementiert Features, schreibt Code, führt Builds und Tests aus. Arbeitet autonom im Scope.', description: 'Implementiert Features, schreibt Code, führt Builds und Tests aus. Arbeitet autonom im Scope.',
tags: ['coding', 'development', 'builds'], tags: ['coding', 'development', 'builds'],
color: '#3b82f6', color: '#4f7cff',
icon: 'code', icon: 'code',
}, },
{ {
@@ -42,7 +42,7 @@ const agents: AgentCardData[] = [
role: 'Code QA', role: 'Code QA',
description: 'Prüft Code auf Bugs, Sicherheit und Wartbarkeit. Fixt Probleme eigenständig.', description: 'Prüft Code auf Bugs, Sicherheit und Wartbarkeit. Fixt Probleme eigenständig.',
tags: ['Quality Assurance', 'Security', 'Code Review'], tags: ['Quality Assurance', 'Security', 'Code Review'],
color: '#a855f7', color: '#b557f6',
icon: 'shield', icon: 'shield',
}, },
{ {
@@ -51,7 +51,7 @@ const agents: AgentCardData[] = [
role: 'Research Analyst', role: 'Research Analyst',
description: 'Recherchiert, analysiert Quellen, prüft Fakten. Nur Lese-Rechte, keine Aktionen.', description: 'Recherchiert, analysiert Quellen, prüft Fakten. Nur Lese-Rechte, keine Aktionen.',
tags: ['Research', 'Analysis', 'Fact-Checking'], tags: ['Research', 'Analysis', 'Fact-Checking'],
color: '#22c55e', color: '#3ddc97',
icon: 'search', icon: 'search',
}, },
{ {
@@ -60,7 +60,7 @@ const agents: AgentCardData[] = [
role: 'Host Executor', role: 'Host Executor',
description: 'Führt Host-Kommandos auf dem VPS aus. Nur auf Iris-Befehl, niemals eigeninitiativ.', description: 'Führt Host-Kommandos auf dem VPS aus. Nur auf Iris-Befehl, niemals eigeninitiativ.',
tags: ['Execution', 'Deployment', 'VPS'], tags: ['Execution', 'Deployment', 'VPS'],
color: '#eab308', color: '#fbbf24',
icon: 'terminal', icon: 'terminal',
}, },
] ]
@@ -133,7 +133,7 @@ function goToAgent(id: string) {
.quote-text { .quote-text {
font-style: italic; font-style: italic;
font-size: 12px; font-size: 12px;
color: #9ea5b3; color: var(--tx-2);
line-height: 1.5; line-height: 1.5;
} }
@@ -144,17 +144,17 @@ function goToAgent(id: string) {
.team-title { .team-title {
font-size: 26px; font-size: 26px;
font-weight: 600; font-weight: 600;
color: #e8eaf0; color: var(--tx);
margin: 0 0 6px; margin: 0 0 6px;
} }
.team-subtitle { .team-subtitle {
font-size: 12px; font-size: 12px;
color: #7e8799; color: var(--tx-3);
margin: 0 0 4px; margin: 0 0 4px;
} }
.team-description { .team-description {
font-size: 10.5px; font-size: 10.5px;
color: #6b7385; color: var(--tx-3);
margin: 0; margin: 0;
max-width: 560px; max-width: 560px;
margin-left: auto; margin-left: auto;
@@ -182,7 +182,7 @@ function goToAgent(id: string) {
align-items: center; align-items: center;
gap: 8px; gap: 8px;
font-size: 10px; font-size: 10px;
color: #7e8799; color: var(--tx-3);
} }
.legend-dot { .legend-dot {
width: 8px; width: 8px;
@@ -191,11 +191,11 @@ function goToAgent(id: string) {
flex-shrink: 0; flex-shrink: 0;
} }
.active-pulse { .active-pulse {
background: #51d49a; background: var(--st-work);
box-shadow: 0 0 6px rgba(81, 212, 154, 0.6); box-shadow: 0 0 6px rgba(81, 212, 154, 0.6);
} }
.idle-pulse { .idle-pulse {
background: #3a3f4b; background: var(--line-2);
} }
.pulse-dot { .pulse-dot {
background: white; background: white;
+3 -2
View File
@@ -1,6 +1,6 @@
# Runtime und Routing # Runtime und Routing
> Letzte Aktualisierung: 2026-06-16 > Letzte Aktualisierung: 2026-07-09
## Aktive Modelle (7 von 8 konfiguriert) ## Aktive Modelle (7 von 8 konfiguriert)
@@ -23,6 +23,7 @@
- Einzige aktive Integration: `OpenClawRuntime` über `IAgentRuntime` - Einzige aktive Integration: `OpenClawRuntime` über `IAgentRuntime`
- Model-Routing läuft zentral über OpenClaw Gateway (kein direct provider routing) - Model-Routing läuft zentral über OpenClaw Gateway (kein direct provider routing)
- API kommuniziert via `host.docker.internal:18789` (Gateway loopback — wird über `openclaw_default` Netzwerk gefixt) - API kommuniziert über Docker-DNS via `http://openclaw-gateway-bao:18789` im gemeinsamen `openclaw_default`-Netzwerk.
- Der frühere Pfad `host.docker.internal:18789` ist auf dem VPS nicht erreichbar und wurde entfernt.
- **Achtung:** `[AllowAnonymous]` auf `/tasks/board` und `/tasks/reset-stale` muss durch ApiKey-Auth ersetzt werden (siehe [Architektur-Review](../docs/architecture-board-first-orchestration.md#61-kritisch--allowanonymous-auf-board-endpunkten)) - **Achtung:** `[AllowAnonymous]` auf `/tasks/board` und `/tasks/reset-stale` muss durch ApiKey-Auth ersetzt werden (siehe [Architektur-Review](../docs/architecture-board-first-orchestration.md#61-kritisch--allowanonymous-auf-board-endpunkten))
- Vollständige Architektur- und Sicherheitsanalyse: [architecture-board-first-orchestration.md](../docs/architecture-board-first-orchestration.md) - Vollständige Architektur- und Sicherheitsanalyse: [architecture-board-first-orchestration.md](../docs/architecture-board-first-orchestration.md)