Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 23 additions & 14 deletions Example/index.html.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -55,25 +55,34 @@
Ext.onReady(function() { Ext.create('PVE.StdWorkspace');});
</script>

<script>
document.addEventListener('DOMContentLoaded', () => {
// Look for the Proxmox dark-theme stylesheet
const darkLink = document.querySelector(
'link[href*="theme-proxmox-dark.css"]'
);
if (darkLink) {
document.body.classList.add('proxmox-theme-dark');
}
});
</script>

<link rel="stylesheet" href="/pve2/images/solarized.css">

</head>
<body>
<!-- Fields required for history management -->
<form id="history-form" class="x-hidden">
<input type="hidden" id="x-history-field"/>
</form>

<script>
function setSolarizedThemeMode() {
const defaultMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
const selectedTheme = document.cookie.split("; ")
.find((row) => row.startsWith("PVEThemeCookie="))
?.split("=")[1];

if (defaultMode && selectedTheme !== "crisp") {
document.body.classList.add('proxmox-theme-dark');
} else if (selectedTheme !== "proxmox-dark") {
document.body.classList.remove('proxmox-theme-dark');
} else {
document.body.classList.add('proxmox-theme-dark');
}
}

window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', setSolarizedThemeMode);
setSolarizedThemeMode();
</script>

<link rel="stylesheet" href="/pve2/images/solarized.css">

