commit b0aa0438afad6e4e38503914eb6f93a71c03b043 Author: jon Date: Mon May 18 13:39:48 2026 -0500 Initial commit: NexusOS project + desktop theme baseline Captures the known-good state after theme consolidation and consistency reconciliation: - NexusOS GTK/xfwm4/icon theme assets (assets/themes, management/Mint-Y-Nexus) - Tightened right-click menus, visible separators, no menu icons - assets/themes/install-theme.sh: idempotent restore of all wiring (symlinks, xfconf xsettings+xfwm4, GTK 3/4 settings.ini) - .gitignore excludes venv/ollama/models/runtime/db Co-Authored-By: Claude Opus 4.7 diff --git a/.DirIcon b/.DirIcon new file mode 100644 index 0000000..dfcab71 Binary files /dev/null and b/.DirIcon differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9017197 --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +# Large machine-specific / regenerable trees (never commit) +# Promethean/ = 16G ROCm venv (recreate from requirements*.txt) +# ollama/ = 7.4G bundled Ollama binary; models/ = 4.9G Ollama blobs +Promethean/ +ollama/ +models/ +interface/web/node_modules/ + +# Runtime state & user data +runtime/ +data/uploads/ +data/exports/ +*.db +*.db-wal +*.db-shm + +# Build / cache artifacts +interface/web/dist/ +__pycache__/ +*.pyc +*.pyo + +# Editor / DE / local cruft +.directory +*.bak +*.bak-* +*.tar.gz + +# Local-only Claude config (machine-specific) +.claude/settings.local.json diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..7c52994 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,92 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What is NexusOS + +NexusOS is a local AI assistant platform. It runs a Python/FastAPI backend (Synapse) that interfaces with a locally bundled Ollama instance, a dedicated memory microservice, and a React/Vite frontend. Everything runs on `localhost` with no external AI API calls — the LLM is served via Ollama. + +## Running the Project + +**Full stack (recommended):** +```bash +./launch_nexus.sh +``` +This activates the `Promethean` venv, starts the memory service on port 8001, the Synapse backend on port 8000, and the Vite frontend (default port 5173). + +**Individual services via CLI:** +```bash +# From nexus-core/ with Promethean venv active: +source Promethean/bin/activate + +# Backend +uvicorn synapse.main:sio_app --host 0.0.0.0 --port 8000 --reload + +# Memory service +uvicorn synapse.memory.service:app --host 0.0.0.0 --port 8001 --reload + +# Frontend +cd interface/web && npm run dev +``` + +**Management CLI** (start/stop individual services with PID tracking): +```bash +./management/nexus-cli.sh start # starts backend + frontend +./management/nexus-cli.sh stop +./management/nexus-cli.sh start_backend / start_frontend +``` + +**Frontend lint:** +```bash +cd interface/web && npm run lint +``` + +**Frontend build:** +```bash +cd interface/web && npm run build +``` + +## Architecture + +### Python venv +All Python code runs inside `Promethean/` (a local venv). Always activate it before running backend commands: `source Promethean/bin/activate`. The AMD ROCm PyTorch stack is installed here (`requirements.txt`). + +### Synapse Backend (`synapse/`) +FastAPI app at `synapse/main.py`. Key responsibilities: +- `/chat` and `/chat/stream` — chat with Ollama; streaming uses SSE. After each exchange the stream endpoint calls the Memory Service to auto-extract persistent facts. +- `/playbooks` — CRUD for playbooks stored in SQLite via `synapse/playbooks/store.py`. +- `/memory` — CRUD for persistent facts (proxies the same SQLite store as the memory service). +- `/models` — lists, pulls, and deletes Ollama models by proxying `ollama/bin/ollama`'s HTTP API. +- `/conversations` — persists and retrieves full chat history from SQLite. + +**System prompt assembly** (in `main.py` `chat_stream_endpoint`): the final system prompt is built by layering the active playbook instructions → reference playbook context → persistent memory facts → relevant past conversation snippets retrieved by `store.search_conversations`. + +### Memory Service (`synapse/memory/`) +A separate FastAPI app on port 8001. `service.py` exposes `/memories/extract` which calls `extractor.py` — an Ollama prompt that decides whether to persist a new fact from a conversation exchange. The main Synapse backend calls this asynchronously after each streaming response. Both services share the same SQLite database (`synapse/memory/memory.db`). + +### Playbook System (`synapse/playbooks/` + `synapse/playbook_manager.py`) +Playbooks are ordered records (title, goal, instructions, tags) stored in SQLite. The **first** playbook by order is the active system prompt; all subsequent playbooks are injected as reference context. `PlaybookManager` is the thin class the backend uses to retrieve and render them. + +### Ollama (`ollama/bin/ollama`) +A bundled Ollama binary lives at `ollama/bin/ollama`. `OllamaManager` in `synapse/ollama_manager.py` manages its lifecycle (start/stop/health-check) and selects the best available model. GPU detection uses Vulkan (`vulkaninfo`) to prefer discrete AMD/NVIDIA GPUs. The Ollama HTTP API is at `http://127.0.0.1:11434` (overridable via `OLLAMA_HOST` env var). + +### Frontend (`interface/web/`) +React 19 + Vite. No routing library — `App.jsx` manages page state in a single `currentPage` useState. All API calls hit `http://localhost:8000` (configured in `src/config.js`). Pages: Chatbot, Playbook editor, Conversation History, Models, Memory, Settings. + +### Persistent Storage +All data lands in `synapse/memory/memory.db` (SQLite, WAL mode). Tables: memory facts, conversations, messages, playbooks, app settings. `synapse/memory/store.py` (`PersistentMemoryStore`) owns the schema and all queries. `nexus_config.py` defines all paths; it also ensures all required directories exist on import. + +### Logs & Runtime State +- `runtime/backend.log`, `runtime/frontend.log` — service stdout +- `runtime/logs/ollama.log`, `runtime/logs/chat.log` +- `runtime/pids/backend.pid`, `runtime/pids/frontend.pid` — used by the management CLI + +## Key Config + +| Concern | Location | +|---|---| +| Ollama host | `OLLAMA_HOST` env var (default `http://127.0.0.1:11434`) | +| All filesystem paths | `synapse/nexus_config.py` `Settings` class | +| Frontend API base URL | `interface/web/src/config.js` | +| Python dependencies (AMD) | `requirements.txt` / `amd_requirements.txt` | +| Python dependencies (base) | `requirements-base.txt` | diff --git a/amd_requirements.txt b/amd_requirements.txt new file mode 100644 index 0000000..7abce69 --- /dev/null +++ b/amd_requirements.txt @@ -0,0 +1,10 @@ +# --- Force AMD/ROCm Priority --- +--index-url https://download.pytorch.org/whl/rocm7.2 +--extra-index-url https://pypi.org/simple + +-r requirements-base.txt + +# GPU Compute Stack +torch +torchaudio +torchvision diff --git a/assets/background.png b/assets/background.png new file mode 100644 index 0000000..16b7e2f Binary files /dev/null and b/assets/background.png differ diff --git a/assets/boot/initramfs-hook-my-custom-logo b/assets/boot/initramfs-hook-my-custom-logo new file mode 100755 index 0000000..f56900d --- /dev/null +++ b/assets/boot/initramfs-hook-my-custom-logo @@ -0,0 +1,29 @@ +#!/bin/sh +# Bakes a real, dereferenced copy of the NexusOS Plymouth theme into the +# initramfs. The theme files live in nexus-core and are exposed at +# /usr/share/plymouth/themes/my-custom-logo via a symlink into /home, which +# the stock initramfs plymouth hook copies verbatim -> it dangles at early +# boot (before /home is mounted) and Plymouth falls back to text mode. +# This hook runs after the stock "plymouth" hook and replaces that dangling +# symlink with the actual theme files. + +PREREQS="plymouth" +prereqs() { echo "$PREREQS"; } + +case "$1" in + prereqs) + prereqs + exit 0 + ;; +esac + +. /usr/share/initramfs-tools/hook-functions + +THEME_SRC="/home/jon/nexus-core/assets/boot/my-custom-logo" +THEME_DEST="${DESTDIR}/usr/share/plymouth/themes/my-custom-logo" + +[ -d "${THEME_SRC}" ] || exit 0 + +rm -rf "${THEME_DEST}" +mkdir -p "${THEME_DEST}" +cp -aL "${THEME_SRC}/." "${THEME_DEST}/" diff --git a/assets/boot/my-custom-logo/animation-0001.png b/assets/boot/my-custom-logo/animation-0001.png new file mode 100644 index 0000000..4275d88 Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0001.png differ diff --git a/assets/boot/my-custom-logo/animation-0002.png b/assets/boot/my-custom-logo/animation-0002.png new file mode 100644 index 0000000..834a4da Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0002.png differ diff --git a/assets/boot/my-custom-logo/animation-0003.png b/assets/boot/my-custom-logo/animation-0003.png new file mode 100644 index 0000000..c57defa Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0003.png differ diff --git a/assets/boot/my-custom-logo/animation-0004.png b/assets/boot/my-custom-logo/animation-0004.png new file mode 100644 index 0000000..5f3d074 Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0004.png differ diff --git a/assets/boot/my-custom-logo/animation-0005.png b/assets/boot/my-custom-logo/animation-0005.png new file mode 100644 index 0000000..891ce97 Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0005.png differ diff --git a/assets/boot/my-custom-logo/animation-0006.png b/assets/boot/my-custom-logo/animation-0006.png new file mode 100644 index 0000000..fd34309 Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0006.png differ diff --git a/assets/boot/my-custom-logo/animation-0007.png b/assets/boot/my-custom-logo/animation-0007.png new file mode 100644 index 0000000..4ea1626 Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0007.png differ diff --git a/assets/boot/my-custom-logo/animation-0008.png b/assets/boot/my-custom-logo/animation-0008.png new file mode 100644 index 0000000..9961b29 Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0008.png differ diff --git a/assets/boot/my-custom-logo/animation-0009.png b/assets/boot/my-custom-logo/animation-0009.png new file mode 100644 index 0000000..e17ded6 Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0009.png differ diff --git a/assets/boot/my-custom-logo/animation-0010.png b/assets/boot/my-custom-logo/animation-0010.png new file mode 100644 index 0000000..2dd2a4e Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0010.png differ diff --git a/assets/boot/my-custom-logo/animation-0011.png b/assets/boot/my-custom-logo/animation-0011.png new file mode 100644 index 0000000..15accdf Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0011.png differ diff --git a/assets/boot/my-custom-logo/animation-0012.png b/assets/boot/my-custom-logo/animation-0012.png new file mode 100644 index 0000000..2847d19 Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0012.png differ diff --git a/assets/boot/my-custom-logo/animation-0013.png b/assets/boot/my-custom-logo/animation-0013.png new file mode 100644 index 0000000..e3a70ad Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0013.png differ diff --git a/assets/boot/my-custom-logo/animation-0014.png b/assets/boot/my-custom-logo/animation-0014.png new file mode 100644 index 0000000..72adbff Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0014.png differ diff --git a/assets/boot/my-custom-logo/animation-0015.png b/assets/boot/my-custom-logo/animation-0015.png new file mode 100644 index 0000000..199f9ac Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0015.png differ diff --git a/assets/boot/my-custom-logo/animation-0016.png b/assets/boot/my-custom-logo/animation-0016.png new file mode 100644 index 0000000..73a985e Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0016.png differ diff --git a/assets/boot/my-custom-logo/animation-0017.png b/assets/boot/my-custom-logo/animation-0017.png new file mode 100644 index 0000000..87d86fb Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0017.png differ diff --git a/assets/boot/my-custom-logo/animation-0018.png b/assets/boot/my-custom-logo/animation-0018.png new file mode 100644 index 0000000..c4af64b Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0018.png differ diff --git a/assets/boot/my-custom-logo/animation-0019.png b/assets/boot/my-custom-logo/animation-0019.png new file mode 100644 index 0000000..f242239 Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0019.png differ diff --git a/assets/boot/my-custom-logo/animation-0020.png b/assets/boot/my-custom-logo/animation-0020.png new file mode 100644 index 0000000..1d6c50b Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0020.png differ diff --git a/assets/boot/my-custom-logo/animation-0021.png b/assets/boot/my-custom-logo/animation-0021.png new file mode 100644 index 0000000..e2e12eb Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0021.png differ diff --git a/assets/boot/my-custom-logo/animation-0022.png b/assets/boot/my-custom-logo/animation-0022.png new file mode 100644 index 0000000..2fe5f19 Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0022.png differ diff --git a/assets/boot/my-custom-logo/animation-0023.png b/assets/boot/my-custom-logo/animation-0023.png new file mode 100644 index 0000000..29e8b80 Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0023.png differ diff --git a/assets/boot/my-custom-logo/animation-0024.png b/assets/boot/my-custom-logo/animation-0024.png new file mode 100644 index 0000000..8fb996d Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0024.png differ diff --git a/assets/boot/my-custom-logo/animation-0025.png b/assets/boot/my-custom-logo/animation-0025.png new file mode 100644 index 0000000..9520100 Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0025.png differ diff --git a/assets/boot/my-custom-logo/animation-0026.png b/assets/boot/my-custom-logo/animation-0026.png new file mode 100644 index 0000000..0cf4df7 Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0026.png differ diff --git a/assets/boot/my-custom-logo/animation-0027.png b/assets/boot/my-custom-logo/animation-0027.png new file mode 100644 index 0000000..e409cc1 Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0027.png differ diff --git a/assets/boot/my-custom-logo/animation-0028.png b/assets/boot/my-custom-logo/animation-0028.png new file mode 100644 index 0000000..945cda3 Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0028.png differ diff --git a/assets/boot/my-custom-logo/animation-0029.png b/assets/boot/my-custom-logo/animation-0029.png new file mode 100644 index 0000000..ec56ba0 Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0029.png differ diff --git a/assets/boot/my-custom-logo/animation-0030.png b/assets/boot/my-custom-logo/animation-0030.png new file mode 100644 index 0000000..fed035e Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0030.png differ diff --git a/assets/boot/my-custom-logo/animation-0031.png b/assets/boot/my-custom-logo/animation-0031.png new file mode 100644 index 0000000..44ed292 Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0031.png differ diff --git a/assets/boot/my-custom-logo/animation-0032.png b/assets/boot/my-custom-logo/animation-0032.png new file mode 100644 index 0000000..aa73ccd Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0032.png differ diff --git a/assets/boot/my-custom-logo/animation-0033.png b/assets/boot/my-custom-logo/animation-0033.png new file mode 100644 index 0000000..4050187 Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0033.png differ diff --git a/assets/boot/my-custom-logo/animation-0034.png b/assets/boot/my-custom-logo/animation-0034.png new file mode 100644 index 0000000..d67b954 Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0034.png differ diff --git a/assets/boot/my-custom-logo/animation-0035.png b/assets/boot/my-custom-logo/animation-0035.png new file mode 100644 index 0000000..2918406 Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0035.png differ diff --git a/assets/boot/my-custom-logo/animation-0036.png b/assets/boot/my-custom-logo/animation-0036.png new file mode 100644 index 0000000..2dd20c8 Binary files /dev/null and b/assets/boot/my-custom-logo/animation-0036.png differ diff --git a/assets/boot/my-custom-logo/bgrt-fallback.png b/assets/boot/my-custom-logo/bgrt-fallback.png new file mode 100644 index 0000000..4720a90 Binary files /dev/null and b/assets/boot/my-custom-logo/bgrt-fallback.png differ diff --git a/assets/boot/my-custom-logo/bullet.png b/assets/boot/my-custom-logo/bullet.png new file mode 100644 index 0000000..e94e877 Binary files /dev/null and b/assets/boot/my-custom-logo/bullet.png differ diff --git a/assets/boot/my-custom-logo/capslock.png b/assets/boot/my-custom-logo/capslock.png new file mode 100644 index 0000000..45afa93 Binary files /dev/null and b/assets/boot/my-custom-logo/capslock.png differ diff --git a/assets/boot/my-custom-logo/entry.png b/assets/boot/my-custom-logo/entry.png new file mode 100644 index 0000000..8fa0a11 Binary files /dev/null and b/assets/boot/my-custom-logo/entry.png differ diff --git a/assets/boot/my-custom-logo/keyboard.png b/assets/boot/my-custom-logo/keyboard.png new file mode 100644 index 0000000..e1fd13b Binary files /dev/null and b/assets/boot/my-custom-logo/keyboard.png differ diff --git a/assets/boot/my-custom-logo/keymap-render.png b/assets/boot/my-custom-logo/keymap-render.png new file mode 100644 index 0000000..91a3eec Binary files /dev/null and b/assets/boot/my-custom-logo/keymap-render.png differ diff --git a/assets/boot/my-custom-logo/lock.png b/assets/boot/my-custom-logo/lock.png new file mode 100644 index 0000000..f3a13ee Binary files /dev/null and b/assets/boot/my-custom-logo/lock.png differ diff --git a/assets/boot/my-custom-logo/my-custom-logo.plymouth b/assets/boot/my-custom-logo/my-custom-logo.plymouth new file mode 100644 index 0000000..6a04ce6 --- /dev/null +++ b/assets/boot/my-custom-logo/my-custom-logo.plymouth @@ -0,0 +1,54 @@ +[Plymouth Theme] +Name=My Custom Logo +Description=Custom boot logo with shimmer effect +ModuleName=two-step + +[two-step] +Font=Cantarell 12 +TitleFont=Cantarell Light 30 +ImageDir=/usr/share/plymouth/themes/my-custom-logo +DialogHorizontalAlignment=.5 +DialogVerticalAlignment=.382 +TitleHorizontalAlignment=.5 +TitleVerticalAlignment=.382 +HorizontalAlignment=.5 +VerticalAlignment=.5 +WatermarkHorizontalAlignment=.5 +WatermarkVerticalAlignment=.96 +Transition=none +TransitionDuration=0.0 +BackgroundStartColor=0x000000 +BackgroundEndColor=0x000000 +ProgressBarBackgroundColor=0x606060 +ProgressBarForegroundColor=0xffffff +MessageBelowAnimation=true + +[boot-up] +UseEndAnimation=false + +[shutdown] +UseEndAnimation=false + +[reboot] +UseEndAnimation=false + +[updates] +SuppressMessages=true +ProgressBarShowPercentComplete=true +UseProgressBar=true +Title=Installing Updates... +SubTitle=Do not turn off your computer + +[system-upgrade] +SuppressMessages=true +ProgressBarShowPercentComplete=true +UseProgressBar=true +Title=Upgrading System... +SubTitle=Do not turn off your computer + +[firmware-upgrade] +SuppressMessages=true +ProgressBarShowPercentComplete=true +UseProgressBar=true +Title=Upgrading Firmware... +SubTitle=Do not turn off your computer diff --git a/assets/boot/my-custom-logo/throbber-0001.png b/assets/boot/my-custom-logo/throbber-0001.png new file mode 100644 index 0000000..4275d88 Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0001.png differ diff --git a/assets/boot/my-custom-logo/throbber-0002.png b/assets/boot/my-custom-logo/throbber-0002.png new file mode 100644 index 0000000..d305c43 Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0002.png differ diff --git a/assets/boot/my-custom-logo/throbber-0003.png b/assets/boot/my-custom-logo/throbber-0003.png new file mode 100644 index 0000000..5079a10 Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0003.png differ diff --git a/assets/boot/my-custom-logo/throbber-0004.png b/assets/boot/my-custom-logo/throbber-0004.png new file mode 100644 index 0000000..afafd5b Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0004.png differ diff --git a/assets/boot/my-custom-logo/throbber-0005.png b/assets/boot/my-custom-logo/throbber-0005.png new file mode 100644 index 0000000..7e70385 Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0005.png differ diff --git a/assets/boot/my-custom-logo/throbber-0006.png b/assets/boot/my-custom-logo/throbber-0006.png new file mode 100644 index 0000000..4ea1626 Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0006.png differ diff --git a/assets/boot/my-custom-logo/throbber-0007.png b/assets/boot/my-custom-logo/throbber-0007.png new file mode 100644 index 0000000..ae7bc8a Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0007.png differ diff --git a/assets/boot/my-custom-logo/throbber-0008.png b/assets/boot/my-custom-logo/throbber-0008.png new file mode 100644 index 0000000..9000ad1 Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0008.png differ diff --git a/assets/boot/my-custom-logo/throbber-0009.png b/assets/boot/my-custom-logo/throbber-0009.png new file mode 100644 index 0000000..1dc98f2 Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0009.png differ diff --git a/assets/boot/my-custom-logo/throbber-0010.png b/assets/boot/my-custom-logo/throbber-0010.png new file mode 100644 index 0000000..0cccf02 Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0010.png differ diff --git a/assets/boot/my-custom-logo/throbber-0011.png b/assets/boot/my-custom-logo/throbber-0011.png new file mode 100644 index 0000000..e3a70ad Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0011.png differ diff --git a/assets/boot/my-custom-logo/throbber-0012.png b/assets/boot/my-custom-logo/throbber-0012.png new file mode 100644 index 0000000..c38a69c Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0012.png differ diff --git a/assets/boot/my-custom-logo/throbber-0013.png b/assets/boot/my-custom-logo/throbber-0013.png new file mode 100644 index 0000000..9b36e13 Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0013.png differ diff --git a/assets/boot/my-custom-logo/throbber-0014.png b/assets/boot/my-custom-logo/throbber-0014.png new file mode 100644 index 0000000..52c2a81 Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0014.png differ diff --git a/assets/boot/my-custom-logo/throbber-0015.png b/assets/boot/my-custom-logo/throbber-0015.png new file mode 100644 index 0000000..7b1b780 Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0015.png differ diff --git a/assets/boot/my-custom-logo/throbber-0016.png b/assets/boot/my-custom-logo/throbber-0016.png new file mode 100644 index 0000000..f242239 Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0016.png differ diff --git a/assets/boot/my-custom-logo/throbber-0017.png b/assets/boot/my-custom-logo/throbber-0017.png new file mode 100644 index 0000000..50b1102 Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0017.png differ diff --git a/assets/boot/my-custom-logo/throbber-0018.png b/assets/boot/my-custom-logo/throbber-0018.png new file mode 100644 index 0000000..9446a83 Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0018.png differ diff --git a/assets/boot/my-custom-logo/throbber-0019.png b/assets/boot/my-custom-logo/throbber-0019.png new file mode 100644 index 0000000..d879178 Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0019.png differ diff --git a/assets/boot/my-custom-logo/throbber-0020.png b/assets/boot/my-custom-logo/throbber-0020.png new file mode 100644 index 0000000..670ae2a Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0020.png differ diff --git a/assets/boot/my-custom-logo/throbber-0021.png b/assets/boot/my-custom-logo/throbber-0021.png new file mode 100644 index 0000000..9520100 Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0021.png differ diff --git a/assets/boot/my-custom-logo/throbber-0022.png b/assets/boot/my-custom-logo/throbber-0022.png new file mode 100644 index 0000000..a58d757 Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0022.png differ diff --git a/assets/boot/my-custom-logo/throbber-0023.png b/assets/boot/my-custom-logo/throbber-0023.png new file mode 100644 index 0000000..2bda4c0 Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0023.png differ diff --git a/assets/boot/my-custom-logo/throbber-0024.png b/assets/boot/my-custom-logo/throbber-0024.png new file mode 100644 index 0000000..55a7268 Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0024.png differ diff --git a/assets/boot/my-custom-logo/throbber-0025.png b/assets/boot/my-custom-logo/throbber-0025.png new file mode 100644 index 0000000..50753d2 Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0025.png differ diff --git a/assets/boot/my-custom-logo/throbber-0026.png b/assets/boot/my-custom-logo/throbber-0026.png new file mode 100644 index 0000000..44ed292 Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0026.png differ diff --git a/assets/boot/my-custom-logo/throbber-0027.png b/assets/boot/my-custom-logo/throbber-0027.png new file mode 100644 index 0000000..59d304c Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0027.png differ diff --git a/assets/boot/my-custom-logo/throbber-0028.png b/assets/boot/my-custom-logo/throbber-0028.png new file mode 100644 index 0000000..aa02fa3 Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0028.png differ diff --git a/assets/boot/my-custom-logo/throbber-0029.png b/assets/boot/my-custom-logo/throbber-0029.png new file mode 100644 index 0000000..e769813 Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0029.png differ diff --git a/assets/boot/my-custom-logo/throbber-0030.png b/assets/boot/my-custom-logo/throbber-0030.png new file mode 100644 index 0000000..852b18f Binary files /dev/null and b/assets/boot/my-custom-logo/throbber-0030.png differ diff --git a/assets/boot/my-custom-logo/watermark.png b/assets/boot/my-custom-logo/watermark.png new file mode 100644 index 0000000..fcdbb92 Binary files /dev/null and b/assets/boot/my-custom-logo/watermark.png differ diff --git a/assets/n-folder.png b/assets/n-folder.png new file mode 100644 index 0000000..dfcab71 Binary files /dev/null and b/assets/n-folder.png differ diff --git a/assets/n-small.png b/assets/n-small.png new file mode 100644 index 0000000..c96bb05 Binary files /dev/null and b/assets/n-small.png differ diff --git a/assets/nexus-terminal.png b/assets/nexus-terminal.png new file mode 100644 index 0000000..59f5a1b Binary files /dev/null and b/assets/nexus-terminal.png differ diff --git a/assets/nexus-terminal.svg b/assets/nexus-terminal.svg new file mode 100644 index 0000000..a63a108 --- /dev/null +++ b/assets/nexus-terminal.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/themes/CREDITS.md b/assets/themes/CREDITS.md new file mode 100644 index 0000000..7aefa06 --- /dev/null +++ b/assets/themes/CREDITS.md @@ -0,0 +1,24 @@ +# Theme Asset Credits + +The NexusOS theme is assembled from original work plus assets adapted from the following upstream projects. All upstream sources are GPL-3.0 (or compatible), so the NexusOS theme inherits GPL-3.0. + +## Sources + +### WhiteSur GTK Theme — `gtk-2.0/`, `xfwm4/` +- **Project**: https://github.com/vinceliuice/WhiteSur-gtk-theme +- **Author**: Vince Liu (vinceliuice) +- **License**: GPL-3.0 +- **Variant used as base**: `WhiteSur-Dark-purple` +- **What we use**: The entire `gtk-2.0/` and `xfwm4/` directories are cloned verbatim from WhiteSur-Dark-purple. We rely on these for macOS-style window controls (stoplight buttons) and the GTK2 application skin. + +### Mint-Y Icon Theme — `NexusOS-icons/` (folder geometry reference) +- **Project**: https://github.com/linuxmint/mint-y-icons +- **Author**: Linux Mint team +- **License**: GPL-3.0 +- **What we use**: Visual reference only for the folder shape language (flat folder with tab + lip). No PNGs are copied from Mint-Y; our folder set is regenerated from scratch via `NexusOS-icons-src/build.py` against a master SVG we authored. + +## NexusOS-original content +- `gtk-3.0/*.css` — original work +- `NexusOS-icons-src/*` and the rendered output in `NexusOS-icons/places/` — original work +- The `n-small.png` badge composited into `folder-nexus-core` is the NexusOS logo at `nexus-core/assets/n-small.png` +- `index.theme` files in each theme directory — original work diff --git a/assets/themes/LICENSE b/assets/themes/LICENSE new file mode 100644 index 0000000..37441ab --- /dev/null +++ b/assets/themes/LICENSE @@ -0,0 +1,23 @@ +NexusOS theme assets — attribution and license +================================================ + +The NexusOS GTK2 and xfwm4 themes are derived from Mint-Y-Dark-Aqua, +part of the mint-themes package shipped by Linux Mint. + +Upstream: + https://github.com/linuxmint/mint-themes + Copyright (c) 2017-2024 Linux Mint + Licensed under the GNU General Public License v3.0 or later. + +Derivative work in this directory: + - NexusOS/gtk-2.0/ (PNGs recolored from Mint-Y-Dark-Aqua/gtk-2.0/) + - NexusOS/xfwm4/ (PNGs recolored from Mint-Y-Dark-Aqua/xfwm4/) + - NexusOS-gtk2-src/ (build script that performs the recolor) + - NexusOS-xfwm4-src/ (build script that performs the recolor) + +As a derivative of GPLv3 material, these files are likewise distributed +under the terms of the GNU General Public License version 3 or later. See +https://www.gnu.org/licenses/gpl-3.0.html for the full license text. + +The NexusOS GTK3 theme (NexusOS/gtk-3.0/) and the NexusOS icon set +(NexusOS-icons*/) are original works and not derived from Mint-Y. diff --git a/assets/themes/NexusOS-gtk2-src/build.py b/assets/themes/NexusOS-gtk2-src/build.py new file mode 100644 index 0000000..e1e9673 --- /dev/null +++ b/assets/themes/NexusOS-gtk2-src/build.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python3 +"""Build NexusOS GTK2 theme from Mint-Y-Dark-Aqua base. + +- Copies .rc files + assets/ from /usr/share/themes/Mint-Y-Dark-Aqua/gtk-2.0/ +- Recolors PNGs containing the Aqua accent (#1f9ede) to NexusOS green (#8cc63f) +- Rewrites the gtk-color-scheme block in gtkrc to NexusOS palette +- Replaces remaining aqua hex literals in .rc files +""" +from __future__ import annotations + +import colorsys +import shutil +import sys +from pathlib import Path + +THEMES_ROOT = Path(__file__).resolve().parent.parent +sys.path.insert(0, str(THEMES_ROOT)) +import _palette as P # noqa: E402 + +from PIL import Image # noqa: E402 + +SRC = Path("/usr/share/themes/Mint-Y-Dark-Aqua/gtk-2.0") +OUT = THEMES_ROOT / "NexusOS" / "gtk-2.0" + +AQUA_RGB = (0x1F, 0x9E, 0xDE) +AQUA_HSV = colorsys.rgb_to_hsv(*(c / 255 for c in AQUA_RGB)) +GREEN_HSV = P.hex_to_hsv(P.BRAND_GREEN) + +HUE_TOLERANCE = 30 / 360 +SAT_FLOOR = 0.18 + +S_SCALE = GREEN_HSV[1] / AQUA_HSV[1] +V_SCALE = GREEN_HSV[2] / AQUA_HSV[2] + + +def hue_distance(a: float, b: float) -> float: + d = abs(a - b) + return min(d, 1 - d) + + +def recolor_pixel(r: int, g: int, b: int, a: int) -> tuple[int, int, int, int]: + if a < 8: + return (r, g, b, a) + h, s, v = colorsys.rgb_to_hsv(r / 255, g / 255, b / 255) + if s < SAT_FLOOR or hue_distance(h, AQUA_HSV[0]) > HUE_TOLERANCE: + return (r, g, b, a) + new_s = min(1.0, s * S_SCALE) + new_v = min(1.0, v * V_SCALE) + nr, ng, nb = colorsys.hsv_to_rgb(GREEN_HSV[0], new_s, new_v) + return (round(nr * 255), round(ng * 255), round(nb * 255), a) + + +def recolor_png(path: Path) -> int: + """Recolor aqua pixels in-place. Returns count of pixels changed.""" + im = Image.open(path).convert("RGBA") + px = im.load() + w, h = im.size + changed = 0 + for y in range(h): + for x in range(w): + r, g, b, a = px[x, y] + new = recolor_pixel(r, g, b, a) + if new != (r, g, b, a): + px[x, y] = new + changed += 1 + if changed: + im.save(path, optimize=True) + return changed + + +# ── gtkrc color-scheme block ────────────────────────────────────────── +NEW_COLOR_SCHEME = ( + f"base_color:#{P.BASE_BG}\\n" + f"fg_color:#{P.TEXT_PRIMARY}\\n" + f"tooltip_fg_color:#{P.TEXT_PRIMARY}\\n" + f"selected_bg_color:#{P.BRAND_PURPLE_DARK}\\n" + f"selected_fg_color:#{P.TEXT_ON_SELECTION}\\n" + f"text_color:#{P.TEXT_PRIMARY}\\n" + f"bg_color:#{P.SURFACE_BG}\\n" + f"insensitive_bg_color:#{P.SURFACE_BG}\\n" + f"insensitive_fg_color:#{P.TEXT_DISABLED}\\n" + f"notebook_bg:#{P.BASE_BG}\\n" + f"dark_sidebar_bg:#{P.SURFACE_BG_ALT}\\n" + f"tooltip_bg_color:#{P.OVERLAY_BG}\\n" + f"link_color:#{P.BRAND_GREEN_LIGHT}\\n" + f"menu_bg:#{P.SURFACE_BG}\\n" + f"menu_separator_color:#{P.BORDER}" +) + + +def patch_gtkrc(path: Path) -> None: + text = path.read_text() + out_lines = [] + for line in text.splitlines(): + if line.startswith("gtk-color-scheme"): + out_lines.append(f'gtk-color-scheme = "{NEW_COLOR_SCHEME}"') + else: + out_lines.append(line) + path.write_text("\n".join(out_lines) + "\n") + + +# ── Remaining hex literals in .rc files ─────────────────────────────── +# Captured from Mint-Y-Dark-Aqua; map source hex → NexusOS replacement. +RC_HEX_REPLACEMENTS = { + # accent / focus / selection + "#1f9ede": f"#{P.BRAND_GREEN}", + "#1F9EDE": f"#{P.BRAND_GREEN}", + "#5294E2": f"#{P.BRAND_GREEN_LIGHT}", # link_color fallback if quoted literal + "#5294e2": f"#{P.BRAND_GREEN_LIGHT}", + # Mint-Y greys we want to nudge onto our surface family + "#2b2b2b": f"#{P.SURFACE_BG_ALT}", + "#383838": f"#{P.SURFACE_BG}", + "#404040": f"#{P.BASE_BG}", + "#3e3e3e": f"#{P.SURFACE_BG}", + "#dadada": f"#{P.TEXT_PRIMARY}", + "#DADADA": f"#{P.TEXT_PRIMARY}", + "#d3d3d3": f"#{P.TEXT_PRIMARY}", + "#D3D3D3": f"#{P.TEXT_PRIMARY}", +} + + +def patch_rc(path: Path) -> int: + text = path.read_text() + count = 0 + for src, dst in RC_HEX_REPLACEMENTS.items(): + n = text.count(src) + if n: + text = text.replace(src, dst) + count += n + path.write_text(text) + return count + + +def main() -> None: + if OUT.exists(): + shutil.rmtree(OUT) + shutil.copytree(SRC, OUT) + print(f"Copied {SRC} → {OUT}") + + # Recolor PNGs + recolored = 0 + for png in sorted((OUT / "assets").glob("*.png")): + changed = recolor_png(png) + if changed: + recolored += 1 + print(f" recolored {png.name}: {changed}px") + print(f"Recolored {recolored} PNGs") + + # Patch rc files + patched_total = 0 + for rc in sorted(OUT.glob("*.rc")): + n = patch_rc(rc) + if n: + print(f" patched {rc.name}: {n} replacements") + patched_total += n + gtkrc = OUT / "gtkrc" + patch_rc(gtkrc) + patch_gtkrc(gtkrc) + print(f"Rewrote gtkrc color scheme; total .rc hex replacements: {patched_total}") + + +if __name__ == "__main__": + main() diff --git a/assets/themes/NexusOS-icons-src/_backup/folder-nexus-core-original/128.png b/assets/themes/NexusOS-icons-src/_backup/folder-nexus-core-original/128.png new file mode 100644 index 0000000..fa71a0a Binary files /dev/null and b/assets/themes/NexusOS-icons-src/_backup/folder-nexus-core-original/128.png differ diff --git a/assets/themes/NexusOS-icons-src/_backup/folder-nexus-core-original/16.png b/assets/themes/NexusOS-icons-src/_backup/folder-nexus-core-original/16.png new file mode 100644 index 0000000..d52512e Binary files /dev/null and b/assets/themes/NexusOS-icons-src/_backup/folder-nexus-core-original/16.png differ diff --git a/assets/themes/NexusOS-icons-src/_backup/folder-nexus-core-original/22.png b/assets/themes/NexusOS-icons-src/_backup/folder-nexus-core-original/22.png new file mode 100644 index 0000000..ef88fa0 Binary files /dev/null and b/assets/themes/NexusOS-icons-src/_backup/folder-nexus-core-original/22.png differ diff --git a/assets/themes/NexusOS-icons-src/_backup/folder-nexus-core-original/24.png b/assets/themes/NexusOS-icons-src/_backup/folder-nexus-core-original/24.png new file mode 100644 index 0000000..981d898 Binary files /dev/null and b/assets/themes/NexusOS-icons-src/_backup/folder-nexus-core-original/24.png differ diff --git a/assets/themes/NexusOS-icons-src/_backup/folder-nexus-core-original/32.png b/assets/themes/NexusOS-icons-src/_backup/folder-nexus-core-original/32.png new file mode 100644 index 0000000..6a54713 Binary files /dev/null and b/assets/themes/NexusOS-icons-src/_backup/folder-nexus-core-original/32.png differ diff --git a/assets/themes/NexusOS-icons-src/_backup/folder-nexus-core-original/48.png b/assets/themes/NexusOS-icons-src/_backup/folder-nexus-core-original/48.png new file mode 100644 index 0000000..a0787a1 Binary files /dev/null and b/assets/themes/NexusOS-icons-src/_backup/folder-nexus-core-original/48.png differ diff --git a/assets/themes/NexusOS-icons-src/_backup/folder-nexus-core-original/64.png b/assets/themes/NexusOS-icons-src/_backup/folder-nexus-core-original/64.png new file mode 100644 index 0000000..4338770 Binary files /dev/null and b/assets/themes/NexusOS-icons-src/_backup/folder-nexus-core-original/64.png differ diff --git a/assets/themes/NexusOS-icons-src/_previews/folder-128.png b/assets/themes/NexusOS-icons-src/_previews/folder-128.png new file mode 100644 index 0000000..f4e42e3 Binary files /dev/null and b/assets/themes/NexusOS-icons-src/_previews/folder-128.png differ diff --git a/assets/themes/NexusOS-icons-src/_previews/folder-documents-128.png b/assets/themes/NexusOS-icons-src/_previews/folder-documents-128.png new file mode 100644 index 0000000..d2ffb23 Binary files /dev/null and b/assets/themes/NexusOS-icons-src/_previews/folder-documents-128.png differ diff --git a/assets/themes/NexusOS-icons-src/_previews/folder-download-128.png b/assets/themes/NexusOS-icons-src/_previews/folder-download-128.png new file mode 100644 index 0000000..575e7c1 Binary files /dev/null and b/assets/themes/NexusOS-icons-src/_previews/folder-download-128.png differ diff --git a/assets/themes/NexusOS-icons-src/_previews/folder-drag-accept-128.png b/assets/themes/NexusOS-icons-src/_previews/folder-drag-accept-128.png new file mode 100644 index 0000000..95f8dea Binary files /dev/null and b/assets/themes/NexusOS-icons-src/_previews/folder-drag-accept-128.png differ diff --git a/assets/themes/NexusOS-icons-src/_previews/folder-home-128.png b/assets/themes/NexusOS-icons-src/_previews/folder-home-128.png new file mode 100644 index 0000000..d1110fb Binary files /dev/null and b/assets/themes/NexusOS-icons-src/_previews/folder-home-128.png differ diff --git a/assets/themes/NexusOS-icons-src/_previews/folder-music-128.png b/assets/themes/NexusOS-icons-src/_previews/folder-music-128.png new file mode 100644 index 0000000..da004e7 Binary files /dev/null and b/assets/themes/NexusOS-icons-src/_previews/folder-music-128.png differ diff --git a/assets/themes/NexusOS-icons-src/_previews/folder-nexus-core-128.png b/assets/themes/NexusOS-icons-src/_previews/folder-nexus-core-128.png new file mode 100644 index 0000000..1fba482 Binary files /dev/null and b/assets/themes/NexusOS-icons-src/_previews/folder-nexus-core-128.png differ diff --git a/assets/themes/NexusOS-icons-src/_previews/folder-open-128.png b/assets/themes/NexusOS-icons-src/_previews/folder-open-128.png new file mode 100644 index 0000000..a007282 Binary files /dev/null and b/assets/themes/NexusOS-icons-src/_previews/folder-open-128.png differ diff --git a/assets/themes/NexusOS-icons-src/_previews/folder-pictures-128.png b/assets/themes/NexusOS-icons-src/_previews/folder-pictures-128.png new file mode 100644 index 0000000..77941cc Binary files /dev/null and b/assets/themes/NexusOS-icons-src/_previews/folder-pictures-128.png differ diff --git a/assets/themes/NexusOS-icons-src/_previews/folder-publicshare-128.png b/assets/themes/NexusOS-icons-src/_previews/folder-publicshare-128.png new file mode 100644 index 0000000..9f37ef0 Binary files /dev/null and b/assets/themes/NexusOS-icons-src/_previews/folder-publicshare-128.png differ diff --git a/assets/themes/NexusOS-icons-src/_previews/folder-recent-128.png b/assets/themes/NexusOS-icons-src/_previews/folder-recent-128.png new file mode 100644 index 0000000..0f18ae2 Binary files /dev/null and b/assets/themes/NexusOS-icons-src/_previews/folder-recent-128.png differ diff --git a/assets/themes/NexusOS-icons-src/_previews/folder-remote-128.png b/assets/themes/NexusOS-icons-src/_previews/folder-remote-128.png new file mode 100644 index 0000000..a7bbefa Binary files /dev/null and b/assets/themes/NexusOS-icons-src/_previews/folder-remote-128.png differ diff --git a/assets/themes/NexusOS-icons-src/_previews/folder-saved-search-128.png b/assets/themes/NexusOS-icons-src/_previews/folder-saved-search-128.png new file mode 100644 index 0000000..b0f6de5 Binary files /dev/null and b/assets/themes/NexusOS-icons-src/_previews/folder-saved-search-128.png differ diff --git a/assets/themes/NexusOS-icons-src/_previews/folder-templates-128.png b/assets/themes/NexusOS-icons-src/_previews/folder-templates-128.png new file mode 100644 index 0000000..9ef2876 Binary files /dev/null and b/assets/themes/NexusOS-icons-src/_previews/folder-templates-128.png differ diff --git a/assets/themes/NexusOS-icons-src/_previews/folder-videos-128.png b/assets/themes/NexusOS-icons-src/_previews/folder-videos-128.png new file mode 100644 index 0000000..643d96b Binary files /dev/null and b/assets/themes/NexusOS-icons-src/_previews/folder-videos-128.png differ diff --git a/assets/themes/NexusOS-icons-src/build.py b/assets/themes/NexusOS-icons-src/build.py new file mode 100644 index 0000000..8699ddb --- /dev/null +++ b/assets/themes/NexusOS-icons-src/build.py @@ -0,0 +1,254 @@ +#!/usr/bin/env python3 +""" +NexusOS folder icon builder. + +Emits one SVG per variant into places/, then rasterizes to +~/.icons/NexusOS//places/.png at 16/22/24/32/48/64/128. + +Run: python3 build.py # builds SVGs + renders all PNGs + python3 build.py --svg-only # just rewrite SVGs +""" + +from pathlib import Path +import base64 +import shutil +import subprocess +import sys + +ROOT = Path(__file__).resolve().parent +PLACES = ROOT / "places" +ICONS_OUT = Path.home() / ".icons" / "NexusOS" +SIZES = [16, 22, 24, 32, 48, 64, 128] + +# N logo source. Inkscape's headless renderer doesn't follow external href +# references, so we inline it as a base64 data URI. +LOGO_PATH = Path.home() / "nexus-core" / "assets" / "n-small.png" +LOGO_DATA_URI = ( + "data:image/png;base64," + + base64.b64encode(LOGO_PATH.read_bytes()).decode("ascii") +) + +# ── master folder geometry ──────────────────────────────────────────── +# viewBox 0 0 128 128. Badge area: roughly (32,52)-(96,108). +MASTER = """\ + + + + + + + + +""" + +# Open-folder geometry used by folder-open and folder-drag-accept. +# The front face is angled forward, exposing the back as a triangle on top. +OPEN_MASTER = """\ + + + + + + + + +""" + +# ── badge fragments ─────────────────────────────────────────────────── +# All badges drawn in white (#f2f2f2) and centered around (64, 78). +# Keep glyphs in roughly a 40-50px box for legibility at 22-32 sizes. + +BADGES = { + "folder": "", # the base, no badge + + "folder-documents": """\ + + + + + + + +""", + + "folder-download": """\ + + + + +""", + + "folder-music": """\ + + + + +""", + + "folder-pictures": """\ + + + + +""", + + "folder-videos": """\ + + + + + + + + + + + + + +""", + + "folder-templates": """\ + + + + + + +""", + + "folder-publicshare": """\ + + + + + + + +""", + + "folder-home": """\ + + +""", + + "folder-recent": """\ + + + + + +""", + + "folder-remote": """\ + + + + + + +""", + + "folder-saved-search": """\ + + + +""", + + "folder-drag-accept": "USE_OPEN_MASTER", # uses OPEN_MASTER, no extra badge + "folder-open": "USE_OPEN_MASTER", + + "folder-nexus-core": f"""\ + + + +""", +} + + +def svg_for(name: str, badge: str) -> str: + if badge == "USE_OPEN_MASTER": + body = OPEN_MASTER + extra = "" + else: + body = MASTER + extra = badge + return f""" + +{body}{extra} +""" + + +def write_svgs() -> list[str]: + PLACES.mkdir(parents=True, exist_ok=True) + written = [] + for name, badge in BADGES.items(): + path = PLACES / f"{name}.svg" + path.write_text(svg_for(name, badge)) + written.append(name) + return written + + +def render_pngs(names: list[str]) -> None: + for name in names: + svg = PLACES / f"{name}.svg" + for size in SIZES: + out_dir = ICONS_OUT / f"{size}x{size}" / "places" + out_dir.mkdir(parents=True, exist_ok=True) + out = out_dir / f"{name}.png" + subprocess.run( + [ + "inkscape", + str(svg), + "--export-type=png", + f"--export-filename={out}", + f"--export-width={size}", + f"--export-height={size}", + ], + check=True, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + print(f" rendered {name} @ {size}") + + +def backup_existing_nexus_core() -> None: + """Move the existing chunky 3D folder-nexus-core PNGs aside before overwriting.""" + backup = ROOT / "_backup" / "folder-nexus-core-original" + backup.mkdir(parents=True, exist_ok=True) + for size in SIZES: + src = ICONS_OUT / f"{size}x{size}" / "places" / "folder-nexus-core.png" + if src.exists(): + shutil.copy2(src, backup / f"{size}.png") + print(f" backed up original folder-nexus-core to {backup}") + + +def main() -> None: + svg_only = "--svg-only" in sys.argv + names = write_svgs() + print(f"Wrote {len(names)} SVGs into {PLACES}") + if svg_only: + return + backup_existing_nexus_core() + render_pngs(names) + # Refresh the GTK icon cache so file managers pick up the new icons. + subprocess.run( + ["gtk-update-icon-cache", "-f", str(ICONS_OUT)], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + print(f"\nDone. Set theme to NexusOS in your DE to see the icons.") + + +if __name__ == "__main__": + main() diff --git a/assets/themes/NexusOS-icons-src/build_icons.py b/assets/themes/NexusOS-icons-src/build_icons.py new file mode 100644 index 0000000..2a6fd02 --- /dev/null +++ b/assets/themes/NexusOS-icons-src/build_icons.py @@ -0,0 +1,270 @@ +#!/usr/bin/env python3 +""" +NexusOS folder icon generator. + +Composes each variant SVG from a shared master + a per-variant badge fragment, +then rasterizes each to PNG at 16/22/24/32/48/64/128 and drops the result into +~/.icons/NexusOS//places/.png. + +Run from this directory: + python3 build_icons.py [--svg-only] [--no-cache-update] +""" +from __future__ import annotations + +import argparse +import base64 +import pathlib +import shutil +import subprocess +import sys +from textwrap import dedent + +ROOT = pathlib.Path(__file__).resolve().parent +PLACES_DIR = ROOT / "places" +LOGO_SRC = ROOT.parent.parent / "assets" / "n-small.png" +ICONS_OUT = pathlib.Path.home() / ".icons" / "NexusOS" +SIZES = (16, 22, 24, 32, 48, 64, 128) + +# ── colors (mirror gtk-3.0/colors.css) ─────────────────────────────────────── +BODY = "#5e0066" # brand_purple_dark — folder body +HIGHLIGHT = "#88008f" # brand_purple — top-of-face highlight stripe +TAB = "#8cc63f" # brand_green — folder tab +TAB_BRIGHT = "#b8e373" # brand_green_light — drag-accept tab +LIP = "#f2f2f2" # text_primary — inner lip stripe & badge fill + +# Embedded logo (base64) populated at runtime +_LOGO_B64: str | None = None + + +def logo_data_uri() -> str: + global _LOGO_B64 + if _LOGO_B64 is None: + _LOGO_B64 = base64.b64encode(LOGO_SRC.read_bytes()).decode("ascii") + return f"data:image/png;base64,{_LOGO_B64}" + + +def folder_svg(badge: str, *, tab_color: str = TAB) -> str: + """Build a full variant SVG by injecting `badge` into the master template.""" + return dedent(f"""\ + + + + + + + {badge} + + """) + + +# ── badge fragments (centered on front face ~x=64, y=78) ───────────────────── +# Each is a simple white-on-purple glyph kept readable at 16-22px. + +BADGES: dict[str, str] = { + # Base folder — no badge + "folder": "", + + # Folder-open: lighter tab + slight perspective on front (simple variant) + "folder-open": ( + f'' + ), + + # Documents — page with folded corner + "folder-documents": ( + f'' + f'' + ), + + # Download — down arrow + "folder-download": ( + f'' + ), + + # Drag-accept — uses bright green tab, plus white plus glyph + "folder-drag-accept": ( + f'' + ), + + # Home — house + "folder-home": ( + f'' + ), + + # Music — eighth note + "folder-music": ( + f'' + f'' + f'' + ), + + # Pictures — sun over mountains + "folder-pictures": ( + f'' + f'' + f'' + ), + + # Publicshare — two people + "folder-publicshare": ( + f'' + f'' + f'' + ), + + # Recent — clock face + "folder-recent": ( + f'' + f'' + ), + + # Remote — globe (circle + ellipse + meridian) + "folder-remote": ( + f'' + f'' + f'' + ), + + # Saved search — magnifying glass + "folder-saved-search": ( + f'' + f'' + ), + + # Templates — page with horizontal lines + "folder-templates": ( + f'' + f'' + f'' + f'' + f'' + f'' + ), + + # Videos — play triangle + "folder-videos": ( + f'' + ), +} + + +def nexus_core_svg() -> str: + """folder-nexus-core embeds the bicolor N logo via base64 data URI.""" + return dedent(f"""\ + + + + + + + + + """) + + +def write_variants() -> list[tuple[str, pathlib.Path]]: + PLACES_DIR.mkdir(parents=True, exist_ok=True) + written: list[tuple[str, pathlib.Path]] = [] + + for name, badge in BADGES.items(): + tab = TAB_BRIGHT if name == "folder-drag-accept" else TAB + path = PLACES_DIR / f"{name}.svg" + path.write_text(folder_svg(badge, tab_color=tab)) + written.append((name, path)) + + nx_path = PLACES_DIR / "folder-nexus-core.svg" + nx_path.write_text(nexus_core_svg()) + written.append(("folder-nexus-core", nx_path)) + + return written + + +def render_one(svg_path: pathlib.Path, name: str) -> None: + for size in SIZES: + out_dir = ICONS_OUT / f"{size}x{size}" / "places" + out_dir.mkdir(parents=True, exist_ok=True) + out_png = out_dir / f"{name}.png" + subprocess.run( + [ + "inkscape", + str(svg_path), + "--export-type=png", + f"--export-filename={out_png}", + f"--export-width={size}", + f"--export-height={size}", + ], + check=True, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + print(f" {name} → {size}x{size}") + + +def backup_existing() -> None: + backup = ROOT / "_backup" / "folder-nexus-core-pre-rebuild" + if backup.exists(): + return + backup.mkdir(parents=True, exist_ok=True) + for size in SIZES: + src = ICONS_OUT / f"{size}x{size}" / "places" / "folder-nexus-core.png" + if src.exists(): + shutil.copy2(src, backup / f"{size}-folder-nexus-core.png") + print(f"Backed up existing folder-nexus-core PNGs → {backup}") + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument("--svg-only", action="store_true", + help="only write SVG sources, skip rasterization") + parser.add_argument("--no-cache-update", action="store_true", + help="skip gtk-update-icon-cache at the end") + args = parser.parse_args() + + if not LOGO_SRC.exists(): + print(f"ERROR: logo source missing at {LOGO_SRC}", file=sys.stderr) + return 1 + + print("Writing variant SVGs…") + variants = write_variants() + print(f" {len(variants)} SVGs written to {PLACES_DIR}") + + if args.svg_only: + return 0 + + backup_existing() + + print("Rendering PNGs…") + for name, svg_path in variants: + render_one(svg_path, name) + + if not args.no_cache_update: + print("Refreshing icon cache…") + subprocess.run( + ["gtk-update-icon-cache", "-f", "-t", str(ICONS_OUT)], + check=False, + ) + + print(f"\nDone. Rendered {len(variants)} variants × {len(SIZES)} sizes " + f"= {len(variants) * len(SIZES)} PNGs.") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/assets/themes/NexusOS-icons-src/places/folder-documents.svg b/assets/themes/NexusOS-icons-src/places/folder-documents.svg new file mode 100644 index 0000000..dfe629c --- /dev/null +++ b/assets/themes/NexusOS-icons-src/places/folder-documents.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/assets/themes/NexusOS-icons-src/places/folder-download.svg b/assets/themes/NexusOS-icons-src/places/folder-download.svg new file mode 100644 index 0000000..7655370 --- /dev/null +++ b/assets/themes/NexusOS-icons-src/places/folder-download.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + diff --git a/assets/themes/NexusOS-icons-src/places/folder-drag-accept.svg b/assets/themes/NexusOS-icons-src/places/folder-drag-accept.svg new file mode 100644 index 0000000..e657e4c --- /dev/null +++ b/assets/themes/NexusOS-icons-src/places/folder-drag-accept.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/assets/themes/NexusOS-icons-src/places/folder-home.svg b/assets/themes/NexusOS-icons-src/places/folder-home.svg new file mode 100644 index 0000000..dd78ae0 --- /dev/null +++ b/assets/themes/NexusOS-icons-src/places/folder-home.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + diff --git a/assets/themes/NexusOS-icons-src/places/folder-music.svg b/assets/themes/NexusOS-icons-src/places/folder-music.svg new file mode 100644 index 0000000..26f0f19 --- /dev/null +++ b/assets/themes/NexusOS-icons-src/places/folder-music.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + diff --git a/assets/themes/NexusOS-icons-src/places/folder-nexus-core.svg b/assets/themes/NexusOS-icons-src/places/folder-nexus-core.svg new file mode 100644 index 0000000..ed4ffc9 --- /dev/null +++ b/assets/themes/NexusOS-icons-src/places/folder-nexus-core.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + diff --git a/assets/themes/NexusOS-icons-src/places/folder-open.svg b/assets/themes/NexusOS-icons-src/places/folder-open.svg new file mode 100644 index 0000000..e657e4c --- /dev/null +++ b/assets/themes/NexusOS-icons-src/places/folder-open.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/assets/themes/NexusOS-icons-src/places/folder-pictures.svg b/assets/themes/NexusOS-icons-src/places/folder-pictures.svg new file mode 100644 index 0000000..94122b8 --- /dev/null +++ b/assets/themes/NexusOS-icons-src/places/folder-pictures.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + diff --git a/assets/themes/NexusOS-icons-src/places/folder-publicshare.svg b/assets/themes/NexusOS-icons-src/places/folder-publicshare.svg new file mode 100644 index 0000000..3290c8b --- /dev/null +++ b/assets/themes/NexusOS-icons-src/places/folder-publicshare.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + diff --git a/assets/themes/NexusOS-icons-src/places/folder-recent.svg b/assets/themes/NexusOS-icons-src/places/folder-recent.svg new file mode 100644 index 0000000..5fb0d75 --- /dev/null +++ b/assets/themes/NexusOS-icons-src/places/folder-recent.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + diff --git a/assets/themes/NexusOS-icons-src/places/folder-remote.svg b/assets/themes/NexusOS-icons-src/places/folder-remote.svg new file mode 100644 index 0000000..6f61960 --- /dev/null +++ b/assets/themes/NexusOS-icons-src/places/folder-remote.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + diff --git a/assets/themes/NexusOS-icons-src/places/folder-saved-search.svg b/assets/themes/NexusOS-icons-src/places/folder-saved-search.svg new file mode 100644 index 0000000..cd1e47d --- /dev/null +++ b/assets/themes/NexusOS-icons-src/places/folder-saved-search.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/assets/themes/NexusOS-icons-src/places/folder-templates.svg b/assets/themes/NexusOS-icons-src/places/folder-templates.svg new file mode 100644 index 0000000..2fa1430 --- /dev/null +++ b/assets/themes/NexusOS-icons-src/places/folder-templates.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + diff --git a/assets/themes/NexusOS-icons-src/places/folder-videos.svg b/assets/themes/NexusOS-icons-src/places/folder-videos.svg new file mode 100644 index 0000000..fc4a8a0 --- /dev/null +++ b/assets/themes/NexusOS-icons-src/places/folder-videos.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/themes/NexusOS-icons-src/places/folder.svg b/assets/themes/NexusOS-icons-src/places/folder.svg new file mode 100644 index 0000000..a930859 --- /dev/null +++ b/assets/themes/NexusOS-icons-src/places/folder.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/assets/themes/NexusOS-icons/128x128/apps/nexusos-logo.png b/assets/themes/NexusOS-icons/128x128/apps/nexusos-logo.png new file mode 100644 index 0000000..c96bb05 Binary files /dev/null and b/assets/themes/NexusOS-icons/128x128/apps/nexusos-logo.png differ diff --git a/assets/themes/NexusOS-icons/128x128/apps/utilities-terminal.png b/assets/themes/NexusOS-icons/128x128/apps/utilities-terminal.png new file mode 100644 index 0000000..def29dd Binary files /dev/null and b/assets/themes/NexusOS-icons/128x128/apps/utilities-terminal.png differ diff --git a/assets/themes/NexusOS-icons/128x128/places/folder-documents.png b/assets/themes/NexusOS-icons/128x128/places/folder-documents.png new file mode 100644 index 0000000..f61db61 Binary files /dev/null and b/assets/themes/NexusOS-icons/128x128/places/folder-documents.png differ diff --git a/assets/themes/NexusOS-icons/128x128/places/folder-download.png b/assets/themes/NexusOS-icons/128x128/places/folder-download.png new file mode 100644 index 0000000..baa037d Binary files /dev/null and b/assets/themes/NexusOS-icons/128x128/places/folder-download.png differ diff --git a/assets/themes/NexusOS-icons/128x128/places/folder-drag-accept.png b/assets/themes/NexusOS-icons/128x128/places/folder-drag-accept.png new file mode 100644 index 0000000..a007282 Binary files /dev/null and b/assets/themes/NexusOS-icons/128x128/places/folder-drag-accept.png differ diff --git a/assets/themes/NexusOS-icons/128x128/places/folder-home.png b/assets/themes/NexusOS-icons/128x128/places/folder-home.png new file mode 100644 index 0000000..1eafb4a Binary files /dev/null and b/assets/themes/NexusOS-icons/128x128/places/folder-home.png differ diff --git a/assets/themes/NexusOS-icons/128x128/places/folder-music.png b/assets/themes/NexusOS-icons/128x128/places/folder-music.png new file mode 100644 index 0000000..02f6dc2 Binary files /dev/null and b/assets/themes/NexusOS-icons/128x128/places/folder-music.png differ diff --git a/assets/themes/NexusOS-icons/128x128/places/folder-nexus-core.png b/assets/themes/NexusOS-icons/128x128/places/folder-nexus-core.png new file mode 100644 index 0000000..79a5b02 Binary files /dev/null and b/assets/themes/NexusOS-icons/128x128/places/folder-nexus-core.png differ diff --git a/assets/themes/NexusOS-icons/128x128/places/folder-open.png b/assets/themes/NexusOS-icons/128x128/places/folder-open.png new file mode 100644 index 0000000..a007282 Binary files /dev/null and b/assets/themes/NexusOS-icons/128x128/places/folder-open.png differ diff --git a/assets/themes/NexusOS-icons/128x128/places/folder-pictures.png b/assets/themes/NexusOS-icons/128x128/places/folder-pictures.png new file mode 100644 index 0000000..77941cc Binary files /dev/null and b/assets/themes/NexusOS-icons/128x128/places/folder-pictures.png differ diff --git a/assets/themes/NexusOS-icons/128x128/places/folder-publicshare.png b/assets/themes/NexusOS-icons/128x128/places/folder-publicshare.png new file mode 100644 index 0000000..9f37ef0 Binary files /dev/null and b/assets/themes/NexusOS-icons/128x128/places/folder-publicshare.png differ diff --git a/assets/themes/NexusOS-icons/128x128/places/folder-recent.png b/assets/themes/NexusOS-icons/128x128/places/folder-recent.png new file mode 100644 index 0000000..0f18ae2 Binary files /dev/null and b/assets/themes/NexusOS-icons/128x128/places/folder-recent.png differ diff --git a/assets/themes/NexusOS-icons/128x128/places/folder-remote.png b/assets/themes/NexusOS-icons/128x128/places/folder-remote.png new file mode 100644 index 0000000..a7bbefa Binary files /dev/null and b/assets/themes/NexusOS-icons/128x128/places/folder-remote.png differ diff --git a/assets/themes/NexusOS-icons/128x128/places/folder-saved-search.png b/assets/themes/NexusOS-icons/128x128/places/folder-saved-search.png new file mode 100644 index 0000000..b0f6de5 Binary files /dev/null and b/assets/themes/NexusOS-icons/128x128/places/folder-saved-search.png differ diff --git a/assets/themes/NexusOS-icons/128x128/places/folder-templates.png b/assets/themes/NexusOS-icons/128x128/places/folder-templates.png new file mode 100644 index 0000000..9ef2876 Binary files /dev/null and b/assets/themes/NexusOS-icons/128x128/places/folder-templates.png differ diff --git a/assets/themes/NexusOS-icons/128x128/places/folder-videos.png b/assets/themes/NexusOS-icons/128x128/places/folder-videos.png new file mode 100644 index 0000000..643d96b Binary files /dev/null and b/assets/themes/NexusOS-icons/128x128/places/folder-videos.png differ diff --git a/assets/themes/NexusOS-icons/128x128/places/folder.png b/assets/themes/NexusOS-icons/128x128/places/folder.png new file mode 100644 index 0000000..f4e42e3 Binary files /dev/null and b/assets/themes/NexusOS-icons/128x128/places/folder.png differ diff --git a/assets/themes/NexusOS-icons/16x16/apps/nexusos-logo.png b/assets/themes/NexusOS-icons/16x16/apps/nexusos-logo.png new file mode 100644 index 0000000..c96bb05 Binary files /dev/null and b/assets/themes/NexusOS-icons/16x16/apps/nexusos-logo.png differ diff --git a/assets/themes/NexusOS-icons/16x16/apps/utilities-terminal.png b/assets/themes/NexusOS-icons/16x16/apps/utilities-terminal.png new file mode 100644 index 0000000..8b7b259 Binary files /dev/null and b/assets/themes/NexusOS-icons/16x16/apps/utilities-terminal.png differ diff --git a/assets/themes/NexusOS-icons/16x16/places/folder-documents.png b/assets/themes/NexusOS-icons/16x16/places/folder-documents.png new file mode 100644 index 0000000..afefc9d Binary files /dev/null and b/assets/themes/NexusOS-icons/16x16/places/folder-documents.png differ diff --git a/assets/themes/NexusOS-icons/16x16/places/folder-download.png b/assets/themes/NexusOS-icons/16x16/places/folder-download.png new file mode 100644 index 0000000..ed6a8f6 Binary files /dev/null and b/assets/themes/NexusOS-icons/16x16/places/folder-download.png differ diff --git a/assets/themes/NexusOS-icons/16x16/places/folder-drag-accept.png b/assets/themes/NexusOS-icons/16x16/places/folder-drag-accept.png new file mode 100644 index 0000000..abcffa8 Binary files /dev/null and b/assets/themes/NexusOS-icons/16x16/places/folder-drag-accept.png differ diff --git a/assets/themes/NexusOS-icons/16x16/places/folder-home.png b/assets/themes/NexusOS-icons/16x16/places/folder-home.png new file mode 100644 index 0000000..aa59ef3 Binary files /dev/null and b/assets/themes/NexusOS-icons/16x16/places/folder-home.png differ diff --git a/assets/themes/NexusOS-icons/16x16/places/folder-music.png b/assets/themes/NexusOS-icons/16x16/places/folder-music.png new file mode 100644 index 0000000..3443376 Binary files /dev/null and b/assets/themes/NexusOS-icons/16x16/places/folder-music.png differ diff --git a/assets/themes/NexusOS-icons/16x16/places/folder-nexus-core.png b/assets/themes/NexusOS-icons/16x16/places/folder-nexus-core.png new file mode 100644 index 0000000..626d329 Binary files /dev/null and b/assets/themes/NexusOS-icons/16x16/places/folder-nexus-core.png differ diff --git a/assets/themes/NexusOS-icons/16x16/places/folder-open.png b/assets/themes/NexusOS-icons/16x16/places/folder-open.png new file mode 100644 index 0000000..abcffa8 Binary files /dev/null and b/assets/themes/NexusOS-icons/16x16/places/folder-open.png differ diff --git a/assets/themes/NexusOS-icons/16x16/places/folder-pictures.png b/assets/themes/NexusOS-icons/16x16/places/folder-pictures.png new file mode 100644 index 0000000..e1ffa5a Binary files /dev/null and b/assets/themes/NexusOS-icons/16x16/places/folder-pictures.png differ diff --git a/assets/themes/NexusOS-icons/16x16/places/folder-publicshare.png b/assets/themes/NexusOS-icons/16x16/places/folder-publicshare.png new file mode 100644 index 0000000..47b2794 Binary files /dev/null and b/assets/themes/NexusOS-icons/16x16/places/folder-publicshare.png differ diff --git a/assets/themes/NexusOS-icons/16x16/places/folder-recent.png b/assets/themes/NexusOS-icons/16x16/places/folder-recent.png new file mode 100644 index 0000000..7765172 Binary files /dev/null and b/assets/themes/NexusOS-icons/16x16/places/folder-recent.png differ diff --git a/assets/themes/NexusOS-icons/16x16/places/folder-remote.png b/assets/themes/NexusOS-icons/16x16/places/folder-remote.png new file mode 100644 index 0000000..53bf9c9 Binary files /dev/null and b/assets/themes/NexusOS-icons/16x16/places/folder-remote.png differ diff --git a/assets/themes/NexusOS-icons/16x16/places/folder-saved-search.png b/assets/themes/NexusOS-icons/16x16/places/folder-saved-search.png new file mode 100644 index 0000000..7f638bb Binary files /dev/null and b/assets/themes/NexusOS-icons/16x16/places/folder-saved-search.png differ diff --git a/assets/themes/NexusOS-icons/16x16/places/folder-templates.png b/assets/themes/NexusOS-icons/16x16/places/folder-templates.png new file mode 100644 index 0000000..63b5295 Binary files /dev/null and b/assets/themes/NexusOS-icons/16x16/places/folder-templates.png differ diff --git a/assets/themes/NexusOS-icons/16x16/places/folder-videos.png b/assets/themes/NexusOS-icons/16x16/places/folder-videos.png new file mode 100644 index 0000000..f46ef59 Binary files /dev/null and b/assets/themes/NexusOS-icons/16x16/places/folder-videos.png differ diff --git a/assets/themes/NexusOS-icons/16x16/places/folder.png b/assets/themes/NexusOS-icons/16x16/places/folder.png new file mode 100644 index 0000000..2921b94 Binary files /dev/null and b/assets/themes/NexusOS-icons/16x16/places/folder.png differ diff --git a/assets/themes/NexusOS-icons/22x22/apps/nexusos-logo.png b/assets/themes/NexusOS-icons/22x22/apps/nexusos-logo.png new file mode 100644 index 0000000..c96bb05 Binary files /dev/null and b/assets/themes/NexusOS-icons/22x22/apps/nexusos-logo.png differ diff --git a/assets/themes/NexusOS-icons/22x22/apps/utilities-terminal.png b/assets/themes/NexusOS-icons/22x22/apps/utilities-terminal.png new file mode 100644 index 0000000..11279ba Binary files /dev/null and b/assets/themes/NexusOS-icons/22x22/apps/utilities-terminal.png differ diff --git a/assets/themes/NexusOS-icons/22x22/places/folder-documents.png b/assets/themes/NexusOS-icons/22x22/places/folder-documents.png new file mode 100644 index 0000000..6474a19 Binary files /dev/null and b/assets/themes/NexusOS-icons/22x22/places/folder-documents.png differ diff --git a/assets/themes/NexusOS-icons/22x22/places/folder-download.png b/assets/themes/NexusOS-icons/22x22/places/folder-download.png new file mode 100644 index 0000000..1121c8e Binary files /dev/null and b/assets/themes/NexusOS-icons/22x22/places/folder-download.png differ diff --git a/assets/themes/NexusOS-icons/22x22/places/folder-drag-accept.png b/assets/themes/NexusOS-icons/22x22/places/folder-drag-accept.png new file mode 100644 index 0000000..396a8a4 Binary files /dev/null and b/assets/themes/NexusOS-icons/22x22/places/folder-drag-accept.png differ diff --git a/assets/themes/NexusOS-icons/22x22/places/folder-home.png b/assets/themes/NexusOS-icons/22x22/places/folder-home.png new file mode 100644 index 0000000..8b634f1 Binary files /dev/null and b/assets/themes/NexusOS-icons/22x22/places/folder-home.png differ diff --git a/assets/themes/NexusOS-icons/22x22/places/folder-music.png b/assets/themes/NexusOS-icons/22x22/places/folder-music.png new file mode 100644 index 0000000..713f21e Binary files /dev/null and b/assets/themes/NexusOS-icons/22x22/places/folder-music.png differ diff --git a/assets/themes/NexusOS-icons/22x22/places/folder-nexus-core.png b/assets/themes/NexusOS-icons/22x22/places/folder-nexus-core.png new file mode 100644 index 0000000..ac68825 Binary files /dev/null and b/assets/themes/NexusOS-icons/22x22/places/folder-nexus-core.png differ diff --git a/assets/themes/NexusOS-icons/22x22/places/folder-open.png b/assets/themes/NexusOS-icons/22x22/places/folder-open.png new file mode 100644 index 0000000..396a8a4 Binary files /dev/null and b/assets/themes/NexusOS-icons/22x22/places/folder-open.png differ diff --git a/assets/themes/NexusOS-icons/22x22/places/folder-pictures.png b/assets/themes/NexusOS-icons/22x22/places/folder-pictures.png new file mode 100644 index 0000000..8b02e98 Binary files /dev/null and b/assets/themes/NexusOS-icons/22x22/places/folder-pictures.png differ diff --git a/assets/themes/NexusOS-icons/22x22/places/folder-publicshare.png b/assets/themes/NexusOS-icons/22x22/places/folder-publicshare.png new file mode 100644 index 0000000..ef8235b Binary files /dev/null and b/assets/themes/NexusOS-icons/22x22/places/folder-publicshare.png differ diff --git a/assets/themes/NexusOS-icons/22x22/places/folder-recent.png b/assets/themes/NexusOS-icons/22x22/places/folder-recent.png new file mode 100644 index 0000000..35033b1 Binary files /dev/null and b/assets/themes/NexusOS-icons/22x22/places/folder-recent.png differ diff --git a/assets/themes/NexusOS-icons/22x22/places/folder-remote.png b/assets/themes/NexusOS-icons/22x22/places/folder-remote.png new file mode 100644 index 0000000..548206e Binary files /dev/null and b/assets/themes/NexusOS-icons/22x22/places/folder-remote.png differ diff --git a/assets/themes/NexusOS-icons/22x22/places/folder-saved-search.png b/assets/themes/NexusOS-icons/22x22/places/folder-saved-search.png new file mode 100644 index 0000000..588b85b Binary files /dev/null and b/assets/themes/NexusOS-icons/22x22/places/folder-saved-search.png differ diff --git a/assets/themes/NexusOS-icons/22x22/places/folder-templates.png b/assets/themes/NexusOS-icons/22x22/places/folder-templates.png new file mode 100644 index 0000000..59caafb Binary files /dev/null and b/assets/themes/NexusOS-icons/22x22/places/folder-templates.png differ diff --git a/assets/themes/NexusOS-icons/22x22/places/folder-videos.png b/assets/themes/NexusOS-icons/22x22/places/folder-videos.png new file mode 100644 index 0000000..7eb56a7 Binary files /dev/null and b/assets/themes/NexusOS-icons/22x22/places/folder-videos.png differ diff --git a/assets/themes/NexusOS-icons/22x22/places/folder.png b/assets/themes/NexusOS-icons/22x22/places/folder.png new file mode 100644 index 0000000..972ce76 Binary files /dev/null and b/assets/themes/NexusOS-icons/22x22/places/folder.png differ diff --git a/assets/themes/NexusOS-icons/24x24/apps/nexusos-logo.png b/assets/themes/NexusOS-icons/24x24/apps/nexusos-logo.png new file mode 100644 index 0000000..c96bb05 Binary files /dev/null and b/assets/themes/NexusOS-icons/24x24/apps/nexusos-logo.png differ diff --git a/assets/themes/NexusOS-icons/24x24/apps/utilities-terminal.png b/assets/themes/NexusOS-icons/24x24/apps/utilities-terminal.png new file mode 100644 index 0000000..63f83c8 Binary files /dev/null and b/assets/themes/NexusOS-icons/24x24/apps/utilities-terminal.png differ diff --git a/assets/themes/NexusOS-icons/24x24/places/folder-documents.png b/assets/themes/NexusOS-icons/24x24/places/folder-documents.png new file mode 100644 index 0000000..671731f Binary files /dev/null and b/assets/themes/NexusOS-icons/24x24/places/folder-documents.png differ diff --git a/assets/themes/NexusOS-icons/24x24/places/folder-download.png b/assets/themes/NexusOS-icons/24x24/places/folder-download.png new file mode 100644 index 0000000..d5faae0 Binary files /dev/null and b/assets/themes/NexusOS-icons/24x24/places/folder-download.png differ diff --git a/assets/themes/NexusOS-icons/24x24/places/folder-drag-accept.png b/assets/themes/NexusOS-icons/24x24/places/folder-drag-accept.png new file mode 100644 index 0000000..a690edb Binary files /dev/null and b/assets/themes/NexusOS-icons/24x24/places/folder-drag-accept.png differ diff --git a/assets/themes/NexusOS-icons/24x24/places/folder-home.png b/assets/themes/NexusOS-icons/24x24/places/folder-home.png new file mode 100644 index 0000000..a9f932e Binary files /dev/null and b/assets/themes/NexusOS-icons/24x24/places/folder-home.png differ diff --git a/assets/themes/NexusOS-icons/24x24/places/folder-music.png b/assets/themes/NexusOS-icons/24x24/places/folder-music.png new file mode 100644 index 0000000..60f8405 Binary files /dev/null and b/assets/themes/NexusOS-icons/24x24/places/folder-music.png differ diff --git a/assets/themes/NexusOS-icons/24x24/places/folder-nexus-core.png b/assets/themes/NexusOS-icons/24x24/places/folder-nexus-core.png new file mode 100644 index 0000000..e5a5824 Binary files /dev/null and b/assets/themes/NexusOS-icons/24x24/places/folder-nexus-core.png differ diff --git a/assets/themes/NexusOS-icons/24x24/places/folder-open.png b/assets/themes/NexusOS-icons/24x24/places/folder-open.png new file mode 100644 index 0000000..a690edb Binary files /dev/null and b/assets/themes/NexusOS-icons/24x24/places/folder-open.png differ diff --git a/assets/themes/NexusOS-icons/24x24/places/folder-pictures.png b/assets/themes/NexusOS-icons/24x24/places/folder-pictures.png new file mode 100644 index 0000000..b995f3c Binary files /dev/null and b/assets/themes/NexusOS-icons/24x24/places/folder-pictures.png differ diff --git a/assets/themes/NexusOS-icons/24x24/places/folder-publicshare.png b/assets/themes/NexusOS-icons/24x24/places/folder-publicshare.png new file mode 100644 index 0000000..cc869c9 Binary files /dev/null and b/assets/themes/NexusOS-icons/24x24/places/folder-publicshare.png differ diff --git a/assets/themes/NexusOS-icons/24x24/places/folder-recent.png b/assets/themes/NexusOS-icons/24x24/places/folder-recent.png new file mode 100644 index 0000000..298c343 Binary files /dev/null and b/assets/themes/NexusOS-icons/24x24/places/folder-recent.png differ diff --git a/assets/themes/NexusOS-icons/24x24/places/folder-remote.png b/assets/themes/NexusOS-icons/24x24/places/folder-remote.png new file mode 100644 index 0000000..ca4f3d4 Binary files /dev/null and b/assets/themes/NexusOS-icons/24x24/places/folder-remote.png differ diff --git a/assets/themes/NexusOS-icons/24x24/places/folder-saved-search.png b/assets/themes/NexusOS-icons/24x24/places/folder-saved-search.png new file mode 100644 index 0000000..14aaf75 Binary files /dev/null and b/assets/themes/NexusOS-icons/24x24/places/folder-saved-search.png differ diff --git a/assets/themes/NexusOS-icons/24x24/places/folder-templates.png b/assets/themes/NexusOS-icons/24x24/places/folder-templates.png new file mode 100644 index 0000000..021409f Binary files /dev/null and b/assets/themes/NexusOS-icons/24x24/places/folder-templates.png differ diff --git a/assets/themes/NexusOS-icons/24x24/places/folder-videos.png b/assets/themes/NexusOS-icons/24x24/places/folder-videos.png new file mode 100644 index 0000000..0fa630e Binary files /dev/null and b/assets/themes/NexusOS-icons/24x24/places/folder-videos.png differ diff --git a/assets/themes/NexusOS-icons/24x24/places/folder.png b/assets/themes/NexusOS-icons/24x24/places/folder.png new file mode 100644 index 0000000..7c055bb Binary files /dev/null and b/assets/themes/NexusOS-icons/24x24/places/folder.png differ diff --git a/assets/themes/NexusOS-icons/32x32/apps/nexusos-logo.png b/assets/themes/NexusOS-icons/32x32/apps/nexusos-logo.png new file mode 100644 index 0000000..c96bb05 Binary files /dev/null and b/assets/themes/NexusOS-icons/32x32/apps/nexusos-logo.png differ diff --git a/assets/themes/NexusOS-icons/32x32/apps/utilities-terminal.png b/assets/themes/NexusOS-icons/32x32/apps/utilities-terminal.png new file mode 100644 index 0000000..178f800 Binary files /dev/null and b/assets/themes/NexusOS-icons/32x32/apps/utilities-terminal.png differ diff --git a/assets/themes/NexusOS-icons/32x32/places/folder-documents.png b/assets/themes/NexusOS-icons/32x32/places/folder-documents.png new file mode 100644 index 0000000..c7f9515 Binary files /dev/null and b/assets/themes/NexusOS-icons/32x32/places/folder-documents.png differ diff --git a/assets/themes/NexusOS-icons/32x32/places/folder-download.png b/assets/themes/NexusOS-icons/32x32/places/folder-download.png new file mode 100644 index 0000000..5757273 Binary files /dev/null and b/assets/themes/NexusOS-icons/32x32/places/folder-download.png differ diff --git a/assets/themes/NexusOS-icons/32x32/places/folder-drag-accept.png b/assets/themes/NexusOS-icons/32x32/places/folder-drag-accept.png new file mode 100644 index 0000000..c7f2116 Binary files /dev/null and b/assets/themes/NexusOS-icons/32x32/places/folder-drag-accept.png differ diff --git a/assets/themes/NexusOS-icons/32x32/places/folder-home.png b/assets/themes/NexusOS-icons/32x32/places/folder-home.png new file mode 100644 index 0000000..cb4e457 Binary files /dev/null and b/assets/themes/NexusOS-icons/32x32/places/folder-home.png differ diff --git a/assets/themes/NexusOS-icons/32x32/places/folder-music.png b/assets/themes/NexusOS-icons/32x32/places/folder-music.png new file mode 100644 index 0000000..54c641f Binary files /dev/null and b/assets/themes/NexusOS-icons/32x32/places/folder-music.png differ diff --git a/assets/themes/NexusOS-icons/32x32/places/folder-nexus-core.png b/assets/themes/NexusOS-icons/32x32/places/folder-nexus-core.png new file mode 100644 index 0000000..6a20755 Binary files /dev/null and b/assets/themes/NexusOS-icons/32x32/places/folder-nexus-core.png differ diff --git a/assets/themes/NexusOS-icons/32x32/places/folder-open.png b/assets/themes/NexusOS-icons/32x32/places/folder-open.png new file mode 100644 index 0000000..c7f2116 Binary files /dev/null and b/assets/themes/NexusOS-icons/32x32/places/folder-open.png differ diff --git a/assets/themes/NexusOS-icons/32x32/places/folder-pictures.png b/assets/themes/NexusOS-icons/32x32/places/folder-pictures.png new file mode 100644 index 0000000..f2938ee Binary files /dev/null and b/assets/themes/NexusOS-icons/32x32/places/folder-pictures.png differ diff --git a/assets/themes/NexusOS-icons/32x32/places/folder-publicshare.png b/assets/themes/NexusOS-icons/32x32/places/folder-publicshare.png new file mode 100644 index 0000000..f32a9b5 Binary files /dev/null and b/assets/themes/NexusOS-icons/32x32/places/folder-publicshare.png differ diff --git a/assets/themes/NexusOS-icons/32x32/places/folder-recent.png b/assets/themes/NexusOS-icons/32x32/places/folder-recent.png new file mode 100644 index 0000000..d7dd720 Binary files /dev/null and b/assets/themes/NexusOS-icons/32x32/places/folder-recent.png differ diff --git a/assets/themes/NexusOS-icons/32x32/places/folder-remote.png b/assets/themes/NexusOS-icons/32x32/places/folder-remote.png new file mode 100644 index 0000000..7055f23 Binary files /dev/null and b/assets/themes/NexusOS-icons/32x32/places/folder-remote.png differ diff --git a/assets/themes/NexusOS-icons/32x32/places/folder-saved-search.png b/assets/themes/NexusOS-icons/32x32/places/folder-saved-search.png new file mode 100644 index 0000000..90a20b1 Binary files /dev/null and b/assets/themes/NexusOS-icons/32x32/places/folder-saved-search.png differ diff --git a/assets/themes/NexusOS-icons/32x32/places/folder-templates.png b/assets/themes/NexusOS-icons/32x32/places/folder-templates.png new file mode 100644 index 0000000..abb32ee Binary files /dev/null and b/assets/themes/NexusOS-icons/32x32/places/folder-templates.png differ diff --git a/assets/themes/NexusOS-icons/32x32/places/folder-videos.png b/assets/themes/NexusOS-icons/32x32/places/folder-videos.png new file mode 100644 index 0000000..5166999 Binary files /dev/null and b/assets/themes/NexusOS-icons/32x32/places/folder-videos.png differ diff --git a/assets/themes/NexusOS-icons/32x32/places/folder.png b/assets/themes/NexusOS-icons/32x32/places/folder.png new file mode 100644 index 0000000..b1d4e3b Binary files /dev/null and b/assets/themes/NexusOS-icons/32x32/places/folder.png differ diff --git a/assets/themes/NexusOS-icons/48x48/apps/nexusos-logo.png b/assets/themes/NexusOS-icons/48x48/apps/nexusos-logo.png new file mode 100644 index 0000000..c96bb05 Binary files /dev/null and b/assets/themes/NexusOS-icons/48x48/apps/nexusos-logo.png differ diff --git a/assets/themes/NexusOS-icons/48x48/apps/utilities-terminal.png b/assets/themes/NexusOS-icons/48x48/apps/utilities-terminal.png new file mode 100644 index 0000000..a7a4039 Binary files /dev/null and b/assets/themes/NexusOS-icons/48x48/apps/utilities-terminal.png differ diff --git a/assets/themes/NexusOS-icons/48x48/places/folder-documents.png b/assets/themes/NexusOS-icons/48x48/places/folder-documents.png new file mode 100644 index 0000000..6d2ed47 Binary files /dev/null and b/assets/themes/NexusOS-icons/48x48/places/folder-documents.png differ diff --git a/assets/themes/NexusOS-icons/48x48/places/folder-download.png b/assets/themes/NexusOS-icons/48x48/places/folder-download.png new file mode 100644 index 0000000..90c5ab3 Binary files /dev/null and b/assets/themes/NexusOS-icons/48x48/places/folder-download.png differ diff --git a/assets/themes/NexusOS-icons/48x48/places/folder-drag-accept.png b/assets/themes/NexusOS-icons/48x48/places/folder-drag-accept.png new file mode 100644 index 0000000..9f4d441 Binary files /dev/null and b/assets/themes/NexusOS-icons/48x48/places/folder-drag-accept.png differ diff --git a/assets/themes/NexusOS-icons/48x48/places/folder-home.png b/assets/themes/NexusOS-icons/48x48/places/folder-home.png new file mode 100644 index 0000000..651856f Binary files /dev/null and b/assets/themes/NexusOS-icons/48x48/places/folder-home.png differ diff --git a/assets/themes/NexusOS-icons/48x48/places/folder-music.png b/assets/themes/NexusOS-icons/48x48/places/folder-music.png new file mode 100644 index 0000000..4b135a4 Binary files /dev/null and b/assets/themes/NexusOS-icons/48x48/places/folder-music.png differ diff --git a/assets/themes/NexusOS-icons/48x48/places/folder-nexus-core.png b/assets/themes/NexusOS-icons/48x48/places/folder-nexus-core.png new file mode 100644 index 0000000..98916cc Binary files /dev/null and b/assets/themes/NexusOS-icons/48x48/places/folder-nexus-core.png differ diff --git a/assets/themes/NexusOS-icons/48x48/places/folder-open.png b/assets/themes/NexusOS-icons/48x48/places/folder-open.png new file mode 100644 index 0000000..9f4d441 Binary files /dev/null and b/assets/themes/NexusOS-icons/48x48/places/folder-open.png differ diff --git a/assets/themes/NexusOS-icons/48x48/places/folder-pictures.png b/assets/themes/NexusOS-icons/48x48/places/folder-pictures.png new file mode 100644 index 0000000..f3cfae5 Binary files /dev/null and b/assets/themes/NexusOS-icons/48x48/places/folder-pictures.png differ diff --git a/assets/themes/NexusOS-icons/48x48/places/folder-publicshare.png b/assets/themes/NexusOS-icons/48x48/places/folder-publicshare.png new file mode 100644 index 0000000..329a5a7 Binary files /dev/null and b/assets/themes/NexusOS-icons/48x48/places/folder-publicshare.png differ diff --git a/assets/themes/NexusOS-icons/48x48/places/folder-recent.png b/assets/themes/NexusOS-icons/48x48/places/folder-recent.png new file mode 100644 index 0000000..45c001d Binary files /dev/null and b/assets/themes/NexusOS-icons/48x48/places/folder-recent.png differ diff --git a/assets/themes/NexusOS-icons/48x48/places/folder-remote.png b/assets/themes/NexusOS-icons/48x48/places/folder-remote.png new file mode 100644 index 0000000..9680e56 Binary files /dev/null and b/assets/themes/NexusOS-icons/48x48/places/folder-remote.png differ diff --git a/assets/themes/NexusOS-icons/48x48/places/folder-saved-search.png b/assets/themes/NexusOS-icons/48x48/places/folder-saved-search.png new file mode 100644 index 0000000..ae80566 Binary files /dev/null and b/assets/themes/NexusOS-icons/48x48/places/folder-saved-search.png differ diff --git a/assets/themes/NexusOS-icons/48x48/places/folder-templates.png b/assets/themes/NexusOS-icons/48x48/places/folder-templates.png new file mode 100644 index 0000000..d707440 Binary files /dev/null and b/assets/themes/NexusOS-icons/48x48/places/folder-templates.png differ diff --git a/assets/themes/NexusOS-icons/48x48/places/folder-videos.png b/assets/themes/NexusOS-icons/48x48/places/folder-videos.png new file mode 100644 index 0000000..314266d Binary files /dev/null and b/assets/themes/NexusOS-icons/48x48/places/folder-videos.png differ diff --git a/assets/themes/NexusOS-icons/48x48/places/folder.png b/assets/themes/NexusOS-icons/48x48/places/folder.png new file mode 100644 index 0000000..069cbad Binary files /dev/null and b/assets/themes/NexusOS-icons/48x48/places/folder.png differ diff --git a/assets/themes/NexusOS-icons/64x64/apps/nexusos-logo.png b/assets/themes/NexusOS-icons/64x64/apps/nexusos-logo.png new file mode 100644 index 0000000..c96bb05 Binary files /dev/null and b/assets/themes/NexusOS-icons/64x64/apps/nexusos-logo.png differ diff --git a/assets/themes/NexusOS-icons/64x64/apps/utilities-terminal.png b/assets/themes/NexusOS-icons/64x64/apps/utilities-terminal.png new file mode 100644 index 0000000..e139c9f Binary files /dev/null and b/assets/themes/NexusOS-icons/64x64/apps/utilities-terminal.png differ diff --git a/assets/themes/NexusOS-icons/64x64/places/folder-documents.png b/assets/themes/NexusOS-icons/64x64/places/folder-documents.png new file mode 100644 index 0000000..7b91c3e Binary files /dev/null and b/assets/themes/NexusOS-icons/64x64/places/folder-documents.png differ diff --git a/assets/themes/NexusOS-icons/64x64/places/folder-download.png b/assets/themes/NexusOS-icons/64x64/places/folder-download.png new file mode 100644 index 0000000..752da81 Binary files /dev/null and b/assets/themes/NexusOS-icons/64x64/places/folder-download.png differ diff --git a/assets/themes/NexusOS-icons/64x64/places/folder-drag-accept.png b/assets/themes/NexusOS-icons/64x64/places/folder-drag-accept.png new file mode 100644 index 0000000..24c279e Binary files /dev/null and b/assets/themes/NexusOS-icons/64x64/places/folder-drag-accept.png differ diff --git a/assets/themes/NexusOS-icons/64x64/places/folder-home.png b/assets/themes/NexusOS-icons/64x64/places/folder-home.png new file mode 100644 index 0000000..c3d6e47 Binary files /dev/null and b/assets/themes/NexusOS-icons/64x64/places/folder-home.png differ diff --git a/assets/themes/NexusOS-icons/64x64/places/folder-music.png b/assets/themes/NexusOS-icons/64x64/places/folder-music.png new file mode 100644 index 0000000..5316d0a Binary files /dev/null and b/assets/themes/NexusOS-icons/64x64/places/folder-music.png differ diff --git a/assets/themes/NexusOS-icons/64x64/places/folder-nexus-core.png b/assets/themes/NexusOS-icons/64x64/places/folder-nexus-core.png new file mode 100644 index 0000000..a15d279 Binary files /dev/null and b/assets/themes/NexusOS-icons/64x64/places/folder-nexus-core.png differ diff --git a/assets/themes/NexusOS-icons/64x64/places/folder-open.png b/assets/themes/NexusOS-icons/64x64/places/folder-open.png new file mode 100644 index 0000000..24c279e Binary files /dev/null and b/assets/themes/NexusOS-icons/64x64/places/folder-open.png differ diff --git a/assets/themes/NexusOS-icons/64x64/places/folder-pictures.png b/assets/themes/NexusOS-icons/64x64/places/folder-pictures.png new file mode 100644 index 0000000..c0cc183 Binary files /dev/null and b/assets/themes/NexusOS-icons/64x64/places/folder-pictures.png differ diff --git a/assets/themes/NexusOS-icons/64x64/places/folder-publicshare.png b/assets/themes/NexusOS-icons/64x64/places/folder-publicshare.png new file mode 100644 index 0000000..6e2a2ee Binary files /dev/null and b/assets/themes/NexusOS-icons/64x64/places/folder-publicshare.png differ diff --git a/assets/themes/NexusOS-icons/64x64/places/folder-recent.png b/assets/themes/NexusOS-icons/64x64/places/folder-recent.png new file mode 100644 index 0000000..a153b82 Binary files /dev/null and b/assets/themes/NexusOS-icons/64x64/places/folder-recent.png differ diff --git a/assets/themes/NexusOS-icons/64x64/places/folder-remote.png b/assets/themes/NexusOS-icons/64x64/places/folder-remote.png new file mode 100644 index 0000000..34ad282 Binary files /dev/null and b/assets/themes/NexusOS-icons/64x64/places/folder-remote.png differ diff --git a/assets/themes/NexusOS-icons/64x64/places/folder-saved-search.png b/assets/themes/NexusOS-icons/64x64/places/folder-saved-search.png new file mode 100644 index 0000000..fabb2e3 Binary files /dev/null and b/assets/themes/NexusOS-icons/64x64/places/folder-saved-search.png differ diff --git a/assets/themes/NexusOS-icons/64x64/places/folder-templates.png b/assets/themes/NexusOS-icons/64x64/places/folder-templates.png new file mode 100644 index 0000000..a5acbcb Binary files /dev/null and b/assets/themes/NexusOS-icons/64x64/places/folder-templates.png differ diff --git a/assets/themes/NexusOS-icons/64x64/places/folder-videos.png b/assets/themes/NexusOS-icons/64x64/places/folder-videos.png new file mode 100644 index 0000000..fe75cac Binary files /dev/null and b/assets/themes/NexusOS-icons/64x64/places/folder-videos.png differ diff --git a/assets/themes/NexusOS-icons/64x64/places/folder.png b/assets/themes/NexusOS-icons/64x64/places/folder.png new file mode 100644 index 0000000..df9c1d2 Binary files /dev/null and b/assets/themes/NexusOS-icons/64x64/places/folder.png differ diff --git a/assets/themes/NexusOS-icons/icon-theme.cache b/assets/themes/NexusOS-icons/icon-theme.cache new file mode 100644 index 0000000..fcde1c8 Binary files /dev/null and b/assets/themes/NexusOS-icons/icon-theme.cache differ diff --git a/assets/themes/NexusOS-icons/index.theme b/assets/themes/NexusOS-icons/index.theme new file mode 100644 index 0000000..dbee5c4 --- /dev/null +++ b/assets/themes/NexusOS-icons/index.theme @@ -0,0 +1,75 @@ +[Icon Theme] +Name=NexusOS +Comment=NexusOS accent icon theme +Inherits=Papirus-Dark +Directories=16x16/apps,22x22/apps,24x24/apps,32x32/apps,48x48/apps,64x64/apps,128x128/apps,16x16/places,22x22/places,24x24/places,32x32/places,48x48/places,64x64/places,128x128/places + +[16x16/apps] +Size=16 +Context=Applications +Type=Fixed + +[22x22/apps] +Size=22 +Context=Applications +Type=Fixed + +[24x24/apps] +Size=24 +Context=Applications +Type=Fixed + +[32x32/apps] +Size=32 +Context=Applications +Type=Fixed + +[48x48/apps] +Size=48 +Context=Applications +Type=Fixed + +[64x64/apps] +Size=64 +Context=Applications +Type=Fixed + +[128x128/apps] +Size=128 +Context=Applications +Type=Fixed + +[16x16/places] +Size=16 +Context=Places +Type=Fixed + +[22x22/places] +Size=22 +Context=Places +Type=Fixed + +[24x24/places] +Size=24 +Context=Places +Type=Fixed + +[32x32/places] +Size=32 +Context=Places +Type=Fixed + +[48x48/places] +Size=48 +Context=Places +Type=Fixed + +[64x64/places] +Size=64 +Context=Places +Type=Fixed + +[128x128/places] +Size=128 +Context=Places +Type=Fixed diff --git a/assets/themes/NexusOS-icons/scalable/apps/utilities-terminal.png b/assets/themes/NexusOS-icons/scalable/apps/utilities-terminal.png new file mode 100644 index 0000000..59f5a1b Binary files /dev/null and b/assets/themes/NexusOS-icons/scalable/apps/utilities-terminal.png differ diff --git a/assets/themes/NexusOS-xfwm4-src/build.py b/assets/themes/NexusOS-xfwm4-src/build.py new file mode 100644 index 0000000..e4b078f --- /dev/null +++ b/assets/themes/NexusOS-xfwm4-src/build.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 +"""Build NexusOS xfwm4 theme from Mint-Y-Dark-Aqua base. + +- Copies all xfwm4 PNGs + themerc +- Aqua pixels (close-active/pressed glyph) → NexusOS green via HSV hue swap +- Dark Mint-Y greys repainted to NexusOS surface_bg_alt / border_strong +- themerc title text colors updated to NexusOS palette +""" +from __future__ import annotations + +import colorsys +import shutil +import sys +from pathlib import Path + +THEMES_ROOT = Path(__file__).resolve().parent.parent +sys.path.insert(0, str(THEMES_ROOT)) +import _palette as P # noqa: E402 + +from PIL import Image # noqa: E402 + +SRC = Path("/usr/share/themes/Mint-Y-Dark-Aqua/xfwm4") +OUT = THEMES_ROOT / "NexusOS" / "xfwm4" + +# Aqua → green HSV swap (identical to gtk2 build) +AQUA_RGB = (0x1F, 0x9E, 0xDE) +AQUA_HSV = colorsys.rgb_to_hsv(*(c / 255 for c in AQUA_RGB)) +GREEN_HSV = P.hex_to_hsv(P.BRAND_GREEN) +S_SCALE = GREEN_HSV[1] / AQUA_HSV[1] +V_SCALE = GREEN_HSV[2] / AQUA_HSV[2] +HUE_TOLERANCE = 30 / 360 +SAT_FLOOR = 0.18 + +# Gray repaints — direct RGB substitutions +GRAY_REMAP = { + (34, 34, 38): P.hex_to_rgb(P.SURFACE_BG_ALT), + (46, 46, 46): P.hex_to_rgb(P.BORDER_STRONG), + (36, 36, 39): P.hex_to_rgb(P.SURFACE_BG_ALT), + (76, 76, 80): P.hex_to_rgb(P.BORDER_STRONG), + (85, 85, 89): (130, 130, 134), + (106, 106, 109): (150, 150, 154), +} + + +def hue_distance(a: float, b: float) -> float: + d = abs(a - b) + return min(d, 1 - d) + + +def recolor_pixel(r: int, g: int, b: int, a: int) -> tuple[int, int, int, int]: + if a < 8: + return (r, g, b, a) + # Direct gray remap + if (r, g, b) in GRAY_REMAP: + nr, ng, nb = GRAY_REMAP[(r, g, b)] + return (nr, ng, nb, a) + # Aqua → green + h, s, v = colorsys.rgb_to_hsv(r / 255, g / 255, b / 255) + if s >= SAT_FLOOR and hue_distance(h, AQUA_HSV[0]) <= HUE_TOLERANCE: + new_s = min(1.0, s * S_SCALE) + new_v = min(1.0, v * V_SCALE) + nr, ng, nb = colorsys.hsv_to_rgb(GREEN_HSV[0], new_s, new_v) + return (round(nr * 255), round(ng * 255), round(nb * 255), a) + return (r, g, b, a) + + +def recolor_png(path: Path) -> int: + im = Image.open(path).convert("RGBA") + px = im.load() + w, h = im.size + changed = 0 + for y in range(h): + for x in range(w): + r, g, b, a = px[x, y] + new = recolor_pixel(r, g, b, a) + if new != (r, g, b, a): + px[x, y] = new + changed += 1 + if changed: + im.save(path, optimize=True) + return changed + + +THEMERC_REPLACEMENTS = { + "active_text_color=#e3e3e3": f"active_text_color=#{P.TEXT_PRIMARY}", + "active_text_shadow_color=#e3e3e3": f"active_text_shadow_color=#{P.TEXT_PRIMARY}", + "inactive_text_color=#acacac": f"inactive_text_color=#{P.TEXT_SECONDARY}", + "inactive_text_shadow_color=#acacac": f"inactive_text_shadow_color=#{P.TEXT_SECONDARY}", +} + + +def patch_themerc(path: Path) -> None: + text = path.read_text() + for src, dst in THEMERC_REPLACEMENTS.items(): + text = text.replace(src, dst) + path.write_text(text) + + +def main() -> None: + if OUT.exists(): + shutil.rmtree(OUT) + shutil.copytree(SRC, OUT) + print(f"Copied {SRC} → {OUT}") + + recolored = 0 + for png in sorted(OUT.glob("*.png")): + changed = recolor_png(png) + if changed: + recolored += 1 + print(f"Recolored {recolored} PNGs") + + patch_themerc(OUT / "themerc") + print("Patched themerc") + + +if __name__ == "__main__": + main() diff --git a/assets/themes/NexusOS/gtk-2.0/apps.rc b/assets/themes/NexusOS/gtk-2.0/apps.rc new file mode 100644 index 0000000..cb3ee0d --- /dev/null +++ b/assets/themes/NexusOS/gtk-2.0/apps.rc @@ -0,0 +1,157 @@ +# +# Thunar +# +style "thunar-handle" { GtkPaned::handle-size = 2 } + +style "dark-sidebar" { + GtkTreeView::odd_row_color = @dark_sidebar_bg + GtkTreeView::even_row_color = @dark_sidebar_bg + + + base[NORMAL] = @dark_sidebar_bg + base[INSENSITIVE] = @dark_sidebar_bg + + text[NORMAL] = @fg_color + text[ACTIVE] = @selected_fg_color + text[SELECTED] = @selected_fg_color +} + +style "thunar-frame" { + xthickness = 0 + ythickness = 0 +} + +widget_class "*ThunarWindow*." style "thunar-frame" +widget_class "*ThunarShortcutsView*" style "dark-sidebar" +widget_class "*ThunarTreeView*" style "dark-sidebar" +widget_class "*ThunarWindow*." style "thunar-handle" + +# +# Workaround for colored entries +# +style "entry_border" { + + xthickness = 7 + ythickness = 5 + + engine "pixmap" { + + image { + function = SHADOW + state = NORMAL + detail = "entry" + file = "assets/entry-border-bg.png" + border = {6, 6, 6, 6} + stretch = TRUE + } + + image { + function = SHADOW + state = ACTIVE + detail = "entry" + file = "assets/entry-border-active-bg.png" + border = {6, 6, 6, 6} + stretch = TRUE + } + + image { + function = FLAT_BOX + state = ACTIVE + detail = "entry_bg" + file = "assets/null.png" + } + + image { + function = FLAT_BOX + state = INSENSITIVE + detail = "entry_bg" + file = "assets/null.png" + } + + image { + function = FLAT_BOX + detail = "entry_bg" + file = "assets/null.png" + } + } +} + +style "combobox_entry_border" = "combobox_entry" { + + engine "pixmap" { + + image { + function = SHADOW + detail = "entry" + state = NORMAL + shadow = IN + file = "assets/combo-entry-border.png" + border = { 4, 4, 12, 12 } + stretch = TRUE + direction = LTR + } + + image { + function = SHADOW + detail = "entry" + state = ACTIVE + file = "assets/combo-entry-border-focus.png" + border = { 4, 4, 12, 12 } + stretch = TRUE + direction = LTR + } + + image { + function = SHADOW + detail = "entry" + state = NORMAL + shadow = IN + file = "assets/combo-entry-border-rtl.png" + border = { 4, 4, 12, 12 } + stretch = TRUE + direction = RTL + } + + image { + function = SHADOW + detail = "entry" + state = ACTIVE + file = "assets/combo-entry-border-focus-rtl.png" + border = { 4, 4, 12, 12 } + stretch = TRUE + direction = RTL + } + + image { + function = FLAT_BOX + state = INSENSITIVE + detail = "entry_bg" + file = "assets/null.png" + } + + image { + function = FLAT_BOX + detail = "entry_bg" + file = "assets/null.png" + } + } +} + + +# Mousepad search entry +widget_class "*MousepadSearchBar*." style "entry_border" + +# Mousepad find and replace +widget_class "*MousepadReplaceDialog*." style "entry_border" + +# Thunar bulk rename +widget_class "*ThunarRenamerDialog*." style "entry_border" + +# Hexchat input box +class "SexySpellEntry" style:highest "entry_border" + +# Geany search entries +widget "*GeanyToolbar.*geany-search-entry-no-match*" style "entry_border" +widget "*GeanyToolbar.*GtkEntry*" style "entry_border" + +widget "GeanyDialogSearch.*GtkComboBoxEntry*.*geany-search-entry-no-match*" style "combobox_entry_border" diff --git a/assets/themes/NexusOS/gtk-2.0/assets/arrow-down-insens.png b/assets/themes/NexusOS/gtk-2.0/assets/arrow-down-insens.png new file mode 100644 index 0000000..13313a8 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/arrow-down-insens.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/arrow-down-prelight.png b/assets/themes/NexusOS/gtk-2.0/assets/arrow-down-prelight.png new file mode 100644 index 0000000..d7031da Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/arrow-down-prelight.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/arrow-down-small-insens.png b/assets/themes/NexusOS/gtk-2.0/assets/arrow-down-small-insens.png new file mode 100644 index 0000000..e1f4dd1 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/arrow-down-small-insens.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/arrow-down-small-prelight.png b/assets/themes/NexusOS/gtk-2.0/assets/arrow-down-small-prelight.png new file mode 100644 index 0000000..5a4efa2 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/arrow-down-small-prelight.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/arrow-down-small.png b/assets/themes/NexusOS/gtk-2.0/assets/arrow-down-small.png new file mode 100644 index 0000000..681fd6f Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/arrow-down-small.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/arrow-down.png b/assets/themes/NexusOS/gtk-2.0/assets/arrow-down.png new file mode 100644 index 0000000..32b997b Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/arrow-down.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/arrow-left-insens.png b/assets/themes/NexusOS/gtk-2.0/assets/arrow-left-insens.png new file mode 100644 index 0000000..7a2c2cf Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/arrow-left-insens.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/arrow-left-prelight.png b/assets/themes/NexusOS/gtk-2.0/assets/arrow-left-prelight.png new file mode 100644 index 0000000..5bd6a2c Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/arrow-left-prelight.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/arrow-left.png b/assets/themes/NexusOS/gtk-2.0/assets/arrow-left.png new file mode 100644 index 0000000..b1764fe Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/arrow-left.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/arrow-right-insens.png b/assets/themes/NexusOS/gtk-2.0/assets/arrow-right-insens.png new file mode 100644 index 0000000..e94f0fb Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/arrow-right-insens.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/arrow-right-prelight.png b/assets/themes/NexusOS/gtk-2.0/assets/arrow-right-prelight.png new file mode 100644 index 0000000..d20b82c Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/arrow-right-prelight.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/arrow-right.png b/assets/themes/NexusOS/gtk-2.0/assets/arrow-right.png new file mode 100644 index 0000000..eb725e6 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/arrow-right.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/arrow-up-insens.png b/assets/themes/NexusOS/gtk-2.0/assets/arrow-up-insens.png new file mode 100644 index 0000000..22c44ff Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/arrow-up-insens.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/arrow-up-prelight.png b/assets/themes/NexusOS/gtk-2.0/assets/arrow-up-prelight.png new file mode 100644 index 0000000..8d9edac Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/arrow-up-prelight.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/arrow-up-small-insens.png b/assets/themes/NexusOS/gtk-2.0/assets/arrow-up-small-insens.png new file mode 100644 index 0000000..11a9e76 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/arrow-up-small-insens.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/arrow-up-small-prelight.png b/assets/themes/NexusOS/gtk-2.0/assets/arrow-up-small-prelight.png new file mode 100644 index 0000000..da76e01 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/arrow-up-small-prelight.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/arrow-up-small.png b/assets/themes/NexusOS/gtk-2.0/assets/arrow-up-small.png new file mode 100644 index 0000000..59e45db Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/arrow-up-small.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/arrow-up.png b/assets/themes/NexusOS/gtk-2.0/assets/arrow-up.png new file mode 100644 index 0000000..1f095b2 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/arrow-up.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/border.png b/assets/themes/NexusOS/gtk-2.0/assets/border.png new file mode 100644 index 0000000..7eafe12 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/border.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/button-active-hover.png b/assets/themes/NexusOS/gtk-2.0/assets/button-active-hover.png new file mode 100644 index 0000000..393812e Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/button-active-hover.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/button-active.png b/assets/themes/NexusOS/gtk-2.0/assets/button-active.png new file mode 100644 index 0000000..0f1be04 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/button-active.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/button-hover.png b/assets/themes/NexusOS/gtk-2.0/assets/button-hover.png new file mode 100644 index 0000000..8273b31 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/button-hover.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/button-insensitive.png b/assets/themes/NexusOS/gtk-2.0/assets/button-insensitive.png new file mode 100644 index 0000000..ebb9e3f Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/button-insensitive.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/button.png b/assets/themes/NexusOS/gtk-2.0/assets/button.png new file mode 100644 index 0000000..ff486df Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/button.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/checkbox-checked-insensitive.png b/assets/themes/NexusOS/gtk-2.0/assets/checkbox-checked-insensitive.png new file mode 100644 index 0000000..2cf6083 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/checkbox-checked-insensitive.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/checkbox-checked.png b/assets/themes/NexusOS/gtk-2.0/assets/checkbox-checked.png new file mode 100644 index 0000000..2230264 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/checkbox-checked.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/checkbox-unchecked-insensitive.png b/assets/themes/NexusOS/gtk-2.0/assets/checkbox-unchecked-insensitive.png new file mode 100644 index 0000000..e11adb5 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/checkbox-unchecked-insensitive.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/checkbox-unchecked.png b/assets/themes/NexusOS/gtk-2.0/assets/checkbox-unchecked.png new file mode 100644 index 0000000..38d8473 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/checkbox-unchecked.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-border-focus-rtl.png b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-border-focus-rtl.png new file mode 100644 index 0000000..361f1c3 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-border-focus-rtl.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-border-focus.png b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-border-focus.png new file mode 100644 index 0000000..7b1ae33 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-border-focus.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-border-rtl.png b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-border-rtl.png new file mode 100644 index 0000000..dbfa580 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-border-rtl.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-border.png b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-border.png new file mode 100644 index 0000000..d18775a Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-border.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-button-active-rtl.png b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-button-active-rtl.png new file mode 100644 index 0000000..e41ee9c Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-button-active-rtl.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-button-active.png b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-button-active.png new file mode 100644 index 0000000..8017f74 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-button-active.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-button-insensitive-rtl.png b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-button-insensitive-rtl.png new file mode 100644 index 0000000..ccda812 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-button-insensitive-rtl.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-button-insensitive.png b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-button-insensitive.png new file mode 100644 index 0000000..fb3453b Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-button-insensitive.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-button-rtl.png b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-button-rtl.png new file mode 100644 index 0000000..ccda812 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-button-rtl.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-button.png b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-button.png new file mode 100644 index 0000000..3061a91 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-button.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-focus-notebook-rtl.png b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-focus-notebook-rtl.png new file mode 100644 index 0000000..2327e14 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-focus-notebook-rtl.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-focus-notebook.png b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-focus-notebook.png new file mode 100644 index 0000000..bb81b3f Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-focus-notebook.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-focus-rtl.png b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-focus-rtl.png new file mode 100644 index 0000000..f559df5 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-focus-rtl.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-focus.png b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-focus.png new file mode 100644 index 0000000..ee711af Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-focus.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-insensitive-notebook-rtl.png b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-insensitive-notebook-rtl.png new file mode 100644 index 0000000..f7b02d7 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-insensitive-notebook-rtl.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-insensitive-notebook.png b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-insensitive-notebook.png new file mode 100644 index 0000000..b162520 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-insensitive-notebook.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-insensitive-rtl.png b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-insensitive-rtl.png new file mode 100644 index 0000000..f7b02d7 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-insensitive-rtl.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-insensitive.png b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-insensitive.png new file mode 100644 index 0000000..e84bcf6 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-insensitive.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-notebook-rtl.png b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-notebook-rtl.png new file mode 100644 index 0000000..e64b763 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-notebook-rtl.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-notebook.png b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-notebook.png new file mode 100644 index 0000000..5fabd1b Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-notebook.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-rtl.png b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-rtl.png new file mode 100644 index 0000000..b0289ae Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry-rtl.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/combo-entry.png b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry.png new file mode 100644 index 0000000..ed16a77 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/combo-entry.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/down-background-disable-rtl.png b/assets/themes/NexusOS/gtk-2.0/assets/down-background-disable-rtl.png new file mode 100644 index 0000000..bb40993 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/down-background-disable-rtl.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/down-background-disable.png b/assets/themes/NexusOS/gtk-2.0/assets/down-background-disable.png new file mode 100644 index 0000000..5cfb997 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/down-background-disable.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/down-background-rtl.png b/assets/themes/NexusOS/gtk-2.0/assets/down-background-rtl.png new file mode 100644 index 0000000..03c300f Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/down-background-rtl.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/down-background.png b/assets/themes/NexusOS/gtk-2.0/assets/down-background.png new file mode 100644 index 0000000..83ca6b5 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/down-background.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/entry-active-bg.png b/assets/themes/NexusOS/gtk-2.0/assets/entry-active-bg.png new file mode 100644 index 0000000..d2a58a9 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/entry-active-bg.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/entry-active-notebook.png b/assets/themes/NexusOS/gtk-2.0/assets/entry-active-notebook.png new file mode 100644 index 0000000..33051ff Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/entry-active-notebook.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/entry-active-toolbar.png b/assets/themes/NexusOS/gtk-2.0/assets/entry-active-toolbar.png new file mode 100644 index 0000000..e8ef5dc Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/entry-active-toolbar.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/entry-background-disabled.png b/assets/themes/NexusOS/gtk-2.0/assets/entry-background-disabled.png new file mode 100644 index 0000000..3bde125 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/entry-background-disabled.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/entry-background.png b/assets/themes/NexusOS/gtk-2.0/assets/entry-background.png new file mode 100644 index 0000000..edbadfd Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/entry-background.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/entry-bg.png b/assets/themes/NexusOS/gtk-2.0/assets/entry-bg.png new file mode 100644 index 0000000..8e13c86 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/entry-bg.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/entry-border-active-bg.png b/assets/themes/NexusOS/gtk-2.0/assets/entry-border-active-bg.png new file mode 100644 index 0000000..d697042 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/entry-border-active-bg.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/entry-border-bg.png b/assets/themes/NexusOS/gtk-2.0/assets/entry-border-bg.png new file mode 100644 index 0000000..bcfd3c1 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/entry-border-bg.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/entry-disabled-bg.png b/assets/themes/NexusOS/gtk-2.0/assets/entry-disabled-bg.png new file mode 100644 index 0000000..31ffd6e Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/entry-disabled-bg.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/entry-disabled-notebook.png b/assets/themes/NexusOS/gtk-2.0/assets/entry-disabled-notebook.png new file mode 100644 index 0000000..af8a9a3 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/entry-disabled-notebook.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/entry-disabled-toolbar.png b/assets/themes/NexusOS/gtk-2.0/assets/entry-disabled-toolbar.png new file mode 100644 index 0000000..8011330 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/entry-disabled-toolbar.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/entry-notebook.png b/assets/themes/NexusOS/gtk-2.0/assets/entry-notebook.png new file mode 100644 index 0000000..433e761 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/entry-notebook.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/entry-toolbar.png b/assets/themes/NexusOS/gtk-2.0/assets/entry-toolbar.png new file mode 100644 index 0000000..499ff69 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/entry-toolbar.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/focus-line.png b/assets/themes/NexusOS/gtk-2.0/assets/focus-line.png new file mode 100644 index 0000000..67162d4 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/focus-line.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/frame-gap-end.png b/assets/themes/NexusOS/gtk-2.0/assets/frame-gap-end.png new file mode 100644 index 0000000..b5549a4 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/frame-gap-end.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/frame-gap-start.png b/assets/themes/NexusOS/gtk-2.0/assets/frame-gap-start.png new file mode 100644 index 0000000..b5549a4 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/frame-gap-start.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/frame.png b/assets/themes/NexusOS/gtk-2.0/assets/frame.png new file mode 100644 index 0000000..9cefc7b Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/frame.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/handle-h.png b/assets/themes/NexusOS/gtk-2.0/assets/handle-h.png new file mode 100644 index 0000000..fab6bf5 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/handle-h.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/handle-v.png b/assets/themes/NexusOS/gtk-2.0/assets/handle-v.png new file mode 100644 index 0000000..6276854 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/handle-v.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/inline-toolbar.png b/assets/themes/NexusOS/gtk-2.0/assets/inline-toolbar.png new file mode 100644 index 0000000..51700d0 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/inline-toolbar.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/line-h.png b/assets/themes/NexusOS/gtk-2.0/assets/line-h.png new file mode 100644 index 0000000..85fcb27 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/line-h.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/line-v.png b/assets/themes/NexusOS/gtk-2.0/assets/line-v.png new file mode 100644 index 0000000..b9cc686 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/line-v.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/menu-arrow-prelight.png b/assets/themes/NexusOS/gtk-2.0/assets/menu-arrow-prelight.png new file mode 100644 index 0000000..45f7574 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/menu-arrow-prelight.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/menu-arrow.png b/assets/themes/NexusOS/gtk-2.0/assets/menu-arrow.png new file mode 100644 index 0000000..7163de7 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/menu-arrow.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/menu-checkbox-checked-insensitive.png b/assets/themes/NexusOS/gtk-2.0/assets/menu-checkbox-checked-insensitive.png new file mode 100644 index 0000000..b8c0617 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/menu-checkbox-checked-insensitive.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/menu-checkbox-checked.png b/assets/themes/NexusOS/gtk-2.0/assets/menu-checkbox-checked.png new file mode 100644 index 0000000..b0e05ba Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/menu-checkbox-checked.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/menu-checkbox-unchecked-insensitive.png b/assets/themes/NexusOS/gtk-2.0/assets/menu-checkbox-unchecked-insensitive.png new file mode 100644 index 0000000..480564b Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/menu-checkbox-unchecked-insensitive.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/menu-checkbox-unchecked.png b/assets/themes/NexusOS/gtk-2.0/assets/menu-checkbox-unchecked.png new file mode 100644 index 0000000..4c1fadc Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/menu-checkbox-unchecked.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/menu-radio-checked-insensitive.png b/assets/themes/NexusOS/gtk-2.0/assets/menu-radio-checked-insensitive.png new file mode 100644 index 0000000..a87f782 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/menu-radio-checked-insensitive.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/menu-radio-checked.png b/assets/themes/NexusOS/gtk-2.0/assets/menu-radio-checked.png new file mode 100644 index 0000000..fd900e1 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/menu-radio-checked.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/menu-radio-unchecked-insensitive.png b/assets/themes/NexusOS/gtk-2.0/assets/menu-radio-unchecked-insensitive.png new file mode 100644 index 0000000..f26dcf8 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/menu-radio-unchecked-insensitive.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/menu-radio-unchecked.png b/assets/themes/NexusOS/gtk-2.0/assets/menu-radio-unchecked.png new file mode 100644 index 0000000..81fb24e Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/menu-radio-unchecked.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/menu-separator.png b/assets/themes/NexusOS/gtk-2.0/assets/menu-separator.png new file mode 100644 index 0000000..f6aec56 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/menu-separator.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/menubar.png b/assets/themes/NexusOS/gtk-2.0/assets/menubar.png new file mode 100644 index 0000000..ba32eed Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/menubar.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/menubar_button.png b/assets/themes/NexusOS/gtk-2.0/assets/menubar_button.png new file mode 100644 index 0000000..935de53 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/menubar_button.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/menuitem.png b/assets/themes/NexusOS/gtk-2.0/assets/menuitem.png new file mode 100644 index 0000000..380cc25 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/menuitem.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/minus.png b/assets/themes/NexusOS/gtk-2.0/assets/minus.png new file mode 100644 index 0000000..6bc78c3 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/minus.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/notebook-gap-horiz.png b/assets/themes/NexusOS/gtk-2.0/assets/notebook-gap-horiz.png new file mode 100644 index 0000000..7acf3be Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/notebook-gap-horiz.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/notebook-gap-vert.png b/assets/themes/NexusOS/gtk-2.0/assets/notebook-gap-vert.png new file mode 100644 index 0000000..ad8092f Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/notebook-gap-vert.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/notebook.png b/assets/themes/NexusOS/gtk-2.0/assets/notebook.png new file mode 100644 index 0000000..7471c8e Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/notebook.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/null.png b/assets/themes/NexusOS/gtk-2.0/assets/null.png new file mode 100644 index 0000000..537156d Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/null.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/pathbar_button_active.png b/assets/themes/NexusOS/gtk-2.0/assets/pathbar_button_active.png new file mode 100644 index 0000000..cc77d06 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/pathbar_button_active.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/pathbar_button_prelight.png b/assets/themes/NexusOS/gtk-2.0/assets/pathbar_button_prelight.png new file mode 100644 index 0000000..9add29c Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/pathbar_button_prelight.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/plus.png b/assets/themes/NexusOS/gtk-2.0/assets/plus.png new file mode 100644 index 0000000..cebf088 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/plus.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/progressbar.png b/assets/themes/NexusOS/gtk-2.0/assets/progressbar.png new file mode 100644 index 0000000..c95291a Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/progressbar.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/progressbar_v.png b/assets/themes/NexusOS/gtk-2.0/assets/progressbar_v.png new file mode 100644 index 0000000..f9c178b Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/progressbar_v.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/radio-checked-insensitive.png b/assets/themes/NexusOS/gtk-2.0/assets/radio-checked-insensitive.png new file mode 100644 index 0000000..50ee95a Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/radio-checked-insensitive.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/radio-checked.png b/assets/themes/NexusOS/gtk-2.0/assets/radio-checked.png new file mode 100644 index 0000000..687ab59 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/radio-checked.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/radio-unchecked-insensitive.png b/assets/themes/NexusOS/gtk-2.0/assets/radio-unchecked-insensitive.png new file mode 100644 index 0000000..aea9150 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/radio-unchecked-insensitive.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/radio-unchecked.png b/assets/themes/NexusOS/gtk-2.0/assets/radio-unchecked.png new file mode 100644 index 0000000..890b7c7 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/radio-unchecked.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/slider-horiz-active.png b/assets/themes/NexusOS/gtk-2.0/assets/slider-horiz-active.png new file mode 100644 index 0000000..efaf2f4 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/slider-horiz-active.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/slider-horiz-insens.png b/assets/themes/NexusOS/gtk-2.0/assets/slider-horiz-insens.png new file mode 100644 index 0000000..b77847a Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/slider-horiz-insens.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/slider-horiz-prelight.png b/assets/themes/NexusOS/gtk-2.0/assets/slider-horiz-prelight.png new file mode 100644 index 0000000..d08a4cb Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/slider-horiz-prelight.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/slider-horiz.png b/assets/themes/NexusOS/gtk-2.0/assets/slider-horiz.png new file mode 100644 index 0000000..1ab5c43 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/slider-horiz.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/slider-insensitive.png b/assets/themes/NexusOS/gtk-2.0/assets/slider-insensitive.png new file mode 100644 index 0000000..5eff626 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/slider-insensitive.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/slider-prelight.png b/assets/themes/NexusOS/gtk-2.0/assets/slider-prelight.png new file mode 100644 index 0000000..f824440 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/slider-prelight.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/slider-vert-active.png b/assets/themes/NexusOS/gtk-2.0/assets/slider-vert-active.png new file mode 100644 index 0000000..30fc643 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/slider-vert-active.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/slider-vert-insens.png b/assets/themes/NexusOS/gtk-2.0/assets/slider-vert-insens.png new file mode 100644 index 0000000..17fde48 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/slider-vert-insens.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/slider-vert-prelight.png b/assets/themes/NexusOS/gtk-2.0/assets/slider-vert-prelight.png new file mode 100644 index 0000000..7cc77bb Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/slider-vert-prelight.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/slider-vert.png b/assets/themes/NexusOS/gtk-2.0/assets/slider-vert.png new file mode 100644 index 0000000..0d4d978 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/slider-vert.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/slider.png b/assets/themes/NexusOS/gtk-2.0/assets/slider.png new file mode 100644 index 0000000..f8680e6 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/slider.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/tab-bottom-active.png b/assets/themes/NexusOS/gtk-2.0/assets/tab-bottom-active.png new file mode 100644 index 0000000..36d315d Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/tab-bottom-active.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/tab-left-active.png b/assets/themes/NexusOS/gtk-2.0/assets/tab-left-active.png new file mode 100644 index 0000000..b6e1f47 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/tab-left-active.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/tab-right-active.png b/assets/themes/NexusOS/gtk-2.0/assets/tab-right-active.png new file mode 100644 index 0000000..73663ab Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/tab-right-active.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/tab-top-active.png b/assets/themes/NexusOS/gtk-2.0/assets/tab-top-active.png new file mode 100644 index 0000000..d316d16 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/tab-top-active.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/toolbar-button-active-hover.png b/assets/themes/NexusOS/gtk-2.0/assets/toolbar-button-active-hover.png new file mode 100644 index 0000000..8273b31 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/toolbar-button-active-hover.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/toolbar-button-active.png b/assets/themes/NexusOS/gtk-2.0/assets/toolbar-button-active.png new file mode 100644 index 0000000..ff486df Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/toolbar-button-active.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/toolbar.png b/assets/themes/NexusOS/gtk-2.0/assets/toolbar.png new file mode 100644 index 0000000..95cfd21 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/toolbar.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/tree_header.png b/assets/themes/NexusOS/gtk-2.0/assets/tree_header.png new file mode 100644 index 0000000..92d0146 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/tree_header.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/trough-horizontal-active.png b/assets/themes/NexusOS/gtk-2.0/assets/trough-horizontal-active.png new file mode 100644 index 0000000..275be24 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/trough-horizontal-active.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/trough-horizontal.png b/assets/themes/NexusOS/gtk-2.0/assets/trough-horizontal.png new file mode 100644 index 0000000..c9257f9 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/trough-horizontal.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/trough-progressbar.png b/assets/themes/NexusOS/gtk-2.0/assets/trough-progressbar.png new file mode 100644 index 0000000..6fc1c27 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/trough-progressbar.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/trough-progressbar_v.png b/assets/themes/NexusOS/gtk-2.0/assets/trough-progressbar_v.png new file mode 100644 index 0000000..03f65bd Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/trough-progressbar_v.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/trough-scrollbar-horiz.png b/assets/themes/NexusOS/gtk-2.0/assets/trough-scrollbar-horiz.png new file mode 100644 index 0000000..8c66765 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/trough-scrollbar-horiz.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/trough-scrollbar-vert.png b/assets/themes/NexusOS/gtk-2.0/assets/trough-scrollbar-vert.png new file mode 100644 index 0000000..b277bb4 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/trough-scrollbar-vert.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/trough-vertical-active.png b/assets/themes/NexusOS/gtk-2.0/assets/trough-vertical-active.png new file mode 100644 index 0000000..152e321 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/trough-vertical-active.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/trough-vertical.png b/assets/themes/NexusOS/gtk-2.0/assets/trough-vertical.png new file mode 100644 index 0000000..1a7a190 Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/trough-vertical.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/up-background-disable-rtl.png b/assets/themes/NexusOS/gtk-2.0/assets/up-background-disable-rtl.png new file mode 100644 index 0000000..625b4bb Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/up-background-disable-rtl.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/up-background-disable.png b/assets/themes/NexusOS/gtk-2.0/assets/up-background-disable.png new file mode 100644 index 0000000..883b78b Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/up-background-disable.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/up-background-rtl.png b/assets/themes/NexusOS/gtk-2.0/assets/up-background-rtl.png new file mode 100644 index 0000000..6cd15ba Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/up-background-rtl.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/assets/up-background.png b/assets/themes/NexusOS/gtk-2.0/assets/up-background.png new file mode 100644 index 0000000..ae2035a Binary files /dev/null and b/assets/themes/NexusOS/gtk-2.0/assets/up-background.png differ diff --git a/assets/themes/NexusOS/gtk-2.0/gtkrc b/assets/themes/NexusOS/gtk-2.0/gtkrc new file mode 100644 index 0000000..d5c5ebb --- /dev/null +++ b/assets/themes/NexusOS/gtk-2.0/gtkrc @@ -0,0 +1,26 @@ +gtk-color-scheme = "base_color: #242424" +gtk-color-scheme = "text_color: #dedede" +gtk-color-scheme = "bg_color: #333333" +gtk-color-scheme = "fg_color: #dedede" +gtk-color-scheme = "tooltip_bg_color: #2a2a2a" +gtk-color-scheme = "tooltip_fg_color: #dedede" +gtk-color-scheme = "selected_bg_color: #9A57A3" +gtk-color-scheme = "selected_fg_color: #ffffff" +gtk-color-scheme = "insensitive_bg_color: #2a2a2a" +gtk-color-scheme = "insensitive_fg_color: #565656" +gtk-color-scheme = "insensitive_button_fg_color: #565656" +gtk-color-scheme = "notebook_bg: #242424" +gtk-color-scheme = "dark_sidebar_bg: #3b3b3b" +gtk-color-scheme = "link_color: #5294e2" +gtk-color-scheme = "menu_bg: #333333" +gtk-color-scheme = "menu_fg: #dedede" + +gtk-icon-sizes = "gtk-button=16,16" # This makes button icons smaller. +gtk-auto-mnemonics = 1 +gtk-primary-button-warps-slider = 1 + +include "main.rc" +include "apps.rc" +include "panel.rc" +include "xfce-notify.rc" +include "menubar-toolbar.rc" diff --git a/assets/themes/NexusOS/gtk-2.0/main.rc b/assets/themes/NexusOS/gtk-2.0/main.rc new file mode 100644 index 0000000..4f21ab2 --- /dev/null +++ b/assets/themes/NexusOS/gtk-2.0/main.rc @@ -0,0 +1,2483 @@ +style "default" { + + xthickness = 1 + ythickness = 1 + + # Style Properties + + GtkWindow::resize-grip-height = 4 + GtkWindow::resize-grip-width = 4 + + GtkWidget::focus-line-width = 1 + GtkMenuBar::window-dragging = 1 + GtkToolbar::window-dragging = 1 + GtkToolbar::internal-padding = 4 + GtkToolButton::icon-spacing = 4 + + GtkWidget::tooltip-radius = 2 + GtkWidget::tooltip-alpha = 235 + GtkWidget::new-tooltip-style = 1 #for compatibility + + GtkSeparatorMenuItem::horizontal-padding = 0 + GtkSeparatorMenuItem::wide-separators = 1 + GtkSeparatorMenuItem::separator-height = 2 + + GtkButton::child-displacement-y = 0 + GtkButton::default-border = { 0, 0, 0, 0 } + GtkButton::default-outside_border = { 0, 0, 0, 0 } + + GtkEntry::state-hint = 1 + + GtkScrollbar::trough-border = 0 + GtkRange::trough-border = 0 + GtkRange::slider-width = 13 + GtkRange::stepper-size = 0 + + GtkScrollbar::activate-slider = 1 + GtkScrollbar::has-backward-stepper = 0 + GtkScrollbar::has-forward-stepper = 0 + GtkScrollbar::min-slider-length = 32 + GtkScrolledWindow::scrollbar-spacing = 0 + GtkScrolledWindow::scrollbars-within-bevel = 1 + + GtkScale::slider_length = 20 + GtkScale::slider_width = 20 + GtkScale::trough-side-details = 1 + + GtkProgressBar::min-horizontal-bar-height = 8 + GtkProgressBar::min-vertical-bar-width = 8 + + GtkStatusbar::shadow_type = GTK_SHADOW_NONE + GtkSpinButton::shadow_type = GTK_SHADOW_NONE + GtkMenuBar::shadow-type = GTK_SHADOW_NONE + GtkToolbar::shadow-type = GTK_SHADOW_NONE + GtkMenuBar::internal-padding = 0 #( every window is misaligned for the sake of menus ): + GtkMenu::horizontal-padding = 0 + GtkMenu::vertical-padding = 0 + + GtkCheckButton::indicator_spacing = 3 + GtkOptionMenu::indicator_spacing = { 8, 2, 0, 0 } + + GtkTreeView::row_ending_details = 0 + GtkTreeView::expander-size = 11 + GtkTreeView::vertical-separator = 4 + GtkTreeView::horizontal-separator = 4 + GtkTreeView::allow-rules = 1 + GtkTreeView::odd_row_color = shade(0.98, @base_color) + + GtkExpander::expander-size = 11 + + GnomeHRef::link_color = @link_color + GtkHTML::link-color = @link_color + GtkIMHtmlr::hyperlink-color = @link_color + GtkIMHtml::hyperlink-color = @link_color + GtkWidget::link-color = @link_color + GtkWidget::visited-link-color = @text_color + + # Colors + + bg[NORMAL] = @bg_color + bg[PRELIGHT] = shade (1.0, @bg_color) + bg[SELECTED] = @selected_bg_color + bg[INSENSITIVE] = @insensitive_bg_color + bg[ACTIVE] = shade (0.9, @bg_color) + + fg[NORMAL] = @text_color + fg[PRELIGHT] = @fg_color + fg[INSENSITIVE] = @insensitive_fg_color + # fg[ACTIVE] = @fg_color + fg[SELECTED] = @selected_fg_color + + text[NORMAL] = @text_color + text[PRELIGHT] = @text_color + text[SELECTED] = @selected_fg_color + text[INSENSITIVE] = @insensitive_fg_color + text[ACTIVE] = @selected_fg_color + + base[NORMAL] = @base_color + base[PRELIGHT] = shade (0.95, @bg_color) + base[SELECTED] = @selected_bg_color + base[INSENSITIVE] = @bg_color + base[ACTIVE] = shade (0.9, @selected_bg_color) + + # For succinctness, all reasonable pixmap options remain here + # This needs to go before pixmap because we need to override some stuff + engine "adwaita" {} + + engine "pixmap" { + + # Check Buttons + + image { + function = CHECK + recolorable = TRUE + state = NORMAL + shadow = OUT + overlay_file = "assets/checkbox-unchecked.png" + overlay_stretch = FALSE + } + + image { + function = CHECK + recolorable = TRUE + state = PRELIGHT + shadow = OUT + overlay_file = "assets/checkbox-unchecked.png" + overlay_stretch = FALSE + } + + image { + function = CHECK + recolorable = TRUE + state = ACTIVE + shadow = OUT + overlay_file = "assets/checkbox-unchecked.png" + overlay_stretch = FALSE + } + + image { + function = CHECK + recolorable = TRUE + state = SELECTED + shadow = OUT + overlay_file = "assets/checkbox-unchecked.png" + overlay_stretch = FALSE + } + + image { + function = CHECK + recolorable = TRUE + state = INSENSITIVE + shadow = OUT + overlay_file = "assets/checkbox-unchecked-insensitive.png" + overlay_stretch = FALSE + } + + image { + function = CHECK + recolorable = TRUE + state = NORMAL + shadow = IN + overlay_file = "assets/checkbox-checked.png" + overlay_stretch = FALSE + } + + image { + function = CHECK + recolorable = TRUE + state = PRELIGHT + shadow = IN + overlay_file = "assets/checkbox-checked.png" + overlay_stretch = FALSE + } + + image { + function = CHECK + recolorable = TRUE + state = ACTIVE + shadow = IN + overlay_file = "assets/checkbox-checked.png" + overlay_stretch = FALSE + } + + image { + function = CHECK + recolorable = TRUE + state = SELECTED + shadow = IN + overlay_file = "assets/checkbox-checked.png" + overlay_stretch = FALSE + } + + image { + function = CHECK + recolorable = TRUE + state = INSENSITIVE + shadow = IN + overlay_file = "assets/checkbox-checked-insensitive.png" + overlay_stretch = FALSE + } + + # Radio Buttons + + image { + function = OPTION + state = NORMAL + shadow = OUT + overlay_file = "assets/radio-unchecked.png" + overlay_stretch = FALSE + } + + image { + function = OPTION + state = PRELIGHT + shadow = OUT + overlay_file = "assets/radio-unchecked.png" + overlay_stretch = FALSE + } + + image { + function = OPTION + state = ACTIVE + shadow = OUT + overlay_file = "assets/radio-unchecked.png" + overlay_stretch = FALSE + } + + image { + function = OPTION + state = SELECTED + shadow = OUT + overlay_file = "assets/radio-unchecked.png" + overlay_stretch = FALSE + } + + image { + function = OPTION + state = INSENSITIVE + shadow = OUT + overlay_file = "assets/radio-unchecked-insensitive.png" + overlay_stretch = FALSE + } + + image { + function = OPTION + state = NORMAL + shadow = IN + overlay_file = "assets/radio-checked.png" + overlay_stretch = FALSE + } + + image { + function = OPTION + state = PRELIGHT + shadow = IN + overlay_file = "assets/radio-checked.png" + overlay_stretch = FALSE + } + + image { + function = OPTION + state = ACTIVE + shadow = IN + overlay_file = "assets/radio-checked.png" + overlay_stretch = FALSE + } + + image { + function = OPTION + state = SELECTED + shadow = IN + overlay_file = "assets/radio-checked.png" + overlay_stretch = FALSE + } + + image { + function = OPTION + state = INSENSITIVE + shadow = IN + overlay_file = "assets/radio-checked-insensitive.png" + overlay_stretch = FALSE + } + + # Arrows + + image { + function = ARROW + overlay_file = "assets/arrow-up.png" + overlay_border = { 0, 0, 0, 0 } + overlay_stretch = FALSE + arrow_direction = UP + } + + image { + function = ARROW + state = PRELIGHT + overlay_file = "assets/arrow-up-prelight.png" + overlay_border = { 0, 0, 0, 0 } + overlay_stretch = FALSE + arrow_direction = UP + } + + image { + function = ARROW + state = ACTIVE + overlay_file = "assets/arrow-up-prelight.png" + overlay_border = { 0, 0, 0, 0 } + overlay_stretch = FALSE + arrow_direction = UP + } + + image { + function = ARROW + state = INSENSITIVE + overlay_file = "assets/arrow-up-insens.png" + overlay_border = { 0, 0, 0, 0 } + overlay_stretch = FALSE + arrow_direction = UP + } + + image { + function = ARROW + state = NORMAL + overlay_file = "assets/arrow-down.png" + overlay_border = { 0, 0, 0, 0 } + overlay_stretch = FALSE + arrow_direction = DOWN + } + + image { + function = ARROW + state = PRELIGHT + overlay_file = "assets/arrow-down-prelight.png" + overlay_border = { 0, 0, 0, 0 } + overlay_stretch = FALSE + arrow_direction = DOWN + } + + image { + function = ARROW + state = ACTIVE + overlay_file = "assets/arrow-down-prelight.png" + overlay_border = { 0, 0, 0, 0 } + overlay_stretch = FALSE + arrow_direction = DOWN + } + + image { + function = ARROW + state = INSENSITIVE + overlay_file = "assets/arrow-down-insens.png" + overlay_border = { 0, 0, 0, 0 } + overlay_stretch = FALSE + arrow_direction = DOWN + } + + image { + function = ARROW + overlay_file = "assets/arrow-left.png" + overlay_border = { 0, 0, 0, 0 } + overlay_stretch = FALSE + arrow_direction = LEFT + } + + image { + function = ARROW + state= PRELIGHT + overlay_file = "assets/arrow-left-prelight.png" + overlay_border = { 0, 0, 0, 0 } + overlay_stretch = FALSE + arrow_direction = LEFT + } + + image { + function = ARROW + state = ACTIVE + overlay_file = "assets/arrow-left-prelight.png" + overlay_border = { 0, 0, 0, 0 } + overlay_stretch = FALSE + arrow_direction = LEFT + } + + image { + function = ARROW + state = INSENSITIVE + overlay_file = "assets/arrow-left-insens.png" + overlay_border = { 0, 0, 0, 0 } + overlay_stretch = FALSE + arrow_direction = LEFT + } + + image { + function = ARROW + overlay_file = "assets/arrow-right.png" + overlay_border = { 0, 0, 0, 0 } + overlay_stretch = FALSE + arrow_direction = RIGHT + } + + image { + function = ARROW + state = PRELIGHT + overlay_file = "assets/arrow-right-prelight.png" + overlay_border = { 0, 0, 0, 0 } + overlay_stretch = FALSE + arrow_direction = RIGHT + } + + image { + function = ARROW + state = ACTIVE + overlay_file = "assets/arrow-right-prelight.png" + overlay_border = { 0, 0, 0, 0 } + overlay_stretch = FALSE + arrow_direction = RIGHT + } + + image { + function = ARROW + state = INSENSITIVE + overlay_file = "assets/arrow-right-insens.png" + overlay_border = { 0, 0, 0, 0 } + overlay_stretch = FALSE + arrow_direction = RIGHT + } + + # Option Menu Arrows + + image { + function = TAB + state = INSENSITIVE + overlay_file = "assets/arrow-down-insens.png" + overlay_stretch = FALSE + } + + image { + function = TAB + state = NORMAL + overlay_file = "assets/arrow-down.png" + overlay_border = { 0, 0, 0, 0 } + overlay_stretch = FALSE + } + + image { + function = TAB + state = PRELIGHT + overlay_file = "assets/arrow-down-prelight.png" + overlay_border = { 0, 0, 0, 0 } + overlay_stretch = FALSE + } + + # Lines + + image { + function = VLINE + file = "assets/border.png" + border = { 1, 0, 0, 0 } + stretch = TRUE + } + + image { + function = HLINE + file = "assets/border.png" + border = { 0, 0, 1, 0 } + stretch = TRUE + } + + # Focuslines + + image { + function = FOCUS + file = "assets/null.png" + border = { 1, 1, 1, 1 } + stretch = TRUE + } + + # Handles + + image { + function = HANDLE + overlay_file = "assets/handle-h.png" + overlay_stretch = FALSE + orientation = HORIZONTAL + } + + image { + function = HANDLE + overlay_file = "assets/handle-v.png" + overlay_stretch = FALSE + orientation = VERTICAL + } + + # Expanders + + image { + function = EXPANDER + expander_style = COLLAPSED + file = "assets/plus.png" + } + + image { + function = EXPANDER + expander_style = EXPANDED + file = "assets/minus.png" + } + + image { + function = EXPANDER + expander_style = SEMI_EXPANDED + file = "assets/minus.png" + } + + image { + function = EXPANDER + expander_style = SEMI_COLLAPSED + file = "assets/plus.png" + } + + image { + function = RESIZE_GRIP + state = NORMAL + detail = "statusbar" + overlay_file = "assets/null.png" + overlay_border = { 0,0,0,0 } + overlay_stretch = FALSE + } + + # Shadows ( this area needs help :P ) + + image { + function = SHADOW_GAP + file = "assets/null.png" + border = { 4, 4, 4, 4 } + stretch = TRUE + } + } +} + + +style "toplevel_hack" { + + engine "adwaita" { + } +} + +style "ooo_stepper_hack" { + + GtkScrollbar::stepper-size = 0 + GtkScrollbar::has-backward-stepper = 0 + GtkScrollbar::has-forward-stepper = 0 + +} + +style "scrollbar" { + + engine "pixmap" { + + image { + function = BOX + detail = "trough" + file = "assets/trough-scrollbar-horiz.png" + border = { 2, 2, 3, 3 } + stretch = TRUE + orientation = HORIZONTAL + } + + image { + function = BOX + detail = "trough" + file = "assets/trough-scrollbar-vert.png" + border = { 3, 3, 2, 2 } + stretch = TRUE + orientation = VERTICAL + } + + image { + function = ARROW + overlay_file = "assets/null.png" + overlay_border = { 0, 0, 0, 0 } + overlay_stretch = FALSE + arrow_direction = UP + } + + image { + function = ARROW + overlay_file = "assets/null.png" + overlay_border = { 0, 0, 0, 0 } + overlay_stretch = FALSE + arrow_direction = DOWN + } + + image { + function = ARROW + overlay_file = "assets/null.png" + overlay_border = { 0, 0, 0, 0 } + overlay_stretch = FALSE + arrow_direction = LEFT + } + + image { + function = ARROW + overlay_file = "assets/null.png" + overlay_border = { 0, 0, 0, 0 } + overlay_stretch = FALSE + arrow_direction = RIGHT + } + + # Sliders + + image { + function = SLIDER + state = NORMAL + file = "assets/slider-horiz.png" + border = { 5, 5, 3, 3 } + stretch = TRUE + orientation = HORIZONTAL + } + + image { + function = SLIDER + state = ACTIVE + file = "assets/slider-horiz-active.png" + border = { 5, 5, 3, 3 } + stretch = TRUE + orientation = HORIZONTAL + } + + image { + function = SLIDER + state = PRELIGHT + file = "assets/slider-horiz-prelight.png" + border = { 5, 5, 3, 3 } + stretch = TRUE + orientation = HORIZONTAL + } + + image { + function = SLIDER + state = INSENSITIVE + file = "assets/slider-horiz-insens.png" + border = { 5, 5, 3, 3 } + stretch = TRUE + orientation = HORIZONTAL + } + +# X Verticals + + image { + function = SLIDER + state = NORMAL + file = "assets/slider-vert.png" + border = { 3, 3, 5, 5 } + stretch = TRUE + orientation = VERTICAL + } + + image { + function = SLIDER + state = ACTIVE + file = "assets/slider-vert-active.png" + border = { 3, 3, 5, 5 } + stretch = TRUE + orientation = VERTICAL + } + + image { + function = SLIDER + state = PRELIGHT + file = "assets/slider-vert-prelight.png" + border = { 3, 3, 5, 5 } + stretch = TRUE + orientation = VERTICAL + } + + image { + function = SLIDER + state = INSENSITIVE + file = "assets/slider-vert-insens.png" + border = { 3, 3, 5, 5 } + stretch = TRUE + orientation = VERTICAL + } + } +} + +style "menu" { + + xthickness = 0 + ythickness = 0 + + GtkMenuItem::arrow-scaling = 0.4 + + bg[NORMAL] = @menu_bg + bg[INSENSITIVE] = @menu_bg + bg[PRELIGHT] = @menu_bg +} + +style "menu_framed_box" { + +# engine "adwaita" { # default menu border +# } + + engine "pixmap" { + image { + function = BOX + file = "assets/frame.png" + border = { 1, 1, 2, 1 } + stretch = TRUE + } + } + +} + +style "menu_item" { + xthickness = 4 + ythickness = 2 + + # HACK: Gtk doesn't actually read this value + # while rendering the menu items, but Libreoffice + # does; setting this value equal to the one in + # fg[PRELIGHT] ensures a code path in the LO theming code + # that falls back to a dark text color for menu item text + # highlight. The price to pay is black text on menus as well, + # but at least it's readable. + # See https://bugs.freedesktop.org/show_bug.cgi?id=38038 + bg[SELECTED] = @selected_bg_color + + fg[NORMAL] = @menu_fg + fg[SELECTED] = @selected_fg_color + + fg[PRELIGHT] = @selected_fg_color + text[PRELIGHT] = @selected_fg_color + + engine "pixmap" { + + image { + function = BOX + state = PRELIGHT + file = "assets/menuitem.png" + border = { 1, 0, 1, 0 } + stretch = TRUE + } + + # Fix invisible scale trough on selected menuitems + + image { + function = BOX + detail = "trough-lower" + file = "assets/trough-horizontal.png" + border = { 8, 8, 0, 0 } + stretch = TRUE + orientation = HORIZONTAL + } + + image { + function = SLIDER + state = PRELIGHT + file = "assets/null.png" + border = { 0, 0, 0, 0 } + stretch = TRUE + overlay_file = "assets/slider.png" + overlay_stretch = FALSE + orientation = HORIZONTAL + } + + # Check Buttons + + image { + function = CHECK + recolorable = TRUE + state = NORMAL + shadow = OUT + overlay_file = "assets/menu-checkbox-unchecked.png" + overlay_stretch = FALSE + } + + image { + function = CHECK + recolorable = TRUE + state = PRELIGHT + shadow = OUT + overlay_file = "assets/menu-checkbox-unchecked.png" + overlay_stretch = FALSE + } + + image { + function = CHECK + recolorable = TRUE + state = ACTIVE + shadow = OUT + overlay_file = "assets/menu-checkbox-unchecked.png" + overlay_stretch = FALSE + } + + image { + function = CHECK + recolorable = TRUE + state = INSENSITIVE + shadow = OUT + overlay_file = "assets/menu-checkbox-unchecked-insensitive.png" + overlay_stretch = FALSE + } + + image { + function = CHECK + recolorable = TRUE + state = NORMAL + shadow = IN + overlay_file = "assets/menu-checkbox-checked.png" + overlay_stretch = FALSE + } + + image { + function = CHECK + recolorable = TRUE + state = PRELIGHT + shadow = IN + overlay_file = "assets/menu-checkbox-checked.png" + overlay_stretch = FALSE + } + + image { + function = CHECK + recolorable = TRUE + state = ACTIVE + shadow = IN + overlay_file = "assets/menu-checkbox-checked.png" + overlay_stretch = FALSE + } + + image { + function = CHECK + recolorable = TRUE + state = INSENSITIVE + shadow = IN + overlay_file = "assets/menu-checkbox-checked-insensitive.png" + overlay_stretch = FALSE + } + + # Radio Buttons + + image { + function = OPTION + state = NORMAL + shadow = OUT + overlay_file = "assets/menu-radio-unchecked.png" + overlay_stretch = FALSE + } + + image { + function = OPTION + state = PRELIGHT + shadow = OUT + overlay_file = "assets/menu-radio-unchecked.png" + overlay_stretch = FALSE + } + + image { + function = OPTION + state = ACTIVE + shadow = OUT + overlay_file = "assets/menu-radio-unchecked.png" + overlay_stretch = FALSE + } + + image { + function = OPTION + state = INSENSITIVE + shadow = OUT + overlay_file = "assets/menu-radio-unchecked-insensitive.png" + overlay_stretch = FALSE + } + + image { + function = OPTION + state = NORMAL + shadow = IN + overlay_file = "assets/menu-radio-checked.png" + overlay_stretch = FALSE + } + + image { + function = OPTION + state = PRELIGHT + shadow = IN + overlay_file = "assets/menu-radio-checked.png" + overlay_stretch = FALSE + } + + image { + function = OPTION + state = ACTIVE + shadow = IN + overlay_file = "assets/menu-radio-checked.png" + overlay_stretch = FALSE + } + + image { + function = OPTION + state = INSENSITIVE + shadow = IN + overlay_file = "assets/menu-radio-checked-insensitive.png" + overlay_stretch = FALSE + } + + image { + function = SHADOW # This fixes boxy Qt menu items + file = "assets/null.png" + border = { 4, 4, 4, 4 } + stretch = TRUE + } + + # Arrow Buttons + + image { + function = ARROW + state = NORMAL + overlay_file = "assets/menu-arrow.png" + overlay_border = { 0, 0, 0, 0 } + overlay_stretch = FALSE + arrow_direction = RIGHT + } + + image { + function = ARROW + state = PRELIGHT + overlay_file = "assets/menu-arrow-prelight.png" + overlay_border = { 0, 0, 0, 0 } + overlay_stretch = FALSE + arrow_direction = RIGHT + } + + image { + function = BOX + state = PRELIGHT + detail = "menu_scroll_arrow_up" + file = "assets/border.png" + border = {0, 0, 1, 0} + } + + image { + function = BOX + detail = "menu_scroll_arrow_up" + file = "assets/border.png" + border = {0, 0, 1, 0} + } + + image { + function = BOX + state = PRELIGHT + detail = "menu_scroll_arrow_down" + file = "assets/border.png" + border = {1, 0, 0, 0} + } + + image { + function = BOX + detail = "menu_scroll_arrow_down" + file = "assets/border.png" + border = {1, 0, 0, 0} + } + } +} + +style "button" { + xthickness = 4 + ythickness = 4 + + engine "murrine" { textstyle = 0 } + + engine "pixmap" { + + image { + function = BOX + state = NORMAL + file = "assets/button.png" + border = {6, 6, 6, 6} + stretch = TRUE + } + + image { + function = BOX + state = PRELIGHT + shadow = OUT + file = "assets/button-hover.png" + border = {6, 6, 6, 6} + stretch = TRUE + } + + # hover effect on pressed buttons + image { + function = BOX + state = PRELIGHT + shadow = IN + file = "assets/button-active-hover.png" + border = {6, 6, 6, 6} + stretch = TRUE + } + + image { + function = BOX + state = ACTIVE + file = "assets/button-active.png" + border = {6, 6, 6, 6} + stretch = TRUE + } + + image { + function = BOX + state = INSENSITIVE + file = "assets/button-insensitive.png" + border = {6, 6, 6, 6} + stretch = TRUE + } + } +} + +style "toolbar_button" { + + engine "pixmap" { + + # hover effect on pressed buttons + image { + function = BOX + state = PRELIGHT + shadow = IN + file = "assets/toolbar-button-active-hover.png" + border = {6, 6, 6, 6} + stretch = TRUE + } + + image { + function = BOX + state = ACTIVE + file = "assets/toolbar-button-active.png" + border = {6, 6, 6, 6} + stretch = TRUE + } + + } +} + +style "button_label" { + + fg[NORMAL] = @text_color + fg[PRELIGHT] = @fg_color + fg[INSENSITIVE] = @insensitive_button_fg_color + fg[ACTIVE] = @fg_color + + engine "murrine" { textstyle = 0 } +} + +style "checkbutton" { + + fg[PRELIGHT] = @text_color + fg[ACTIVE] = @text_color + +} + +style "link_button" { + # Disable the button effect, leave just the link + engine "pixmap" { + image { + function = BOX + } + } +} + +style "entry" { + + xthickness = 6 + ythickness = 4 + + engine "pixmap" { + + image { + function = SHADOW + state = NORMAL + detail = "entry" + file = "assets/entry-bg.png" + border = {6, 6, 6, 6} + stretch = TRUE + } + + image { + function = SHADOW + state = ACTIVE + detail = "entry" + file = "assets/entry-active-bg.png" + border = {6, 6, 6, 6} + stretch = TRUE + } + + image { + function = SHADOW + state = INSENSITIVE + detail = "entry" + file = "assets/entry-disabled-bg.png" + border = {6, 6, 6, 6} + stretch = TRUE + } + + image { + function = FLAT_BOX + state = ACTIVE + detail = "entry_bg" + file = "assets/entry-background.png" + } + + image { + function = FLAT_BOX + state = INSENSITIVE + detail = "entry_bg" + file = "assets/entry-background-disabled.png" + } + + image { + function = FLAT_BOX + detail = "entry_bg" + file = "assets/entry-background.png" + } + } +} + +style "notebook_entry" { + + engine "pixmap" { + + image { + function = SHADOW + state = NORMAL + detail = "entry" + file = "assets/entry-notebook.png" + border = {6, 6, 6, 6} + stretch = TRUE + } + + image { + function = SHADOW + state = ACTIVE + detail = "entry" + file = "assets/entry-active-notebook.png" + border = {6, 6, 6, 6} + stretch = TRUE + } + + image { + function = SHADOW + state = INSENSITIVE + detail = "entry" + file = "assets/entry-disabled-notebook.png" + border = {6, 6, 6, 6} + stretch = TRUE + } + } +} + +style "notebook_button_bg" { + + bg[NORMAL] = @notebook_bg + bg[PRELIGHT] = @notebook_bg + bg[INSENSITIVE] = @notebook_bg + bg[ACTIVE] = @notebook_bg + +} + +style "notebook_tab_label" { + + fg[NORMAL] = @text_color + fg[PRELIGHT] = @fg_color + fg[INSENSITIVE] = @insensitive_fg_color + fg[ACTIVE] = @text_color + +} + +style "combobox_entry" { + + xthickness = 3 + ythickness = 4 + + engine "pixmap" { + + # LTR version + + image { + function = SHADOW + detail = "entry" + state = NORMAL + shadow = IN + file = "assets/combo-entry.png" + border = { 4, 4, 5, 4 } + stretch = TRUE + direction = LTR + } + + image { + function = SHADOW + detail = "entry" + state = INSENSITIVE + shadow = IN + file = "assets/combo-entry-insensitive.png" + border = { 4, 4, 5, 4 } + stretch = TRUE + direction = LTR + } + + image { + function = SHADOW + detail = "entry" + state = ACTIVE + file = "assets/combo-entry-focus.png" + border = { 4, 4, 5, 4 } + stretch = TRUE + direction = LTR + } + + # RTL version + + image { + function = SHADOW + detail = "entry" + state = NORMAL + shadow = IN + file = "assets/combo-entry-rtl.png" + border = { 4, 4, 5, 4 } + stretch = TRUE + direction = RTL + } + + image { + function = SHADOW + detail = "entry" + state = INSENSITIVE + shadow = IN + file = "assets/combo-entry-insensitive-rtl.png" + border = { 4, 4, 5, 4 } + stretch = TRUE + direction = RTL + } + + image { + function = SHADOW + detail = "entry" + state = ACTIVE + file = "assets/combo-entry-focus-rtl.png" + border = { 4, 4, 5, 4 } + stretch = TRUE + direction = RTL + } + } +} + +style "notebook_combobox_entry" { + + engine "pixmap" { + + # LTR version + + image { + function = SHADOW + detail = "entry" + state = NORMAL + shadow = IN + file = "assets/combo-entry-notebook.png" + border = { 4, 4, 5, 4 } + stretch = TRUE + direction = LTR + } + + image { + function = SHADOW + detail = "entry" + state = INSENSITIVE + shadow = IN + file = "assets/combo-entry-insensitive-notebook.png" + border = { 4, 4, 5, 4 } + stretch = TRUE + direction = LTR + } + + image { + function = SHADOW + detail = "entry" + state = ACTIVE + file = "assets/combo-entry-focus-notebook.png" + border = { 4, 4, 5, 4 } + stretch = TRUE + direction = LTR + } + + # RTL version + + image { + function = SHADOW + detail = "entry" + state = NORMAL + shadow = IN + file = "assets/combo-entry-notebook-rtl.png" + border = { 4, 4, 5, 4 } + stretch = TRUE + direction = RTL + } + + image { + function = SHADOW + detail = "entry" + state = INSENSITIVE + shadow = IN + file = "assets/combo-entry-insensitive-notebook-rtl.png" + border = { 4, 4, 5, 4 } + stretch = TRUE + direction = RTL + } + + image { + function = SHADOW + detail = "entry" + state = ACTIVE + file = "assets/combo-entry-focus-notebook-rtl.png" + border = { 4, 4, 5, 4 } + stretch = TRUE + direction = RTL + } + } +} + +style "combobox_entry_button" { + + xthickness = 6 + + fg[ACTIVE] = @text_color + + engine "pixmap" { + + # LTR version + + image { + function = BOX + state = NORMAL + file = "assets/combo-entry-button.png" + border = { 4, 4, 5, 4 } + stretch = TRUE + direction = LTR + } + + image { + function = BOX + state = PRELIGHT + file = "assets/combo-entry-button.png" + border = { 4, 4, 5, 4 } + stretch = TRUE + direction = LTR + } + + image { + function = BOX + state = INSENSITIVE + file = "assets/combo-entry-button-insensitive.png" + border = { 4, 4, 5, 4 } + stretch = TRUE + direction = LTR + } + + image { + function = BOX + state = ACTIVE + file = "assets/combo-entry-button-active.png" + border = { 4, 4, 5, 4 } + stretch = TRUE + direction = LTR + } + + # RTL version + image { + function = BOX + state = NORMAL + file = "assets/combo-entry-button-rtl.png" + border = { 4, 4, 5, 4 } + stretch = TRUE + direction = RTL + } + + image { + function = BOX + state = PRELIGHT + file = "assets/combo-entry-button-rtl.png" + border = { 4, 4, 5, 4 } + stretch = TRUE + direction = RTL + } + + image { + function = BOX + state = INSENSITIVE + file = "assets/combo-entry-button-insensitive-rtl.png" + border = { 4, 4, 5, 4 } + stretch = TRUE + direction = RTL + } + + image { + function = BOX + state = ACTIVE + file = "assets/combo-entry-button-active-rtl.png" + border = { 4, 4, 5, 4 } + stretch = TRUE + direction = RTL + } + } +} + +style "spinbutton" { + + bg[NORMAL] = @bg_color + + xthickness = 6 + ythickness = 4 + + engine "pixmap" { + + image { + function = ARROW + } + + # Spin-Up LTR + + image { + function = BOX + state = NORMAL + detail = "spinbutton_up" + file = "assets/up-background.png" + border = { 1, 4, 5, 0 } + stretch = TRUE + overlay_file = "assets/arrow-up-small.png" + overlay_stretch = FALSE + direction = LTR + } + + image { + function = BOX + state = PRELIGHT + detail = "spinbutton_up" + file = "assets/up-background.png" + border = { 1, 4, 5, 0 } + stretch = TRUE + overlay_file = "assets/arrow-up-small-prelight.png" + overlay_stretch = FALSE + direction = LTR + } + + image { + function = BOX + state = INSENSITIVE + detail = "spinbutton_up" + file = "assets/up-background-disable.png" + border = { 1, 4, 5, 0 } + stretch = TRUE + overlay_file = "assets/arrow-up-small-insens.png" + overlay_stretch = FALSE + direction = LTR + } + + image { + function = BOX + state = ACTIVE + detail = "spinbutton_up" + file = "assets/up-background.png" + border = { 1, 4, 5, 0 } + stretch = TRUE + overlay_file = "assets/arrow-up-small-prelight.png" + overlay_stretch = FALSE + direction = LTR + } + + # Spin-Up RTL + + image { + function = BOX + state = NORMAL + detail = "spinbutton_up" + file = "assets/up-background-rtl.png" + border = { 4, 1, 5, 0 } + stretch = TRUE + overlay_file = "assets/arrow-up-small.png" + overlay_stretch = FALSE + direction = RTL + } + + image { + function = BOX + state = PRELIGHT + detail = "spinbutton_up" + file = "assets/up-background-rtl.png" + border = { 4, 1, 5, 0 } + stretch = TRUE + overlay_file = "assets/arrow-up-small-prelight.png" + overlay_stretch = FALSE + direction = RTL + } + + image { + function = BOX + state = INSENSITIVE + detail = "spinbutton_up" + file = "assets/up-background-disable-rtl.png" + border = { 4, 1, 5, 0 } + stretch = TRUE + overlay_file = "assets/arrow-up-small-insens.png" + overlay_stretch = FALSE + direction = RTL + } + + image { + function = BOX + state = ACTIVE + detail = "spinbutton_up" + file = "assets/up-background-rtl.png" + border = { 4, 1, 5, 0 } + stretch = TRUE + overlay_file = "assets/arrow-up-small-prelight.png" + overlay_stretch = FALSE + direction = RTL + } + + # Spin-Down LTR + + image { + function = BOX + state = NORMAL + detail = "spinbutton_down" + file = "assets/down-background.png" + border = { 1, 4, 1, 4 } + stretch = TRUE + overlay_file = "assets/arrow-down-small.png" + overlay_stretch = FALSE + direction = LTR + } + + image { + function = BOX + state = PRELIGHT + detail = "spinbutton_down" + file = "assets/down-background.png" + border = { 1, 4, 1, 4 } + stretch = TRUE + overlay_file = "assets/arrow-down-small-prelight.png" + overlay_stretch = FALSE + direction = LTR + } + + image { + function = BOX + state = INSENSITIVE + detail = "spinbutton_down" + file = "assets/down-background-disable.png" + border = { 1, 4, 1, 4 } + stretch = TRUE + overlay_file = "assets/arrow-down-small-insens.png" + overlay_stretch = FALSE + direction = LTR + } + + image { + function = BOX + state = ACTIVE + detail = "spinbutton_down" + file = "assets/down-background.png" + border = { 1, 4, 1, 4 } + stretch = TRUE + overlay_file = "assets/arrow-down-small-prelight.png" + overlay_stretch = FALSE + direction = LTR + } + + # Spin-Down RTL + + image { + function = BOX + state = NORMAL + detail = "spinbutton_down" + file = "assets/down-background-rtl.png" + border = { 4, 1, 1, 4 } + stretch = TRUE + overlay_file = "assets/arrow-down-small.png" + overlay_stretch = FALSE + direction = RTL + } + + image { + function = BOX + state = PRELIGHT + detail = "spinbutton_down" + file = "assets/down-background-rtl.png" + border = { 4, 1, 1, 4 } + stretch = TRUE + overlay_file = "assets/arrow-down-small-prelight.png" + overlay_stretch = FALSE + direction = RTL + } + + image { + function = BOX + state = INSENSITIVE + detail = "spinbutton_down" + file = "assets/down-background-disable-rtl.png" + border = { 4, 1, 1, 4 } + stretch = TRUE + overlay_file = "assets/arrow-down-small-insens.png" + overlay_stretch = FALSE + direction = RTL + } + + image { + function = BOX + state = ACTIVE + detail = "spinbutton_down" + file = "assets/down-background-rtl.png" + border = { 4, 1, 1, 4 } + stretch = TRUE + overlay_file = "assets/arrow-down-small-prelight.png" + overlay_stretch = FALSE + direction = RTL + } + } +} + +style "gimp_spin_scale" { + + bg[NORMAL] = @base_color + + engine "pixmap" { + + image { + function = FLAT_BOX + detail = "entry_bg" + state = NORMAL + } + + image { + function = FLAT_BOX + detail = "entry_bg" + state = ACTIVE + } + + image { + function = BOX + state = NORMAL + detail = "spinbutton_up" + overlay_file = "assets/arrow-up-small.png" + overlay_stretch = FALSE + } + + image { + function = BOX + state = PRELIGHT + detail = "spinbutton_up" + overlay_file = "assets/arrow-up-small-prelight.png" + overlay_stretch = FALSE + } + + image { + function = BOX + state = ACTIVE + detail = "spinbutton_up" + overlay_file = "assets/arrow-up-small-prelight.png" + overlay_stretch = FALSE + } + + image { + function = BOX + state = INSENSITIVE + detail = "spinbutton_up" + overlay_file = "assets/arrow-up-small-insens.png" + overlay_stretch = FALSE + } + + image { + function = BOX + state = NORMAL + detail = "spinbutton_down" + overlay_file = "assets/arrow-down-small.png" + overlay_stretch = FALSE + } + + image { + function = BOX + state = PRELIGHT + detail = "spinbutton_down" + overlay_file = "assets/arrow-down-small-prelight.png" + overlay_stretch = FALSE + } + + image { + function = BOX + state = ACTIVE + detail = "spinbutton_down" + overlay_file = "assets/arrow-down-small-prelight.png" + overlay_stretch = FALSE + } + + image { + function = BOX + state = INSENSITIVE + detail = "spinbutton_down" + overlay_file = "assets/arrow-down-small-insens.png" + overlay_stretch = FALSE + } + } +} + +style "notebook" { + + xthickness = 5 + ythickness = 2 + + engine "pixmap" { + + image { + function = EXTENSION + state = ACTIVE + file = "assets/null.png" + border = { 0,0,0,0 } + stretch = TRUE + gap_side = TOP + } + + image { + function = EXTENSION + state = ACTIVE + file = "assets/null.png" + border = { 0,0,0,0 } + stretch = TRUE + gap_side = BOTTOM + } + + image { + function = EXTENSION + state = ACTIVE + file = "assets/null.png" + border = { 0,0,0,0 } + stretch = TRUE + gap_side = RIGHT + } + + image { + function = EXTENSION + state = ACTIVE + file = "assets/null.png" + border = { 0,0,0,0 } + stretch = TRUE + gap_side = LEFT + } + + image { + function = EXTENSION + file = "assets/tab-top-active.png" + border = { 3,3,3,3 } + stretch = TRUE + gap_side = BOTTOM + } + + image { + function = EXTENSION + file = "assets/tab-bottom-active.png" + border = { 3,3,3,3 } + stretch = TRUE + gap_side = TOP + } + + image { + function = EXTENSION + file = "assets/tab-left-active.png" + border = { 3,3,3,3 } + stretch = TRUE + gap_side = RIGHT + } + + image { + function = EXTENSION + file = "assets/tab-right-active.png" + border = { 3,3,3,3 } + stretch = TRUE + gap_side = LEFT + } + + # How to draw boxes with a gap on one side (ie the page of a notebook) + + image { + function = BOX_GAP + file = "assets/notebook.png" + border = { 4, 4, 4, 4 } + stretch = TRUE + gap_file = "assets/notebook-gap-horiz.png" + gap_border = { 1, 1, 0, 0 } + gap_side = TOP + } + + image { + function = BOX_GAP + file = "assets/notebook.png" + border = { 4, 4, 4, 4 } + stretch = TRUE + gap_file = "assets/notebook-gap-horiz.png" + gap_border = { 1, 1, 0, 0 } + gap_side = BOTTOM + } + + image { + function = BOX_GAP + file = "assets/notebook.png" + border = { 4, 4, 4, 4 } + stretch = TRUE + gap_file = "assets/notebook-gap-vert.png" + gap_border = { 0, 0, 1, 1 } + gap_side = LEFT + } + + image { + function = BOX_GAP + file = "assets/notebook.png" + border = { 4, 4, 4, 4 } + stretch = TRUE + gap_file = "assets/notebook-gap-vert.png" + gap_border = { 0, 0, 1, 1 } + gap_side = RIGHT + } + + # How to draw the box of a notebook when it isnt attached to a tab + + image { + function = BOX + file = "assets/notebook.png" + border = { 4, 4, 4, 4 } + stretch = TRUE + } + } +} + +style "handlebox" { + + engine "pixmap" { + + image { + function = BOX + file = "assets/null.png" + border = { 4, 4, 4, 4 } + stretch = TRUE + detail = "handlebox_bin" + shadow = IN + } + + image { + function = BOX + file = "assets/null.png" + border = { 4, 4, 4, 4 } + stretch = TRUE + detail = "handlebox_bin" + shadow = OUT + } + } +} + +style "combobox_separator" { + + xthickness = 0 + ythickness = 0 + GtkWidget::wide-separators = 1 + +} + +style "combobox" { + + xthickness = 0 + ythickness = 0 + +} + +style "combobox_button" { + + xthickness = 3 + ythickness = 3 + +} + +style "range" { + + engine "pixmap" { + + image { + function = BOX + detail = "trough-upper" + file = "assets/trough-horizontal.png" + border = { 8, 8, 0, 0 } + stretch = TRUE + orientation = HORIZONTAL + } + + image { + function = BOX + detail = "trough-lower" + file = "assets/trough-horizontal-active.png" + border = { 8, 8, 0, 0 } + stretch = TRUE + orientation = HORIZONTAL + } + + image { + function = BOX + detail = "trough-upper" + file = "assets/trough-vertical.png" + border = { 0, 0, 8, 8 } + stretch = TRUE + orientation = VERTICAL + } + + image { + function = BOX + detail = "trough-lower" + file = "assets/trough-vertical-active.png" + border = { 0, 0, 8, 8 } + stretch = TRUE + orientation = VERTICAL + } + + # Horizontal + + image { + function = SLIDER + state = NORMAL + file = "assets/null.png" + border = { 0, 0, 0, 0 } + stretch = TRUE + overlay_file = "assets/slider.png" + overlay_stretch = FALSE + orientation = HORIZONTAL + } + + image { + function = SLIDER + state = PRELIGHT + file = "assets/null.png" + border = { 0, 0, 0, 0 } + stretch = TRUE + overlay_file = "assets/slider-prelight.png" + overlay_stretch = FALSE + orientation = HORIZONTAL + } + + image { + function = SLIDER + state = INSENSITIVE + file = "assets/null.png" + border = { 0, 0, 0, 0 } + stretch = TRUE + overlay_file = "assets/slider-insensitive.png" + overlay_stretch = FALSE + orientation = HORIZONTAL + } + + # Vertical + + image { + function = SLIDER + state = NORMAL + file = "assets/null.png" + border = { 0, 0, 0, 0 } + stretch = TRUE + overlay_file = "assets/slider.png" + overlay_stretch = FALSE + orientation = VERTICAL + } + + image { + function = SLIDER + state = PRELIGHT + file = "assets/null.png" + border = { 0, 0, 0, 0 } + stretch = TRUE + overlay_file = "assets/slider-prelight.png" + overlay_stretch = FALSE + orientation = VERTICAL + } + + image { + function = SLIDER + state = INSENSITIVE + file = "assets/null.png" + border = { 0, 0, 0, 0 } + stretch = TRUE + overlay_file = "assets/slider-insensitive.png" + overlay_stretch = FALSE + orientation = VERTICAL + } + + # Function below removes ugly boxes + + image { + function = BOX + file = "assets/null.png" + border = { 3, 3, 3, 3 } + stretch = TRUE + } + } +} + +style "progressbar" { + + xthickness = 1 + ythickness = 1 + + fg[NORMAL] = @fg_color + fg[PRELIGHT] = @selected_fg_color + + engine "pixmap" { + + image { + function = BOX + detail = "trough" + file = "assets/trough-progressbar.png" + border = { 4, 4, 4, 4 } + stretch = TRUE + orientation = HORIZONTAL + } + + image { + function = BOX + detail = "bar" + file = "assets/progressbar.png" + stretch = TRUE + border = { 3, 3, 3, 3 } + orientation = HORIZONTAL + } + + image { + function = BOX + detail = "trough" + file = "assets/trough-progressbar_v.png" + border = { 4, 4, 4, 4 } + stretch = TRUE + orientation = VERTICAL + } + + image { + function = BOX + detail = "bar" + file = "assets/progressbar_v.png" + stretch = TRUE + border = { 3, 3, 3, 3 } + orientation = VERTICAL + } + } +} + +style "separator_menu_item" { + xthickness = 0 + ythickness = 2 + + engine "pixmap" { + image { + function = BOX + file = "assets/menu-separator.png" + border = {0, 0, 2, 0} + } + } +} + +style "treeview_header" { + ythickness = 1 + + fg[PRELIGHT] = mix(0.70, @text_color, @base_color) + font_name = "Bold" + + engine "pixmap" { + + image { + function = BOX + file = "assets/tree_header.png" + border = { 1, 1, 1, 1 } + stretch = TRUE + } + } +} + +# Treeview Rows + +style "treeview" { + + xthickness = 2 + ythickness = 0 + +} + +style "scrolled_window" { + + xthickness = 1 + ythickness = 1 + + engine "pixmap" { + + image { + function = SHADOW + file = "assets/frame.png" + border = { 5, 5, 5, 5 } + stretch = TRUE + } + } +} + +style "frame" { + + xthickness = 1 + ythickness = 1 + + engine "pixmap" { + + image { + function = SHADOW + file = "assets/frame.png" + border = { 1, 1, 1, 1 } + stretch = TRUE + shadow = IN + } + + image { + function = SHADOW_GAP + file = "assets/frame.png" + border = { 1, 1, 1, 1 } + stretch = TRUE + gap_start_file = "assets/frame-gap-start.png" + gap_start_border = { 1, 0, 0, 0 } + gap_end_file = "assets/frame-gap-end.png" + gap_end_border = { 0, 1, 0, 0 } + shadow = IN + } + + image { + function = SHADOW + file = "assets/frame.png" + border = { 1, 1, 1, 1 } + stretch = TRUE + shadow = OUT + } + + image { + function = SHADOW_GAP + file = "assets/frame.png" + border = { 1, 1, 1, 1 } + stretch = TRUE + gap_start_file = "assets/frame-gap-start.png" + gap_start_border = { 1, 0, 0, 0 } + gap_end_file = "assets/frame-gap-end.png" + gap_end_border = { 0, 1, 0, 0 } + shadow = OUT + } + + image { + function = SHADOW + file = "assets/frame.png" + border = { 1, 1, 1, 1 } + stretch = TRUE + shadow = ETCHED_IN + } + + image { + function = SHADOW_GAP + file = "assets/frame.png" + border = { 1, 1, 1, 1 } + stretch = TRUE + gap_start_file = "assets/frame-gap-start.png" + gap_start_border = { 1, 0, 0, 0 } + gap_end_file = "assets/frame-gap-end.png" + gap_end_border = { 0, 1, 0, 0 } + shadow = ETCHED_IN + } + + image { + function = SHADOW + file = "assets/frame.png" + border = { 1, 1, 1, 1 } + stretch = TRUE + shadow = ETCHED_OUT + } + + image { + function = SHADOW_GAP + file = "assets/frame.png" + border = { 1, 1, 1, 1 } + stretch = TRUE + gap_start_file = "assets/frame-gap-start.png" + gap_start_border = { 1, 0, 0, 0 } + gap_end_file = "assets/frame-gap-end.png" + gap_end_border = { 0, 1, 0, 0 } + shadow = ETCHED_OUT + } + } +} + +style "gimp_toolbox_frame" { + + engine "pixmap" { + + image { + function = SHADOW + } + + } +} + +style "toolbar" { + + engine "pixmap" { + + image { + function = BOX + file = "assets/toolbar.png" + stretch = TRUE + border = { 1, 1, 1, 1 } + } + + image { + function = HANDLE + overlay_file = "assets/handle-h.png" + overlay_stretch = FALSE + orientation = HORIZONTAL + } + + image { + function = HANDLE + overlay_file = "assets/handle-v.png" + overlay_stretch = FALSE + orientation = VERTICAL + } + + ######### + # Lines # + ######### + + image { + function = VLINE + file = "assets/border.png" + border = {1, 0, 0, 0} + } + + image { + function = HLINE + file = "assets/border.png" + border = {0, 0, 1, 0} + } + } +} + +style "toolbar_separator" { + GtkWidget::wide-separators = 1 + GtkWidget::separator-width = 1 + GtkWidget::separator-height = 1 + + engine "pixmap" { + image { + function = BOX + file = "assets/border.png" + } + } +} + +style "inline_toolbar" { + + GtkToolbar::button-relief = GTK_RELIEF_NORMAL + + engine "pixmap" { + + image { + function = BOX + file = "assets/inline-toolbar.png" + stretch = TRUE + border = { 1, 1, 1, 1 } + } + } +} + +style "notebook_viewport" { + + bg[NORMAL] = @notebook_bg +} + + +style "notebook_eventbox" { + + bg[NORMAL] = @notebook_bg + bg[ACTIVE] = @bg_color +} + +style "tooltips" { + + xthickness = 8 + ythickness = 4 + + bg[NORMAL] = @tooltip_bg_color + fg[NORMAL] = @tooltip_fg_color + bg[SELECTED] = @tooltip_bg_color + +} + +style "eclipse-tooltips" { + + xthickness = 8 + ythickness = 4 + + bg[NORMAL] = shade(1.05, @bg_color) + fg[NORMAL] = @text_color + bg[SELECTED] = shade(1.05, @bg_color) + +} + +style "xfdesktop-icon-view" { + XfdesktopIconView::label-alpha = 0 + XfdesktopIconView::selected-label-alpha = 100 + XfdesktopIconView::shadow-x-offset = 0 + XfdesktopIconView::shadow-y-offset = 1 + XfdesktopIconView::selected-shadow-x-offset = 0 + XfdesktopIconView::selected-shadow-y-offset = 1 + XfdesktopIconView::shadow-color = "#000000" + XfdesktopIconView::selected-shadow-color = "#000000" + XfdesktopIconView::shadow-blur-radius = 2 + XfdesktopIconView::cell-spacing = 2 + XfdesktopIconView::cell-padding = 6 + XfdesktopIconView::cell-text-width-proportion = 1.9 + + fg[NORMAL] = @selected_fg_color + fg[ACTIVE] = @selected_fg_color +} + +style "xfwm-tabwin" { + Xfwm4TabwinWidget::border-width = 1 + Xfwm4TabwinWidget::border-alpha = 1.0 + Xfwm4TabwinWidget::icon-size = 64 + Xfwm4TabwinWidget::alpha = 1.0 + Xfwm4TabwinWidget::border-radius = 2 + + bg[NORMAL] = @bg_color + bg[SELECTED] = @bg_color + + fg[NORMAL] = @fg_color + + engine "murrine" { + contrast = 0.7 + glazestyle = 0 + glowstyle = 0 + highlight_shade = 1.0 + gradient_shades = {1.0,1.0,1.0,1.0} + border_shades = { 0.8, 0.8 } + } +} + +style "xfwm-tabwin-button" { + font_name = "bold" + bg[SELECTED] = @selected_bg_color +} + +# Chromium +style "chrome_menu_item" { + + bg[SELECTED] = @selected_bg_color + +} + +# Text Style +style "text" = "default" { + fg[NORMAL] = @fg_color # FIXME: VMWare needs this? + + engine "murrine" { textstyle = 0 } +} + +style "menu_text" = "menu_item" { + engine "murrine" { textstyle = 0 } +} + +style "null" { + + engine "pixmap" { + + image { + function = BOX + file = "assets/null.png" + stretch = TRUE + } + } +} + + +class "GtkWidget" style "default" +class "GtkScrollbar" style "scrollbar" +class "GtkButton" style "button" +class "GtkLinkButton" style "link_button" +class "GtkEntry" style "entry" +class "GtkOldEditable" style "entry" +class "GtkSpinButton" style "spinbutton" +class "GtkNotebook" style "notebook" +class "GtkRange" style "range" +class "GtkProgressBar" style "progressbar" +class "GtkScrolledWindow" style "scrolled_window" +class "GtkFrame" style "frame" +class "GtkTreeView" style "treeview" +class "GtkToolbar" style "toolbar" +class "*HandleBox" style "toolbar" + +widget_class "**" style "menu" +widget_class "**" style "menu_framed_box" +widget_class "**" style "menu_item" +widget_class "**" style "separator_menu_item" +widget_class "**" style "checkbutton" +widget_class "*" style "combobox" +widget_class "**" style "combobox_button" +widget_class "**" style "combobox_separator" +widget_class "***" style "treeview_header" +widget_class "**" style "inline_toolbar" +widget_class "**" style "combobox_entry" +widget_class "**" style "combobox_entry_button" +widget_class "***" style "notebook_viewport" +widget_class "*HandleBox" style "toolbar" + +widget_class "**" style "button_label" +widget_class "**" style "button_label" +#widget_class "**" style "button_label" +#widget_class "**" style "button_label" + +widget_class "**" style "toolbar_button" +widget_class "***" style "button_label" + +widget_class "*" style "toolbar_button" +widget_class "**" style "button_label" + +# Entries in notebooks draw with notebook's base color, but not if there's +# something else in the middle that draws gray again +widget_class "**" style "notebook_entry" +widget_class "***" style "entry" + +widget_class "***" style "notebook_combobox_entry" +widget_class "****" style "combobox_entry" + +widget_class "**" style "notebook_button_bg" + +# We also need to avoid changing fg color for the inactive notebook tab labels +widget_class "**" style "notebook_tab_label" +widget_class "***" style "button_label" + +# GTK tooltips +widget "gtk-tooltip*" style "tooltips" + +#Fix GVim tabs +widget_class "**" style "notebook_eventbox" + +# Xchat special cases +widget "*xchat-inputbox" style "entry" + +# GIMP +# Disable gradients completely for GimpSpinScale +#class "GimpSpinScale" style "gimp_spin_scale" + +# Remove borders from "Wilbert frame" in Gimp +widget_class "**" style "gimp_toolbox_frame" + +# Chrome/Chromium +widget_class "*Chrom*Button*" style "button" +widget_class "***" style "chrome_menu_item" + +# Eclipse/SWT +widget "gtk-tooltips*" style "eclipse-tooltips" +widget "*swt-toolbar-flat" style "null" + +# Openoffice, Libreoffice +class "GtkWindow" style "toplevel_hack" +widget "*openoffice-toplevel*" style "ooo_stepper_hack" + +# Xfce +widget_class "*XfdesktopIconView*" style "xfdesktop-icon-view" +widget "xfwm4-tabwin*" style "xfwm-tabwin" +widget "xfwm4-tabwin*GtkButton*" style "xfwm-tabwin-button" + +# Fixes ugly text shadows for insensitive text +widget_class "*" style "text" +widget_class "**" style "menu_text" +widget_class "**" style "text" +widget_class "**" style "text" +widget_class "**" style "text" diff --git a/assets/themes/NexusOS/gtk-2.0/menubar-toolbar.rc b/assets/themes/NexusOS/gtk-2.0/menubar-toolbar.rc new file mode 100644 index 0000000..55d05ff --- /dev/null +++ b/assets/themes/NexusOS/gtk-2.0/menubar-toolbar.rc @@ -0,0 +1,212 @@ +style "menubar" { + + bg[NORMAL] = @tooltip_bg_color + fg[NORMAL] = @tooltip_fg_color + fg[PRELIGHT] = shade(1.15, @tooltip_fg_color) + fg[ACTIVE] = shade(1.15, @tooltip_fg_color) + fg[SELECTED] = @selected_fg_color + fg[INSENSITIVE] = shade(0.7, @tooltip_fg_color) + + xthickness = 0 + ythickness = 0 + + engine "pixmap" { + + image { + function = BOX + file = "assets/menubar.png" + stretch = TRUE + border = { 1, 1, 1, 1 } + } + } +} + +style "menubar-borderless" { + + bg[NORMAL] = @tooltip_bg_color + fg[NORMAL] = @tooltip_fg_color + fg[SELECTED] = @selected_fg_color + fg[INSENSITIVE] = shade(0.7, @tooltip_fg_color) + + xthickness = 0 + ythickness = 0 + + engine "pixmap" { + + image { + function = BOX + file = "assets/null.png" + stretch = TRUE + border = { 1, 1, 1, 1 } + } + } +} + +style "menubar_item" { + + xthickness = 2 + ythickness = 2 + + fg[PRELIGHT] = @selected_fg_color + + engine "pixmap" { + + image { + function = BOX + state = PRELIGHT + file = "assets/menubar_button.png" + border = { 2, 2, 2, 2 } + stretch = TRUE + } + } +} + +style "toolbar_text" { + fg[NORMAL] = @tooltip_fg_color + fg[PRELIGHT] = shade(1.15, @tooltip_fg_color) + fg[INSENSITIVE] = shade(0.7, @tooltip_fg_color) + fg[ACTIVE] = shade(0.9, @tooltip_fg_color) + + text[NORMAL] = @tooltip_fg_color + text[PRELIGHT] = shade(1.15, @tooltip_fg_color) + text[INSENSITIVE] = shade(0.7, @tooltip_fg_color) + text[ACTIVE] = shade(0.9, @tooltip_fg_color) + +} + +style "toolbar_button" { + + xthickness = 4 + ythickness = 4 + + engine "pixmap" { + + image { + function = BOX + state = NORMAL + file = "assets/button.png" + border = { 4, 4, 4, 4 } + stretch = TRUE + } + + image { + function = BOX + state = PRELIGHT + file = "assets/button-hover.png" + border = { 4, 4, 4, 4 } + stretch = TRUE + } + + image { + function = BOX + state = ACTIVE + file = "assets/button-active.png" + border = { 4, 4, 4, 4 } + stretch = TRUE + } + + image { + function = BOX + state = INSENSITIVE + file = "assets/button-insensitive.png" + border = { 4, 4, 4, 4 } + stretch = TRUE + } + } +} + +style "toolbar_entry" { + + base[NORMAL] = @base_color + base[ACTIVE] = @base_color + base[INSENSITIVE] = @insensitive_bg_color + + text[NORMAL] = @text_color + + engine "pixmap" { + + image { + function = SHADOW + state = NORMAL + detail = "entry" + file = "assets/entry-toolbar.png" + border = {6, 6, 6, 6} + stretch = TRUE + } + + image { + function = SHADOW + state = ACTIVE + detail = "entry" + file = "assets/entry-active-toolbar.png" + border = {6, 6, 6, 6} + stretch = TRUE + } + + image { + function = SHADOW + state = INSENSITIVE + detail = "entry" + file = "assets/entry-disabled-toolbar.png" + border = {6, 6, 6, 6} + stretch = TRUE + } + + image { + function = FLAT_BOX + state = ACTIVE + detail = "entry_bg" + file = "assets/null.png" + } + + image { + function = FLAT_BOX + state = INSENSITIVE + detail = "entry_bg" + file = "assets/null.png" + } + + image { + function = FLAT_BOX + detail = "entry_bg" + file = "assets/null.png" + } + } +} + +#Chromium +style "chrome-gtk-frame" { + + ChromeGtkFrame::frame-color = @tooltip_bg_color + ChromeGtkFrame::inactive-frame-color = @tooltip_bg_color + + ChromeGtkFrame::frame-gradient-size = 0 + ChromeGtkFrame::frame-gradient-color = shade(0.5, @bg_color) + + ChromeGtkFrame::incognito-frame-color = shade(0.85, @bg_color) + ChromeGtkFrame::incognito-inactive-frame-color = @bg_color + + ChromeGtkFrame::incognito-frame-gradient-color = @bg_color + + ChromeGtkFrame::scrollbar-trough-color = shade(0.912, @bg_color) + ChromeGtkFrame::scrollbar-slider-prelight-color = shade(1.04, @bg_color) + ChromeGtkFrame::scrollbar-slider-normal-color = @bg_color + +} + +widget_class "**" style "menubar" +widget_class "*.*" style "menubar_item" + +widget_class "*ThunarWindow*" style "menubar" + +class "ChromeGtkFrame" style "chrome-gtk-frame" + +# Whitelist for dark toolbars +widget_class "*ThunarWindow*" style "menubar-borderless" +widget_class "*ThunarWindow**" style "toolbar_entry" +widget_class "*ThunarWindow**" style "toolbar_button" +widget_class "*ThunarWindow**" style "toolbar_text" + +# GtkCheckButton +widget_class "*" style "button" + diff --git a/assets/themes/NexusOS/gtk-2.0/panel.rc b/assets/themes/NexusOS/gtk-2.0/panel.rc new file mode 100644 index 0000000..178128b --- /dev/null +++ b/assets/themes/NexusOS/gtk-2.0/panel.rc @@ -0,0 +1,188 @@ +style "theme-panel" { + GtkButton::inner-border = { 0, 0, 0, 0 } + xthickness = 2 + ythickness = 0 + + bg[NORMAL] = shade(1.0, @tooltip_bg_color) + bg[ACTIVE] = @selected_bg_color + bg[PRELIGHT] = shade(1.2, @tooltip_bg_color) + bg[SELECTED] = @selected_bg_color + + fg[NORMAL] = shade(1.0, @tooltip_fg_color) + fg[PRELIGHT] = @fg_color + fg[ACTIVE] = @tooltip_fg_color + fg[SELECTED] = @tooltip_fg_color + + text[NORMAL] = shade(1.0, @tooltip_fg_color) + text[PRELIGHT] = shade(1.1, @tooltip_fg_color) + text[ACTIVE] = shade(1.0, @tooltip_fg_color) + text[SELECTED] = @tooltip_fg_color + + engine "pixmap" { + image { + function = SHADOW + file = "assets/null.png" + border = { 0, 0, 0, 0 } + stretch = TRUE + } + } +} + +style "theme-panel-progressbar" { + bg[ACTIVE] = shade(0.8, @tooltip_bg_color) +} + +style "panelbar" { + fg[NORMAL] = shade(1.0, @tooltip_fg_color) + fg[ACTIVE] = shade(1.0, @tooltip_fg_color) + fg[PRELIGHT] = shade(1.1, @tooltip_fg_color) + fg[SELECTED] = @tooltip_fg_color +} + +style "panelbuttons" { + GtkButton::inner-border = { 0, 0, 0, 0 } + xthickness = 4 + ythickness = 0 + + fg[NORMAL] = shade(0.8, @tooltip_fg_color) + fg[PRELIGHT] = @tooltip_fg_color + fg[ACTIVE] = @tooltip_fg_color + fg[SELECTED] = @tooltip_fg_color + fg[INSENSITIVE] = mix(0.28, @tooltip_fg_color, @tooltip_bg_color) + bg[PRELIGHT] = shade(1.2, @tooltip_bg_color) + bg[ACTIVE] = shade(1.5, @tooltip_bg_color) + + engine "pixmap" { + image { + function = BOX + state = NORMAL + file = "assets/null.png" + border = { 0, 0, 0, 2 } + stretch = TRUE + } + image { + function = BOX + state = ACTIVE + file = "assets/pathbar_button_active.png" + border = { 0, 0, 0, 2 } + stretch = TRUE + } + image { + function = BOX + state = PRELIGHT + file = "assets/pathbar_button_prelight.png" + border = { 0, 0, 0, 2 } + stretch = TRUE + } + image { + function = BOX + state = INSENSITIVE + file = "assets/null.png" + border = { 0, 0, 0, 2 } + stretch = TRUE + } + } +} + +style "regular-label" { + font_name = "Regular" +} + +style "theme-panel-text" { + fg[NORMAL] = shade(1.0, @tooltip_fg_color) + fg[PRELIGHT] = @tooltip_fg_color + fg[ACTIVE] = shade(1.0, @tooltip_fg_color) + + text[NORMAL] = shade(1.0, @tooltip_fg_color) + text[PRELIGHT] = @tooltip_fg_color + text[ACTIVE] = shade(1.0, @tooltip_fg_color) +} + +style "panel-entry" { + fg[NORMAL] = @text_color + fg[PRELIGHT] = @text_color + fg[ACTIVE] = @text_color + fg[SELECTED] = @text_color + fg[INSENSITIVE] = @text_color + + text[NORMAL] = @text_color + text[PRELIGHT] = @text_color + text[ACTIVE] = @text_color + text[SELECTED] = @text_color + text[INSENSITIVE] = @text_color +} + +style "theme-main-menu-text" = "theme-panel-text" { + fg[PRELIGHT] = @tooltip_fg_color + text[PRELIGHT] = @tooltip_fg_color +} + +style "workspace-switcher" = "theme-panel" { + fg[SELECTED] = @selected_fg_color + bg[SELECTED] = @selected_bg_color +} + +style "indicator" = "theme-panel" { + xthickness = 0 + ythickness = 0 +} + +widget "*tasklist*" style "panelbuttons" +widget_class "*Xfce*Panel*.GtkToggleButton" style "panelbuttons" +widget_class "*Xfce*NetkTasklist*GtkToggleButton" style "panelbuttons" +widget_class "*PanelToplevel*Button" style "panelbuttons" +widget_class "*Panel*GtkToggleButton" style "panelbuttons" +widget_class "*Xfce*Panel*Button*" style "panelbuttons" +widget_class "*" style "panelbuttons" +widget_class "**" style "panelbuttons" +widget_class "*XfcePanelPlugin.GtkButton" style "panelbuttons" +widget_class "*XfcePanelPlugin.GtkToggleButton" style "panelbuttons" +widget "*dict*Applet*" style "panelbuttons" +widget_class "*Xfce*NetkTasklist*GtkToggleButton" style "panelbuttons" +widget_class "*Tasklist*" style:highest "panelbuttons" +widget_class "*Tasklist*.GtkLabel" style:highest "regular-label" +widget_class "*Mixer*lugin*" style:highest "panelbuttons" + +class "*Panel*MenuBar*" style "panelbar" +widget_class "*Panel*MenuBar*" style "panelbar" +widget_class "*Panel*MenuBar*Item*" style:highest "panelbar" + +widget "*PanelWidget*" style "theme-panel" +widget "*PanelApplet*" style "theme-panel" +widget "*fast-user-switch*" style "theme-panel" +widget "*CPUFreq*Applet*" style "theme-panel" +class "PanelApp*" style "theme-panel" +class "PanelToplevel*" style "theme-panel" +widget_class "*PanelToplevel*" style "theme-panel" +widget_class "*notif*" style "theme-panel" +widget_class "*Notif*" style "theme-panel" +widget_class "*Tray*" style "theme-panel" +widget_class "*tray*" style "theme-panel" +widget_class "*computertemp*" style "theme-panel" +widget_class "*Applet*Tomboy*" style "theme-panel" +widget_class "*Applet*Netstatus*" style "theme-panel" + +# Fixes for tooltip text in some apps. +widget_class "*Notif*Beagle*" style "theme-panel" +widget_class "*Notif*Brasero*" style "theme-panel" + +# XFCE panel theming. +widget "*Xfce*Panel*" style "theme-panel" +class "*Xfce*Panel*" style "theme-panel" +widget "*Xfce*Panel*GtkProgressBar" style "theme-panel-progressbar" +widget "*WnckPager*" style "workspace-switcher" +widget "*TopMenu*" style "theme-panel" +widget "*XfceTasklist*" style "panelbuttons" + +# Fix gtk-entries in the panel +widget "*bookmark*GtkEntry" style "panel-entry" # fixes smartbookmark-plugin + +# Make sure panel text color doesn't change +widget_class "*Panel*MenuBar*" style "theme-main-menu-text" +widget_class "*Panel**" style "theme-main-menu-text" +widget "*.clock-applet-button.*" style "theme-panel-text" +widget "*PanelApplet*" style "theme-panel-text" + +# Override general panel-style with specific plugin-styles +widget "*indicator-applet*" style "indicator" +widget "*indicator-button*" style "indicator" diff --git a/assets/themes/NexusOS/gtk-2.0/xfce-notify.rc b/assets/themes/NexusOS/gtk-2.0/xfce-notify.rc new file mode 100644 index 0000000..3ac7956 --- /dev/null +++ b/assets/themes/NexusOS/gtk-2.0/xfce-notify.rc @@ -0,0 +1,52 @@ + +style "notify-window" { + XfceNotifyWindow::summary-bold = 1 + XfceNotifyWindow::border-color = shade(1.3, @tooltip_bg_color) + XfceNotifyWindow::border-color-hover = shade(1.3, @tooltip_bg_color) + XfceNotifyWindow::border-radius = 3.0 + XfceNotifyWindow::border-width = 1.0 + XfceNotifyWindow::border-width-hover = 1.0 + + bg[NORMAL] = @tooltip_bg_color +} + +style "notify-button" { + bg[NORMAL] = shade(1.1, @tooltip_bg_color) + bg[PRELIGHT] = shade(1.2, @tooltip_bg_color) + bg[ACTIVE] = shade(1.15, @tooltip_bg_color) + + fg[NORMAL] = @tooltip_fg_color + fg[PRELIGHT] = shade(1.1, @tooltip_fg_color) + fg[ACTIVE] = @selected_fg_color +} + +style "notify-text" { + GtkWidget::link-color = @selected_bg_color + + fg[NORMAL] = shade(1.0, @tooltip_fg_color) + fg[PRELIGHT] = shade(1.1, @tooltip_fg_color) + fg[ACTIVE] = shade(1.0, @tooltip_fg_color) +} + +style "notify-summary" { + font_name = "Bold" +} + +style "notify-progressbar" { + GtkProgressBar::min-horizontal-bar-height = 4 + + xthickness = 0 + ythickness = 0 + + fg[PRELIGHT] = shade(0.8, @tooltip_bg_color) + bg[NORMAL] = @selected_bg_color + bg[ACTIVE] = shade(0.8, @tooltip_bg_color) + bg[SELECTED] = @selected_bg_color +} + +class "XfceNotifyWindow" style "notify-window" +widget "XfceNotifyWindow.*.summary" style "notify-summary" +widget_class "XfceNotifyWindow.*" style "notify-button" +widget_class "XfceNotifyWindow.*." style "notify-text" +widget_class "XfceNotifyWindow.*." style "notify-progressbar" +widget_class "XfceNotifyWindow.*." style "notify-progressbar" diff --git a/assets/themes/NexusOS/gtk-3.0/buttons-entries.css b/assets/themes/NexusOS/gtk-3.0/buttons-entries.css new file mode 100644 index 0000000..9fa0d9c --- /dev/null +++ b/assets/themes/NexusOS/gtk-3.0/buttons-entries.css @@ -0,0 +1,342 @@ +/* NexusOS — Segment 2: buttons & entries. + Foundation widgets. Lime green = primary accent (hover/active/focus), + purple = selection within text. */ + +/* ── Buttons ─────────────────────────────────────────────── */ + +button { + min-height: 24px; + min-width: 16px; + padding: 6px 12px; + border: 1px solid @border_strong; + border-radius: 6px; + background-color: @surface_bg; + background-image: none; + color: @text_primary; + transition: background-color 120ms ease, + border-color 120ms ease, + color 120ms ease, + box-shadow 120ms ease; + text-shadow: none; + -gtk-icon-shadow: none; +} + +button:hover { + background-color: @hover_bg; + border-color: @brand_green_dark; + color: @text_primary; +} + +button:active, +button:checked { + background-color: @active_bg; + border-color: @brand_green_dark; + color: @active_fg; +} + +button:checked:hover { + background-color: @brand_green_light; + border-color: @brand_green; + color: @active_fg; +} + +button:focus, +button:focus-visible { + outline: 2px solid @focus_ring; + outline-offset: -1px; + border-color: @brand_green; +} + +button:disabled, +button:disabled:hover, +button:disabled:active { + background-color: @surface_bg; + border-color: @border; + color: @text_disabled; + -gtk-icon-effect: dim; +} + +/* Flat buttons — transparent until interacted with */ +button.flat { + background-color: transparent; + border-color: transparent; + box-shadow: none; +} + +button.flat:hover { + background-color: @hover_bg; + border-color: transparent; +} + +button.flat:active, +button.flat:checked { + background-color: @active_bg; + border-color: transparent; + color: @active_fg; +} + +button.flat:disabled { + background-color: transparent; + border-color: transparent; + color: @text_disabled; +} + +/* Suggested-action — primary CTA, solid lime green */ +button.suggested-action { + background-color: @brand_green; + border-color: @brand_green_dark; + color: @text_on_accent; + font-weight: 600; +} + +button.suggested-action:hover { + background-color: @brand_green_light; + border-color: @brand_green; + color: @text_on_accent; +} + +button.suggested-action:active, +button.suggested-action:checked { + background-color: @brand_green_dark; + border-color: @brand_green_dark; + color: @text_on_accent; +} + +button.suggested-action:disabled { + background-color: alpha(@brand_green, 0.25); + border-color: transparent; + color: @text_disabled; +} + +/* Destructive-action — solid red */ +button.destructive-action { + background-color: @error_color; + border-color: shade(@error_color, 0.85); + color: #ffffff; + font-weight: 600; +} + +button.destructive-action:hover { + background-color: shade(@error_color, 1.10); + border-color: shade(@error_color, 0.85); +} + +button.destructive-action:active, +button.destructive-action:checked { + background-color: shade(@error_color, 0.85); + border-color: shade(@error_color, 0.75); +} + +button.destructive-action:disabled { + background-color: alpha(@error_color, 0.30); + border-color: transparent; + color: @text_disabled; +} + +/* Image-only buttons — slightly tighter padding */ +button.image-button { + padding: 6px 8px; + min-width: 24px; +} + +/* Linked button groups — share borders, only the ends round */ +.linked > button, +.linked > entry { + border-radius: 0; + border-right-width: 0; +} + +.linked > button:first-child, +.linked > entry:first-child { + border-top-left-radius: 6px; + border-bottom-left-radius: 6px; +} + +.linked > button:last-child, +.linked > entry:last-child { + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; + border-right-width: 1px; +} + +.linked.vertical > button, +.linked.vertical > entry { + border-radius: 0; + border-right-width: 1px; + border-bottom-width: 0; +} + +.linked.vertical > button:first-child, +.linked.vertical > entry:first-child { + border-top-left-radius: 6px; + border-top-right-radius: 6px; +} + +.linked.vertical > button:last-child, +.linked.vertical > entry:last-child { + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; + border-bottom-width: 1px; +} + +/* Link buttons — inline hyperlink style */ +button.link, +*.link { + background-color: transparent; + border-color: transparent; + padding: 0; + color: @link_color; + text-shadow: none; +} + +button.link:hover, +*.link:hover { + background-color: transparent; + color: @brand_green_light; + text-decoration: underline; +} + +button.link:visited, +*.link:visited { + color: @link_visited_color; +} + +button.link:disabled { + color: @text_disabled; +} + +/* ── Entries ─────────────────────────────────────────────── */ + +entry, +spinbutton:not(.vertical) { + min-height: 24px; + padding: 6px 10px; + border: 1px solid @border_strong; + border-radius: 6px; + background-color: @surface_bg; + background-image: none; + color: @text_primary; + caret-color: @brand_green; + transition: border-color 120ms ease, + box-shadow 120ms ease, + background-color 120ms ease; +} + +entry:hover { + border-color: @brand_green_dark; +} + +entry:focus, +entry:focus-within { + border-color: @brand_green; + box-shadow: inset 0 0 0 1px @brand_green; + background-color: @surface_bg; +} + +entry:disabled { + background-color: @insensitive_bg_color; + border-color: @border; + color: @text_disabled; +} + +entry selection { + background-color: @selected_bg; + color: @selected_fg; +} + +entry:selected { + background-color: @selected_bg; + color: @selected_fg; +} + +entry image { + color: @text_secondary; + padding: 0 4px; +} + +entry image:hover { + color: @brand_green; +} + +entry progress { + background-color: @brand_green; + background-image: none; + border: none; + border-radius: 2px; + margin: 0 -10px -6px -10px; + min-height: 2px; +} + +/* Error / warning / success states */ +entry.error { + border-color: @error_color; + box-shadow: inset 0 0 0 1px @error_color; + color: @error_color; +} + +entry.warning { + border-color: @warning_color; + box-shadow: inset 0 0 0 1px @warning_color; + color: @warning_color; +} + +entry.success { + border-color: @success_color; + box-shadow: inset 0 0 0 1px @success_color; +} + +/* Search entries — slight visual tweak */ +entry.search { + border-radius: 999px; + padding-left: 14px; + padding-right: 14px; +} + +/* ── Spinbuttons ─────────────────────────────────────────── */ + +spinbutton button { + background-color: transparent; + border-color: transparent; + border-radius: 0; + color: @text_secondary; + min-width: 18px; + padding: 4px 6px; +} + +spinbutton button:hover { + background-color: @hover_bg; + color: @text_primary; +} + +spinbutton button:active { + background-color: @active_bg; + color: @active_fg; +} + +spinbutton button:disabled { + background-color: transparent; + color: @text_disabled; +} + +spinbutton.vertical button { + border-left: 1px solid @border; +} + +/* ── Text views (multi-line) ────────────────────────────── */ + +textview, +textview text { + background-color: @base_bg; + color: @text_primary; + caret-color: @brand_green; +} + +textview text selection { + background-color: @selected_bg; + color: @selected_fg; +} + +textview:disabled, +textview:disabled text { + color: @text_disabled; +} diff --git a/assets/themes/NexusOS/gtk-3.0/colors.css b/assets/themes/NexusOS/gtk-3.0/colors.css new file mode 100644 index 0000000..1b419cb --- /dev/null +++ b/assets/themes/NexusOS/gtk-3.0/colors.css @@ -0,0 +1,70 @@ +/* NexusOS palette — derived from the n-small.png logo. + Lime green = primary accent (hover/active/focus). + Purple = secondary accent (selection/highlight). + Swap their roles in later segments if preferred. */ + +/* ── Brand ─────────────────────────────────────────── */ +@define-color brand_green #8cc63f; +@define-color brand_green_light #b8e373; +@define-color brand_green_dark #6ba62a; +@define-color brand_purple #88008f; +@define-color brand_purple_light #a232a8; +@define-color brand_purple_dark #5e0066; + +/* ── Foundation (dark) ─────────────────────────────── */ +@define-color base_bg #16181a; /* deepest background */ +@define-color surface_bg #1f2225; /* cards, popovers, entries */ +@define-color surface_bg_alt #2a2e32; /* alt rows, headerbars */ +@define-color overlay_bg #2e3236; /* tooltips, raised surfaces */ +@define-color border #2e3236; +@define-color border_strong #3a3d41; + +/* ── Text ──────────────────────────────────────────── */ +@define-color text_primary #f2f2f2; +@define-color text_secondary #a8a8a8; +@define-color text_disabled #6e7173; +@define-color text_on_accent #0a0a00; /* sits on lime green */ +@define-color text_on_selection #ffffff; /* sits on purple */ + +/* ── Interaction states ────────────────────────────── */ +@define-color hover_bg alpha(@brand_green, 0.18); +@define-color active_bg @brand_green; +@define-color active_fg @text_on_accent; +@define-color selected_bg @brand_purple; +@define-color selected_fg @text_on_selection; +@define-color focus_ring @brand_green; + +/* ── Semantic ──────────────────────────────────────── */ +@define-color success_color #27ae60; +@define-color warning_color #f67400; +@define-color error_color #da4453; +@define-color info_color @brand_green; + +/* ── GTK named-color aliases (compatibility) ───────── */ +/* GTK widgets reference these well-known names internally; + keeping them in sync with our brand palette avoids gaps. */ +@define-color theme_bg_color @base_bg; +@define-color theme_fg_color @text_primary; +@define-color theme_base_color @base_bg; +@define-color theme_text_color @text_primary; +@define-color theme_selected_bg_color @brand_green; +@define-color theme_selected_fg_color @active_fg; +@define-color theme_hovering_selected_bg_color @brand_green_light; +@define-color theme_unfocused_bg_color @surface_bg; +@define-color theme_unfocused_fg_color @text_secondary; +@define-color theme_unfocused_base_color @base_bg; +@define-color theme_unfocused_text_color @text_secondary; +@define-color theme_unfocused_selected_bg_color @brand_purple_dark; +@define-color theme_unfocused_selected_fg_color @selected_fg; +@define-color borders @border; +@define-color unfocused_borders @border; +@define-color insensitive_bg_color @surface_bg; +@define-color insensitive_fg_color @text_disabled; +@define-color insensitive_base_color @base_bg; +@define-color insensitive_borders @border_strong; +@define-color content_view_bg @base_bg; +@define-color link_color @brand_green_light; +@define-color link_visited_color @brand_purple_light; +@define-color tooltip_background @overlay_bg; +@define-color tooltip_text @text_primary; +@define-color tooltip_border @border_strong; diff --git a/assets/themes/NexusOS/gtk-3.0/dialogs-infobars.css b/assets/themes/NexusOS/gtk-3.0/dialogs-infobars.css new file mode 100644 index 0000000..82fd921 --- /dev/null +++ b/assets/themes/NexusOS/gtk-3.0/dialogs-infobars.css @@ -0,0 +1,319 @@ +/* NexusOS — Segment 9: dialogs, message dialogs, infobars, app notifications, + assistants/wizards. Semantic colors (info/warning/error/success) get matched + bg + a left-edge accent so the message type reads at a glance. */ + +/* ── Generic dialog window ───────────────────────────────── */ + +dialog, +messagedialog { + background-color: @base_bg; + color: @text_primary; +} + +dialog.background, +messagedialog.background { + background-color: @base_bg; +} + +dialog > box.dialog-vbox, +messagedialog > box.dialog-vbox { + padding: 6px; +} + +/* The titlebar on dialogs (when CSD) — already styled by Segment 3, but + trim the bottom border so it reads as "part of the dialog" not "separate + chrome". */ +dialog > headerbar, +messagedialog > headerbar { + background-color: @surface_bg_alt; + border-bottom: 1px solid @border; +} + +dialog > headerbar.flat, +messagedialog > headerbar.flat { + background-color: transparent; + border-bottom-color: transparent; +} + +/* Action button row at the bottom of a dialog */ +dialog .dialog-action-area, +messagedialog .dialog-action-area, +.dialog-action-box { + background-color: @surface_bg; + border-top: 1px solid @border; + padding: 10px 12px; +} + +dialog .dialog-action-area > button, +messagedialog .dialog-action-area > button, +.dialog-action-box > button { + min-width: 84px; +} + +/* Body / icon area of a message dialog */ +messagedialog .dialog-vbox > box { + padding: 18px 18px 8px 18px; +} + +messagedialog .horizontal { + padding: 8px; +} + +messagedialog .titlebar:not(.flat) { + background-color: @surface_bg_alt; +} + +/* Title and secondary text in a message dialog */ +messagedialog label.title { + font-weight: 700; + font-size: 1.1em; + color: @text_primary; +} + +messagedialog label { + color: @text_primary; +} + +messagedialog label.dim-label, +messagedialog .dim-label { + color: @text_secondary; +} + +/* ── About / file-chooser dialog tweaks ──────────────────── */ + +filechooser stack { + background-color: @base_bg; +} + +filechooser actionbar { + background-color: @surface_bg; + border-top: 1px solid @border; +} + +/* Path bar inside the file chooser */ +.path-bar button { + border-radius: 0; + border: none; + border-right: 1px solid @border; + background-color: transparent; +} + +.path-bar button:first-child { + border-top-left-radius: 6px; + border-bottom-left-radius: 6px; +} + +.path-bar button:last-child { + border-right: none; + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; +} + +.path-bar button:checked { + background-color: @active_bg; + color: @active_fg; +} + +.path-bar button.text-button:not(:only-child):not(:first-child) { + padding-left: 8px; +} + +/* ── Infobars ────────────────────────────────────────────── */ + +infobar { + background-color: @surface_bg_alt; + color: @text_primary; + border: 1px solid @border; + border-radius: 6px; + padding: 8px 12px; + box-shadow: inset 4px 0 0 0 @brand_green; /* default = info accent */ + min-height: 36px; +} + +infobar > revealer > box { + padding: 0; +} + +infobar label { + color: @text_primary; +} + +infobar button { + /* Buttons inside infobars stay flat, with brand hover */ + background-color: transparent; + border-color: transparent; + color: @text_primary; +} + +infobar button:hover { + background-color: alpha(@text_primary, 0.10); +} + +infobar button:focus { + outline: 2px solid @focus_ring; + outline-offset: -2px; +} + +infobar button.text-button { + font-weight: 500; +} + +/* Semantic variants — left-edge accent + tinted background */ + +infobar.info { + background-color: alpha(@info_color, 0.12); + box-shadow: inset 4px 0 0 0 @info_color; +} + +infobar.info label { + color: @text_primary; +} + +infobar.question { + background-color: alpha(@brand_purple, 0.18); + box-shadow: inset 4px 0 0 0 @brand_purple; +} + +infobar.warning { + background-color: alpha(@warning_color, 0.18); + box-shadow: inset 4px 0 0 0 @warning_color; +} + +infobar.warning label { + color: @text_primary; +} + +infobar.error { + background-color: alpha(@error_color, 0.18); + box-shadow: inset 4px 0 0 0 @error_color; +} + +infobar.error label { + color: @text_primary; +} + +infobar.success { + background-color: alpha(@success_color, 0.18); + box-shadow: inset 4px 0 0 0 @success_color; +} + +infobar.success label { + color: @text_primary; +} + +/* The close (X) button on an infobar */ +infobar button.close { + min-width: 22px; + min-height: 22px; + padding: 2px; + border-radius: 999px; + color: @text_secondary; +} + +infobar button.close:hover { + background-color: alpha(@text_primary, 0.15); + color: @text_primary; +} + +/* ── App notifications (overlay banners) ─────────────────── */ + +.app-notification, +.app-notification.frame { + background-color: @overlay_bg; + color: @text_primary; + border: 1px solid @border_strong; + border-radius: 8px; + padding: 10px 14px; + margin: 8px; + box-shadow: 0 6px 18px rgba(0, 0, 0, 0.45), + 0 2px 4px rgba(0, 0, 0, 0.30); +} + +.app-notification button, +.app-notification.frame button { + background-color: transparent; + border-color: transparent; + color: @brand_green_light; +} + +.app-notification button:hover { + background-color: @hover_bg; + color: @brand_green; +} + +.app-notification button.suggested-action { + background-color: @brand_green; + color: @text_on_accent; + border-color: @brand_green_dark; +} + +.app-notification button.destructive-action { + background-color: @error_color; + color: #ffffff; +} + +/* ── Assistant / wizard ──────────────────────────────────── */ + +assistant { + background-color: @base_bg; + color: @text_primary; +} + +assistant .sidebar { + background-color: @surface_bg; + border-right: 1px solid @border; + padding: 6px; +} + +assistant .sidebar label { + padding: 6px 10px; + color: @text_secondary; + border-radius: 4px; +} + +assistant .sidebar label.highlight { + background-color: @selected_bg; + color: @selected_fg; + font-weight: 500; +} + +assistant headerbar { + background-color: @surface_bg_alt; +} + +/* ── Frames & separators inside dialogs ──────────────────── */ + +frame > border, +.frame { + border: 1px solid @border; + border-radius: 6px; + padding: 0; +} + +frame > label, +.frame > label { + color: @text_secondary; + font-weight: 500; + padding: 0 4px; +} + +separator { + background-color: @border; + min-width: 1px; + min-height: 1px; +} + +separator.horizontal { + min-height: 1px; +} + +separator.vertical { + min-width: 1px; +} + +/* Dim label utility — used in lots of dialog body text */ +.dim-label, +label.dim-label { + color: @text_secondary; + opacity: 1.0; /* GTK's default also dims via opacity — we just recolor */ +} diff --git a/assets/themes/NexusOS/gtk-3.0/gtk-dark.css b/assets/themes/NexusOS/gtk-3.0/gtk-dark.css new file mode 100644 index 0000000..7aa1541 --- /dev/null +++ b/assets/themes/NexusOS/gtk-3.0/gtk-dark.css @@ -0,0 +1,2 @@ +/* NexusOS is dark-only by design — gtk-dark.css mirrors gtk.css. */ +@import url("gtk.css"); diff --git a/assets/themes/NexusOS/gtk-3.0/gtk.css b/assets/themes/NexusOS/gtk-3.0/gtk.css new file mode 100644 index 0000000..c0ee34e --- /dev/null +++ b/assets/themes/NexusOS/gtk-3.0/gtk.css @@ -0,0 +1,34 @@ +/* NexusOS — GTK3 theme entry point. + Each segment lives in its own file and is imported below in the order it + was built. A trailing fallback rule keeps unstyled widgets legible on the + dark base if a future segment hasn't landed yet. */ + +@import url("colors.css"); + +/* Segment 2 — buttons & entries */ +@import url("buttons-entries.css"); + +/* Segment 3 — headerbars, titlebars, window controls, window chrome */ +@import url("headerbars.css"); + +/* Segment 4 — menus, popovers, tooltips */ +@import url("menus-popovers.css"); + +/* Segment 5 — sidebars, lists, treeviews */ +@import url("lists-sidebars.css"); + +/* Segment 6 — notebooks (tabs) and stack switchers */ +@import url("notebooks.css"); + +/* Segment 7 — scrollbars, progress bars, level bars, spinners */ +@import url("scrollbars-progress.css"); + +/* Segment 8 — switches, checkboxes, radios, scales/sliders */ +@import url("toggles-sliders.css"); + +/* Segment 9 — dialogs, infobars, app notifications, assistants */ +@import url("dialogs-infobars.css"); + +/* Segment 10 — polish (combobox, toolbar, actionbar, statusbar, paned, + expander, calendar, iconview, shortcuts-window, OSD, focus rings) */ +@import url("polish.css"); diff --git a/assets/themes/NexusOS/gtk-3.0/headerbars.css b/assets/themes/NexusOS/gtk-3.0/headerbars.css new file mode 100644 index 0000000..186f1f4 --- /dev/null +++ b/assets/themes/NexusOS/gtk-3.0/headerbars.css @@ -0,0 +1,298 @@ +/* NexusOS — Segment 3: headerbars, titlebars, window controls, window chrome. + Headerbars use the alt surface to distinguish chrome from content. + Buttons in headerbars default to flat; close button warns red on hover. */ + +/* ── Window ──────────────────────────────────────────────── */ + +window, +window.background { + background-color: @base_bg; + color: @text_primary; +} + +window:backdrop { + background-color: @base_bg; + color: @text_secondary; +} + +/* CSD (client-side decorated) windows — rounded corners + subtle border */ +window.csd { + border-radius: 8px; + box-shadow: 0 0 0 1px @border, + 0 8px 24px rgba(0, 0, 0, 0.45), + 0 2px 6px rgba(0, 0, 0, 0.30); +} + +window.csd:backdrop { + box-shadow: 0 0 0 1px @border, + 0 4px 12px rgba(0, 0, 0, 0.30); +} + +window.ssd { + /* server-side decorated — leave decoration to WM */ + box-shadow: none; +} + +/* Maximized / tiled / fullscreen — no rounded corners, no shadow */ +window.maximized, +window.tiled, +window.tiled-top, +window.tiled-bottom, +window.tiled-left, +window.tiled-right, +window.fullscreen { + border-radius: 0; + box-shadow: none; +} + +/* ── Headerbar / titlebar ────────────────────────────────── */ + +headerbar, +.titlebar { + padding: 4px 6px; + min-height: 38px; + border: none; + border-bottom: 1px solid @border; + background-color: @surface_bg_alt; + background-image: none; + color: @text_primary; + box-shadow: none; + text-shadow: none; +} + +headerbar:backdrop, +.titlebar:backdrop { + background-color: @surface_bg; + color: @text_secondary; + border-bottom-color: @border; +} + +/* Rounded top corners on CSD headerbars */ +window.csd > headerbar:first-child, +window.csd > .titlebar:first-child, +window.csd > deck > headerbar:first-child, +window.csd > box > headerbar:first-child { + border-top-left-radius: 7px; + border-top-right-radius: 7px; +} + +window.maximized > headerbar, +window.tiled > headerbar, +window.fullscreen > headerbar { + border-radius: 0; +} + +/* Title / subtitle text */ +headerbar .title, +.titlebar .title { + font-weight: 600; + color: @text_primary; + padding: 0 12px; +} + +headerbar .subtitle, +.titlebar .subtitle { + font-size: smaller; + color: @text_secondary; + padding: 0 12px; +} + +headerbar:backdrop .title, +.titlebar:backdrop .title, +headerbar:backdrop .subtitle, +.titlebar:backdrop .subtitle { + color: @text_secondary; +} + +/* Separator between title and other widgets */ +headerbar separator.titlebutton, +.titlebar separator.titlebutton { + background-color: @border; + min-width: 1px; + margin: 6px 4px; +} + +/* ── Buttons inside headerbars ───────────────────────────── */ + +headerbar button, +.titlebar button { + padding: 4px 8px; + min-height: 24px; + border: 1px solid transparent; + background-color: transparent; + background-image: none; + color: @text_primary; + box-shadow: none; +} + +headerbar button:hover, +.titlebar button:hover { + background-color: @hover_bg; + border-color: transparent; + color: @text_primary; +} + +headerbar button:active, +headerbar button:checked, +.titlebar button:active, +.titlebar button:checked { + background-color: @active_bg; + border-color: transparent; + color: @active_fg; +} + +headerbar button:disabled, +.titlebar button:disabled { + background-color: transparent; + color: @text_disabled; +} + +headerbar button:focus, +.titlebar button:focus { + outline: 2px solid @focus_ring; + outline-offset: -2px; +} + +headerbar button:backdrop, +.titlebar button:backdrop { + color: @text_secondary; +} + +/* Suggested-action in a headerbar keeps its solid lime fill */ +headerbar button.suggested-action, +.titlebar button.suggested-action { + background-color: @brand_green; + border-color: @brand_green_dark; + color: @text_on_accent; +} + +headerbar button.suggested-action:hover, +.titlebar button.suggested-action:hover { + background-color: @brand_green_light; + color: @text_on_accent; +} + +headerbar button.destructive-action, +.titlebar button.destructive-action { + background-color: @error_color; + color: #ffffff; +} + +/* Entries in headerbars — pick up the alt surface */ +headerbar entry, +.titlebar entry { + background-color: @base_bg; + border-color: @border_strong; +} + +headerbar entry:focus, +.titlebar entry:focus { + border-color: @brand_green; + box-shadow: inset 0 0 0 1px @brand_green; +} + +/* ── Window control buttons (close, min, max) ────────────── */ + +.titlebutton, +headerbar button.titlebutton, +.titlebar button.titlebutton, +button.titlebutton { + min-width: 22px; + min-height: 22px; + padding: 4px; + margin: 0 2px; + border-radius: 999px; /* circular control dots */ + border: 1px solid transparent; + background-color: alpha(@text_primary, 0.08); + color: @text_primary; + -gtk-icon-shadow: none; +} + +.titlebutton:hover, +headerbar button.titlebutton:hover, +.titlebar button.titlebutton:hover { + background-color: @hover_bg; + border-color: @brand_green_dark; + color: @text_primary; +} + +.titlebutton:active, +.titlebutton:checked { + background-color: @active_bg; + border-color: @brand_green_dark; + color: @active_fg; +} + +.titlebutton:backdrop, +.titlebutton:disabled { + background-color: alpha(@text_primary, 0.04); + color: @text_disabled; + border-color: transparent; +} + +/* Close button — warn red on hover so it can't be confused with accent actions */ +.titlebutton.close, +button.titlebutton.close { + background-color: alpha(@error_color, 0.18); + color: @text_primary; +} + +.titlebutton.close:hover, +button.titlebutton.close:hover { + background-color: @error_color; + border-color: shade(@error_color, 0.85); + color: #ffffff; +} + +.titlebutton.close:active, +button.titlebutton.close:active { + background-color: shade(@error_color, 0.85); + color: #ffffff; +} + +.titlebutton.close:backdrop { + background-color: alpha(@error_color, 0.10); + color: @text_disabled; +} + +/* Minimize / maximize — explicit selectors in case theming engines key off them */ +.titlebutton.minimize:hover, +.titlebutton.maximize:hover, +button.titlebutton.minimize:hover, +button.titlebutton.maximize:hover { + background-color: @hover_bg; + border-color: @brand_green_dark; + color: @text_primary; +} + +/* ── Stack-of-headerbars (e.g. libhandy/libadwaita-style split) ── */ + +headerbar.flat { + background-color: transparent; + border-bottom-color: transparent; +} + +/* Selection-mode headerbar (e.g. when picking files) — purple to match selection accent */ +headerbar.selection-mode, +.titlebar.selection-mode { + background-color: @brand_purple_dark; + color: @selected_fg; + border-bottom-color: @brand_purple; +} + +headerbar.selection-mode .title, +.titlebar.selection-mode .title, +headerbar.selection-mode .subtitle, +.titlebar.selection-mode .subtitle { + color: @selected_fg; +} + +headerbar.selection-mode button, +.titlebar.selection-mode button { + color: @selected_fg; +} + +headerbar.selection-mode button:hover, +.titlebar.selection-mode button:hover { + background-color: alpha(@selected_fg, 0.15); +} diff --git a/assets/themes/NexusOS/gtk-3.0/lists-sidebars.css b/assets/themes/NexusOS/gtk-3.0/lists-sidebars.css new file mode 100644 index 0000000..3d77fb4 --- /dev/null +++ b/assets/themes/NexusOS/gtk-3.0/lists-sidebars.css @@ -0,0 +1,357 @@ +/* NexusOS — Segment 5: sidebars, list boxes, tree views, places sidebars. + Row selection is purple (the secondary accent), hover is the lime wash. + This keeps "selected" visually distinct from "the thing my cursor is on". */ + +/* ── Generic listbox ─────────────────────────────────────── */ + +list, +listview, +.list { + background-color: @base_bg; + color: @text_primary; + border-color: @border; +} + +list row, +listview row, +.list row, +.list-row { + padding: 8px 12px; + background-color: transparent; + color: @text_primary; + border-bottom: 1px solid alpha(@border, 0.45); + transition: background-color 100ms ease, + color 100ms ease; +} + +list row:last-child, +listview row:last-child, +.list row:last-child { + border-bottom: none; +} + +list row:hover, +listview row:hover, +.list row:hover { + background-color: @hover_bg; + color: @text_primary; +} + +list row:selected, +listview row:selected, +.list row:selected, +list row.activatable:selected { + background-color: @selected_bg; + color: @selected_fg; + border-bottom-color: alpha(@brand_purple_dark, 0.6); +} + +list row:selected:hover, +listview row:selected:hover { + background-color: shade(@selected_bg, 1.12); + color: @selected_fg; +} + +list row:disabled, +listview row:disabled { + color: @text_disabled; +} + +/* .activatable rows (clickable) get a subtle hover hint */ +list row.activatable:hover { + background-color: @hover_bg; +} + +list row.activatable:active { + background-color: shade(@hover_bg, 1.2); +} + +/* Separator row */ +list row.separator, +list separator { + background-color: @border; + min-height: 1px; + padding: 0; + margin: 0; +} + +/* Rich-list rows (titles + subtitles) */ +list.rich-list row { + padding: 10px 14px; +} + +list.rich-list row .title { + font-weight: 500; + color: @text_primary; +} + +list.rich-list row .subtitle { + color: @text_secondary; + font-size: smaller; +} + +list.rich-list row:selected .subtitle { + color: alpha(@selected_fg, 0.85); +} + +/* ── Sidebars ────────────────────────────────────────────── */ + +.sidebar, +stacksidebar, +stacksidebar.sidebar { + background-color: @surface_bg; + color: @text_primary; + border-right: 1px solid @border; + padding: 0; +} + +.sidebar:dir(rtl), +stacksidebar:dir(rtl) { + border-left: 1px solid @border; + border-right: none; +} + +.sidebar:backdrop, +stacksidebar:backdrop { + background-color: @surface_bg; + color: @text_secondary; +} + +.sidebar list, +.sidebar listview, +stacksidebar list { + background-color: transparent; + color: @text_primary; +} + +.sidebar list row, +.sidebar listview row, +stacksidebar list row { + padding: 8px 14px; + border-bottom: none; + border-radius: 4px; + margin: 2px 6px; +} + +.sidebar list row:hover, +stacksidebar list row:hover { + background-color: @hover_bg; +} + +.sidebar list row:selected, +.sidebar listview row:selected, +stacksidebar list row:selected { + background-color: @selected_bg; + color: @selected_fg; +} + +.sidebar list row:selected:hover, +stacksidebar list row:selected:hover { + background-color: shade(@selected_bg, 1.12); +} + +/* Header rows inside a sidebar (libhandy/libadwaita) */ +.sidebar .navigation-sidebar > row, +.navigation-sidebar > row { + padding: 8px 14px; + margin: 2px 6px; + border-radius: 4px; + border-bottom: none; +} + +/* ── Places sidebar (file managers, GtkFileChooser) ──────── */ + +placessidebar { + background-color: @surface_bg; + color: @text_primary; +} + +placessidebar > viewport.frame { + border: none; +} + +placessidebar list { + background-color: transparent; +} + +placessidebar row { + padding: 6px 12px; + border-radius: 4px; + margin: 1px 6px; +} + +placessidebar row:hover { + background-color: @hover_bg; +} + +placessidebar row:selected { + background-color: @selected_bg; + color: @selected_fg; +} + +placessidebar row:selected image { + color: @selected_fg; +} + +placessidebar row image { + color: @text_secondary; + min-width: 16px; + padding-right: 6px; +} + +placessidebar row:hover image { + color: @brand_green; +} + +placessidebar row.has-open-popup { + background-color: @hover_bg; +} + +/* Drop-target highlight when dragging onto a places row */ +placessidebar row.sidebar-new-bookmark-row { + color: @brand_green; +} + +placessidebar row:drop(active) { + background-color: alpha(@brand_green, 0.25); + color: @text_primary; + box-shadow: inset 0 0 0 2px @brand_green; +} + +/* ── Tree views / column views ───────────────────────────── */ + +treeview, +columnview, +treeview.view, +columnview.view { + background-color: @base_bg; + color: @text_primary; + border-color: @border; + -GtkTreeView-grid-line-pattern: "\7\7"; + -GtkTreeView-grid-line-width: 1; +} + +treeview.view:hover, +columnview.view:hover { + background-color: @hover_bg; +} + +treeview.view:selected, +columnview.view:selected, +treeview.view:selected:focus, +columnview.view:selected:focus, +treeview.view row:selected, +columnview.view row:selected { + background-color: @selected_bg; + color: @selected_fg; +} + +treeview.view:selected:hover, +columnview.view:selected:hover { + background-color: shade(@selected_bg, 1.12); +} + +treeview.view:disabled, +columnview.view:disabled { + color: @text_disabled; +} + +/* Alternate-row background for "rules-hint" tree views */ +treeview.view:nth-child(even) { + background-color: alpha(@surface_bg, 0.5); +} + +/* Tree expander arrows */ +treeview.view expander, +columnview.view expander { + color: @text_secondary; + min-width: 14px; + min-height: 14px; + -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); +} + +treeview.view expander:hover, +columnview.view expander:hover { + color: @brand_green; +} + +treeview.view expander:checked, +columnview.view expander:checked { + -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); + color: @brand_green; +} + +treeview.view expander:dir(rtl) { + -gtk-icon-source: -gtk-icontheme("pan-start-symbolic"); +} + +/* Cell separators (vertical grid lines) */ +treeview.view.separator, +columnview.view.separator { + color: @border; + background-color: @border; +} + +/* Column headers — sit on the alt surface so they read as chrome */ +treeview header button, +columnview header button, +treeview.view header button, +columnview.view header button { + background-color: @surface_bg_alt; + background-image: none; + border: none; + border-right: 1px solid @border; + border-bottom: 1px solid @border; + border-radius: 0; + color: @text_primary; + padding: 6px 10px; + font-weight: 500; + box-shadow: none; +} + +treeview header button:hover, +columnview header button:hover { + background-color: @overlay_bg; + color: @brand_green; +} + +treeview header button:active, +treeview header button:checked, +columnview header button:active { + background-color: @overlay_bg; + color: @brand_green; + box-shadow: inset 0 -2px 0 0 @brand_green; +} + +treeview header button:last-child, +columnview header button:last-child { + border-right: none; +} + +/* Drag-and-drop indicators */ +treeview.view.dnd, +columnview.view.dnd { + border-style: solid none; + border-width: 1px; + border-color: @brand_green; +} + +treeview.view:drop(active), +columnview.view:drop(active) { + background-color: alpha(@brand_green, 0.20); + box-shadow: inset 0 0 0 1px @brand_green; +} + +/* In-cell progress bar */ +treeview.view.progressbar, +columnview.view.progressbar { + background-color: @brand_green; + color: @text_on_accent; + border-radius: 2px; +} + +treeview.view.trough, +columnview.view.trough { + background-color: @surface_bg_alt; + border-radius: 2px; +} diff --git a/assets/themes/NexusOS/gtk-3.0/menus-popovers.css b/assets/themes/NexusOS/gtk-3.0/menus-popovers.css new file mode 100644 index 0000000..8bb69f8 --- /dev/null +++ b/assets/themes/NexusOS/gtk-3.0/menus-popovers.css @@ -0,0 +1,345 @@ +/* NexusOS — Segment 4: menus, popovers, tooltips. + Surfaces lift one step above the window base. Hovered menu items use the + lime hover wash; selected/checked items go to solid lime. */ + +/* ── Menubar (top-level) ─────────────────────────────────── */ + +menubar, +.menubar { + background-color: @surface_bg_alt; + color: @text_primary; + border-bottom: 1px solid @border; + padding: 0; +} + +menubar > menuitem, +.menubar > menuitem { + padding: 6px 10px; + color: @text_primary; + background-color: transparent; +} + +menubar > menuitem:hover, +.menubar > menuitem:hover { + background-color: @hover_bg; + color: @text_primary; +} + +menubar > menuitem:active, +menubar > menuitem:checked, +.menubar > menuitem:active { + background-color: @active_bg; + color: @active_fg; +} + +menubar > menuitem:disabled, +.menubar > menuitem:disabled { + color: @text_disabled; +} + +/* ── Pop-up menus (classic GtkMenu) ──────────────────────── */ + +menu, +.menu, +.context-menu { + padding: 1px 0; + background-color: @overlay_bg; + background-image: none; + border: 1px solid @border_strong; + border-radius: 6px; + color: @text_primary; + box-shadow: 0 6px 18px rgba(0, 0, 0, 0.45), + 0 2px 4px rgba(0, 0, 0, 0.30); +} + +menu menuitem, +.menu menuitem, +.context-menu menuitem { + padding: 2px 10px; + min-height: 10px; + color: @text_primary; + background-color: transparent; + text-shadow: none; +} + +/* Normalize the optional menu icon (gtk-menu-images=true) so an icon'd + row — e.g. xfdesktop's "Desktop Settings…" — is the same height as a + text-only row instead of being sized by the raw icon + GTK defaults. */ +menu menuitem image, +.menu menuitem image, +.context-menu menuitem image { + min-width: 16px; + min-height: 16px; + margin: 0 8px 0 0; + -gtk-icon-transform: scale(1); +} + +menu menuitem box, +.menu menuitem box, +.context-menu menuitem box { + margin: 0; + padding: 0; + border-spacing: 0; +} + +menu menuitem:hover, +.menu menuitem:hover, +.context-menu menuitem:hover { + background-color: @hover_bg; + color: @text_primary; +} + +menu menuitem:active, +menu menuitem:checked, +.menu menuitem:active { + background-color: @active_bg; + color: @active_fg; +} + +menu menuitem:disabled, +.menu menuitem:disabled, +.context-menu menuitem:disabled { + color: @text_disabled; +} + +/* Keyboard accelerator hint text on the right side */ +menuitem accelerator, +.menuitem accelerator { + color: @text_secondary; + padding-left: 16px; +} + +menuitem:hover accelerator { + color: @text_primary; +} + +menuitem:active accelerator, +menuitem:checked accelerator { + color: @active_fg; +} + +menuitem:disabled accelerator { + color: @text_disabled; +} + +/* Submenu arrow */ +menuitem arrow, +.menuitem arrow { + color: @text_secondary; + min-width: 12px; + min-height: 12px; + -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); +} + +menuitem:hover arrow { + color: @text_primary; +} + +menuitem:dir(rtl) arrow { + -gtk-icon-source: -gtk-icontheme("pan-start-symbolic"); +} + +/* Check / radio inside menus */ +menuitem check, +menuitem radio, +.menuitem check, +.menuitem radio { + min-width: 14px; + min-height: 14px; + color: @brand_green; + margin-right: 8px; +} + +menuitem check:checked, +menuitem radio:checked { + color: @brand_green; + -gtk-icon-shadow: none; +} + +/* Separator inside menus */ +menu separator, +.menu separator, +.context-menu separator { + background-color: @border_strong; + min-height: 1px; + margin: 3px 0; +} + +/* ── Popovers (modern) ───────────────────────────────────── */ + +popover, +popover.background { + background-color: @overlay_bg; + background-image: none; + border: 1px solid @border_strong; + border-radius: 8px; + color: @text_primary; + padding: 6px; + box-shadow: 0 6px 18px rgba(0, 0, 0, 0.45), + 0 2px 4px rgba(0, 0, 0, 0.30); +} + +popover > arrow, +popover.background > arrow { + background-color: @overlay_bg; + border: 1px solid @border_strong; +} + +/* Modelbutton — the flat row-style button used in popover menus */ +modelbutton, +popover modelbutton { + padding: 6px 10px; + min-height: 24px; + border-radius: 4px; + background-color: transparent; + color: @text_primary; + outline: none; +} + +modelbutton:hover, +popover modelbutton:hover { + background-color: @hover_bg; + color: @text_primary; +} + +modelbutton:active, +modelbutton:checked, +popover modelbutton:active, +popover modelbutton:checked { + background-color: @active_bg; + color: @active_fg; +} + +modelbutton:disabled, +popover modelbutton:disabled { + background-color: transparent; + color: @text_disabled; +} + +modelbutton check, +modelbutton radio { + color: @brand_green; +} + +modelbutton arrow.left, +modelbutton arrow.right { + color: @text_secondary; + min-width: 12px; + min-height: 12px; +} + +modelbutton:hover arrow { + color: @text_primary; +} + +/* Separators inside popovers */ +popover separator { + background-color: @border_strong; + min-height: 1px; + margin: 3px 2px; +} + +/* Entries inside popovers — keep the entry style but match the surface */ +popover entry { + background-color: @surface_bg; + border-color: @border_strong; +} + +popover entry:focus { + border-color: @brand_green; + box-shadow: inset 0 0 0 1px @brand_green; +} + +/* Buttons inside popovers — flat by default */ +popover button { + background-color: transparent; + border-color: transparent; + color: @text_primary; +} + +popover button:hover { + background-color: @hover_bg; +} + +popover button:active, +popover button:checked { + background-color: @active_bg; + color: @active_fg; +} + +popover button.suggested-action { + background-color: @brand_green; + color: @text_on_accent; +} + +popover button.destructive-action { + background-color: @error_color; + color: #ffffff; +} + +/* ── Tooltips ────────────────────────────────────────────── */ + +tooltip, +tooltip.background { + background-color: @tooltip_background; + background-image: none; + border: 1px solid @tooltip_border; + border-radius: 6px; + color: @tooltip_text; + padding: 4px 8px; + text-shadow: none; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.40); +} + +tooltip label, +tooltip.background label { + padding: 0; + color: @tooltip_text; +} + +/* ── Whisker menu (xfce4-whiskermenu-plugin) ─────────────── */ +/* Whisker has no menuitems — the app/category lists are GtkTreeViews. + Row height = cell padding + the icon-size set in Whisker's own + settings, so trim padding here and keep icons small in Whisker. */ + +.whisker-menu { + background-color: @overlay_bg; + padding: 2px; +} + +.whisker-menu .view, +.whisker-menu treeview.view { + padding: 1px 4px; + -GtkTreeView-vertical-separator: 0; +} + +.whisker-menu treeview.view:hover { + background-color: @hover_bg; + color: @text_primary; +} + +.whisker-menu treeview.view:selected { + background-color: @active_bg; + color: @active_fg; +} + +/* Search entry and the bottom command buttons */ +.whisker-menu entry { + margin: 2px; +} + +.whisker-menu button { + padding: 2px 6px; + min-height: 0; +} + +.whisker-menu separator { + margin: 2px 0; +} + +/* ── Tooltips (cont.) ────────────────────────────────────── */ + +tooltip * { + background-color: transparent; + color: @tooltip_text; +} diff --git a/assets/themes/NexusOS/gtk-3.0/notebooks.css b/assets/themes/NexusOS/gtk-3.0/notebooks.css new file mode 100644 index 0000000..6081125 --- /dev/null +++ b/assets/themes/NexusOS/gtk-3.0/notebooks.css @@ -0,0 +1,253 @@ +/* NexusOS — Segment 6: notebooks (tabs) and stack switchers. + Active tab gets a lime underline (or side-line for vertical tab strips). + Stack switchers behave like a pill-shaped segmented control. */ + +/* ── Notebook container ──────────────────────────────────── */ + +notebook { + background-color: transparent; + color: @text_primary; + padding: 0; +} + +notebook > stack { + background-color: @base_bg; + color: @text_primary; +} + +/* ── Tab strip header ────────────────────────────────────── */ + +notebook > header { + background-color: @surface_bg; + border-color: @border; + padding: 0; +} + +notebook > header.top { + border-bottom: 1px solid @border; +} + +notebook > header.bottom { + border-top: 1px solid @border; +} + +notebook > header.left { + border-right: 1px solid @border; +} + +notebook > header.right { + border-left: 1px solid @border; +} + +/* Tab strip background gap (the part not covered by tabs) */ +notebook > header > tabs { + margin: 0; + padding: 0; +} + +/* ── Individual tabs ─────────────────────────────────────── */ + +notebook > header > tabs > tab { + background-color: transparent; + background-image: none; + color: @text_secondary; + padding: 8px 14px; + min-height: 28px; + border: none; + border-radius: 0; + transition: background-color 120ms ease, + color 120ms ease, + box-shadow 120ms ease; +} + +notebook > header > tabs > tab:hover { + background-color: @hover_bg; + color: @text_primary; +} + +notebook > header > tabs > tab:checked { + background-color: @base_bg; + color: @text_primary; + font-weight: 500; +} + +notebook > header > tabs > tab:disabled { + color: @text_disabled; +} + +/* Position-specific active-tab accent line */ +notebook > header.top > tabs > tab:checked { + box-shadow: inset 0 -2px 0 0 @brand_green; +} + +notebook > header.bottom > tabs > tab:checked { + box-shadow: inset 0 2px 0 0 @brand_green; +} + +notebook > header.left > tabs > tab:checked { + box-shadow: inset -2px 0 0 0 @brand_green; +} + +notebook > header.right > tabs > tab:checked { + box-shadow: inset 2px 0 0 0 @brand_green; +} + +/* Focused tab ring */ +notebook > header > tabs > tab:focus, +notebook > header > tabs > tab:focus-visible { + outline: 2px solid @focus_ring; + outline-offset: -3px; +} + +/* Close button on a tab */ +notebook > header > tabs > tab button.flat, +notebook > header > tabs > tab > button { + padding: 2px; + margin: 0 0 0 6px; + min-width: 18px; + min-height: 18px; + border-radius: 999px; + background-color: transparent; + border-color: transparent; + color: @text_secondary; +} + +notebook > header > tabs > tab button.flat:hover, +notebook > header > tabs > tab > button:hover { + background-color: @error_color; + color: #ffffff; +} + +notebook > header > tabs > tab:checked button.flat, +notebook > header > tabs > tab:checked > button { + color: @text_primary; +} + +/* Scrolling arrows when the tab strip overflows */ +notebook > header > arrow { + color: @text_secondary; + min-width: 18px; + min-height: 18px; + padding: 0 4px; +} + +notebook > header > arrow:hover { + color: @brand_green; + background-color: @hover_bg; +} + +notebook > header > arrow:disabled { + color: @text_disabled; +} + +/* "Reorderable" drag indicator */ +notebook > header > tabs > tab.reorderable-page:drop(active) { + box-shadow: inset 0 -2px 0 0 @brand_green; + background-color: @hover_bg; +} + +/* ── Stack switcher (pill-style segmented control) ───────── */ + +stackswitcher { + padding: 2px; + background-color: transparent; + border-radius: 999px; +} + +stackswitcher > button { + padding: 6px 14px; + min-height: 24px; + min-width: 64px; + border: 1px solid @border_strong; + border-radius: 0; + border-right-width: 0; + background-color: @surface_bg; + background-image: none; + color: @text_primary; + font-weight: 500; + box-shadow: none; +} + +stackswitcher > button:first-child { + border-top-left-radius: 999px; + border-bottom-left-radius: 999px; +} + +stackswitcher > button:last-child { + border-top-right-radius: 999px; + border-bottom-right-radius: 999px; + border-right-width: 1px; +} + +stackswitcher > button:hover { + background-color: @hover_bg; + border-color: @brand_green_dark; + color: @text_primary; +} + +stackswitcher > button:checked { + background-color: @active_bg; + border-color: @brand_green_dark; + color: @active_fg; +} + +stackswitcher > button:checked:hover { + background-color: @brand_green_light; + color: @text_on_accent; +} + +stackswitcher > button:disabled { + background-color: @surface_bg; + border-color: @border; + color: @text_disabled; +} + +stackswitcher > button:focus { + outline: 2px solid @focus_ring; + outline-offset: -2px; +} + +/* Notification dot when a hidden stack page needs attention */ +stackswitcher > button.needs-attention > label { + animation: none; + background-image: radial-gradient(circle at center, + @brand_green 30%, + transparent 32%); + background-size: 6px 6px; + background-repeat: no-repeat; + background-position: right top; + padding-right: 12px; +} + +/* ── Vertical stack switcher (e.g. preferences) ──────────── */ + +stackswitcher.vertical { + background-color: transparent; + padding: 0; +} + +stackswitcher.vertical > button { + border-radius: 6px; + border: 1px solid transparent; + border-right-width: 1px; + background-color: transparent; + margin: 2px 4px; + padding: 8px 12px; + min-width: 120px; +} + +stackswitcher.vertical > button:hover { + background-color: @hover_bg; + border-color: transparent; +} + +stackswitcher.vertical > button:checked { + background-color: @selected_bg; + border-color: transparent; + color: @selected_fg; +} + +stackswitcher.vertical > button:checked:hover { + background-color: shade(@selected_bg, 1.12); + color: @selected_fg; +} diff --git a/assets/themes/NexusOS/gtk-3.0/polish.css b/assets/themes/NexusOS/gtk-3.0/polish.css new file mode 100644 index 0000000..3391175 --- /dev/null +++ b/assets/themes/NexusOS/gtk-3.0/polish.css @@ -0,0 +1,493 @@ +/* NexusOS — Segment 10: polish pass. + Catches widgets not covered by earlier segments (combobox, toolbar, + searchbar, actionbar, statusbar, paned, expander, calendar, iconview, + shortcuts-window, OSD overlays, etc.) and tightens focus/disabled rules. */ + +/* ── Comboboxes / dropdowns ──────────────────────────────── */ + +combobox, +combobox.combo, +combobox button { + background-color: @surface_bg; + color: @text_primary; +} + +combobox button.combo { + padding: 4px 10px; + border: 1px solid @border_strong; + border-radius: 6px; +} + +combobox button.combo:hover { + border-color: @brand_green_dark; + background-color: @hover_bg; +} + +combobox button.combo:focus { + border-color: @brand_green; + box-shadow: inset 0 0 0 1px @brand_green; +} + +combobox button.combo:active, +combobox button.combo:checked { + background-color: @overlay_bg; +} + +combobox arrow { + color: @text_secondary; + min-width: 12px; + min-height: 12px; + -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); +} + +combobox button.combo:hover arrow { + color: @brand_green; +} + +/* The popup list for a combobox */ +combobox > window.popup, +combobox window.combo { + background-color: @overlay_bg; + border: 1px solid @border_strong; + border-radius: 6px; + box-shadow: 0 6px 18px rgba(0, 0, 0, 0.45); +} + +combobox treeview.view { + background-color: @overlay_bg; +} + +combobox treeview.view:selected, +combobox treeview.view:hover { + background-color: @hover_bg; + color: @text_primary; +} + +/* ── Toolbars ────────────────────────────────────────────── */ + +toolbar { + background-color: @surface_bg_alt; + border-color: @border; + padding: 4px 6px; + color: @text_primary; +} + +toolbar.horizontal { + border-bottom: 1px solid @border; +} + +toolbar.vertical { + border-right: 1px solid @border; +} + +toolbar > button, +toolbar button.flat { + background-color: transparent; + border-color: transparent; + color: @text_primary; +} + +toolbar > button:hover, +toolbar button.flat:hover { + background-color: @hover_bg; +} + +toolbar > button:active, +toolbar > button:checked, +toolbar button.flat:checked { + background-color: @active_bg; + color: @active_fg; +} + +toolbar separator { + background-color: @border; + margin: 4px 4px; +} + +/* Inline toolbar — sits inside content, lower contrast */ +toolbar.inline-toolbar { + background-color: @surface_bg; + border: 1px solid @border; + border-radius: 0 0 6px 6px; + border-top: none; +} + +/* OSD-style toolbar (overlay) */ +toolbar.osd { + background-color: alpha(@overlay_bg, 0.92); + border: 1px solid @border_strong; + border-radius: 8px; + box-shadow: 0 6px 18px rgba(0, 0, 0, 0.55); + color: @text_primary; + padding: 4px; +} + +/* ── Searchbars, actionbars, statusbars ──────────────────── */ + +searchbar { + background-color: @surface_bg_alt; + border-bottom: 1px solid @border; + padding: 6px; +} + +searchbar > revealer > box { + padding: 0 6px; +} + +actionbar { + background-color: @surface_bg; + border-top: 1px solid @border; + padding: 6px 10px; + color: @text_primary; +} + +statusbar { + background-color: @surface_bg; + border-top: 1px solid @border; + padding: 4px 10px; + color: @text_secondary; + font-size: smaller; +} + +/* ── Paned (resizable split-view divider) ────────────────── */ + +paned > separator { + background-color: @border; + background-image: none; + min-width: 1px; + min-height: 1px; +} + +paned > separator:hover, +paned > separator:active { + background-color: @brand_green; +} + +paned.wide > separator { + min-width: 4px; + min-height: 4px; + background-color: @border; +} + +paned.wide > separator:hover { + background-color: alpha(@brand_green, 0.6); +} + +/* ── Expander (disclosure triangle + label) ──────────────── */ + +expander { + color: @text_primary; +} + +expander title > arrow { + color: @text_secondary; + min-width: 12px; + min-height: 12px; + -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); +} + +expander title:hover > arrow { + color: @brand_green; +} + +expander title > arrow:checked { + -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); + color: @brand_green; +} + +expander title:hover { + color: @brand_green; +} + +/* ── Calendar ────────────────────────────────────────────── */ + +calendar { + background-color: @base_bg; + color: @text_primary; + border: 1px solid @border; + border-radius: 6px; + padding: 4px; +} + +calendar:selected { + background-color: @selected_bg; + color: @selected_fg; + border-radius: 4px; +} + +calendar.header { + background-color: @surface_bg_alt; + border-bottom: 1px solid @border; + color: @text_primary; + font-weight: 600; +} + +calendar.button { + color: @text_secondary; + background-color: transparent; + border-color: transparent; +} + +calendar.button:hover { + color: @brand_green; + background-color: @hover_bg; +} + +calendar.button:disabled { + color: @text_disabled; +} + +calendar.highlight { + color: @brand_green; + font-weight: 600; +} + +calendar:indeterminate { + color: @text_disabled; +} + +/* ── Icon view (e.g. file manager grid view) ─────────────── */ + +iconview { + background-color: @base_bg; + color: @text_primary; +} + +iconview:hover, +iconview .cell:hover { + background-color: @hover_bg; +} + +iconview:selected, +iconview .cell:selected { + background-color: @selected_bg; + color: @selected_fg; + border-radius: 6px; +} + +iconview:selected:focus, +iconview .cell:selected:focus { + background-color: shade(@selected_bg, 1.10); +} + +iconview.dnd { + box-shadow: inset 0 0 0 1px @brand_green; +} + +iconview > rubberband, +.view > rubberband { + background-color: alpha(@brand_green, 0.18); + border: 1px solid @brand_green; +} + +/* ── Generic .view (CellRenderer-based widgets) ──────────── */ + +.view { + background-color: @base_bg; + color: @text_primary; +} + +.view:selected { + background-color: @selected_bg; + color: @selected_fg; +} + +.view:hover { + background-color: @hover_bg; +} + +.view:disabled { + color: @text_disabled; +} + +/* ── Shortcuts window (Ctrl+? help) ──────────────────────── */ + +shortcuts-section, +shortcut { + background-color: @base_bg; + color: @text_primary; +} + +shortcut > .keycap { + background-color: @surface_bg_alt; + border: 1px solid @border_strong; + border-radius: 4px; + color: @text_primary; + min-width: 16px; + padding: 1px 6px; + font-family: monospace; + box-shadow: 0 1px 0 0 @border; +} + +/* ── Selection-mode helpers (matches headerbar selection-mode) ── */ + +.selection-mode { + background-color: @brand_purple_dark; + color: @selected_fg; +} + +.selection-mode button:hover { + background-color: alpha(@selected_fg, 0.15); +} + +/* ── OSD overlay class (generic) ─────────────────────────── */ + +.osd { + background-color: alpha(@overlay_bg, 0.92); + color: @text_primary; + border: 1px solid @border_strong; + border-radius: 8px; + box-shadow: 0 6px 18px rgba(0, 0, 0, 0.55); +} + +.osd button { + background-color: transparent; + border-color: transparent; + color: @text_primary; +} + +.osd button:hover { + background-color: alpha(@text_primary, 0.10); +} + +.osd entry { + background-color: alpha(#000000, 0.40); + border-color: @border_strong; + color: @text_primary; +} + +.osd entry:focus { + border-color: @brand_green; + box-shadow: inset 0 0 0 1px @brand_green; +} + +/* ── Globally consistent focus ring on common widgets ─────── */ + +*:focus-visible { + outline: 2px solid @focus_ring; + outline-offset: 1px; +} + +/* Some widgets are better off without an outline ring */ +button:focus-visible, +entry:focus-visible, +notebook > header > tabs > tab:focus-visible, +treeview.view:focus-visible, +columnview.view:focus-visible { + /* These have their own focus treatment from earlier segments; the + universal rule above is fine, but keep an explicit empty block to + document the intent rather than chasing override specificity. */ +} + +/* ── Universal insensitive (disabled) handling ───────────── */ + +:disabled, +*:disabled { + -gtk-icon-effect: dim; +} + +/* ── Labels: dim-label, error-label, etc. ────────────────── */ + +label.error, +label.error-message { + color: @error_color; +} + +label.warning { + color: @warning_color; +} + +label.success { + color: @success_color; +} + +label.heading, +.heading { + font-weight: 600; + color: @text_primary; +} + +/* ── Drag-and-drop highlight surfaces ────────────────────── */ + +box:drop(active), +grid:drop(active), +flowbox:drop(active) { + box-shadow: inset 0 0 0 2px @brand_green; + background-color: alpha(@brand_green, 0.08); +} + +/* ── Selection rubberband (drag-select) ──────────────────── */ + +rubberband, +.rubberband { + background-color: alpha(@brand_green, 0.18); + border: 1px solid @brand_green; +} + +/* ── Color & font choosers — small surface touches ───────── */ + +colorswatch, +colorswatch.color-active-badge { + border-radius: 4px; + border: 1px solid @border_strong; +} + +colorswatch:hover { + border-color: @brand_green; +} + +colorswatch.color-light { + color: @text_on_accent; +} + +colorswatch.color-dark { + color: @text_primary; +} + +colorchooser .popover { + background-color: @overlay_bg; +} + +fontchooser .dim-label { + color: @text_secondary; +} + +/* ── Emoji chooser ───────────────────────────────────────── */ + +emoji-chooser, +emoji-chooser .emoji { + background-color: @overlay_bg; + color: @text_primary; + border-radius: 6px; + padding: 2px; +} + +emoji-chooser .emoji:hover { + background-color: @hover_bg; +} + +emoji-chooser .emoji:focus, +emoji-chooser .emoji:checked { + background-color: @selected_bg; +} + +emoji-chooser .emoji-section { + border-top: 1px solid @border; + padding-top: 4px; +} + +/* ── Placeholder text in entries ─────────────────────────── */ + +entry placeholder, +.entry placeholder { + color: @text_disabled; + opacity: 1.0; +} + +/* ── Scaling fonts / image effects in disabled state ─────── */ + +image:disabled, +icon:disabled { + -gtk-icon-effect: dim; + opacity: 0.5; +} diff --git a/assets/themes/NexusOS/gtk-3.0/scrollbars-progress.css b/assets/themes/NexusOS/gtk-3.0/scrollbars-progress.css new file mode 100644 index 0000000..dbebc43 --- /dev/null +++ b/assets/themes/NexusOS/gtk-3.0/scrollbars-progress.css @@ -0,0 +1,306 @@ +/* NexusOS — Segment 7: scrollbars, progress bars, level bars, spinners. + Scrollbars are slim and overlay-ish; the slider thickens on hover. + Progress fills use the lime brand color. Spinners are lime too. */ + +/* ── Scrollbars ──────────────────────────────────────────── */ + +scrollbar { + background-color: transparent; + border: none; + transition: all 160ms ease; +} + +scrollbar.horizontal { + min-height: 12px; +} + +scrollbar.vertical { + min-width: 12px; +} + +scrollbar trough { + background-color: transparent; + border: none; + border-radius: 999px; + margin: 0; +} + +scrollbar:hover trough { + background-color: alpha(@surface_bg, 0.55); +} + +/* The draggable slider */ +scrollbar slider { + background-color: alpha(@text_primary, 0.25); + border: 2px solid transparent; + border-radius: 999px; + background-clip: padding-box; + min-width: 4px; + min-height: 4px; + transition: background-color 160ms ease, + min-width 160ms ease, + min-height 160ms ease; +} + +scrollbar.horizontal slider { + min-width: 32px; + min-height: 4px; +} + +scrollbar.vertical slider { + min-width: 4px; + min-height: 32px; +} + +scrollbar:hover slider, +scrollbar.hovering slider { + background-color: alpha(@brand_green, 0.55); +} + +scrollbar.horizontal:hover slider, +scrollbar.horizontal.hovering slider { + min-height: 8px; +} + +scrollbar.vertical:hover slider, +scrollbar.vertical.hovering slider { + min-width: 8px; +} + +scrollbar slider:hover { + background-color: @brand_green; +} + +scrollbar slider:active, +scrollbar slider:hover:active { + background-color: @brand_green_dark; +} + +scrollbar slider:disabled { + background-color: transparent; +} + +/* Fine-tune mode (the user is scrolling slowly with Shift held) */ +scrollbar.fine-tune slider { + min-width: 4px; + min-height: 4px; +} + +/* Hide the legacy stepper buttons unless the app explicitly opts in */ +scrollbar button { + min-width: 0; + min-height: 0; + padding: 0; + margin: 0; + border: none; + background: transparent; + -GtkScrollbar-has-backward-stepper: 0; + -GtkScrollbar-has-forward-stepper: 0; +} + +/* Overlay vs always-shown — overlay variant fades in over content */ +scrollbar.overlay-indicator { + background-color: transparent; +} + +scrollbar.overlay-indicator:not(.dragging):not(.hovering) { + opacity: 0.45; +} + +scrollbar.overlay-indicator.dragging, +scrollbar.overlay-indicator.hovering { + opacity: 1.0; +} + +/* Undershoot / overshoot hints in scrolled windows */ +scrolledwindow undershoot.top, +scrolledwindow undershoot.bottom, +scrolledwindow undershoot.left, +scrolledwindow undershoot.right { + background-image: none; + background-color: transparent; +} + +scrolledwindow overshoot.top { + background-image: linear-gradient(to bottom, + alpha(@brand_green, 0.25), + transparent); + background-repeat: no-repeat; + background-size: 100% 24px; + background-position: top; +} + +scrolledwindow overshoot.bottom { + background-image: linear-gradient(to top, + alpha(@brand_green, 0.25), + transparent); + background-repeat: no-repeat; + background-size: 100% 24px; + background-position: bottom; +} + +scrolledwindow overshoot.left { + background-image: linear-gradient(to right, + alpha(@brand_green, 0.25), + transparent); + background-repeat: no-repeat; + background-size: 24px 100%; + background-position: left; +} + +scrolledwindow overshoot.right { + background-image: linear-gradient(to left, + alpha(@brand_green, 0.25), + transparent); + background-repeat: no-repeat; + background-size: 24px 100%; + background-position: right; +} + +/* Junction (the small square where horizontal + vertical scrollbars meet) */ +scrolledwindow junction { + background-color: transparent; + border: none; +} + +/* ── Progress bars ───────────────────────────────────────── */ + +progressbar { + color: @text_secondary; + font-size: smaller; +} + +progressbar trough { + background-color: @surface_bg_alt; + background-image: none; + border: 1px solid @border; + border-radius: 999px; + min-height: 6px; + min-width: 6px; +} + +progressbar progress { + background-color: @brand_green; + background-image: none; + border: none; + border-radius: 999px; + box-shadow: 0 0 6px alpha(@brand_green, 0.35); +} + +progressbar.horizontal trough, +progressbar.horizontal progress { + min-height: 6px; +} + +progressbar.vertical trough, +progressbar.vertical progress { + min-width: 6px; +} + +progressbar:disabled trough { + background-color: @surface_bg; +} + +progressbar:disabled progress { + background-color: @text_disabled; + box-shadow: none; +} + +/* OSD progressbar — used as an overlay on top of media etc. */ +progressbar.osd { + color: #ffffff; +} + +progressbar.osd trough { + background-color: alpha(#000000, 0.45); + border-color: transparent; +} + +progressbar.osd progress { + background-color: @brand_green; + box-shadow: 0 0 8px alpha(@brand_green, 0.55); +} + +/* ── Level bars ──────────────────────────────────────────── */ + +levelbar { + color: @text_secondary; +} + +levelbar trough { + background-color: @surface_bg_alt; + border: 1px solid @border; + border-radius: 4px; + padding: 2px; + min-height: 6px; + min-width: 6px; +} + +levelbar.horizontal trough, +levelbar.horizontal block { + min-height: 6px; +} + +levelbar.vertical trough, +levelbar.vertical block { + min-width: 6px; +} + +levelbar block { + border-radius: 2px; + margin: 0 1px; + min-width: 32px; + background-color: @brand_green; + border: none; +} + +levelbar block.empty { + background-color: alpha(@text_primary, 0.10); +} + +levelbar block.low { + background-color: @warning_color; +} + +levelbar block.high { + background-color: @brand_green; +} + +levelbar block.full { + background-color: @brand_green_light; +} + +levelbar.discrete block { + min-width: 24px; + margin: 0 1px; +} + +levelbar:disabled block { + background-color: @text_disabled; +} + +/* ── Spinner ─────────────────────────────────────────────── */ + +spinner { + background: none; + opacity: 0; + -gtk-icon-source: -gtk-icontheme("process-working-symbolic"); + color: @brand_green; + min-width: 16px; + min-height: 16px; + transition: opacity 200ms ease; +} + +spinner:checked { + opacity: 1; + animation: nexus_spinner 1s linear infinite; +} + +spinner:disabled { + opacity: 0.4; + color: @text_disabled; +} + +@keyframes nexus_spinner { + to { -gtk-icon-transform: rotate(1turn); } +} diff --git a/assets/themes/NexusOS/gtk-3.0/toggles-sliders.css b/assets/themes/NexusOS/gtk-3.0/toggles-sliders.css new file mode 100644 index 0000000..7da4402 --- /dev/null +++ b/assets/themes/NexusOS/gtk-3.0/toggles-sliders.css @@ -0,0 +1,364 @@ +/* NexusOS — Segment 8: switches, checkboxes, radios, scales/sliders. + Switches and checks fill with lime when on. Scales use the lime knob and + a purple highlight on the filled portion of the track. */ + +/* ── Switch (GtkSwitch) ──────────────────────────────────── */ + +switch { + background-color: @surface_bg_alt; + background-image: none; + border: 1px solid @border_strong; + border-radius: 999px; + min-width: 42px; + min-height: 22px; + padding: 0; + color: transparent; /* hide internal ON/OFF labels */ + font-size: 0; + box-shadow: none; + transition: background-color 160ms ease, + border-color 160ms ease; +} + +switch:hover { + background-color: @overlay_bg; + border-color: @border_strong; +} + +switch:focus, +switch:focus-visible { + outline: 2px solid @focus_ring; + outline-offset: 2px; +} + +switch:checked { + background-color: @brand_green; + border-color: @brand_green_dark; + color: transparent; +} + +switch:checked:hover { + background-color: @brand_green_light; + border-color: @brand_green; +} + +switch:disabled { + background-color: @surface_bg; + border-color: @border; + opacity: 0.6; +} + +switch:checked:disabled { + background-color: alpha(@brand_green, 0.35); + border-color: transparent; +} + +/* The sliding knob */ +switch slider { + background-color: @text_primary; + background-image: none; + border: 1px solid @border_strong; + border-radius: 999px; + min-width: 18px; + min-height: 18px; + margin: 1px; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.35); + transition: all 160ms ease; +} + +switch:checked slider { + background-color: #ffffff; + border-color: @brand_green_dark; +} + +switch:disabled slider { + background-color: @text_disabled; + box-shadow: none; +} + +/* ── Checkbox ────────────────────────────────────────────── */ + +check, +checkbutton check { + min-width: 16px; + min-height: 16px; + padding: 1px; + background-color: @surface_bg; + background-image: none; + border: 1px solid @border_strong; + border-radius: 4px; + color: transparent; + -gtk-icon-source: none; + -gtk-icon-shadow: none; + transition: background-color 120ms ease, + border-color 120ms ease; +} + +check:hover, +checkbutton check:hover { + border-color: @brand_green_dark; + background-color: @hover_bg; +} + +check:focus, +checkbutton check:focus { + outline: 2px solid @focus_ring; + outline-offset: 1px; +} + +check:checked, +checkbutton check:checked { + background-color: @brand_green; + border-color: @brand_green_dark; + color: @text_on_accent; + -gtk-icon-source: -gtk-icontheme("object-select-symbolic"); +} + +check:checked:hover, +checkbutton check:checked:hover { + background-color: @brand_green_light; + border-color: @brand_green; +} + +check:indeterminate, +checkbutton check:indeterminate { + background-color: @brand_green; + border-color: @brand_green_dark; + color: @text_on_accent; + -gtk-icon-source: -gtk-icontheme("checkbox-mixed-symbolic"); +} + +check:disabled, +checkbutton check:disabled { + background-color: @insensitive_bg_color; + border-color: @border; + color: @text_disabled; +} + +check:checked:disabled, +checkbutton check:checked:disabled { + background-color: alpha(@brand_green, 0.35); + color: @text_disabled; + border-color: transparent; +} + +/* The label next to the check */ +checkbutton:disabled, +checkbutton:disabled label { + color: @text_disabled; +} + +/* ── Radio button ────────────────────────────────────────── */ + +radio, +radiobutton radio { + min-width: 16px; + min-height: 16px; + padding: 1px; + background-color: @surface_bg; + background-image: none; + border: 1px solid @border_strong; + border-radius: 999px; + color: transparent; + -gtk-icon-source: none; + transition: background-color 120ms ease, + border-color 120ms ease; +} + +radio:hover, +radiobutton radio:hover { + border-color: @brand_green_dark; + background-color: @hover_bg; +} + +radio:focus, +radiobutton radio:focus { + outline: 2px solid @focus_ring; + outline-offset: 1px; +} + +radio:checked, +radiobutton radio:checked { + background-color: @surface_bg; + border-color: @brand_green; + color: @brand_green; + /* Inner filled dot via icon */ + -gtk-icon-source: -gtk-icontheme("radio-checked-symbolic"); +} + +radio:checked:hover, +radiobutton radio:checked:hover { + border-color: @brand_green_light; +} + +radio:disabled, +radiobutton radio:disabled { + background-color: @insensitive_bg_color; + border-color: @border; +} + +radio:checked:disabled, +radiobutton radio:checked:disabled { + color: @text_disabled; + border-color: @border; +} + +radiobutton:disabled, +radiobutton:disabled label { + color: @text_disabled; +} + +/* ── Scale / slider (GtkScale) ───────────────────────────── */ + +scale { + min-height: 18px; + min-width: 18px; + padding: 8px 4px; + color: @text_primary; +} + +scale.horizontal { + min-height: 18px; +} + +scale.vertical { + min-width: 18px; +} + +/* The track */ +scale trough { + background-color: @surface_bg_alt; + border: 1px solid @border; + border-radius: 999px; + min-height: 4px; + min-width: 4px; +} + +scale.horizontal trough { + min-height: 4px; +} + +scale.vertical trough { + min-width: 4px; +} + +/* The filled portion (left of the knob on a horizontal scale) */ +scale highlight { + background-color: @brand_purple; + background-image: none; + border-radius: 999px; + min-height: 4px; + min-width: 4px; +} + +scale.horizontal highlight { + min-height: 4px; +} + +scale.vertical highlight { + min-width: 4px; +} + +/* A secondary fill (e.g. media-player buffered range) */ +scale fill { + background-color: alpha(@brand_purple, 0.35); + border-radius: 999px; + min-height: 4px; + min-width: 4px; +} + +scale:disabled trough, +scale:disabled highlight, +scale:disabled fill { + background-color: @insensitive_bg_color; +} + +scale:disabled highlight { + background-color: alpha(@brand_purple, 0.30); +} + +/* The knob */ +scale slider { + background-color: @brand_green; + background-image: none; + border: 1px solid @brand_green_dark; + border-radius: 999px; + min-width: 14px; + min-height: 14px; + margin: -6px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.40); + transition: background-color 120ms ease, + box-shadow 120ms ease, + min-width 120ms ease, + min-height 120ms ease; +} + +scale slider:hover { + background-color: @brand_green_light; + border-color: @brand_green; + box-shadow: 0 0 0 4px alpha(@brand_green, 0.18), + 0 1px 3px rgba(0, 0, 0, 0.40); +} + +scale slider:active { + background-color: @brand_green_dark; + box-shadow: 0 0 0 6px alpha(@brand_green, 0.25), + 0 1px 3px rgba(0, 0, 0, 0.40); +} + +scale slider:focus { + outline: 2px solid @focus_ring; + outline-offset: 2px; +} + +scale slider:disabled { + background-color: @text_disabled; + border-color: @border; + box-shadow: none; +} + +/* Tick marks */ +scale marks { + color: @text_secondary; +} + +scale marks indicator { + background-color: @text_secondary; + min-height: 4px; + min-width: 1px; +} + +scale.has-marks-above { + margin-top: 4px; +} + +scale.has-marks-below { + margin-bottom: 4px; +} + +/* Value label (shown when draw-value is set) */ +scale value { + color: @text_primary; + padding: 0 6px; + font-feature-settings: "tnum"; +} + +/* "Fine-tune" mode — the slider gets a slightly bigger halo */ +scale.fine-tune slider { + box-shadow: 0 0 0 6px alpha(@brand_green, 0.25), + 0 1px 3px rgba(0, 0, 0, 0.40); +} + +/* OSD scale (used in media players over video) */ +scale.osd trough { + background-color: alpha(#000000, 0.45); + border-color: transparent; +} + +scale.osd highlight { + background-color: @brand_green; +} + +scale.osd slider { + background-color: @brand_green; + border-color: @brand_green_dark; +} diff --git a/assets/themes/NexusOS/index.theme b/assets/themes/NexusOS/index.theme new file mode 100644 index 0000000..78db4c5 --- /dev/null +++ b/assets/themes/NexusOS/index.theme @@ -0,0 +1,12 @@ +[Desktop Entry] +Type=X-GNOME-Metatheme +Name=NexusOS +Comment=NexusOS dark theme — lime green + purple accents drawn from the NexusOS logo +Encoding=UTF-8 + +[X-GNOME-Metatheme] +GtkTheme=NexusOS +MetacityTheme=NexusOS +IconTheme=NexusOS +CursorTheme=DMZ-White +ButtonLayout=close,minimize,maximize:menu diff --git a/assets/themes/NexusOS/xfwm4/bottom-active.png b/assets/themes/NexusOS/xfwm4/bottom-active.png new file mode 100644 index 0000000..82b980d Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/bottom-active.png differ diff --git a/assets/themes/NexusOS/xfwm4/bottom-inactive.png b/assets/themes/NexusOS/xfwm4/bottom-inactive.png new file mode 100644 index 0000000..82b980d Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/bottom-inactive.png differ diff --git a/assets/themes/NexusOS/xfwm4/bottom-left-active.png b/assets/themes/NexusOS/xfwm4/bottom-left-active.png new file mode 100644 index 0000000..62a022c Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/bottom-left-active.png differ diff --git a/assets/themes/NexusOS/xfwm4/bottom-left-inactive.png b/assets/themes/NexusOS/xfwm4/bottom-left-inactive.png new file mode 100644 index 0000000..62a022c Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/bottom-left-inactive.png differ diff --git a/assets/themes/NexusOS/xfwm4/bottom-right-active.png b/assets/themes/NexusOS/xfwm4/bottom-right-active.png new file mode 100644 index 0000000..158a577 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/bottom-right-active.png differ diff --git a/assets/themes/NexusOS/xfwm4/bottom-right-inactive.png b/assets/themes/NexusOS/xfwm4/bottom-right-inactive.png new file mode 100644 index 0000000..158a577 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/bottom-right-inactive.png differ diff --git a/assets/themes/NexusOS/xfwm4/close-active.png b/assets/themes/NexusOS/xfwm4/close-active.png new file mode 100644 index 0000000..ff2f95e Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/close-active.png differ diff --git a/assets/themes/NexusOS/xfwm4/close-inactive.png b/assets/themes/NexusOS/xfwm4/close-inactive.png new file mode 100644 index 0000000..76211a8 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/close-inactive.png differ diff --git a/assets/themes/NexusOS/xfwm4/close-prelight.png b/assets/themes/NexusOS/xfwm4/close-prelight.png new file mode 100644 index 0000000..b8b0d2a Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/close-prelight.png differ diff --git a/assets/themes/NexusOS/xfwm4/close-pressed.png b/assets/themes/NexusOS/xfwm4/close-pressed.png new file mode 100644 index 0000000..52285e4 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/close-pressed.png differ diff --git a/assets/themes/NexusOS/xfwm4/hide-active.png b/assets/themes/NexusOS/xfwm4/hide-active.png new file mode 100644 index 0000000..7b1f0d6 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/hide-active.png differ diff --git a/assets/themes/NexusOS/xfwm4/hide-inactive.png b/assets/themes/NexusOS/xfwm4/hide-inactive.png new file mode 100644 index 0000000..76211a8 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/hide-inactive.png differ diff --git a/assets/themes/NexusOS/xfwm4/hide-prelight.png b/assets/themes/NexusOS/xfwm4/hide-prelight.png new file mode 100644 index 0000000..861ae67 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/hide-prelight.png differ diff --git a/assets/themes/NexusOS/xfwm4/hide-pressed.png b/assets/themes/NexusOS/xfwm4/hide-pressed.png new file mode 100644 index 0000000..c343c8d Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/hide-pressed.png differ diff --git a/assets/themes/NexusOS/xfwm4/left-active.png b/assets/themes/NexusOS/xfwm4/left-active.png new file mode 100644 index 0000000..9ee3767 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/left-active.png differ diff --git a/assets/themes/NexusOS/xfwm4/left-inactive.png b/assets/themes/NexusOS/xfwm4/left-inactive.png new file mode 100644 index 0000000..9ee3767 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/left-inactive.png differ diff --git a/assets/themes/NexusOS/xfwm4/maximize-active.png b/assets/themes/NexusOS/xfwm4/maximize-active.png new file mode 100644 index 0000000..4007a17 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/maximize-active.png differ diff --git a/assets/themes/NexusOS/xfwm4/maximize-inactive.png b/assets/themes/NexusOS/xfwm4/maximize-inactive.png new file mode 100644 index 0000000..76211a8 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/maximize-inactive.png differ diff --git a/assets/themes/NexusOS/xfwm4/maximize-prelight.png b/assets/themes/NexusOS/xfwm4/maximize-prelight.png new file mode 100644 index 0000000..f9233c2 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/maximize-prelight.png differ diff --git a/assets/themes/NexusOS/xfwm4/maximize-pressed.png b/assets/themes/NexusOS/xfwm4/maximize-pressed.png new file mode 100644 index 0000000..a0dcd98 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/maximize-pressed.png differ diff --git a/assets/themes/NexusOS/xfwm4/maximize-toggled-active.png b/assets/themes/NexusOS/xfwm4/maximize-toggled-active.png new file mode 100644 index 0000000..4007a17 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/maximize-toggled-active.png differ diff --git a/assets/themes/NexusOS/xfwm4/maximize-toggled-inactive.png b/assets/themes/NexusOS/xfwm4/maximize-toggled-inactive.png new file mode 100644 index 0000000..76211a8 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/maximize-toggled-inactive.png differ diff --git a/assets/themes/NexusOS/xfwm4/maximize-toggled-prelight.png b/assets/themes/NexusOS/xfwm4/maximize-toggled-prelight.png new file mode 100644 index 0000000..c63497d Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/maximize-toggled-prelight.png differ diff --git a/assets/themes/NexusOS/xfwm4/maximize-toggled-pressed.png b/assets/themes/NexusOS/xfwm4/maximize-toggled-pressed.png new file mode 100644 index 0000000..6407f40 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/maximize-toggled-pressed.png differ diff --git a/assets/themes/NexusOS/xfwm4/menu-active.png b/assets/themes/NexusOS/xfwm4/menu-active.png new file mode 100644 index 0000000..c56a275 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/menu-active.png differ diff --git a/assets/themes/NexusOS/xfwm4/menu-inactive.png b/assets/themes/NexusOS/xfwm4/menu-inactive.png new file mode 100644 index 0000000..3545fd1 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/menu-inactive.png differ diff --git a/assets/themes/NexusOS/xfwm4/menu-pressed.png b/assets/themes/NexusOS/xfwm4/menu-pressed.png new file mode 100644 index 0000000..69aad60 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/menu-pressed.png differ diff --git a/assets/themes/NexusOS/xfwm4/right-active.png b/assets/themes/NexusOS/xfwm4/right-active.png new file mode 100644 index 0000000..4a9cb4e Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/right-active.png differ diff --git a/assets/themes/NexusOS/xfwm4/right-inactive.png b/assets/themes/NexusOS/xfwm4/right-inactive.png new file mode 100644 index 0000000..4a9cb4e Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/right-inactive.png differ diff --git a/assets/themes/NexusOS/xfwm4/shade-active.png b/assets/themes/NexusOS/xfwm4/shade-active.png new file mode 100644 index 0000000..1153daa Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/shade-active.png differ diff --git a/assets/themes/NexusOS/xfwm4/shade-inactive.png b/assets/themes/NexusOS/xfwm4/shade-inactive.png new file mode 100644 index 0000000..0549f20 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/shade-inactive.png differ diff --git a/assets/themes/NexusOS/xfwm4/shade-pressed.png b/assets/themes/NexusOS/xfwm4/shade-pressed.png new file mode 100644 index 0000000..f515f06 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/shade-pressed.png differ diff --git a/assets/themes/NexusOS/xfwm4/stick-active.png b/assets/themes/NexusOS/xfwm4/stick-active.png new file mode 100644 index 0000000..e1a6542 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/stick-active.png differ diff --git a/assets/themes/NexusOS/xfwm4/stick-inactive.png b/assets/themes/NexusOS/xfwm4/stick-inactive.png new file mode 100644 index 0000000..4d31a33 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/stick-inactive.png differ diff --git a/assets/themes/NexusOS/xfwm4/stick-pressed.png b/assets/themes/NexusOS/xfwm4/stick-pressed.png new file mode 100644 index 0000000..d2d205a Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/stick-pressed.png differ diff --git a/assets/themes/NexusOS/xfwm4/themerc b/assets/themes/NexusOS/xfwm4/themerc new file mode 100644 index 0000000..8ed1a77 --- /dev/null +++ b/assets/themes/NexusOS/xfwm4/themerc @@ -0,0 +1,23 @@ +button_offset=10 +button_spacing=0 + +show_app_icon=false + +full_width_title=true + +title_shadow_active=false +title_shadow_inactive=false + +title_horizontal_offset=3 + +active_text_color=#afafaf +active_text_shadow_color=#252525 + +inactive_text_color=#808080 +inactive_text_shadow_color=#252525 + +shadow_delta_height=2 +shadow_delta_width=0 +shadow_delta_x=0 +shadow_delta_y=-5 +shadow_opacity=40 diff --git a/assets/themes/NexusOS/xfwm4/title-1-active.png b/assets/themes/NexusOS/xfwm4/title-1-active.png new file mode 100644 index 0000000..fb0122e Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/title-1-active.png differ diff --git a/assets/themes/NexusOS/xfwm4/title-1-inactive.png b/assets/themes/NexusOS/xfwm4/title-1-inactive.png new file mode 100644 index 0000000..fb0122e Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/title-1-inactive.png differ diff --git a/assets/themes/NexusOS/xfwm4/title-2-active.png b/assets/themes/NexusOS/xfwm4/title-2-active.png new file mode 100644 index 0000000..fb0122e Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/title-2-active.png differ diff --git a/assets/themes/NexusOS/xfwm4/title-2-inactive.png b/assets/themes/NexusOS/xfwm4/title-2-inactive.png new file mode 100644 index 0000000..fb0122e Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/title-2-inactive.png differ diff --git a/assets/themes/NexusOS/xfwm4/title-3-active.png b/assets/themes/NexusOS/xfwm4/title-3-active.png new file mode 100644 index 0000000..fb0122e Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/title-3-active.png differ diff --git a/assets/themes/NexusOS/xfwm4/title-3-inactive.png b/assets/themes/NexusOS/xfwm4/title-3-inactive.png new file mode 100644 index 0000000..fb0122e Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/title-3-inactive.png differ diff --git a/assets/themes/NexusOS/xfwm4/title-4-active.png b/assets/themes/NexusOS/xfwm4/title-4-active.png new file mode 100644 index 0000000..fb0122e Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/title-4-active.png differ diff --git a/assets/themes/NexusOS/xfwm4/title-4-inactive.png b/assets/themes/NexusOS/xfwm4/title-4-inactive.png new file mode 100644 index 0000000..fb0122e Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/title-4-inactive.png differ diff --git a/assets/themes/NexusOS/xfwm4/title-5-active.png b/assets/themes/NexusOS/xfwm4/title-5-active.png new file mode 100644 index 0000000..fb0122e Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/title-5-active.png differ diff --git a/assets/themes/NexusOS/xfwm4/title-5-inactive.png b/assets/themes/NexusOS/xfwm4/title-5-inactive.png new file mode 100644 index 0000000..fb0122e Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/title-5-inactive.png differ diff --git a/assets/themes/NexusOS/xfwm4/top-left-active.png b/assets/themes/NexusOS/xfwm4/top-left-active.png new file mode 100644 index 0000000..b733ef8 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/top-left-active.png differ diff --git a/assets/themes/NexusOS/xfwm4/top-left-inactive.png b/assets/themes/NexusOS/xfwm4/top-left-inactive.png new file mode 100644 index 0000000..b733ef8 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/top-left-inactive.png differ diff --git a/assets/themes/NexusOS/xfwm4/top-right-active.png b/assets/themes/NexusOS/xfwm4/top-right-active.png new file mode 100644 index 0000000..8e85f93 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/top-right-active.png differ diff --git a/assets/themes/NexusOS/xfwm4/top-right-inactive.png b/assets/themes/NexusOS/xfwm4/top-right-inactive.png new file mode 100644 index 0000000..8e85f93 Binary files /dev/null and b/assets/themes/NexusOS/xfwm4/top-right-inactive.png differ diff --git a/assets/themes/_palette.py b/assets/themes/_palette.py new file mode 100644 index 0000000..143ad87 --- /dev/null +++ b/assets/themes/_palette.py @@ -0,0 +1,44 @@ +"""Shared color palette for NexusOS theme builds. + +Source of truth is NexusOS/gtk-3.0/colors.css. Keep these in sync. +Hex strings have no leading '#'. +""" + +# Brand +BRAND_GREEN = "8cc63f" +BRAND_GREEN_LIGHT = "b8e373" +BRAND_GREEN_DARK = "6ba62a" +BRAND_PURPLE = "88008f" +BRAND_PURPLE_LIGHT = "a232a8" +BRAND_PURPLE_DARK = "5e0066" + +# Foundation +BASE_BG = "16181a" +SURFACE_BG = "1f2225" +SURFACE_BG_ALT = "2a2e32" +OVERLAY_BG = "2e3236" +BORDER = "2e3236" +BORDER_STRONG = "3a3d41" + +# Text +TEXT_PRIMARY = "f2f2f2" +TEXT_SECONDARY = "a8a8a8" +TEXT_DISABLED = "6e7173" +TEXT_ON_ACCENT = "0a0a00" +TEXT_ON_SELECTION = "ffffff" + +# Semantic +SUCCESS = "27ae60" +WARNING = "f67400" +ERROR = "da4453" + + +def hex_to_rgb(h): + h = h.lstrip("#") + return (int(h[0:2], 16), int(h[2:4], 16), int(h[4:6], 16)) + + +def hex_to_hsv(h): + import colorsys + r, g, b = hex_to_rgb(h) + return colorsys.rgb_to_hsv(r / 255, g / 255, b / 255) diff --git a/assets/themes/gtk3-user-overrides.css b/assets/themes/gtk3-user-overrides.css new file mode 100644 index 0000000..4384d30 --- /dev/null +++ b/assets/themes/gtk3-user-overrides.css @@ -0,0 +1,6 @@ +/* NexusOS — user-level GTK3 overrides. + Symlinked to ~/.config/gtk-3.0/gtk.css so it lives with the rest of + the NexusOS theme in nexus-core. The theme proper is in NexusOS/. */ +* { + caret-color: #8cc63f; +} diff --git a/assets/themes/install-theme.sh b/assets/themes/install-theme.sh new file mode 100755 index 0000000..6dfe370 --- /dev/null +++ b/assets/themes/install-theme.sh @@ -0,0 +1,122 @@ +#!/usr/bin/env bash +# install-theme.sh — restore the NexusOS desktop theme wiring. +# +# The theme *assets* live in this repo (assets/themes/, management/Mint-Y-Nexus/). +# This script recreates everything OUTSIDE the repo that makes the desktop +# actually use them: symlinks, xfconf (xsettings + xfwm4), and the canonical +# lines in the GTK 3/4 settings.ini files. +# +# Idempotent and safe: re-running only fixes drift; any real file it would +# replace with a symlink is backed up to .bak-YYYYMMDD first. +# +# Usage: ./assets/themes/install-theme.sh (apply + reload) +# ./assets/themes/install-theme.sh --no-reload +set -euo pipefail + +REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +RELOAD=1 +[[ "${1:-}" == "--no-reload" ]] && RELOAD=0 +STAMP="$(date +%Y%m%d)" + +# Canonical values — keep in sync with assets/themes/NexusOS/index.theme +GTK_THEME="NexusOS" +ICON_THEME="NexusOS" +CURSOR_THEME="DMZ-White" +CURSOR_SIZE="24" +FONT_NAME="Ubuntu 10" + +say() { printf ' %s\n' "$*"; } + +# link : make linkname a symlink to target, backing up +# any pre-existing real file/dir that isn't already the correct link. +link() { + local target="$1" linkname="$2" + mkdir -p "$(dirname "$linkname")" + if [[ -L "$linkname" && "$(readlink -f "$linkname")" == "$(readlink -f "$target")" ]]; then + say "ok $linkname" + return + fi + if [[ -e "$linkname" || -L "$linkname" ]]; then + mv "$linkname" "$linkname.bak-$STAMP" + say "backup $linkname -> $linkname.bak-$STAMP" + fi + ln -sfn "$target" "$linkname" + say "link $linkname -> $target" +} + +# set_ini : ensure key=value under [Settings], +# creating the file/section/key as needed, replacing in place otherwise. +set_ini() { + local file="$1" key="$2" value="$3" + if [[ ! -f "$file" ]]; then + mkdir -p "$(dirname "$file")" + printf '[Settings]\n%s=%s\n' "$key" "$value" > "$file" + say "create $file ($key)" + return + fi + if grep -qE "^${key}=" "$file"; then + sed -i "s|^${key}=.*|${key}=${value}|" "$file" + else + sed -i "0,/^\[Settings\]/s//[Settings]\n${key}=${value}/" "$file" + fi + say "ini $file : $key=$value" +} + +xset() { # xfconf set, creating the prop with the right type if absent + local channel="$1" prop="$2" type="$3" val="$4" + command -v xfconf-query >/dev/null || return 0 + xfconf-query -c "$channel" -p "$prop" -n -t "$type" -s "$val" 2>/dev/null \ + || xfconf-query -c "$channel" -p "$prop" -s "$val" 2>/dev/null || true + say "xfconf $channel$prop = $val" +} + +echo "NexusOS theme — restoring wiring from $REPO" + +echo "[1/4] Symlinks" +link "$REPO/assets/themes/NexusOS" "$HOME/.themes/NexusOS" +link "$REPO/assets/themes/NexusOS-icons" "$HOME/.icons/NexusOS" +link "$REPO/management/Mint-Y-Nexus" "$HOME/.icons/Mint-Y-Nexus" +link "$REPO/assets/themes/gtk3-user-overrides.css" "$HOME/.config/gtk-3.0/gtk.css" + +echo "[2/4] xfconf (xsettings + xfwm4)" +xset xsettings /Net/ThemeName string "$GTK_THEME" +xset xsettings /Net/IconThemeName string "$ICON_THEME" +xset xsettings /Gtk/CursorThemeName string "$CURSOR_THEME" +xset xsettings /Gtk/CursorThemeSize int "$CURSOR_SIZE" +xset xsettings /Gtk/FontName string "$FONT_NAME" +xset xfwm4 /general/theme string "$GTK_THEME" + +echo "[3/4] GTK 3 / GTK 4 settings.ini" +for f in "$HOME/.config/gtk-3.0/settings.ini" "$HOME/.config/gtk-4.0/settings.ini"; do + set_ini "$f" gtk-theme-name "$GTK_THEME" + set_ini "$f" gtk-icon-theme-name "$ICON_THEME" + set_ini "$f" gtk-cursor-theme-name "$CURSOR_THEME" + set_ini "$f" gtk-cursor-theme-size "$CURSOR_SIZE" + set_ini "$f" gtk-font-name "$FONT_NAME" +done + +echo "[4/4] Sanity" +for dir in /usr/share/icons ~/.icons ~/.local/share/icons; do + [[ -d "$dir/$CURSOR_THEME" ]] && { say "ok cursor '$CURSOR_THEME' found"; CUR_OK=1; break; } +done +[[ "${CUR_OK:-0}" == 1 ]] || say "WARN cursor theme '$CURSOR_THEME' not installed — will fall back" +INH="$(grep -i '^Inherits=' "$REPO/assets/themes/NexusOS-icons/index.theme" 2>/dev/null | cut -d= -f2)" +if [[ -n "$INH" ]]; then + INH_OK=0 + for dir in /usr/share/icons ~/.icons ~/.local/share/icons; do + [[ -d "$dir/$INH" ]] && { INH_OK=1; break; } + done + [[ "$INH_OK" == 1 ]] \ + && say "ok icon fallback '$INH' found" \ + || say "WARN icon fallback '$INH' not installed — icons may be missing" +fi + +if [[ "$RELOAD" == 1 ]] && command -v xfconf-query >/dev/null && [[ -n "${DISPLAY:-}" ]]; then + xfconf-query -c xsettings -p /Net/ThemeName -s "Adwaita" 2>/dev/null || true + xfconf-query -c xsettings -p /Net/ThemeName -s "$GTK_THEME" 2>/dev/null || true + command -v xfdesktop >/dev/null && (xfdesktop --reload >/dev/null 2>&1 &) || true + command -v xfce4-panel >/dev/null && (xfce4-panel -r >/dev/null 2>&1 &) || true + echo "Reloaded. (some already-running apps may need a restart)" +else + echo "Done. Skipped live reload (no X session or --no-reload)." +fi diff --git a/bin/backup-smart.sh b/bin/backup-smart.sh new file mode 100755 index 0000000..ff9ced9 --- /dev/null +++ b/bin/backup-smart.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +NEXUS_ROOT="$HOME/nexus-core" + +rsync -avz --delete \ + --exclude='Promethean/' \ + --exclude='models/blobs/' \ + --exclude='ollama/' \ + --exclude='management/Mint-Y-Nexus/' \ + --exclude='interface/web/node_modules/' \ + --exclude='interface/web/dist/' \ + --exclude='runtime/' \ + --exclude='__pycache__/' \ + --exclude='*.pyc' \ + -e ssh \ + "$NEXUS_ROOT/" "router:/tmp/mnt/Wingdrive2/nexus-backup/" diff --git a/bin/backup.sh b/bin/backup.sh new file mode 100755 index 0000000..186bff7 --- /dev/null +++ b/bin/backup.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +lftp sftp://router:2022 << 'LFTP' +set sftp:connect-program "ssh -a -x -p 2022" +set cmd:interactive yes +mirror --reverse --delete --verbose --dereference --exclude "^Promethean/" --exclude "^models/blobs/" --exclude "^ollama/" --exclude "^interface/web/node_modules/" --exclude "^interface/web/dist/" --exclude "^runtime/logs/" --exclude "runtime/backend\.log$" --exclude "runtime/frontend\.log$" --exclude "__pycache__" --exclude "\.pyc$" /home/jon/nexus-core /Wingdrive2/nexus-backup +quit +LFTP diff --git a/bin/gen-nvidia-reqs.py b/bin/gen-nvidia-reqs.py new file mode 100644 index 0000000..c9bc650 --- /dev/null +++ b/bin/gen-nvidia-reqs.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 + +import re, subprocess, sys +from pathlib import Path + +NEXUS_ROOT = Path.home() / "nexus-core" +NVIDIA_REQS = NEXUS_ROOT / "nvidia_requirements.txt" + +CUDA_TO_WHEEL = [ + ((12, 8), "cu128"), + ((12, 6), "cu126"), + ((12, 4), "cu124"), + ((12, 1), "cu121"), + ((11, 8), "cu118"), +] + +def detect_cuda(): + try: + out = subprocess.run(["nvidia-smi"], capture_output=True, text=True, timeout=10).stdout + m = re.search(r"CUDA Version:\s*(\d+)\.(\d+)", out) + if m: + return int(m.group(1)), int(m.group(2)) + except (FileNotFoundError, subprocess.TimeoutExpired): + pass + return None, None + +def wheel_suffix(major, minor): + for (req_major, req_minor), suffix in CUDA_TO_WHEEL: + if (major, minor) >= (req_major, req_minor): + return suffix + return "cu118" + +def main(): + print("Detecting NVIDIA GPU...") + major, minor = detect_cuda() + + if major is None: + print("Error: nvidia-smi not found or CUDA version unreadable.") + print("Ensure NVIDIA drivers are installed and nvidia-smi is on your PATH.") + sys.exit(1) + + print(f"CUDA {major}.{minor} detected.") + suffix = wheel_suffix(major, minor) + print(f"PyTorch wheel: {suffix}") + + NVIDIA_REQS.write_text(f"""\ +# --- Force NVIDIA/CUDA Priority --- +--index-url https://download.pytorch.org/whl/{suffix} +--extra-index-url https://pypi.org/simple + +-r requirements-base.txt + +# GPU Compute Stack +torch +torchaudio +torchvision +""") + + print(f"\nWritten: {NVIDIA_REQS}") + print("Run 'ncp backup' to push it to the router.") + +if __name__ == "__main__": + main() diff --git a/bin/install.sh b/bin/install.sh new file mode 100755 index 0000000..a868a0a --- /dev/null +++ b/bin/install.sh @@ -0,0 +1,185 @@ +#!/bin/bash + +NEXUS_ROOT="$HOME/nexus-core" +ROUTER_BACKUP="router:/tmp/mnt/Wingdrive2/nexus-backup/" + +# ─── Helpers ────────────────────────────────────────────────────────────────── + +is_wsl() { + grep -qi microsoft /proc/version 2>/dev/null +} + +detect_requirements() { + if command -v nvidia-smi &>/dev/null && nvidia-smi &>/dev/null 2>&1; then + echo "nvidia_requirements.txt" + elif lspci 2>/dev/null | grep -qi nvidia; then + echo "nvidia_requirements.txt" + else + echo "amd_requirements.txt" + fi +} + +get_windows_user() { + powershell.exe -command '$env:USERNAME' 2>/dev/null | tr -d '\r\n' +} + +setup_windows() { + local win_user distro icon_src icon_win_dir icon_win_path wt_settings + + win_user=$(get_windows_user) + distro="${WSL_DISTRO_NAME:-$(uname -n)}" + + if [ -z "$win_user" ] || [ ! -d "/mnt/c/Users/$win_user" ]; then + echo "Could not locate Windows user directory — skipping Windows setup." + return 1 + fi + + # Copy icon to Windows filesystem + icon_src="$NEXUS_ROOT/assets/nexus-terminal.png" + icon_win_dir="/mnt/c/Users/$win_user/AppData/Local/Nexus" + mkdir -p "$icon_win_dir" + cp "$icon_src" "$icon_win_dir/nexus-terminal.png" + icon_win_path="C:\\Users\\$win_user\\AppData\\Local\\Nexus\\nexus-terminal.png" + + # Create combined init file so WT session has ncp, nvm, and Promethean prompt + cat > "$HOME/.promethean_init" << 'EOF' +[[ -f ~/.bashrc ]] && source ~/.bashrc +[[ -f ~/.promethean_bashrc ]] && source ~/.promethean_bashrc +EOF + + # Patch Windows Terminal settings.json + python3 - "$win_user" "$distro" "$icon_win_path" << 'PYEOF' +import json, uuid, sys +from pathlib import Path + +win_user, distro, icon_path = sys.argv[1], sys.argv[2], sys.argv[3] + +wt_candidates = [ + f"/mnt/c/Users/{win_user}/AppData/Local/Packages/Microsoft.WindowsTerminal_8wekyb3d8bbwe/LocalState/settings.json", + f"/mnt/c/Users/{win_user}/AppData/Local/Packages/Microsoft.WindowsTerminalPreview_8wekyb3d8bbwe/LocalState/settings.json", +] + +settings_path = next((Path(p) for p in wt_candidates if Path(p).exists()), None) + +if not settings_path: + print("Windows Terminal settings.json not found — skipping.") + sys.exit(0) + +with open(settings_path) as f: + settings = json.load(f) + +profiles = settings.setdefault("profiles", {}).setdefault("list", []) + +if any(p.get("name") == "Promethean" for p in profiles): + print("Promethean profile already exists — skipping.") + sys.exit(0) + +profiles.insert(0, { + "guid": "{" + str(uuid.uuid4()) + "}", + "name": "Promethean", + "commandline": f"wsl.exe -d {distro} bash --init-file ~/.promethean_init", + "startingDirectory": "~", + "icon": icon_path, +}) + +with open(settings_path, "w") as f: + json.dump(settings, f, indent=4) + +print(f"Promethean profile added to Windows Terminal ({settings_path.parent.parent.name}).") +PYEOF + + # Create desktop shortcut + powershell.exe -command " +\$ws = New-Object -ComObject WScript.Shell +\$s = \$ws.CreateShortcut(\"\$env:USERPROFILE\Desktop\Promethean.lnk\") +\$s.TargetPath = 'wt.exe' +\$s.Arguments = '--profile Promethean' +\$s.IconLocation = 'wt.exe,0' +\$s.Save() +" 2>/dev/null && echo "Desktop shortcut created." || echo "Could not create desktop shortcut — open Windows Terminal manually." +} + +# ─── Step 1: Sync from router ───────────────────────────────────────────────── + +echo "Pulling Nexus from router..." +mkdir -p "$NEXUS_ROOT" +rsync -avz --delete \ + --exclude='Promethean/' \ + --exclude='models/blobs/' \ + --exclude='ollama/' \ + --exclude='interface/web/node_modules/' \ + --exclude='interface/web/dist/' \ + --exclude='runtime/' \ + --exclude='__pycache__/' \ + --exclude='*.pyc' \ + -e ssh \ + "$ROUTER_BACKUP" "$NEXUS_ROOT/" + +# ─── Step 2: Python venv ────────────────────────────────────────────────────── + +echo "" +echo "Creating Python environment..." +python3 -m venv "$NEXUS_ROOT/Promethean" + +# ─── Step 3: pip install ────────────────────────────────────────────────────── + +echo "" +echo "Installing Python dependencies..." +req=$(detect_requirements) +echo "Detected: $req" +if [ -f "$NEXUS_ROOT/$req" ]; then + "$NEXUS_ROOT/Promethean/bin/pip" install --upgrade pip -q + "$NEXUS_ROOT/Promethean/bin/pip" install -r "$NEXUS_ROOT/$req" +else + echo "Warning: $req not found — skipping pip install." +fi + +# ─── Step 4: npm install ────────────────────────────────────────────────────── + +echo "" +echo "Installing frontend dependencies..." +export NVM_DIR="$HOME/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" +if command -v npm &>/dev/null; then + cd "$NEXUS_ROOT/interface/web" && npm install +else + echo "npm not found — install nvm/node then run 'cd $NEXUS_ROOT/interface/web && npm install'." +fi + +# ─── Step 5: Register ncp in ~/.bashrc ─────────────────────────────────────── + +echo "" +echo "Registering ncp..." +if ! grep -q "nexus-core/management/nexus-cli.sh" "$HOME/.bashrc"; then + cat >> "$HOME/.bashrc" << 'EOF' + +# Nexus +ncp() { + ~/nexus-core/management/nexus-cli.sh "$@" +} +alias promethean='source ~/.promethean_bashrc' +EOF + echo "ncp registered in ~/.bashrc." +else + echo "ncp already in ~/.bashrc — skipping." +fi + +# ─── Step 6: Windows Terminal + desktop shortcut ────────────────────────────── + +if is_wsl; then + echo "" + echo "Configuring Windows environment..." + setup_windows || true + echo "" + echo "Reload your shell or open a new terminal for ncp to take effect." +fi + +# ─── Done ───────────────────────────────────────────────────────────────────── + +echo "" +echo "Installation complete. Nexus is ready." +if is_wsl; then + echo "Open Windows Terminal → Promethean profile, or use the desktop shortcut." +else + echo "Run 'ncp start' to launch Nexus." +fi diff --git a/bin/promethean-terminal b/bin/promethean-terminal new file mode 100755 index 0000000..c668abd --- /dev/null +++ b/bin/promethean-terminal @@ -0,0 +1,3 @@ +#!/bin/bash +export GDK_PROGRAM_CLASS=promethean-terminal +exec xfce4-terminal --working-directory ~ -e "bash --rcfile ~/.promethean_bashrc -i" "$@" diff --git a/bin/restore-full.sh b/bin/restore-full.sh new file mode 100755 index 0000000..1b580c8 --- /dev/null +++ b/bin/restore-full.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +NEXUS_ROOT="$HOME/nexus-core" + +detect_requirements() { + if command -v nvidia-smi &>/dev/null || lspci 2>/dev/null | grep -qi nvidia; then + echo "nvidia_requirements.txt" + else + echo "amd_requirements.txt" + fi +} + +echo "Restoring full Nexus backup from router..." +lftp sftp://router:2022 << 'LFTP' +set sftp:connect-program "ssh -a -x -p 2022" +set cmd:interactive yes +mirror --delete --verbose --dereference --exclude "^Promethean/" --exclude "^models/blobs/" --exclude "^ollama/" --exclude "^interface/web/node_modules/" --exclude "^interface/web/dist/" --exclude "^runtime/" --exclude "__pycache__" --exclude "\.pyc$" /Wingdrive2/nexus-backup /home/jon/nexus-core +quit +LFTP + +echo "" +echo "Rebuilding Python environment..." +req=$(detect_requirements) +if [ -f "$NEXUS_ROOT/$req" ]; then + "$NEXUS_ROOT/Promethean/bin/pip" install -r "$NEXUS_ROOT/$req" +else + echo "Warning: $req not found — skipping pip install." +fi + +echo "" +echo "Rebuilding frontend dependencies..." +cd "$NEXUS_ROOT/interface/web" && npm install + +echo "" +echo "Restore complete. Nexus is ready to start." diff --git a/bin/restore.sh b/bin/restore.sh new file mode 100755 index 0000000..c81127e --- /dev/null +++ b/bin/restore.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +NEXUS_ROOT="$HOME/nexus-core" + +detect_requirements() { + if command -v nvidia-smi &>/dev/null || lspci 2>/dev/null | grep -qi nvidia; then + echo "nvidia_requirements.txt" + else + echo "amd_requirements.txt" + fi +} + +echo "Restoring Nexus from router..." +rsync -avz --delete \ + --exclude='Promethean/' \ + --exclude='models/blobs/' \ + --exclude='ollama/' \ + --exclude='interface/web/node_modules/' \ + --exclude='interface/web/dist/' \ + --exclude='runtime/' \ + --exclude='__pycache__/' \ + --exclude='*.pyc' \ + -e ssh \ + "router:/tmp/mnt/Wingdrive2/nexus-backup/" "$NEXUS_ROOT/" + +echo "" +echo "Rebuilding Python environment..." +req=$(detect_requirements) +if [ -f "$NEXUS_ROOT/$req" ]; then + "$NEXUS_ROOT/Promethean/bin/pip" install -r "$NEXUS_ROOT/$req" +else + echo "Warning: $req not found — skipping pip install." +fi + +echo "" +echo "Rebuilding frontend dependencies..." +cd "$NEXUS_ROOT/interface/web" && npm install + +echo "" +echo "Restore complete. Nexus is ready to start." diff --git a/interface/web/.gitignore b/interface/web/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/interface/web/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/interface/web/.nvmrc b/interface/web/.nvmrc new file mode 100644 index 0000000..209e3ef --- /dev/null +++ b/interface/web/.nvmrc @@ -0,0 +1 @@ +20 diff --git a/interface/web/README.md b/interface/web/README.md new file mode 100644 index 0000000..a36934d --- /dev/null +++ b/interface/web/README.md @@ -0,0 +1,16 @@ +# React + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs) +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) + +## React Compiler + +The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation). + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project. diff --git a/interface/web/eslint.config.js b/interface/web/eslint.config.js new file mode 100644 index 0000000..4fa125d --- /dev/null +++ b/interface/web/eslint.config.js @@ -0,0 +1,29 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import { defineConfig, globalIgnores } from 'eslint/config' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{js,jsx}'], + extends: [ + js.configs.recommended, + reactHooks.configs.flat.recommended, + reactRefresh.configs.vite, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + parserOptions: { + ecmaVersion: 'latest', + ecmaFeatures: { jsx: true }, + sourceType: 'module', + }, + }, + rules: { + 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }], + }, + }, +]) diff --git a/interface/web/index.html b/interface/web/index.html new file mode 100644 index 0000000..6c697db --- /dev/null +++ b/interface/web/index.html @@ -0,0 +1,13 @@ + + + + + + + NexusOS + + +
+ + + diff --git a/interface/web/package-lock.json b/interface/web/package-lock.json new file mode 100644 index 0000000..dfe520c --- /dev/null +++ b/interface/web/package-lock.json @@ -0,0 +1,2603 @@ +{ + "name": "web", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "web", + "version": "0.0.0", + "dependencies": { + "react": "^19.2.4", + "react-dom": "^19.2.4" + }, + "devDependencies": { + "@eslint/js": "^9.39.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "eslint": "^9.39.4", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-refresh": "^0.5.2", + "globals": "^17.4.0", + "vite": "^8.0.4" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz", + "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", + "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.124.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.124.0.tgz", + "integrity": "sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.15.tgz", + "integrity": "sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.15.tgz", + "integrity": "sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.15.tgz", + "integrity": "sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.15.tgz", + "integrity": "sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.15.tgz", + "integrity": "sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.15.tgz", + "integrity": "sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.15.tgz", + "integrity": "sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.15.tgz", + "integrity": "sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.15.tgz", + "integrity": "sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.9.2", + "@emnapi/runtime": "1.9.2", + "@napi-rs/wasm-runtime": "^1.1.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.15.tgz", + "integrity": "sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.15.tgz", + "integrity": "sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.7", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.7.tgz", + "integrity": "sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.1.tgz", + "integrity": "sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-rc.7" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.19.tgz", + "integrity": "sha512-qCkNLi2sfBOn8XhZQ0FXsT1Ki/Yo5P90hrkRamVFRS7/KV9hpfA4HkoWNU152+8w0zPjnxo5psx5NL3PSGgv5g==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001788", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001788.tgz", + "integrity": "sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.336", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.336.tgz", + "integrity": "sha512-AbH9q9J455r/nLmdNZes0G0ZKcRX73FicwowalLs6ijwOmCJSRRrLX63lcAlzy9ux3dWK1w1+1nsBJEWN11hcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz", + "integrity": "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.5.2.tgz", + "integrity": "sha512-hmgTH57GfzoTFjVN0yBwTggnsVUF2tcqi7RJZHqi9lIezSs4eFyAMktA68YD4r5kNw1mxyY4dmkyoFDb3FIqrA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": "^9 || ^10" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "17.5.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.5.0.tgz", + "integrity": "sha512-qoV+HK2yFl/366t2/Cb3+xxPUo5BuMynomoDmiaZBIdbs+0pYbjfZU+twLhGKp4uCZ/+NbtpVepH5bGCxRyy2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.37", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.37.tgz", + "integrity": "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==", + "dev": true, + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", + "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/react": { + "version": "19.2.5", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.5.tgz", + "integrity": "sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.5", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.5.tgz", + "integrity": "sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.5" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/rolldown": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.15.tgz", + "integrity": "sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.124.0", + "@rolldown/pluginutils": "1.0.0-rc.15" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-rc.15", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.15", + "@rolldown/binding-darwin-x64": "1.0.0-rc.15", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.15", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.15", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.15", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.15", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.15", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.15", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.15", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.15" + } + }, + "node_modules/rolldown/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.15.tgz", + "integrity": "sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==", + "dev": true, + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vite": { + "version": "8.0.8", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.8.tgz", + "integrity": "sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.8", + "rolldown": "1.0.0-rc.15", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + } + } +} diff --git a/interface/web/package.json b/interface/web/package.json new file mode 100644 index 0000000..244254d --- /dev/null +++ b/interface/web/package.json @@ -0,0 +1,27 @@ +{ + "name": "web", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "react": "^19.2.4", + "react-dom": "^19.2.4" + }, + "devDependencies": { + "@eslint/js": "^9.39.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "eslint": "^9.39.4", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-refresh": "^0.5.2", + "globals": "^17.4.0", + "vite": "^8.0.4" + } +} diff --git a/interface/web/public/favicon.svg b/interface/web/public/favicon.svg new file mode 100644 index 0000000..6893eb1 --- /dev/null +++ b/interface/web/public/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/interface/web/public/icons.svg b/interface/web/public/icons.svg new file mode 100644 index 0000000..e952219 --- /dev/null +++ b/interface/web/public/icons.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interface/web/public/n small.png b/interface/web/public/n small.png new file mode 100644 index 0000000..c96bb05 Binary files /dev/null and b/interface/web/public/n small.png differ diff --git a/interface/web/src/App.css b/interface/web/src/App.css new file mode 100644 index 0000000..f90339d --- /dev/null +++ b/interface/web/src/App.css @@ -0,0 +1,184 @@ +.counter { + font-size: 16px; + padding: 5px 10px; + border-radius: 5px; + color: var(--accent); + background: var(--accent-bg); + border: 2px solid transparent; + transition: border-color 0.3s; + margin-bottom: 24px; + + &:hover { + border-color: var(--accent-border); + } + &:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; + } +} + +.hero { + position: relative; + + .base, + .framework, + .vite { + inset-inline: 0; + margin: 0 auto; + } + + .base { + width: 170px; + position: relative; + z-index: 0; + } + + .framework, + .vite { + position: absolute; + } + + .framework { + z-index: 1; + top: 34px; + height: 28px; + transform: perspective(2000px) rotateZ(300deg) rotateX(44deg) rotateY(39deg) + scale(1.4); + } + + .vite { + z-index: 0; + top: 107px; + height: 26px; + width: auto; + transform: perspective(2000px) rotateZ(300deg) rotateX(40deg) rotateY(39deg) + scale(0.8); + } +} + +#center { + display: flex; + flex-direction: column; + gap: 25px; + place-content: center; + place-items: center; + flex-grow: 1; + + @media (max-width: 1024px) { + padding: 32px 20px 24px; + gap: 18px; + } +} + +#next-steps { + display: flex; + border-top: 1px solid var(--border); + text-align: left; + + & > div { + flex: 1 1 0; + padding: 32px; + @media (max-width: 1024px) { + padding: 24px 20px; + } + } + + .icon { + margin-bottom: 16px; + width: 22px; + height: 22px; + } + + @media (max-width: 1024px) { + flex-direction: column; + text-align: center; + } +} + +#docs { + border-right: 1px solid var(--border); + + @media (max-width: 1024px) { + border-right: none; + border-bottom: 1px solid var(--border); + } +} + +#next-steps ul { + list-style: none; + padding: 0; + display: flex; + gap: 8px; + margin: 32px 0 0; + + .logo { + height: 18px; + } + + a { + color: var(--text-h); + font-size: 16px; + border-radius: 6px; + background: var(--social-bg); + display: flex; + padding: 6px 12px; + align-items: center; + gap: 8px; + text-decoration: none; + transition: box-shadow 0.3s; + + &:hover { + box-shadow: var(--shadow); + } + .button-icon { + height: 18px; + width: 18px; + } + } + + @media (max-width: 1024px) { + margin-top: 20px; + flex-wrap: wrap; + justify-content: center; + + li { + flex: 1 1 calc(50% - 8px); + } + + a { + width: 100%; + justify-content: center; + box-sizing: border-box; + } + } +} + +#spacer { + height: 88px; + border-top: 1px solid var(--border); + @media (max-width: 1024px) { + height: 48px; + } +} + +.ticks { + position: relative; + width: 100%; + + &::before, + &::after { + content: ''; + position: absolute; + top: -4.5px; + border: 5px solid transparent; + } + + &::before { + left: 0; + border-left-color: var(--border); + } + &::after { + right: 0; + border-right-color: var(--border); + } +} diff --git a/interface/web/src/App.jsx b/interface/web/src/App.jsx new file mode 100644 index 0000000..dc76e46 --- /dev/null +++ b/interface/web/src/App.jsx @@ -0,0 +1,338 @@ +import { useCallback, useEffect, useRef, useState } from "react"; +import { Chatbot } from "./Chatbot"; +import { Playbook } from "./Playbook"; +import { Models } from "./Models"; +import { Settings } from "./Settings"; +import { Memory } from "./Memory"; + +import { API_BASE } from "./config"; + +function timeAgo(epochSeconds) { + const diff = Math.floor(Date.now() / 1000) - epochSeconds; + if (diff < 60) return "just now"; + if (diff < 3600) return `${Math.floor(diff / 60)}m ago`; + if (diff < 86400) return `${Math.floor(diff / 3600)}h ago`; + if (diff < 604800) return `${Math.floor(diff / 86400)}d ago`; + return new Date(epochSeconds * 1000).toLocaleDateString(); +} + +function App() { + const [currentPage, setCurrentPage] = useState("chatbot"); + const [status, setStatus] = useState("Checking Synapse..."); + const [ollamaStatus, setOllamaStatus] = useState("checking"); + const [showStatusTooltip, setShowStatusTooltip] = useState(false); + + const [activeConversationId, setActiveConversationId] = useState(() => crypto.randomUUID()); + const [conversations, setConversations] = useState([]); + const [search, setSearch] = useState(""); + const [hoveredConvId, setHoveredConvId] = useState(null); + const searchDebounce = useRef(null); + + const loadStatus = () => { + fetch(`${API_BASE}/`) + .then(r => r.json()) + .then(d => { + setStatus(d.status ?? "Unknown"); + setOllamaStatus(d.ollama ?? "unavailable"); + }) + .catch(() => { + setStatus("Offline"); + setOllamaStatus("unavailable"); + }); + }; + + const loadConversations = useCallback(async (q = "") => { + try { + const url = q.trim() + ? `${API_BASE}/conversations?q=${encodeURIComponent(q.trim())}` + : `${API_BASE}/conversations`; + const response = await fetch(url); + if (response.ok) { + const data = await response.json(); + setConversations(data.conversations || []); + } + } catch (error) { + console.error("Failed to load conversations:", error); + } + }, []); + + useEffect(() => { + loadStatus(); + const interval = setInterval(loadStatus, 5000); + return () => clearInterval(interval); + }, []); + + useEffect(() => { + let cancelled = false; + fetch(`${API_BASE}/conversations`) + .then(r => r.ok ? r.json() : null) + .then(data => { + if (cancelled || !data) return; + setConversations(data.conversations || []); + }) + .catch(err => console.error("Failed to load conversations:", err)); + return () => { cancelled = true; }; + }, []); + + const handleSearch = (e) => { + const q = e.target.value; + setSearch(q); + clearTimeout(searchDebounce.current); + searchDebounce.current = setTimeout(() => loadConversations(q), 300); + }; + + const selectConversation = (id) => { + setActiveConversationId(id); + setCurrentPage("chatbot"); + }; + + const startNewChat = () => { + setActiveConversationId(crypto.randomUUID()); + setCurrentPage("chatbot"); + }; + + const deleteConversation = async (e, conversationId) => { + e.stopPropagation(); + if (!window.confirm("Delete this conversation?")) return; + try { + const response = await fetch(`${API_BASE}/conversations/${conversationId}`, { method: "DELETE" }); + if (response.ok) { + if (activeConversationId === conversationId) { + setActiveConversationId(crypto.randomUUID()); + } + loadConversations(search); + } + } catch (error) { + console.error("Failed to delete conversation:", error); + } + }; + + const navItems = [ + { key: "chatbot", label: "💬 Chatbot" }, + { key: "playbook", label: "📖 Playbook" }, + { key: "models", label: "🤖 Models" }, + { key: "memory", label: "🧠 Memory" }, + { key: "settings", label: "⚙️ Settings" }, + ]; + + return ( +
+ {/* Sidebar */} + + + {/* Main Content */} +
+ {currentPage === "chatbot" ? ( + loadConversations(search)} + /> + ) + : currentPage === "playbook" ? + : currentPage === "models" ? + : currentPage === "memory" ? + : } +
+
+ ); +} + +export default App; diff --git a/interface/web/src/Chatbot.jsx b/interface/web/src/Chatbot.jsx new file mode 100644 index 0000000..d3c498c --- /dev/null +++ b/interface/web/src/Chatbot.jsx @@ -0,0 +1,453 @@ +import { useState, useRef, useEffect } from "react"; + +import { API_BASE } from "./config"; +import { Markdown } from "./Markdown"; + +export function Chatbot({ status, conversationId, setConversationId, onConversationChanged }) { + const [messages, setMessages] = useState([]); + const [input, setInput] = useState(""); + const [loading, setLoading] = useState(false); + const [modelList, setModelList] = useState([]); + const [selectedModel, setSelectedModel] = useState(""); // "" = auto + const [autoModel, setAutoModel] = useState(null); + const [showPicker, setShowPicker] = useState(false); + const [copiedIdx, setCopiedIdx] = useState(null); + const [lastStats, setLastStats] = useState(null); + const [memoryToast, setMemoryToast] = useState(null); + + const abortRef = useRef(null); + const messagesEndRef = useRef(null); + const pickerRef = useRef(null); + + useEffect(() => { + messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); + }, [messages]); + + useEffect(() => { + if (!conversationId) return; + if (abortRef.current) abortRef.current.abort(); + let cancelled = false; + setLastStats(null); + fetch(`${API_BASE}/conversations/${conversationId}`) + .then(r => r.ok ? r.json() : null) + .then(data => { + if (cancelled) return; + setMessages(data?.messages?.map(m => ({ role: m.role, content: m.content })) || []); + }) + .catch(() => { if (!cancelled) setMessages([]); }); + return () => { cancelled = true; }; + }, [conversationId]); + + useEffect(() => { + Promise.all([ + fetch(`${API_BASE}/models`).then(r => r.ok ? r.json() : null), + fetch(`${API_BASE}/settings`).then(r => r.ok ? r.json() : null), + ]).then(([models, settings]) => { + if (models?.models) setModelList(models.models); + if (models?.selected) setAutoModel(models.selected); + if (settings) setSelectedModel(settings.model || ""); + }).catch(() => {}); + }, []); + + useEffect(() => { + if (!showPicker) return; + const handle = (e) => { + if (pickerRef.current && !pickerRef.current.contains(e.target)) setShowPicker(false); + }; + document.addEventListener("mousedown", handle); + return () => document.removeEventListener("mousedown", handle); + }, [showPicker]); + + const setModelChoice = async (model) => { + setSelectedModel(model); + setShowPicker(false); + try { + await fetch(`${API_BASE}/settings`, { + method: "PUT", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ model }), + }); + } catch {} + }; + + const startNewChat = () => { + if (abortRef.current) abortRef.current.abort(); + setInput(""); + setLoading(false); + setLastStats(null); + setConversationId(crypto.randomUUID()); + }; + + const sendMessage = async () => { + if (!input.trim() || loading) return; + + const userMessage = input.trim(); + setInput(""); + + // Add user message + setMessages(prev => [...prev, { role: "user", content: userMessage }]); + + // Prepare assistant placeholder + const assistantIndex = messages.length + 1; + setMessages(prev => [...prev, { role: "assistant", content: "" }]); + + setLoading(true); + + // Abort previous stream if still open + if (abortRef.current) abortRef.current.abort(); + const controller = new AbortController(); + abortRef.current = controller; + + try { + // Exclude the empty assistant placeholder that was just appended + const historySnapshot = messages.filter(m => m.content.trim() !== ""); + + const response = await fetch(`${API_BASE}/chat/stream`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + message: userMessage, + conversation_id: conversationId, + history: historySnapshot.map(m => ({ role: m.role, content: m.content })), + }), + signal: controller.signal, + }); + + if (!response.ok) { + const text = await response.text(); + updateAssistant(assistantIndex, `Error: ${text}`); + setLoading(false); + return; + } + + const reader = response.body.getReader(); + const decoder = new TextDecoder(); + + let buffer = ""; + let pendingEventType = null; + + while (true) { + const { value, done } = await reader.read(); + if (done) break; + + buffer += decoder.decode(value, { stream: true }); + + const lines = buffer.split("\n"); + buffer = lines.pop(); + + for (const line of lines) { + if (line.startsWith("event: ")) { + pendingEventType = line.slice(7).trim(); + continue; + } + if (line.startsWith("data: ")) { + const payload = line.slice(6); + if (!payload.trim()) { pendingEventType = null; continue; } + + if (pendingEventType === "meta") { + try { setLastStats(JSON.parse(payload)); } catch { /* ignore */ } + pendingEventType = null; + continue; + } + if (pendingEventType === "memory") { + try { + const mem = JSON.parse(payload); + setMemoryToast(mem); + setTimeout(() => setMemoryToast(null), 5000); + } catch { /* ignore */ } + pendingEventType = null; + continue; + } + if (pendingEventType === "error") { + try { + const err = JSON.parse(payload); + updateAssistant(assistantIndex, `Error: ${err.detail || payload}`); + } catch { + updateAssistant(assistantIndex, `Error: ${payload}`); + } + pendingEventType = null; + setLoading(false); + return; + } + pendingEventType = null; + + setMessages(prev => { + const updated = [...prev]; + updated[assistantIndex] = { + ...updated[assistantIndex], + content: (updated[assistantIndex].content || "") + payload, + }; + return updated; + }); + } + } + } + + } catch (err) { + if (err.name !== "AbortError") { + updateAssistant(assistantIndex, `Connection error: ${err.message}`); + } + } finally { + setLoading(false); + if (onConversationChanged) onConversationChanged(); + } + }; + + const updateAssistant = (index, text) => { + setMessages(prev => { + const updated = [...prev]; + updated[index] = { ...updated[index], content: text }; + return updated; + }); + }; + + const handleKeyDown = (e) => { + if (e.key === "Enter" && !e.shiftKey) { + e.preventDefault(); + sendMessage(); + } + }; + + return ( +
+ {memoryToast && ( +
+ 🧠 Memory saved [{memoryToast.section}]
+ {memoryToast.text} +
+ )} +
+ {/* Header */} +
+
+ + {messages.length === 0 ? "New conversation" : `${Math.ceil(messages.length / 2)} exchange${messages.length > 2 ? "s" : ""}`} + +
+ + {showPicker && ( +
+
setModelChoice("")} + style={{ + padding: "0.55rem 0.85rem", + cursor: "pointer", + fontSize: "0.8rem", + color: !selectedModel ? "#7aa" : "#888", + background: !selectedModel ? "#1a2a2a" : "transparent", + borderBottom: "1px solid #262626", + display: "flex", + justifyContent: "space-between", + alignItems: "center", + }} + > + Auto {autoModel ? `(${autoModel})` : ""} + {!selectedModel && } +
+ {modelList.map(m => ( +
setModelChoice(m)} + style={{ + padding: "0.55rem 0.85rem", + cursor: "pointer", + fontSize: "0.8rem", + color: selectedModel === m ? "#7aa" : "#ccc", + background: selectedModel === m ? "#1a2a2a" : "transparent", + display: "flex", + justifyContent: "space-between", + alignItems: "center", + }} + > + {m} + {selectedModel === m && } +
+ ))} +
+ )} +
+ {lastStats && ( + + {lastStats.tokens} tok · {lastStats.elapsed_s}s + {lastStats.tokens_per_s > 0 ? ` · ${lastStats.tokens_per_s} t/s` : ""} + + )} +
+ +
+ +
+ {messages.length === 0 ? ( +
+

Start a conversation with the chatbot...

+
+ ) : ( + messages.map((msg, idx) => ( +
+
+ {msg.role === "user" + ? {msg.content} + : msg.content + ? + : Thinking... + } +
+ {msg.content && ( + + )} +
+ )) + )} + +
+
+ +
+