diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..79518f7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,21 @@
+node_modules
+
+# Output
+.output
+.vercel
+/.svelte-kit
+/build
+
+# OS
+.DS_Store
+Thumbs.db
+
+# Env
+.env
+.env.*
+!.env.example
+!.env.test
+
+# Vite
+vite.config.js.timestamp-*
+vite.config.ts.timestamp-*
diff --git a/.npmrc b/.npmrc
new file mode 100644
index 0000000..b6f27f1
--- /dev/null
+++ b/.npmrc
@@ -0,0 +1 @@
+engine-strict=true
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..ab78a95
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,4 @@
+# Package Managers
+package-lock.json
+pnpm-lock.yaml
+yarn.lock
diff --git a/README.md b/README.md
index cc2b8ac..716e04d 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,8 @@
# 🟦 Neobrutal [Zebar](https://github.com/glzr-io/zebar)
+An Zebar configuration for Zebar V2 build in Svelte with Tailwind. If you are
+still using V1 of Zebar the old config is available in the [V1 branch](https://github.com/adriankarlen/neobrutal-zebar/tree/v1).
+
## ✨ Features
- Process icons for current workspace, with current focus indicator.
@@ -33,44 +36,9 @@ https://github.com/user-attachments/assets/185f238c-03b8-4f63-87a2-2d36d6b31039
Download the `neobrutal-zebar.zip` from the latest release. Unzip the contents
inside your zebar config directory.
-### Replacing values
-
-In order for imports to work you will need to update some paths in the files
-
-#### 1. config.yaml
-
-In order for zebar to able to import the css file, you need to url encode all
-special character, this can be done via services like https://www.urldecoder.org/.
-
-For instance if you zebar config is stored at
-_C:/Users/MyCoolUsername/.glzr/zebar_. Your import link would look like this:
-`http://asset.localhost/C:/Users/MyCoolUsername/.glzr/zebar/styles/global.css`.
-Everything following `localhost/` needs to be url encoded for the import to work
-inside the yaml. This would mean that you would take _C:/Users/MyCoolUsername/.glzr/zebar/styles/global.css_
-and paste it to https://www.urldecoder.org/ and replace the import with that string.
-The resulting string will then look like this: _"http://asset.localhost/C%3A%2FUsers%2FMyCoolUsername%2F.glzr%2Fzebar%2Fstyles%2Fglobal.css"_
-
-```yaml
-# Change the following line to match your path
-@import "http://asset.localhost/>> PATH TO YOUR YOUR GLZR CONFIG FOLDER<<.glzr%2Fzebar%2Fstyles%2Fglobal.css";
-```
-
-#### 2. styles/global.css
-
-```css
-/* Change the following imports, you don't need to url encode these like in config.yaml */
-@import "http://asset.localhost/>> PATH TO YOUR YOUR GLZR CONFIG FOLDER<> PATH TO YOUR YOUR GLZR CONFIG FOLDER<> PATH TO YOUR YOUR GLZR CONFIG FOLDER<> PATH TO YOUR YOUR GLZR CONFIG FOLDER<> PATH TO YOUR YOUR GLZR CONFIG FOLDER<> PATH TO YOUR YOUR GLZR CONFIG FOLDER<> PATH TO YOUR YOUR GLZR CONFIG FOLDER<
Example config
-##### config.css
+##### src/app.css
```css
/* colors */
--text: var(--rp-text);
@@ -117,15 +85,14 @@ Utilizes [Catppuccin Palette](https://github.com/catppuccin/palette/blob/main/do
Config show in picture above
-##### config.css
+##### src/app.css
```css
/* border */
---border-size: 2px;
--radius: 9999px;
/* shadow */
---shadow-size-bar: 0px;
---shadow-size-button: 0px;
+--shadow-size-bar: 0;
+--shadow-size-button: 0;
/* colors */
--text: var(--ctp-mocha-text);
@@ -155,12 +122,12 @@ Utilizes [Catppuccin Palette](https://github.com/catppuccin/palette/blob/main/do
--weather: var(--ctp-mocha-text);
```
-##### config.yaml
-```html
+##### src/components/RightGroup.svelte
+```svelte
-
+
-
+
```
diff --git a/bar.zebar.json b/bar.zebar.json
new file mode 100644
index 0000000..74559d4
--- /dev/null
+++ b/bar.zebar.json
@@ -0,0 +1,22 @@
+{
+ "htmlPath": "./build/index.html",
+ "launchOptions": {
+ "zOrder": "normal",
+ "shownInTaskbar": false,
+ "focused": false,
+ "resizable": false,
+ "transparent": true,
+ "placements": [
+ {
+ "anchor": "top_left",
+ "offsetX": "0px",
+ "offsetY": "0px",
+ "width": "100%",
+ "height": "60px",
+ "monitorSelection": {
+ "type": "all"
+ }
+ }
+ ]
+ }
+}
diff --git a/bun.lockb b/bun.lockb
new file mode 100644
index 0000000..93959df
Binary files /dev/null and b/bun.lockb differ
diff --git a/config.yaml b/config.yaml
deleted file mode 100644
index 8ec01b9..0000000
--- a/config.yaml
+++ /dev/null
@@ -1,185 +0,0 @@
-global:
- enable_devtools: true
-
-window/bar:
- providers: ["self"]
- width: "{{ self.args.MONITOR_WIDTH }}"
- height: "275"
- position_x: "{{ self.args.MONITOR_X }}"
- position_y: "{{ self.args.MONITOR_Y }}"
- z_order: "normal"
- resizable: false
- global_styles: |
- @import "https://www.nerdfonts.com/assets/css/webfont.css";
- @import "https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/dist/tabler-icons.min.css";
- @import "http://asset.localhost/>> PATH TO YOUR YOUR GLZR CONFIG FOLDER<<.glzr%5Czebar%5Cstyles%5Cglobal.css";
-
- group/left:
- template/menu:
- events:
- - type: "click"
- fn_path: "scripts/menu.js#toggleDropdown"
- selector: ".dropdown-button"
- template: |
-
-
-
-
- template/dropdown:
- events:
- - type: "click"
- fn_path: "scripts/menu.js#powerDown"
- selector: "#powerdown"
- - type: "click"
- fn_path: "scripts/menu.js#sleep"
- selector: "#sleep"
- - type: "click"
- fn_path: "scripts/menu.js#logout"
- selector: "#logout"
- template:
-
-
-
-
-
-
-
-
-
-
- template/memory:
- providers: ["memory"]
- template: |
-
-
- {{ Math.round(memory.usage) }}%
-
-
-
-
-
- template/cpu:
- providers: ["cpu"]
- template: |
- 85 ? "high-usage" : ""}}>
-
-
- {{ Math.round(cpu.usage) }}%
-
-
-
-
-
-
- template/battery:
- providers: ["battery"]
- template: |
-
-
-
- {{ Math.round(battery.chargePercent) }}%
-
-
-
-
-
-
- group/center:
- template/glazewm_workspaces:
- providers: ["glazewm"]
- events:
- - type: "click"
- fn_path: "scripts/glazewm.js#focusWorkspace"
- selector: ".workspace"
- template: |
- @for (workspace of glazewm.currentWorkspaces) {
-
-
-
- }
-
-
- @for (child of glazewm.focusedWorkspace.children) {
- @if (child.state != null && child.state.type != "minimized") {
-
-
-
- }
- }
-
-
- group/right:
- template/now-playing:
- providers: ["glazewm"]
- template: |
- @for (workspace of glazewm.allWorkspaces) {
- @for (child of workspace.children) {
- @if (child?.processName === "Spotify") {
- @if (child.title === "Spotify Premium") {
-
- nothing is playing
- } @else {
-
- 62 ? "move" : ""}}>
- {{ child.title }}
-
- }
- }
- }
- }
-
- template/network:
- providers: ["network"]
- template: |
- @if (network.defaultInterface?.type === 'ethernet') {
-
- } @else if (network.defaultInterface?.type === 'wifi') {
- @if (network.defaultGateway?.signalStrength >= 75) { }
- @else if (network.defaultGateway?.signalStrength >= 50) { }
- @else if (network.defaultGateway?.signalStrength >= 25) { }
- @else { }
- {{ network.defaultGateway?.ssid }}
- } @else {
-
- }
-
- template/weather:
- providers: ["weather"]
- template: |
- @switch (weather.status) {
- @case ('clear_day') { }
- @case ('clear_night') { }
- @case ('cloudy_day') { }
- @case ('cloudy_night') { }
- @case ('light_rain_day') { }
- @case ('light_rain_night') { }
- @case ('heavy_rain_day') { }
- @case ('heavy_rain_night') { }
- @case ('snow_day') { }
- @case ('snow_night') { }
- @case ('thunder_day') { }
- @case ('thunder_night') { }
- }
- {{ weather.celsiusTemp }}°
-
- template/separator:
- template: |
- >
-
- template/clock:
- providers: ["date"]
- template: |
- {{ date.toFormat(date.now, 't') }}
diff --git a/eslint.config.js b/eslint.config.js
new file mode 100644
index 0000000..62dbd03
--- /dev/null
+++ b/eslint.config.js
@@ -0,0 +1,33 @@
+import js from '@eslint/js';
+import ts from 'typescript-eslint';
+import svelte from 'eslint-plugin-svelte';
+import prettier from 'eslint-config-prettier';
+import globals from 'globals';
+
+/** @type {import('eslint').Linter.Config[]} */
+export default [
+ js.configs.recommended,
+ ...ts.configs.recommended,
+ ...svelte.configs['flat/recommended'],
+ prettier,
+ ...svelte.configs['flat/prettier'],
+ {
+ languageOptions: {
+ globals: {
+ ...globals.browser,
+ ...globals.node
+ }
+ }
+ },
+ {
+ files: ['**/*.svelte'],
+ languageOptions: {
+ parserOptions: {
+ parser: ts.parser
+ }
+ }
+ },
+ {
+ ignores: ['build/', '.svelte-kit/', 'dist/']
+ }
+];
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..50c99a5
--- /dev/null
+++ b/package.json
@@ -0,0 +1,40 @@
+{
+ "name": "neobrutal",
+ "version": "0.0.1",
+ "private": true,
+ "scripts": {
+ "dev": "vite dev",
+ "build": "vite build",
+ "preview": "vite preview",
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
+ "lint": "prettier --check . && eslint .",
+ "format": "prettier --write ."
+ },
+ "devDependencies": {
+ "@sveltejs/adapter-auto": "^3.0.0",
+ "@sveltejs/adapter-static": "^3.0.4",
+ "@sveltejs/kit": "^2.0.0",
+ "@sveltejs/vite-plugin-svelte": "^4.0.0-next.6",
+ "@types/eslint": "^9.6.0",
+ "autoprefixer": "^10.4.20",
+ "eslint": "^9.0.0",
+ "eslint-config-prettier": "^9.1.0",
+ "eslint-plugin-svelte": "^2.36.0",
+ "globals": "^15.0.0",
+ "postcss": "^8.4.47",
+ "prettier": "^3.1.1",
+ "prettier-plugin-svelte": "^3.1.2",
+ "svelte": "^5.0.0-next.1",
+ "svelte-check": "^4.0.0",
+ "tailwindcss": "^3.4.11",
+ "typescript": "^5.0.0",
+ "typescript-eslint": "^8.0.0",
+ "vite": "^5.0.3"
+ },
+ "type": "module",
+ "dependencies": {
+ "glazewm": "^1.4.3",
+ "zebar": "^2.0.0-beta.9"
+ }
+}
diff --git a/postcss.config.js b/postcss.config.js
new file mode 100644
index 0000000..2e7af2b
--- /dev/null
+++ b/postcss.config.js
@@ -0,0 +1,6 @@
+export default {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {},
+ },
+}
diff --git a/scripts/glazewm.js b/scripts/glazewm.js
deleted file mode 100644
index 59654fb..0000000
--- a/scripts/glazewm.js
+++ /dev/null
@@ -1,84 +0,0 @@
-const iconMap = {
- // Terminals
- "wezterm-gui": { icon: "ti-terminal-2" },
- alacritty: { icon: "ti-terminal-2" },
- windowsterminal: { icon: "ti-terminal-2" },
-
- // Editors
- code: { icon: "ti-brand-vscode" }, // VS Code
- devenv: { icon: "ti-brand-visual-studio" }, // Visual Studio
-
- // Communication
- "ms-teams": { icon: "ti-brand-teams" },
- olk: { icon: "ti-mail" }, // Outlook
-
- // VPN
- "azure vpn client": { icon: "ti-spy" }, // Azure VPN Client
-
- // Browsers
- zen: { icon: "ti-circle-letter-z" },
- msedge: { icon: "ti-brand-edge" },
-
- // Utils
- snippingtool: { icon: "ti-screenshot" },
- "control panel": { icon: "ti-settings" },
- explorer: { icon: "ti-folder" },
- photos: { icon: "ti-photo" },
- sound: { icon: "ti-headphones" },
- excel: { icon: "ti-file-spreadsheet" },
- onenote: { icon: "ti-note" },
- powerpnt: { icon: "ti-presentation" },
- winword: { icon: "ti-file-word" },
- mspaint: { icon: "ti-palette" },
-
- // Ignore
- msedgewebview2: { ignore: true },
-};
-
-export const focusWorkspace = (event, context) => {
- const id = event.target.id;
- context.providers.glazewm.focusWorkspace(id);
-};
-
-const addProcessIconCallback = (mutationsList) => {
- for (const mutation of mutationsList) {
- if (mutation.type === "childList") {
- const node = document.querySelector("#process-container");
- if (node) {
- const iconNodes = node.querySelectorAll(".ti");
-
- iconNodes.forEach((iconNode) => {
- const processName = iconNode.getAttribute("data-process-name");
- const title = iconNode.getAttribute("data-title");
-
- if (!processName && !title) return;
- const process = iconMap[processName] || iconMap[title];
- const unmapped = process == null;
- if (!unmapped && process.ignore) {
- iconNode.remove();
- return;
- }
-
- /** INFO: Edge case, all Windows apps has this process name,
- * to avoid some manual mapping, use title without brand */
- if (unmapped && processName == "applicationframehost") {
- iconNode.classList.add(`ti-${title}`);
- }
-
- iconNode.classList.add(
- unmapped ? `ti-brand-${processName}` : process.icon,
- );
- });
- }
- }
- }
-};
-
-const observer = new MutationObserver(addProcessIconCallback);
-const config = { childList: true, subtree: false };
-const parentNode = document.querySelector("#glazewm-workspaces");
-if (parentNode) {
- observer.observe(parentNode, config);
-} else {
- console.error("Parent node #glazewm-workspaces not found.");
-}
diff --git a/scripts/menu.js b/scripts/menu.js
deleted file mode 100644
index 4e2ecb4..0000000
--- a/scripts/menu.js
+++ /dev/null
@@ -1,19 +0,0 @@
-export function toggleDropdown() {
- const menu = document.querySelector("#dropdown");
- menu.style.display = menu.style.display === "flex" ? "none" : "flex";
-}
-
-export function powerDown() {
- const menu = document.querySelector("#dropdown");
- menu.style.display = "none";
-}
-
-export function sleep() {
- const menu = document.querySelector("#dropdown");
- menu.style.display = "none";
-}
-
-export function logout() {
- const menu = document.querySelector("#dropdown");
- menu.style.display = "none";
-}
diff --git a/styles/config.css b/src/app.css
similarity index 63%
rename from styles/config.css
rename to src/app.css
index 0e8c807..715af59 100644
--- a/styles/config.css
+++ b/src/app.css
@@ -1,8 +1,17 @@
+@import "https://www.nerdfonts.com/assets/css/webfont.css";
+@import "https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/dist/tabler-icons.min.css";
+@import "themes/rose-pine.css";
+@import "themes/catppuccin.css";
+
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
:root {
/* sizes */
- --height: 40px;
- --bar-margin-y: 10px;
- --bar-margin-x: 20px;
+ --height: 2.5rem;
+ --bar-margin-y: 0.625rem;
+ --bar-margin-x: 1.25rem;
/* fonts */
--font-family: "SF Pro Display", Roboto, Helvetica, Arial, sans-serif;
@@ -10,13 +19,13 @@
--font-weight: 500;
/* border */
- --border-size: 2px;
- --radius: 0px;
+ --border-size: 0.125rem;
+ --radius: 0;
/* shadow */
- --shadow-size-bar: 4px;
- --shadow-size-button: 2px;
-
+ --shadow-size-bar: 0.25rem;
+ --shadow-size-button: 0.125rem;
+
/* colors */
--text: var(--rp-text);
--bg: var(--rp-overlay);
@@ -43,3 +52,9 @@
--network: var(--rp-text);
--weather: var(--rp-text);
}
+
+@layer base {
+ body {
+ font-size: var(--font-size);
+ }
+}
diff --git a/src/app.d.ts b/src/app.d.ts
new file mode 100644
index 0000000..743f07b
--- /dev/null
+++ b/src/app.d.ts
@@ -0,0 +1,13 @@
+// See https://kit.svelte.dev/docs/types#app
+// for information about these interfaces
+declare global {
+ namespace App {
+ // interface Error {}
+ // interface Locals {}
+ // interface PageData {}
+ // interface PageState {}
+ // interface Platform {}
+ }
+}
+
+export {};
diff --git a/src/app.html b/src/app.html
new file mode 100644
index 0000000..adf8bd8
--- /dev/null
+++ b/src/app.html
@@ -0,0 +1,11 @@
+
+
+
+
+
+ %sveltekit.head%
+
+
+ %sveltekit.body%
+
+
diff --git a/src/components/Button.svelte b/src/components/Button.svelte
new file mode 100644
index 0000000..6d5986e
--- /dev/null
+++ b/src/components/Button.svelte
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/src/components/Group.svelte b/src/components/Group.svelte
new file mode 100644
index 0000000..e1c77af
--- /dev/null
+++ b/src/components/Group.svelte
@@ -0,0 +1,14 @@
+
+
+
+ {@render children()}
+
diff --git a/src/components/LeftGroup.svelte b/src/components/LeftGroup.svelte
new file mode 100644
index 0000000..7620e2a
--- /dev/null
+++ b/src/components/LeftGroup.svelte
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/Meter.svelte b/src/components/Meter.svelte
new file mode 100644
index 0000000..1db0996
--- /dev/null
+++ b/src/components/Meter.svelte
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+ {percent}%
+
+
diff --git a/src/components/NowPlaying.svelte b/src/components/NowPlaying.svelte
new file mode 100644
index 0000000..b45436b
--- /dev/null
+++ b/src/components/NowPlaying.svelte
@@ -0,0 +1,32 @@
+
+
+{#if glazewmOutput}
+
+ {#each glazewmOutput.allWorkspaces as workspace}
+ {#each workspace.children as child}
+
+ {#if "state" in child && child.processName.toLowerCase() === "spotify"}
+ {#if child.title.toLowerCase() === "spotify premium"}
+
+ nothing is playing
+ {:else}
+
+ {child.title}
+ {/if}
+ {/if}
+ {/each}
+ {/each}
+
+{/if}
diff --git a/src/components/RightGroup.svelte b/src/components/RightGroup.svelte
new file mode 100644
index 0000000..f43edb4
--- /dev/null
+++ b/src/components/RightGroup.svelte
@@ -0,0 +1,82 @@
+
+
+
+
+
+ {#if networkOutput?.defaultInterface?.type === "ethernet"}
+
+ {:else if networkOutput?.defaultInterface!.type === "wifi"}
+ {#if networkOutput.defaultGateway!.signalStrength! >= 75}
+
+ {:else if networkOutput.defaultGateway!.signalStrength! >= 50}
+
+ {:else if networkOutput.defaultGateway!.signalStrength! >= 25}
+
+ {:else}
+
+ {/if}
+ {networkOutput.defaultGateway?.ssid}
+ {:else}
+
+ {/if}
+
+ {#if weatherOutput}
+
+ {#if weatherOutput.status === "clear_day"}
+
+ {:else if weatherOutput.status === "clear_night"}
+
+ {:else if weatherOutput.status === "cloudy_day"}
+
+ {:else if weatherOutput.status === "cloudy_night"}
+
+ {:else if weatherOutput.status === "light_rain_day"}
+
+ {:else if weatherOutput.status === "light_rain_night"}
+
+ {:else if weatherOutput.status === "heavy_rain_day"}
+
+ {:else if weatherOutput.status === "heavy_rain_night"}
+
+ {:else if weatherOutput.status === "snow_day"}
+
+ {:else if weatherOutput.status === "snow_night"}
+
+ {:else if weatherOutput.status === "thunder_day"}
+
+ {:else if weatherOutput.status === "thunder_night"}
+
+ {/if}
+ {Math.round(weatherOutput.celsiusTemp)}°
+
+ {/if}
+
+ {dateOutput?.formatted}
+
diff --git a/src/components/Workspaces.svelte b/src/components/Workspaces.svelte
new file mode 100644
index 0000000..7a73a3f
--- /dev/null
+++ b/src/components/Workspaces.svelte
@@ -0,0 +1,101 @@
+
+
+{#if glazewmOutput}
+
+ {#each glazewmOutput.currentWorkspaces as workspace, i}
+
+ {/each}
+
+
+
+
+ {#if glazewmOutput.focusedWorkspace}
+ {#each glazewmOutput.focusedWorkspace!.children as child}
+ {#if "state" in child && child.state?.type != "minimized"}
+
+
+
+ {/if}
+ {/each}
+ {/if}
+
+
+{/if}
diff --git a/src/lib/index.ts b/src/lib/index.ts
new file mode 100644
index 0000000..856f2b6
--- /dev/null
+++ b/src/lib/index.ts
@@ -0,0 +1 @@
+// place files you want to import through the `$lib` alias in this folder.
diff --git a/src/routes/+layout.ts b/src/routes/+layout.ts
new file mode 100644
index 0000000..6d63253
--- /dev/null
+++ b/src/routes/+layout.ts
@@ -0,0 +1,2 @@
+// This can be false if you're using a fallback (i.e. SPA mode)
+export const prerender = true;
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
new file mode 100644
index 0000000..225c1ca
--- /dev/null
+++ b/src/routes/+page.svelte
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/styles/themes/catppuccin.css b/src/themes/catppuccin.css
similarity index 100%
rename from styles/themes/catppuccin.css
rename to src/themes/catppuccin.css
diff --git a/src/themes/rose-pine.css b/src/themes/rose-pine.css
new file mode 100644
index 0000000..637c531
--- /dev/null
+++ b/src/themes/rose-pine.css
@@ -0,0 +1,56 @@
+:root {
+ /* Rosé Pine Dawn */
+ --rp-base: 32 57 95;
+ --rp-surface: 35 100 98;
+ --rp-overlay: 33 43 91;
+ --rp-muted: 257 9 61;
+ --rp-subtle: 248 12 52;
+ --rp-text: 248 19 40;
+ --rp-love: 343 35 55;
+ --rp-gold: 35 81 56;
+ --rp-rose: 3 53 67;
+ --rp-pine: 197 53 34;
+ --rp-foam: 189 30 48;
+ --rp-iris: 268 21 57;
+ --rp-highlight-low: 25 35 93;
+ --rp-highlight-med: 10 9 86;
+ --rp-highlight-high: 315 4 80;
+}
+
+@media (prefers-color-scheme: dark) {
+ :root {
+ /* Rosé Pine */
+ /* --rp-base: 249 22 12; */
+ /* --rp-surface: 247 23 15; */
+ /* --rp-overlay: 248 25 18; */
+ /* --rp-muted: 249 12 47; */
+ /* --rp-subtle: 248 15 61; */
+ /* --rp-text: 245 50 91; */
+ /* --rp-love: 343 76 68; */
+ /* --rp-gold: 35 88 72; */
+ /* --rp-rose: 2 55 83; */
+ /* --rp-pine: 197 49 38; */
+ /* --rp-foam: 189 43 73; */
+ /* --rp-iris: 267 57 78; */
+ /* --rp-highlight-low: 244 18 15; */
+ /* --rp-highlight-med: 249 15 28; */
+ /* --rp-highlight-high: 248 13 36; */
+
+ /* Rosé Pine Moon */
+ --rp-base: 246 24 17;
+ --rp-surface: 248 24 20;
+ --rp-overlay: 248 21 26;
+ --rp-muted: 249 12 47;
+ --rp-subtle: 248 15 61;
+ --rp-text: 245 50 91;
+ --rp-love: 343 76 68;
+ --rp-gold: 35 88 72;
+ --rp-rose: 2 66 75;
+ --rp-pine: 197 48 47;
+ --rp-foam: 189 43 73;
+ --rp-iris: 267 57 78;
+ --rp-highlight-low: 245 22 20;
+ --rp-highlight-med: 247 16 30;
+ --rp-highlight-high: 249 15 38;
+ }
+}
diff --git a/src/types/providers.d.ts b/src/types/providers.d.ts
new file mode 100644
index 0000000..0de813e
--- /dev/null
+++ b/src/types/providers.d.ts
@@ -0,0 +1,124 @@
+import { Workspace, Monitor as Monitor$1, Container, TilingDirection, BindingModeConfig, RunCommandResponse } from 'glazewm';
+
+export interface BatteryOutput {
+ chargePercent: number;
+ cycleCount: number;
+ healthPercent: number;
+ powerConsumption: number;
+ state: 'discharging' | 'charging' | 'full' | 'empty' | 'unknown';
+ isCharging: boolean;
+ timeTillEmpty: number | null;
+ timeTillFull: number | null;
+ voltage: number | null;
+}
+
+export interface CpuOutput {
+ frequency: number;
+ usage: number;
+ logicalCoreCount: number;
+ physicalCoreCount: number;
+ vendor: string;
+}
+
+export interface DateOutput {
+ formatted: string;
+ new: Date;
+ now: number;
+ iso: string;
+}
+
+export interface GlazeWmOutput {
+ displayedWorkspace: Workspace;
+ focusedWorkspace: Workspace;
+ currentWorkspaces: Workspace[];
+ allWorkspaces: Workspace[];
+ allMonitors: Monitor$1[];
+ focusedMonitor: Monitor$1;
+ currentMonitor: Monitor$1;
+ focusedContainer: Container;
+ tilingDirection: TilingDirection;
+ bindingModes: BindingModeConfig[];
+ runCommand(command: string, subjectContainerId?: string): Promise;
+}
+
+export interface MemoryOutput {
+ usage: number;
+ freeMemory: number;
+ usedMemory: number;
+ totalMemory: number;
+ freeSwap: number;
+ usedSwap: number;
+ totalSwap: number;
+}
+
+export interface NetworkOutput {
+ defaultInterface: NetworkInterface | null;
+ defaultGateway: NetworkGateway | null;
+ interfaces: NetworkInterface[];
+ traffic: NetworkTraffic | null;
+}
+interface NetworkInterface {
+ name: string;
+ friendlyName: string | null;
+ description: string | null;
+ type: InterfaceType;
+ ipv4Addresses: string[];
+ ipv6Addresses: string[];
+ macAddress: string | null;
+ transmitSeed: number | null;
+ receiveSpeed: number | null;
+ dnsServers: string[];
+ isDefault: boolean;
+}
+interface NetworkGateway {
+ macAddress: string;
+ ipv4Addresses: string[];
+ ipv6Addresses: string[];
+ ssid: string | null;
+ signalStrength: number | null;
+}
+declare enum InterfaceType {
+ UNKNOWN = "unknown",
+ ETHERNET = "ethernet",
+ TOKEN_RING = "token_ring",
+ FDDI = "fddi",
+ PPP = "ppp",
+ LOOPBACK = "loopback",
+ SLIP = "slip",
+ ATM = "atm",
+ GENERIC_MODEM = "generic_modem",
+ ISDN = "isdn",
+ WIFI = "wifi",
+ DSL = "dsl",
+ TUNNEL = "tunnel",
+ HIGH_PERFORMANCE_SERIAL_BUS = "high_performance_serial_bus",
+ MOBILE_BROADBAND = "mobile_broadband",
+ BRIDGE = "bridge"
+}
+interface NetworkTraffic {
+ received: number | null;
+ transmitted: number | null;
+}
+
+declare enum WeatherStatus {
+ CLEAR_DAY = "clear_day",
+ CLEAR_NIGHT = "clear_night",
+ CLOUDY_DAY = "cloudy_day",
+ CLOUDY_NIGHT = "cloudy_night",
+ LIGHT_RAIN_DAY = "light_rain_day",
+ LIGHT_RAIN_NIGHT = "light_rain_night",
+ HEAVY_RAIN_DAY = "heavy_rain_day",
+ HEAVY_RAIN_NIGHT = "heavy_rain_night",
+ SNOW_DAY = "snow_day",
+ SNOW_NIGHT = "snow_night",
+ THUNDER_DAY = "thunder_day",
+ THUNDER_NIGHT = "thunder_night"
+}
+
+interface WeatherOutput {
+ isDaytime: boolean;
+ status: WeatherStatus;
+ celsiusTemp: number;
+ fahrenheitTemp: number;
+ windSpeed: number;
+}
diff --git a/styles/animations.css b/styles/animations.css
deleted file mode 100644
index 3166559..0000000
--- a/styles/animations.css
+++ /dev/null
@@ -1,82 +0,0 @@
-@keyframes flash {
- from {
- opacity: 1;
- }
- 50% {
- opacity: 0.5;
- }
- to {
- opacity: 1;
- }
-}
-
-@keyframes pulse {
- 0% {
- transform: scale(1);
- }
- 50% {
- transform: scale(1.1);
- }
- 100% {
- transform: scale(1);
- }
-}
-
-@keyframes wiggle {
- 0% {
- transform: rotate(0deg);
- }
- 2% {
- transform: rotate(10deg);
- }
- 4% {
- transform: rotate(-10deg);
- }
- 6% {
- transform: rotate(10deg);
- }
- 8% {
- transform: rotate(-10deg);
- }
- 10% {
- transform: rotate(10deg);
- }
- 12% {
- transform: rotate(-10deg);
- }
- 14% {
- transform: rotate(10deg);
- }
- 16% {
- transform: rotate(-10deg);
- }
- 18% {
- transform: rotate(10deg);
- }
- 20% {
- transform: rotate(0deg);
- }
-}
-
-@keyframes press {
- from {
- transform: translateY(0px) translateX(0px);
- }
- to {
- box-shadow: none;
- transform: translateY(2px) translateX(2px);
- }
-}
-
-@keyframes move {
- 0%,
- 25% {
- transform: translateX(0%);
- left: 0%;
- }
- 75%,
- 100% {
- transform: translateX(-100%);
- left: 100%;
- }
-}
diff --git a/styles/bar.css b/styles/bar.css
deleted file mode 100644
index 1f59dfb..0000000
--- a/styles/bar.css
+++ /dev/null
@@ -1,15 +0,0 @@
-#bar {
- display: grid;
- grid-template-columns: 1fr 1fr 1fr;
- align-items: center;
- height: var(--height);
- margin: var(--bar-margin-y) var(--bar-margin-x);
- color: var(--text);
- font-family: var(--font-family);
- font-size: var(--font-size);
- font-weight: var(--font-weight);
-
- i {
- pointer-events: none;
- }
-}
diff --git a/styles/global.css b/styles/global.css
deleted file mode 100644
index c6c9629..0000000
--- a/styles/global.css
+++ /dev/null
@@ -1,8 +0,0 @@
-@import "http://asset.localhost/>> PATH TO YOUR YOUR GLZR CONFIG FOLDER<> PATH TO YOUR YOUR GLZR CONFIG FOLDER<> PATH TO YOUR YOUR GLZR CONFIG FOLDER<> PATH TO YOUR YOUR GLZR CONFIG FOLDER<> PATH TO YOUR YOUR GLZR CONFIG FOLDER<> PATH TO YOUR YOUR GLZR CONFIG FOLDER<> PATH TO YOUR YOUR GLZR CONFIG FOLDER<> PATH TO YOUR YOUR GLZR CONFIG FOLDER< div {
- display: flex;
- align-items: center;
- }
-
- i {
- font-size: 19px;
- margin-right: 7px;
- }
- }
-
- .meter {
- display: inline-block;
- height: 1rem;
- width: 3rem;
- border: var(--border-size) solid var(--border);
- border-radius: var(--radius);
- overflow: hidden;
- opacity: 1;
- transform: translateY(0%);
- transition:
- transform 0.3s ease,
- opacity 0.3s ease;
-
- span {
- display: block;
- height: 100%;
- width: 0;
- border-right: var(--border-size) solid var(--border);
- }
- }
-
- .label {
- position: absolute;
- display: flex;
- left: 30px;
- flex-direction: column;
- opacity: 0;
- transform: translateY(-100%);
- transition:
- transform 0.3s ease,
- opacity 0.3s ease;
- user-select: none;
- display: flex;
- }
-
- #menu {
- background: color-mix(in srgb, currentColor 30%, transparent);
- border: var(--border-size) solid var(--border);
- border-radius: var(--radius);
- box-shadow: var(--shadow-size-button) var(--shadow-size-button) 0 var(--shadow);
- transition:
- box-shadow 0.2s,
- transform 0.3s;
- color: var(--icon);
- padding: 3px;
- cursor: pointer;
-
- > div {
- display: flex;
- align-items: center;
- justify-content: center;
- }
-
- &:hover {
- box-shadow: none;
- transform: translateY(var(--shadow-size-button)) translateX(var(--shadow-size-button));
- }
-
- i {
- font-size: 1rem;
- }
- }
-
- #memory .meter span {
- background: var(--memory);
- }
-
- #cpu {
- .meter span {
- background: var(--cpu);
- }
-
- .high-usage {
- & .meter span {
- background: var(--cpu-high-usage);
- }
- & i {
- animation: flash 0.5s infinite;
- }
- }
- }
-
- #battery {
- .critical {
- i {
- animation: flash 1s infinite;
- }
- .meter span {
- background: var(--battery-low);
- }
- }
-
- .low {
- .meter span {
- background: var(--battery-low);
- }
- }
-
- .mid {
- .meter span {
- background: var(--battery-mid);
- }
- }
-
- .good {
- .meter span {
- background: var(--battery-good);
- }
- }
-
- .full {
- .meter span {
- background: var(--battery-good);
- border-right: none;
- }
- }
-
- .charging {
- animation: pulse 2s infinite;
- }
- }
-
- #dropdown {
- display: none;
- flex-direction: column;
- top: calc(var(--height) + (2 * var(--bar-margin-y)));
- left: var(--bar-margin-x);
- position: absolute;
- background: var(--bg);
- border: var(--border-size) solid var(--border);
- border-radius: var(--radius);
- box-shadow: var(--shadow-size-bar) var(--shadow-size-bar) 0 var(--shadow);
- color: var(--text);
- background-color: var(--bg);
- width: fit-content;
-
- a {
- color: var(--text);
- text-decoration: none;
- display: flex;
- align-items: center;
- justify-content: center;
- width: fit-content;
- padding: 8px;
- border-bottom: 2px solid var(--border);
- }
-
- a:last-child {
- border-bottom: none;
- }
-
- #powerdown {
- color: var(--rp-moon-love);
- &:hover {
- background: color-mix(in srgb, currentColor 30%, transparent);
- }
- }
- #sleep {
- color: var(--rp-moon-rose);
- &:hover {
- background: color-mix(in srgb, currentColor 30%, transparent);
- }
- }
- #logout {
- color: var(--rp-moon-gold);
- &:hover {
- background: color-mix(in srgb, currentColor 30%, transparent);
- }
- }
-
- i {
- font-size: 19px;
- }
- }
-}
diff --git a/styles/group-right.css b/styles/group-right.css
deleted file mode 100644
index d0ae765..0000000
--- a/styles/group-right.css
+++ /dev/null
@@ -1,61 +0,0 @@
-#right {
- height: 100%;
- justify-self: end;
- display: flex;
- align-items: center;
- background: var(--bg);
- border: 2px solid var(--border);
- border-radius: var(--radius);
- box-shadow: var(--shadow-size-bar) var(--shadow-size-bar) 0 var(--shadow);
- margin-right: 4px;
- overflow: hidden;
- white-space: nowrap;
-
- .template {
- margin: 4px;
- display: flex;
- align-items: center;
- }
-
- #now-playing,
- #network,
- #weather {
- padding: 6px;
- overflow: hidden;
- white-space: nowrap;
- max-width: 25vw;
-
- i {
- margin-right: 7px;
- }
- }
-
- #now-playing {
- & > i {
- color: var(--not-playing);
- &.playing {
- color: var(--now-playing);
- animation: wiggle 10s infinite;
- }
- }
-
- .move {
- display: inline-block;
- position: relative;
- }
- }
-
- #network i {
- font-size: 1.2rem;
- color: var(--network);
- }
-
- #weather i {
- font-size: 1.2rem;
- color: var(--weather);
- }
-
- #clock {
- padding-right: 6px;
- }
-}
diff --git a/styles/themes/rose-pine.css b/styles/themes/rose-pine.css
deleted file mode 100644
index b6d266c..0000000
--- a/styles/themes/rose-pine.css
+++ /dev/null
@@ -1 +0,0 @@
-@import url('https://unpkg.com/@rose-pine/palette@4.0.1/dist/css/rose-pine.css');
diff --git a/svelte.config.js b/svelte.config.js
new file mode 100644
index 0000000..530516c
--- /dev/null
+++ b/svelte.config.js
@@ -0,0 +1,17 @@
+import adapter from '@sveltejs/adapter-static';
+import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
+
+const config = {
+ preprocess: vitePreprocess(),
+ kit: {
+ adapter: adapter({
+ pages: "build",
+ assets: "build",
+ fallback: undefined,
+ precompress: false,
+ strict: true
+ })
+ }
+};
+
+export default config;
diff --git a/tailwind.config.js b/tailwind.config.js
new file mode 100644
index 0000000..dd5e0ea
--- /dev/null
+++ b/tailwind.config.js
@@ -0,0 +1,97 @@
+// eslint-disable-next-line @typescript-eslint/no-require-imports
+const defaultTheme = require("tailwindcss/defaultTheme");
+/** @type {import('tailwindcss').Config} */
+export default {
+ content: ["./src/**/*.{html,js,svelte,ts}"],
+ theme: {
+ extend: {
+ colors: {
+ zb: {
+ text: "hsl( var(--text) / )",
+ base: "hsl( var(--bg) / )",
+ border: "hsl(var(--border) / )",
+ shadow: "hsl(var(--shadow) / )",
+ icon: "hsl(var(--icon) / )",
+ memory: "hsl(var(--memory) / )",
+ cpu: "hsl(var(--cpu) / )",
+ "cpu-high-usage": "hsl(var(--cpu-high-usage) / )",
+ battery: {
+ good: "hsl(var(--battery-good) / )",
+ mid: "hsl(var(--battery-mid) / )",
+ low: "hsl(var(--battery-low) / )"
+ },
+ "focused-process": "hsl(var(--focused-process) / )",
+ process: "hsl(var(--process) / )",
+ displayed: "hsl(var(--displayed) / )",
+ ws: {
+ 0: "hsl(var(--ws-1) / )",
+ 1: "hsl(var(--ws-2) / )",
+ 2: "hsl(var(--ws-3) / )",
+ 3: "hsl(var(--ws-4) / )",
+ 4: "hsl(var(--ws-5) / )"
+ },
+ "tiling-direction": "hsl(var(--tiling-direction) / )",
+ spotify: {
+ playing: "hsl(var(--now-playing) / )",
+ paused: "hsl(var(--not-playing) / )"
+ },
+ network: "hsl(var(--network) / )",
+ weather: "hsl(var(--weather) / )"
+ },
+ blend: generateBlends()
+ },
+ borderRadius: {
+ base: "var(--radius)"
+ },
+ borderWidth: {
+ DEFAULT: "var(--border-size)"
+ },
+ boxShadow: {
+ button:
+ "var(--shadow-size-button) var(--shadow-size-button) 0 hsl(var(--shadow))",
+ bar: "var(--shadow-size-bar) var(--shadow-size-bar) 0 hsl(var(--shadow))"
+ },
+ translate: {
+ boxShadowX: "var(--shadow-size-button)",
+ boxShadowY: "var(--shadow-size-button)",
+ reverseBoxShadowX: "-var(--shadow-size-button)",
+ reverseBoxShadowY: "-var(--shadow-size-button)"
+ },
+ fontFamily: {
+ sans: ["SF Pro Display", ...defaultTheme.fontFamily.sans]
+ },
+ fontWeight: {
+ base: "var(--font-weight)"
+ },
+ fontSize: {
+ "zb-size": "var(--font-size)"
+ },
+ height: {
+ bar: "var(--height)"
+ },
+ margin: {
+ zbx: "var(--bar-margin-x)",
+ zby: "var(--bar-margin-y)"
+ }
+ }
+ },
+ safelist: [
+ "text-zb-ws-0",
+ "text-zb-ws-1",
+ "text-zb-ws-2",
+ "text-zb-ws-3",
+ "text-zb-ws-4",
+ "justify-self-start",
+ "justify-self-center",
+ "justify-self-end"
+ ],
+ plugins: []
+};
+
+function generateBlends() {
+ const blends = {};
+ for (let i = 5; i <= 100; i += 5) {
+ blends[i] = `color-mix(in srgb, currentColor ${i}%, transparent)`;
+ }
+ return blends;
+}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..fc93cbd
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "extends": "./.svelte-kit/tsconfig.json",
+ "compilerOptions": {
+ "allowJs": true,
+ "checkJs": true,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "resolveJsonModule": true,
+ "skipLibCheck": true,
+ "sourceMap": true,
+ "strict": true,
+ "moduleResolution": "bundler"
+ }
+ // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
+ // except $lib which is handled by https://kit.svelte.dev/docs/configuration#files
+ //
+ // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
+ // from the referenced tsconfig.json - TypeScript does not merge them in
+}
diff --git a/vite.config.ts b/vite.config.ts
new file mode 100644
index 0000000..bbf8c7d
--- /dev/null
+++ b/vite.config.ts
@@ -0,0 +1,6 @@
+import { sveltekit } from '@sveltejs/kit/vite';
+import { defineConfig } from 'vite';
+
+export default defineConfig({
+ plugins: [sveltekit()]
+});