</body>
</html>
74 changes: 41 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
![Header](./images/header.png)
(Generated with [PixelPoSH](https://github.com/dabeastnet/PixelPoSH))

# SolarPVE

A **[Solarized](https://ethanschoonover.com/solarized/)**-inspired light & dark CSS theme for Proxmox VE’s web UI.
Automatically switches to dark mode whenever Proxmox’s `theme-proxmox-dark.css` is loaded.
Automatically switches between light + dark themes based on system preference.

---

## Screenshots

Lightmode:
![Lightmode](./images/light.png)

Darkmode:
![Darkmode](./images/dark.png)


## Features

- **Light** (Solarized Light) by default
- **Dark** (Solarized Dark) when Proxmox’s dark stylesheet is present
- No JS-framework dependencies—just vanilla CSS & a tiny inline script
- **Light** (Solarized Light) when selected
- **Dark** (Solarized Dark) when selected
- **Auto** - when selected, automatically chooses theme based on user/system preferences, via the `prefers-color-scheme: dark` attribute
- No JS-framework dependencies—just vanilla CSS & a tiny inline script
- Easy to install and override via Proxmox’s `index.html.tpl`

---
Expand All @@ -30,37 +32,41 @@ Darkmode:

1. **Copy the CSS**
Place `solarized.css` into your Proxmox server’s static‐assets folder.
By default this is:
By default this is:

```

/usr/share/pve-manager/images/solarized.css

```

2. **Patch the Proxmox template**
Edit (or better: override) Proxmox’s `index.html.tpl`—usually at:
Edit (or better: override) Proxmox’s `index.html.tpl`—usually at:

```

/usr/share/pve-manager/index.html.tpl

````
and add *before* the existing `</head>` the following snippet:
```

and add _before_ the existing `</body>` (near the bottom of the document) the following snippet:

```html
<script>
document.addEventListener('DOMContentLoaded', () => {
document.addEventListener("DOMContentLoaded", () => {
// Detect if Proxmox’s dark stylesheet is loaded
const darkLink = document.querySelector(
'link[href*="theme-proxmox-dark.css"]'
'link[href*="theme-proxmox-dark.css"]',
);
if (darkLink) {
document.body.classList.add('proxmox-theme-dark');
document.body.classList.add("proxmox-theme-dark");
}
});
</script>

<link rel="stylesheet" href="/pve2/images/solarized.css">
````
<link rel="stylesheet" href="/pve2/images/solarized.css" />
```

(An example index.html.tpl ships in this repo, see the `Example` folder)

3. **Clear browser cache**
Expand All @@ -73,14 +79,14 @@ and add *before* the existing `</head>` the following snippet:
```

### Ansible playbook (auto installer)

> See the ansible subfolder

#### 🛠️ Prerequisites

* **Ansible 2.9+** installed on your control machine
* SSH access (with `become`/sudo rights) to one or more Proxmox hosts
* A copy of your `solarized.css` in `files/solarized.css`

- **Ansible 2.9+** installed on your control machine
- SSH access (with `become`/sudo rights) to one or more Proxmox hosts
- A copy of your `solarized.css` in `files/solarized.css`

#### ⚙️ Usage

Expand All @@ -99,40 +105,44 @@ and add *before* the existing `</head>` the following snippet:

> This will:
>
> * Copy `solarized.css` to `/usr/share/pve-manager/images/solarized.css`
> * Patch Proxmox’s `index.html.tpl` to include light & dark-mode logic
> * Restart `pveproxy` to serve your new theme
> - Copy `solarized.css` to `/usr/share/pve-manager/images/solarized.css`
> - Patch Proxmox’s `index.html.tpl` to include light & dark-mode logic
> - Restart `pveproxy` to serve your new theme

---

#### 🔧 Configuration

* **Playbook file**: `solarized-theme.yml`
* **Key variables** (override via `-e` or `group_vars` if desired):
- **Playbook file**: `solarized-theme.yml`
- **Key variables** (override via `-e` or `group_vars` if desired):

| Variable | Default path |
| ---------- | ------------------------------------------------- |
| `css_src` | `files/solarized.css` |
| `css_dest` | `/usr/share/pve-manager/images/solarized.css` |
| `tpl_path` | `/usr/share/pve-manager/templates/index.html.tpl` |


---

## How It Works

* **Light mode**
- Determines selected theme via the `PVEThemeCookie` value that is set when choosing light, dark or default.

- **Light mode**
All rules scoped under `body:not(.proxmox-theme-dark)` apply Solarized Light defaults.

* **Dark mode**
When Proxmox itself loads its `theme-proxmox-dark.css`, our small `<script>` adds `.proxmox-theme-dark` to `<body>` and you can write complementary CSS rules (e.g. under `body.proxmox-theme-dark`) for Solarized Dark.
- **Dark mode**
When detected, the `<script>` adds `.proxmox-theme-dark` to `<body>` and you can write complementary CSS rules (e.g. under `body.proxmox-theme-dark`) for Solarized Dark.

- **Auto Mode**
Dynamically changes theme between light + dark modes based on system preferences. Checks for the presence of the `prefers-color-scheme: dark` attribute.

---

## Customization

* Feel free to edit any of the `--baseXX` or `--accent` variables at the top of `solarized.css` to tweak colors.
* To add new dark-mode overrides, target:
- Feel free to edit any of the `--baseXX` or `--accent` variables at the top of `solarized.css` to tweak colors.
- To add new dark-mode overrides, target:

```css
body.proxmox-theme-dark .your-selector {
Expand All @@ -157,11 +167,9 @@ Bug reports and PRs for improved selectors, additional components, or accessibil

This repo is licensed under **CC BY-NC 4.0**.

* ✅ Free to use, modify & share for **non-commercial** purposes (with attribution).
* ❗️ For commercial use please see the license file
- ✅ Free to use, modify & share for **non-commercial** purposes (with attribution).
- ❗️ For commercial use please see the license file

---

Enjoy a Solarized-themed Proxmox UI! 🚀


36 changes: 22 additions & 14 deletions ansible/playbooks/solarized-theme.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
---
- name: Install Solarized Proxmox theme
# Playbook: solarized-theme.yml
# Author: Dieter Beckers
# Author: Dieter Beckers & vhsdream
# Github: https://github.com/dabeastnet/SolarPVE
# Description: Install Solarized Proxmox theme (light + dark-mode detection)
# Description: Install Solarized Proxmox theme (automatic light + dark-mode detection)
# License: CC BY-NC 4.0.
#
#Change this to match your inventory grouping
# Change this to match your inventory grouping
hosts: pve
become: yes
become: true
vars:
css_src: files/solarized.css
css_dest: /usr/share/pve-manager/images/solarized.css
Expand All @@ -31,27 +31,35 @@
group: root
mode: '0644'

- name: Inject dark-mode detector + Solarized link into index.html.tpl
- name: Inject auto-theme-mode detector + Solarized link into index.html.tpl
blockinfile:
path: "{{ tpl_path }}"
backup: yes
marker: "<!-- {mark} solarized theme -->"
insertbefore: "</head>"
insertbefore: "</body>"
block: |
<script>
document.addEventListener('DOMContentLoaded', () => {
// Look for the Proxmox dark-theme stylesheet
const darkLink = document.querySelector(
'link[href*="theme-proxmox-dark.css"]'
);
if (darkLink) {
function setSolarizedThemeMode() {
const defaultMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
const selectedTheme = document.cookie.split("; ")
.find((row) => row.startsWith("PVEThemeCookie="))
?.split("=")[1];

if (defaultMode && selectedTheme !== "crisp") {
document.body.classList.add('proxmox-theme-dark');
} else if (selectedTheme !== "proxmox-dark") {
document.body.classList.remove('proxmox-theme-dark');
} else {
document.body.classList.add('proxmox-theme-dark');
}
});
}

window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', setSolarizedThemeMode);
setSolarizedThemeMode();
</script>
<link rel="stylesheet" href="/pve2/images/solarized.css">

- name: Restart pveproxy so new CSS is served
service:
name: pveproxy
state: restarted
state: restarted