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