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} +
+{/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()] +});