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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ Once the server is restarted, you can open the Activity view in the web UI, clic

It should now work. Click save and you're done!

The custom visualization supports both light and dark mode, and will follow the ActivityWatch Theme setting (including "Auto (System)").

# Notes

This was massively inspired by ulogme by @karpathy, here's a screenshot of how it looks:
Expand Down
67 changes: 67 additions & 0 deletions visualization/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,70 @@ function add(accumulator, a) {
return accumulator + a;
}

const VALID_THEMES = ["light", "dark", "auto"];

function normalizeTheme(theme) {
return VALID_THEMES.includes(theme) ? theme : null;
}

function getStoredThemePreference() {
try {
return normalizeTheme(localStorage.getItem("theme"));
} catch (_err) {
return null;
}
}

function resolveThemePreference() {
return getStoredThemePreference() || "auto";
}

function resolveActualTheme(themePreference) {
if (themePreference === "light" || themePreference === "dark") {
return themePreference;
}

if (window.matchMedia) {
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
}
return "light";
}

function applyTheme(actualTheme) {
document.documentElement.dataset.theme = actualTheme;
}

function applyCurrentTheme() {
const themePreference = resolveThemePreference();
const actualTheme = resolveActualTheme(themePreference);
applyTheme(actualTheme);
}

function installThemeSync() {
window.addEventListener("storage", (event) => {
if (event.key === "theme") {
applyCurrentTheme();
}
});

if (!window.matchMedia) {
return;
}

const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
const onSystemThemeChange = () => {
if (resolveThemePreference() === "auto") {
applyCurrentTheme();
}
};

if (mediaQuery.addEventListener) {
mediaQuery.addEventListener("change", onSystemThemeChange);
} else if (mediaQuery.addListener) {
mediaQuery.addListener(onSystemThemeChange);
}
}

// TODO: Avoid testing-port assumption
const testing = url.port != 5600;

Expand All @@ -27,6 +91,9 @@ const aw = new aw_client.AWClient("aw-watcher-input", {
});

function load() {
applyCurrentTheme();
installThemeSync();

const statusEl = document.getElementById("status");
const pressesEl = document.getElementById("presses");
const clicksEl = document.getElementById("clicks");
Expand Down
13 changes: 12 additions & 1 deletion visualization/src/index.pug
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,19 @@ html
head
title aw-watcher-input visualization
style
| :root {
| --bg: #ffffff;
| --text: #000000;
| --status: #000000;
| }
| html[data-theme="dark"] {
| --bg: #1a1d24;
| --text: #e4e9f2;
| --status: #a5b4cc;
| }
| th { text-align: left; }
| body { font-family: sans-serif; }
| body { font-family: sans-serif; background: var(--bg); color: var(--text); }
| #status { color: var(--status); }
body
p#status

Expand Down