diff --git a/.dockerignore b/.dockerignore
index 289e7d21..35379377 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,5 +1,5 @@
-/build
-/node_modules
-/.git
-/.vscode
+/build
+/node_modules
+/.git
+/.vscode
/.github
\ No newline at end of file
diff --git a/.github/workflows/deploy-pages.yml b/.github/workflows/deploy-pages.yml
index 8274e0ec..6e23b087 100644
--- a/.github/workflows/deploy-pages.yml
+++ b/.github/workflows/deploy-pages.yml
@@ -1,58 +1,58 @@
-name: Deploy to GitHub Pages
-
-on:
- push:
- branches:
- - main
- pull_request:
- branches:
- - main
-
-permissions:
- contents: read
- pages: write
- id-token: write
-
-concurrency:
- group: "pages"
- cancel-in-progress: false
-
-jobs:
- deploy:
- runs-on: ubuntu-latest
- environment:
- name: github-pages
- url: ${{ steps.deployment.outputs.page_url }}
-
- steps:
- - name: Checkout code
- uses: actions/checkout@v5
-
- - name: Set up Node.js
- uses: actions/setup-node@v6
- with:
- node-version: "lts/*"
- cache: npm
-
- - name: Disable AppArmor
- run: echo 0 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns
-
- - name: Install dependencies
- run: npm ci
-
- - name: Build project
- run: npm run build
- env:
- PUBLIC_PATH: /Yasgui/
-
- - name: Setup Pages
- uses: actions/configure-pages@v4
-
- - name: Upload artifact
- uses: actions/upload-pages-artifact@v3
- with:
- path: ./build
-
- - name: Deploy to GitHub Pages
- id: deployment
- uses: actions/deploy-pages@v4
+name: Deploy to GitHub Pages
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+ branches:
+ - main
+
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+concurrency:
+ group: "pages"
+ cancel-in-progress: false
+
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v5
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v6
+ with:
+ node-version: "lts/*"
+ cache: npm
+
+ - name: Disable AppArmor
+ run: echo 0 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns
+
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Build project
+ run: npm run build
+ env:
+ PUBLIC_PATH: /Yasgui/
+
+ - name: Setup Pages
+ uses: actions/configure-pages@v4
+
+ - name: Upload artifact
+ uses: actions/upload-pages-artifact@v3
+ with:
+ path: ./build
+
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 9d56bc41..ad009063 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -1,60 +1,60 @@
-name: Publish to npm
-
-on:
- release:
- types: [published]
-
-permissions:
- contents: read
- id-token: write
-
-jobs:
- publish:
- runs-on: ubuntu-latest
- steps:
- - name: Checkout code
- uses: actions/checkout@v4
-
- - name: Setup Node.js
- uses: actions/setup-node@v4
- with:
- node-version: '20'
- registry-url: 'https://registry.npmjs.org'
-
- # Ensure npm 11.5.1 or later for trusted publishing
- - run: npm install -g npm@latest
-
- - name: Install dependencies
- run: npm ci
-
- - name: Build packages
- run: npm run build
-
- - name: Update package versions from release tag
- run: |
- TAG_VERSION=${GITHUB_REF#refs/tags/}
- TAG_VERSION=${TAG_VERSION#v}
- echo "Updating all packages to version $TAG_VERSION"
-
- # Update each package version
- for package_dir in packages/*/; do
- if [ -f "${package_dir}package.json" ]; then
- echo "Updating version in ${package_dir}package.json"
- cd "$package_dir"
- npm version $TAG_VERSION --no-git-tag-version --allow-same-version
- cd ../..
- fi
- done
-
- - name: Copy README to all packages
- run: |
- echo "Copying README.md to all packages"
- for package_dir in packages/*/; do
- if [ -f "${package_dir}package.json" ]; then
- echo "Copying README.md to ${package_dir}"
- cp README.md "${package_dir}README.md"
- fi
- done
-
- - name: Publish to npm using Changesets
+name: Publish to npm
+
+on:
+ release:
+ types: [published]
+
+permissions:
+ contents: read
+ id-token: write
+
+jobs:
+ publish:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+ registry-url: 'https://registry.npmjs.org'
+
+ # Ensure npm 11.5.1 or later for trusted publishing
+ - run: npm install -g npm@latest
+
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Build packages
+ run: npm run build
+
+ - name: Update package versions from release tag
+ run: |
+ TAG_VERSION=${GITHUB_REF#refs/tags/}
+ TAG_VERSION=${TAG_VERSION#v}
+ echo "Updating all packages to version $TAG_VERSION"
+
+ # Update each package version
+ for package_dir in packages/*/; do
+ if [ -f "${package_dir}package.json" ]; then
+ echo "Updating version in ${package_dir}package.json"
+ cd "$package_dir"
+ npm version $TAG_VERSION --no-git-tag-version --allow-same-version
+ cd ../..
+ fi
+ done
+
+ - name: Copy README to all packages
+ run: |
+ echo "Copying README.md to all packages"
+ for package_dir in packages/*/; do
+ if [ -f "${package_dir}package.json" ]; then
+ echo "Copying README.md to ${package_dir}"
+ cp README.md "${package_dir}README.md"
+ fi
+ done
+
+ - name: Publish to npm using Changesets
run: npx changeset publish --no-git-tag
\ No newline at end of file
diff --git a/.github/workflows/push-docker.yml b/.github/workflows/push-docker.yml
index b3002341..e6642d58 100644
--- a/.github/workflows/push-docker.yml
+++ b/.github/workflows/push-docker.yml
@@ -1,50 +1,50 @@
-name: Build and Push Docker Image
-
-permissions:
- contents: read
- id-token: write
-
-on:
- release:
- types: [published]
-
-jobs:
- build-and-push:
- runs-on: ubuntu-latest
-
- steps:
- - name: Checkout repository
- uses: actions/checkout@v4
-
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@885d1462b80bc1c1c7f0b00334ad271f09369c55
-
- - name: Login to DockerHub
- uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc
- with:
- username: ${{ secrets.DOCKERHUB_USERNAME }}
- password: ${{ secrets.DOCKERHUB_TOKEN }}
-
- - name: Extract metadata (tags, labels) for Docker
- id: meta
- uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
- with:
- images: ${{ vars.DOCKERHUB_REPO }}
-
- - name: Build and push Docker image
- uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671
- with:
- context: .
- file: ./docker/Dockerfile
- push: true
- build-args: GITHUB_REF=${{ github.ref_name }}
- tags: ${{ steps.meta.outputs.tags }}
- labels: ${{ steps.meta.outputs.labels }}
- platforms: linux/amd64,linux/arm64
-
- - uses: shrink/actions-docker-extract@f97780187d59e88f06a98b166a7e700c0f400314
- id: extract
- with:
- image: ${{ vars.DOCKERHUB_REPO }}
- path: /usr/share/nginx/html/.
+name: Build and Push Docker Image
+
+permissions:
+ contents: read
+ id-token: write
+
+on:
+ release:
+ types: [published]
+
+jobs:
+ build-and-push:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@885d1462b80bc1c1c7f0b00334ad271f09369c55
+
+ - name: Login to DockerHub
+ uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+ - name: Extract metadata (tags, labels) for Docker
+ id: meta
+ uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
+ with:
+ images: ${{ vars.DOCKERHUB_REPO }}
+
+ - name: Build and push Docker image
+ uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671
+ with:
+ context: .
+ file: ./docker/Dockerfile
+ push: true
+ build-args: GITHUB_REF=${{ github.ref_name }}
+ tags: ${{ steps.meta.outputs.tags }}
+ labels: ${{ steps.meta.outputs.labels }}
+ platforms: linux/amd64,linux/arm64
+
+ - uses: shrink/actions-docker-extract@f97780187d59e88f06a98b166a7e700c0f400314
+ id: extract
+ with:
+ image: ${{ vars.DOCKERHUB_REPO }}
+ path: /usr/share/nginx/html/.
destination: dist
\ No newline at end of file
diff --git a/README.md b/README.md
index a241f8b3..bceabdf3 100644
--- a/README.md
+++ b/README.md
@@ -1,129 +1,140 @@
-# YASGUI
-
-YASGUI (Yet Another SPARQL GUI) is an advanced SPARQL client for querying and exploring RDF data. It provides a user-friendly interface for writing SPARQL queries, executing them against SPARQL endpoints, and visualizing the results in various formats.
-
-Go to https://yasgui.matdata.eu/ and use it freely in production. Or fork this repo and extend it yourself. Contributions are certainly welcome!
-
-## Table of Contents
-
-- [Useful Links](#useful-links)
-- [Features](#features)
- - [Keyboard Shortcuts](#keyboard-shortcuts)
- - [Query Editor (Yasqe)](#query-editor-yasqe)
- - [Fullscreen Mode](#fullscreen-mode)
- - [URI Explorer](#uri-explorer)
- - [Prefix Management](#prefix-management)
- - [Result Visualization Plugins (Yasr)](#result-visualization-plugins-yasr)
-- [Installation](#installation)
- - [npm](#npm)
- - [Yarn](#yarn)
-- [Local Development](#local-development)
-- [License](#license)
-
-## Useful Links
-
-- Production environment: https://yasgui.matdata.eu/
-- Dev environment: https://yasgui-dev.matdata.eu/ (GitHub Pages - automatically updated with every commit to main branch)
-- User documentation: https://docs.triply.cc/yasgui/
-- Developer documentation: https://docs.triply.cc/yasgui-api/
-- Docker Hub: https://hub.docker.com/r/mathiasvda/yasgui
-
-## Features
-
-### Keyboard Shortcuts
-
-#### Query Editor (Yasqe)
-- **Ctrl+Enter** / **Cmd+Enter**: Execute the current query
-- **Ctrl+Space**: Trigger autocomplete
-- **Ctrl+S**: Save query to local storage
-- **Shift+Ctrl+F**: Auto-format the query
-- **Ctrl+/**: Comment/uncomment selected lines
-- **Shift+Ctrl+D**: Duplicate the current line
-- **Shift+Ctrl+K**: Delete the current line
-- **Esc**: Remove focus from the editor
-
-#### Fullscreen Mode
-- **F11**: Toggle fullscreen mode for the query editor (Yasqe)
-- **F10**: Toggle fullscreen mode for the results viewer (Yasr)
-- **Ctrl+Shift+F**: Switch between Yasqe and Yasr fullscreen modes
-
-#### URI Explorer
-- **Ctrl+Click** on any URI in the query editor: Automatically executes a CONSTRUCT query to explore the clicked URI's connections (incoming and outgoing triples). The query runs in the background without modifying your current query in the editor.
-
-### Prefix Management
-- **PREFIX Button**: Insert saved prefix declarations into your query (replaces existing PREFIX lines at the beginning)
-- **Settings Modal**: Access via the settings button (⚙) to manage:
- - **Saved Prefixes**: Define reusable PREFIX declarations
- - **Auto-capture**: Automatically captures new prefixes from your queries (enabled by default)
- - **Request Configuration**: Configure HTTP request method, accept headers, arguments, headers, and named/default graphs
-- **Default Prefixes**: Automatically includes `rdf:` and `rdfs:` prefixes for new users
-- **Prefix Autocomplete**: When typing a prefix declaration (e.g., `PREFIX foaf:`), the editor automatically queries [prefix.cc](https://prefix.cc) to suggest and auto-complete the full URI commonly associated with that prefix. This helps you quickly add standard prefixes without needing to remember their full URIs.
-
-### Result Visualization Plugins (Yasr)
-
-Yasgui includes several built-in plugins to visualize SPARQL query results:
-
-- **Table**: Interactive table view with sorting, filtering, pagination, and column resizing. Ideal for SELECT query results.
-- **Boolean**: Displays boolean results (true/false) with visual indicators. Automatically used for ASK queries.
-- **Response**: Raw response viewer with syntax highlighting and code folding. Shows the original response from the endpoint in JSON, XML, Turtle, or other formats.
-- **Geo**: Geographic visualization plugin for displaying spatial data on interactive maps. Visualizes geospatial triples with coordinates. See [Yasgui Geo TG Plugin](https://github.com/Thib-G/yasgui-geo-tg) for more details.
-- **Graph**: Visual graph representation of RDF data using nodes and edges. Ideal for CONSTRUCT/DESCRIBE query results. See [Yasgui Graph Plugin](https://github.com/Matdata-eu/yasgui-graph-plugin) for more details.
-- **Error**: Displays error messages and diagnostics when queries fail, including CORS troubleshooting guidance.
-
-Plugins are automatically selected based on the query type and response format. You can manually switch between available plugins using the view selector in the results pane.
-
-## Installation
-
-Below are instructions on how to include Yasgui in your project.
-If you only want to install Yasr or Yasqe, replace yasgui in the commands below.
-
-### npm
-
-```sh
-npm i @matdata/yasgui
-```
-
-### Yarn
-
-```sh
-yarn add @matdata/yasgui
-```
-
-### Docker
-
-Yasgui is also available as a Docker image on Docker Hub. Images are built and published automatically when a new release is created.
-
-```sh
-docker pull mathiasvda/yasgui:latest
-docker run -p 8080:8080 mathiasvda/yasgui:latest
-```
-
-You can customize the default SPARQL endpoint by setting the `YASGUI_DEFAULT_ENDPOINT` environment variable:
-
-```sh
-docker run -p 8080:8080 -e YASGUI_DEFAULT_ENDPOINT=https://your-endpoint.com/sparql mathiasvda/yasgui:latest
-```
-
-The application will be available at `http://localhost:8080`.
-
-## Local Development
-
-#### Installing dependencies
-
-Run `npm install`.
-
-#### Running Yasgui locally
-
-To develop locally, run `npm run dev`
-
-Go to `http://localhost:5173/demo` in your browser to see Yasgui in action.
-
-#### Compiling Yasgui
-
-Run `npm run build`. It'll store the transpiled js/css files in the `build` directory.
-
-## License
-
-This is a fork from [Zazuko](https://github.com/zazuko/Yasgui) who forked it from [Triply](https://github.com/TriplyDB/Yasgui).
-
-This code is released under the MIT license.
+# YASGUI
+
+YASGUI (Yet Another SPARQL GUI) is an advanced SPARQL client for querying and exploring RDF data. It provides a user-friendly interface for writing SPARQL queries, executing them against SPARQL endpoints, and visualizing the results in various formats.
+
+Go to https://yasgui.matdata.eu/ and use it freely in production. Or fork this repo and extend it yourself. Contributions are certainly welcome!
+
+## Table of Contents
+
+- [Useful Links](#useful-links)
+- [Features](#features)
+ - [Keyboard Shortcuts](#keyboard-shortcuts)
+ - [Query Editor (Yasqe)](#query-editor-yasqe)
+ - [Fullscreen Mode](#fullscreen-mode)
+ - [URI Explorer](#uri-explorer)
+ - [Prefix Management](#prefix-management)
+ - [Result Visualization Plugins (Yasr)](#result-visualization-plugins-yasr)
+- [Installation](#installation)
+ - [npm](#npm)
+ - [Yarn](#yarn)
+- [Local Development](#local-development)
+- [License](#license)
+
+## Useful Links
+
+- Production environment: https://yasgui.matdata.eu/
+- Dev environment: https://yasgui-dev.matdata.eu/ (GitHub Pages - automatically updated with every commit to main branch)
+- User documentation: https://docs.triply.cc/yasgui/
+- Developer documentation: https://docs.triply.cc/yasgui-api/
+- Docker Hub: https://hub.docker.com/r/mathiasvda/yasgui
+
+## Features
+
+### Themes
+
+Yasgui supports both **light** and **dark** themes with instant switching:
+
+- **Theme Toggle Button**: Quickly switch between light and dark modes using the button in the tab bar
+- **Persistent Preference**: Your theme choice is automatically saved
+- **System Detection**: Automatically matches your system's dark/light mode preference
+- **Full Coverage**: Consistent theming across all components (editor, results, modals)
+
+See the [Theme Guide](./THEME_GUIDE.md) for detailed configuration options and usage examples.
+
+### Keyboard Shortcuts
+
+#### Query Editor (Yasqe)
+- **Ctrl+Enter** / **Cmd+Enter**: Execute the current query
+- **Ctrl+Space**: Trigger autocomplete
+- **Ctrl+S**: Save query to local storage
+- **Shift+Ctrl+F**: Auto-format the query
+- **Ctrl+/**: Comment/uncomment selected lines
+- **Shift+Ctrl+D**: Duplicate the current line
+- **Shift+Ctrl+K**: Delete the current line
+- **Esc**: Remove focus from the editor
+
+#### Fullscreen Mode
+- **F11**: Toggle fullscreen mode for the query editor (Yasqe)
+- **F10**: Toggle fullscreen mode for the results viewer (Yasr)
+- **Ctrl+Shift+F**: Switch between Yasqe and Yasr fullscreen modes
+
+#### URI Explorer
+- **Ctrl+Click** on any URI in the query editor: Automatically executes a CONSTRUCT query to explore the clicked URI's connections (incoming and outgoing triples). The query runs in the background without modifying your current query in the editor.
+
+### Prefix Management
+- **PREFIX Button**: Insert saved prefix declarations into your query (replaces existing PREFIX lines at the beginning)
+- **Settings Modal**: Access via the settings button (⚙) to manage:
+ - **Saved Prefixes**: Define reusable PREFIX declarations
+ - **Auto-capture**: Automatically captures new prefixes from your queries (enabled by default)
+ - **Request Configuration**: Configure HTTP request method, accept headers, arguments, headers, and named/default graphs
+- **Default Prefixes**: Automatically includes `rdf:` and `rdfs:` prefixes for new users
+- **Prefix Autocomplete**: When typing a prefix declaration (e.g., `PREFIX foaf:`), the editor automatically queries [prefix.cc](https://prefix.cc) to suggest and auto-complete the full URI commonly associated with that prefix. This helps you quickly add standard prefixes without needing to remember their full URIs.
+
+### Result Visualization Plugins (Yasr)
+
+Yasgui includes several built-in plugins to visualize SPARQL query results:
+
+- **Table**: Interactive table view with sorting, filtering, pagination, and column resizing. Ideal for SELECT query results.
+- **Boolean**: Displays boolean results (true/false) with visual indicators. Automatically used for ASK queries.
+- **Response**: Raw response viewer with syntax highlighting and code folding. Shows the original response from the endpoint in JSON, XML, Turtle, or other formats.
+- **Geo**: Geographic visualization plugin for displaying spatial data on interactive maps. Visualizes geospatial triples with coordinates. See [Yasgui Geo TG Plugin](https://github.com/Thib-G/yasgui-geo-tg) for more details.
+- **Graph**: Visual graph representation of RDF data using nodes and edges. Ideal for CONSTRUCT/DESCRIBE query results. See [Yasgui Graph Plugin](https://github.com/Matdata-eu/yasgui-graph-plugin) for more details.
+- **Error**: Displays error messages and diagnostics when queries fail, including CORS troubleshooting guidance.
+
+Plugins are automatically selected based on the query type and response format. You can manually switch between available plugins using the view selector in the results pane.
+
+## Installation
+
+Below are instructions on how to include Yasgui in your project.
+If you only want to install Yasr or Yasqe, replace yasgui in the commands below.
+
+### npm
+
+```sh
+npm i @matdata/yasgui
+```
+
+### Yarn
+
+```sh
+yarn add @matdata/yasgui
+```
+
+### Docker
+
+Yasgui is also available as a Docker image on Docker Hub. Images are built and published automatically when a new release is created.
+
+```sh
+docker pull mathiasvda/yasgui:latest
+docker run -p 8080:8080 mathiasvda/yasgui:latest
+```
+
+You can customize the default SPARQL endpoint by setting the `YASGUI_DEFAULT_ENDPOINT` environment variable:
+
+```sh
+docker run -p 8080:8080 -e YASGUI_DEFAULT_ENDPOINT=https://your-endpoint.com/sparql mathiasvda/yasgui:latest
+```
+
+The application will be available at `http://localhost:8080`.
+
+## Local Development
+
+#### Installing dependencies
+
+Run `npm install`.
+
+#### Running Yasgui locally
+
+To develop locally, run `npm run dev`
+
+Go to `http://localhost:5173/demo` in your browser to see Yasgui in action.
+
+#### Compiling Yasgui
+
+Run `npm run build`. It'll store the transpiled js/css files in the `build` directory.
+
+## License
+
+This is a fork from [Zazuko](https://github.com/zazuko/Yasgui) who forked it from [Triply](https://github.com/TriplyDB/Yasgui).
+
+This code is released under the MIT license.
diff --git a/THEME_GUIDE.md b/THEME_GUIDE.md
new file mode 100644
index 00000000..dd489ddc
--- /dev/null
+++ b/THEME_GUIDE.md
@@ -0,0 +1,162 @@
+# Yasgui Theme Guide
+
+Yasgui now supports both light and dark themes, allowing users to customize the appearance of the SPARQL IDE according to their preferences.
+
+## Features
+
+- **Light Theme**: Default bright theme suitable for well-lit environments
+- **Dark Theme**: Easy on the eyes dark theme with syntax highlighting
+- **Theme Toggle**: Quick switching between themes via UI button
+- **Persistence**: User's theme preference is saved in localStorage
+- **System Preference**: Automatically detects and applies system theme preference
+- **Programmatic Control**: Set theme via JavaScript API
+
+## Usage
+
+### Theme Toggle Button
+
+By default, a theme toggle button appears in the tab bar (top-right area). Users can click this button to instantly switch between light and dark themes.
+
+- **Light Mode**: Shows a sun icon (☀️) - clicking switches to dark mode
+- **Dark Mode**: Shows a moon icon (🌙) - clicking switches to light mode
+
+### Configuration Options
+
+You can configure the theme when initializing Yasgui:
+
+```javascript
+import Yasgui from '@matdata/yasgui';
+
+// Initialize with dark theme
+const yasgui = new Yasgui(document.getElementById('yasgui'), {
+ theme: 'dark'
+});
+
+// Initialize with light theme (default)
+const yasgui = new Yasgui(document.getElementById('yasgui'), {
+ theme: 'light'
+});
+
+// Hide the theme toggle button
+const yasgui = new Yasgui(document.getElementById('yasgui'), {
+ showThemeToggle: false
+});
+```
+
+### Programmatic Theme Control
+
+You can control the theme programmatically using the Yasgui API:
+
+```javascript
+// Get current theme
+const currentTheme = yasgui.getTheme(); // Returns 'light' or 'dark'
+
+// Set theme
+yasgui.setTheme('dark'); // Switch to dark theme
+yasgui.setTheme('light'); // Switch to light theme
+
+// Toggle theme
+const newTheme = yasgui.toggleTheme(); // Returns the new theme
+```
+
+## Theme Details
+
+### Light Theme
+- Clean, bright interface with high contrast
+- Default CodeMirror syntax highlighting
+- White backgrounds with dark text
+- Blue accent color (#337ab7)
+
+### Dark Theme
+- Dark backgrounds with light text
+- Material Palenight CodeMirror theme for syntax highlighting
+- Reduced eye strain in low-light environments
+- Cyan accent color (#4fc3f7)
+
+## Technical Details
+
+### CSS Custom Properties
+
+Themes are implemented using CSS custom properties (variables). The following variables are available:
+
+```css
+--yasgui-bg-primary /* Primary background color */
+--yasgui-bg-secondary /* Secondary background (hover states, etc.) */
+--yasgui-bg-tertiary /* Tertiary background */
+--yasgui-text-primary /* Primary text color */
+--yasgui-text-secondary /* Secondary text color */
+--yasgui-text-muted /* Muted text color */
+--yasgui-border-color /* Primary border color */
+--yasgui-link-color /* Link color */
+--yasgui-accent-color /* Accent color for highlights */
+--yasgui-error-color /* Error message color */
+/* ... and more */
+```
+
+### Theme Persistence
+
+The selected theme is automatically saved to localStorage under the key `yasgui_theme`. This means:
+
+- Theme preference persists across page reloads
+- Each user's preference is independent
+- No server-side configuration needed
+
+### System Theme Detection
+
+If no theme is explicitly set and no saved preference exists, Yasgui will:
+1. Check the system's color scheme preference (`prefers-color-scheme` media query)
+2. Apply dark theme if system prefers dark mode
+3. Apply light theme otherwise
+
+The system theme listener will automatically update the theme if the user changes their system preference (and they haven't manually selected a theme in Yasgui).
+
+## TypeScript
+
+Theme types are exported for TypeScript users:
+
+```typescript
+import Yasgui, { Theme } from '@matdata/yasgui';
+
+const theme: Theme = 'dark'; // Type-safe: only 'light' or 'dark' allowed
+yasgui.setTheme(theme);
+```
+
+## Browser Compatibility
+
+Themes work in all modern browsers that support:
+- CSS Custom Properties
+- localStorage
+- Media Queries (for system theme detection)
+
+This includes all recent versions of Chrome, Firefox, Safari, and Edge.
+
+## Customization
+
+If you want to customize the theme colors, you can override the CSS custom properties in your own stylesheet:
+
+```css
+/* Custom dark theme colors */
+[data-theme="dark"] {
+ --yasgui-bg-primary: #0d1117;
+ --yasgui-accent-color: #58a6ff;
+ /* Override other variables as needed */
+}
+```
+
+## Troubleshooting
+
+**Theme doesn't persist after page reload**
+
+Ensure localStorage is enabled in the browser. Some browsers in private/incognito mode may not persist localStorage data.
+
+**Theme toggle button is not visible**
+
+Check that `showThemeToggle` is not set to `false` in the configuration.
+
+**CodeMirror theme doesn't match**
+
+The CodeMirror theme is automatically synchronized with the Yasgui theme. If you see a mismatch, try manually refreshing:
+
+```javascript
+yasgui.themeManager.refresh();
+```
diff --git a/dev/yasgui.html b/dev/yasgui.html
index a7a9214d..5bc4283d 100644
--- a/dev/yasgui.html
+++ b/dev/yasgui.html
@@ -1,54 +1,99 @@
-
-
-