diff --git a/.gitignore b/.gitignore
index 32a3502..ebfba8d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,6 @@
+# Log
+*.log
+
# Private Files
*private*
.private.env.*
diff --git a/.vscode/settings.json b/.vscode/settings.json
index a719ff3..5826f1c 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -30,4 +30,8 @@
".wslconfig": "properties",
"WindowsTerminal.json": "jsonc",
},
-}
\ No newline at end of file
+ "[json]": {
+ "editor.formatOnPaste": false,
+ "editor.formatOnSave": false,
+ }
+}
diff --git a/bootstrap/common-pm.txt b/bootstrap/common-pm.txt
new file mode 100644
index 0000000..c7c52a4
--- /dev/null
+++ b/bootstrap/common-pm.txt
@@ -0,0 +1,17 @@
+# nodejs
+npm install -g typescript
+npm install -g tsx
+
+# dotnet
+dotnet tool install -g dotnet-script
+dotnet tool install -g dotnet-repl
+
+# python
+pip install neovim
+pip install requests
+pip install ipython
+pip install jupyter
+pip install numpy
+pip install matplotlib
+pip install pandas
+pip install scipy
diff --git a/bootstrap/win/Defender.ps1 b/bootstrap/win/Defender.ps1
new file mode 100644
index 0000000..007c5f1
--- /dev/null
+++ b/bootstrap/win/Defender.ps1
@@ -0,0 +1,20 @@
+# Run as Administrator
+
+Set-MpPreference -EnableControlledFolderAccess 1
+
+$protected = (Get-MpPreference).ControlledFolderAccessProtectedFolders
+$protected += "$env:USERPROFILE\.ssh"
+$protected += "$env:USERPROFILE\.config"
+Set-MpPreference -ControlledFolderAccessProtectedFolders $protected
+
+$apps = (Get-MpPreference).ControlledFolderAccessAllowedApplications
+$apps += "$Env:Windir\System32\OpenSSH\ssh.exe"
+$apps += "$Env:ProgramFiles\GPSoftware\Directory Opus\DOpus.exe"
+$apps += "$Env:UserProfile\scoop\apps\pwsh\current\pwsh.exe"
+Set-MpPreference -ControlledFolderAccessAllowedApplications $apps
+
+$exclusion = (Get-MpPreference).ExclusionPath
+$exclusion += "$env:ProgramFiles\JetBrains"
+$exclusion += "$env:LocalAppData\JetBrains"
+$exclusion += "D:\Source"
+Set-MpPreference -ExclusionPath $exclusion
diff --git a/platforms/win/glzr/.gitignore b/platforms/win/glzr/.gitignore
new file mode 100644
index 0000000..40ddb92
--- /dev/null
+++ b/platforms/win/glzr/.gitignore
@@ -0,0 +1,4 @@
+# New-Item -ItemType SymbolicLink -Path $Env:UserProfile\.glzr -Target $DOTFILES\platforms\win\glzr -Force
+boilerplate*
+starter/
+neobrutal/
diff --git a/platforms/win/glzr/glazewm/config.yaml b/platforms/win/glzr/glazewm/config.yaml
new file mode 100644
index 0000000..79984ea
--- /dev/null
+++ b/platforms/win/glzr/glazewm/config.yaml
@@ -0,0 +1,314 @@
+# $DOTFILES/platforms/win/glzr/glazewm/config.yaml
+# Date: 2025-01-05
+# Author: js0ny
+
+# Location:
+# - %UserProfile%\.glzr\glazewm\config.yaml
+# Linking: Link to whole directory
+# New-Item -ItemType SymbolicLink -Path $Env:UserProfile\.glzr -Target $DOTFILES\platforms\win\glzr -Force
+
+general:
+ # Commands to run when the WM has started. This is useful for running a
+ # script or launching another application.
+ # Example: The below command launches Zebar.
+ startup_commands: ["shell-exec zebar"]
+
+ # Commands to run just before the WM is shutdown.
+ # Example: The below command kills Zebar.
+ shutdown_commands: ["shell-exec taskkill /IM zebar.exe /F"]
+
+ # Commands to run after the WM config is reloaded.
+ config_reload_commands: []
+
+ # Whether to automatically focus windows underneath the cursor.
+ focus_follows_cursor: false
+
+ # Whether to switch back and forth between the previously focused
+ # workspace when focusing the current workspace.
+ toggle_workspace_on_refocus: false
+
+ cursor_jump:
+ # Whether to automatically move the cursor on the specified trigger.
+ enabled: true
+
+ # Trigger for cursor jump:
+ # - 'monitor_focus': Jump when focus changes between monitors.
+ # - 'window_focus': Jump when focus changes between windows.
+ trigger: "monitor_focus"
+
+ # How windows should be hidden when switching workspaces.
+ # - 'cloak': Recommended. Hides windows with no animation.
+ # - 'hide': Legacy method (v3.5 and earlier) that has a brief animation,
+ # but has stability issues with some apps.
+ hide_method: "cloak"
+
+ # Affects which windows get shown in the native Windows taskbar. Has no
+ # effect if `hide_method: 'hide'`.
+ # - 'true': Show all windows (regardless of workspace).
+ # - 'false': Only show windows from the currently shown workspaces.
+ show_all_in_taskbar: false
+
+gaps:
+ # Whether to scale the gaps with the DPI of the monitor.
+ scale_with_dpi: true
+
+ # Gap between adjacent windows.
+ inner_gap: "20px"
+
+ # Gap between windows and the screen edge.
+ outer_gap:
+ top: "60px"
+ right: "20px"
+ bottom: "20px"
+ left: "20px"
+
+window_effects:
+ # Visual effects to apply to the focused window.
+ focused_window:
+ # Highlight the window with a colored border.
+ # ** Exclusive to Windows 11 due to API limitations.
+ border:
+ enabled: true
+ color: "#8dbcff"
+
+ # Remove the title bar from the window's frame. Note that this can
+ # cause rendering issues for some applications.
+ hide_title_bar:
+ enabled: false
+
+ # Change the corner style of the window's frame.
+ # ** Exclusive to Windows 11 due to API limitations.
+ corner_style:
+ enabled: false
+ # Allowed values: 'square', 'rounded', 'small_rounded'.
+ style: "square"
+
+ # Visual effects to apply to non-focused windows.
+ other_windows:
+ border:
+ enabled: true
+ color: "#a1a1a1"
+ hide_title_bar:
+ enabled: false
+ corner_style:
+ enabled: false
+ style: "square"
+
+window_behavior:
+ # New windows are created in this state whenever possible.
+ # Allowed values: 'tiling', 'floating'.
+ initial_state: "tiling"
+
+ # Sets the default options for when a new window is created. This also
+ # changes the defaults for when the state change commands, like
+ # `set-floating`, are used without any flags.
+ state_defaults:
+ floating:
+ # Whether to center floating windows by default.
+ centered: true
+
+ # Whether to show floating windows as always on top.
+ shown_on_top: false
+
+ fullscreen:
+ # Maximize the window if possible. If the window doesn't have a
+ # maximize button, then it'll be fullscreen'ed normally instead.
+ maximized: false
+
+ # Whether to show fullscreen windows as always on top.
+ shown_on_top: false
+
+workspaces:
+ - name: "1"
+ - name: "2"
+ - name: "3"
+ - name: "4"
+ - name: "5"
+ - name: "6"
+ - name: "7"
+ - name: "8"
+ - name: "9"
+
+window_rules:
+ - commands: ["ignore"]
+ match:
+ # Ignores any Zebar windows.
+ - window_process: { equals: "zebar" }
+
+ # Ignores picture-in-picture windows for browsers.
+ - window_title: { regex: "[Pp]icture.in.[Pp]icture" }
+ window_class: { regex: "Chrome_WidgetWin_1|MozillaDialogClass" }
+
+ # Ignore rules for various 3rd-party apps.
+ - window_process: { equals: "PowerToys" }
+ window_class: { regex: 'HwndWrapper\[PowerToys\.PowerAccent.*?\]' }
+ - window_process: { equals: "PowerToys" }
+ window_title: { regex: ".*? - Peek" }
+ - window_process: { equals: "Lively" }
+ window_class: { regex: "HwndWrapper" }
+
+binding_modes:
+ # When enabled, the focused window can be resized via arrow keys or HJKL.
+ - name: "resize"
+ keybindings:
+ - commands: ["resize --width -2%"]
+ bindings: ["h", "left"]
+ - commands: ["resize --width +2%"]
+ bindings: ["i", "right"]
+ - commands: ["resize --height +2%"]
+ bindings: ["e", "up"]
+ - commands: ["resize --height -2%"]
+ bindings: ["n", "down"]
+ # Press enter/escape to return to default keybindings.
+ - commands: ["wm-disable-binding-mode --name resize"]
+ bindings: ["escape", "enter"]
+
+keybindings:
+ # Shift focus in a given direction.
+ - commands: ["focus --direction left"]
+ bindings: ["lwin+h", "lwin+left"]
+ - commands: ["focus --direction right"]
+ bindings: ["lwin+i", "lwin+right"]
+ - commands: ["focus --direction up"]
+ bindings: ["lwin+e", "lwin+up"]
+ - commands: ["focus --direction down"]
+ bindings: ["lwin+n", "lwin+down"]
+
+ # Move focused window in a given direction.
+ - commands: ["move --direction left"]
+ bindings: ["lwin+shift+h", "lwin+shift+left"]
+ - commands: ["move --direction right"]
+ bindings: ["lwin+shift+i", "lwin+shift+right"]
+ - commands: ["move --direction up"]
+ bindings: ["lwin+shift+e", "lwin+shift+up"]
+ - commands: ["move --direction down"]
+ bindings: ["lwin+shift+n", "lwin+shift+down"]
+
+ # Resize focused window by a percentage or pixel amount.
+ - commands: ["resize --width -2%"]
+ bindings: ["alt+u"]
+ - commands: ["resize --width +2%"]
+ bindings: ["alt+p"]
+ - commands: ["resize --height +2%"]
+ bindings: ["alt+o"]
+ - commands: ["resize --height -2%"]
+ bindings: ["alt+i"]
+
+ # As an alternative to the resize keybindings above, resize mode enables
+ # resizing via arrow keys or HJKL. The binding mode is defined above with
+ # the name 'resize'.
+ - commands: ["wm-enable-binding-mode --name resize"]
+ bindings: ["lwin+shift+r"]
+
+ # Disables window management and all other keybindings until alt+shift+p
+ # is pressed again.
+ - commands: ["wm-toggle-pause"]
+ bindings: ["alt+shift+p"]
+
+ # Change tiling direction. This determines where new tiling windows will
+ # be inserted.
+ - commands: ["toggle-tiling-direction"]
+ bindings: ["lwin+v"]
+
+ # Change focus from tiling windows -> floating -> fullscreen.
+ # - commands: ["wm-cycle-focus"]
+ # bindings: ["alt+space"]
+
+ # Change the focused window to be floating.
+ - commands: ["toggle-floating --centered"]
+ bindings: ["alt+shift+space"]
+
+ # Change the focused window to be tiling.
+ - commands: ["toggle-tiling"]
+ bindings: ["lwin+t"]
+
+ # Change the focused window to be fullscreen.
+ - commands: ["toggle-fullscreen"]
+ bindings: ["lwin+f"]
+
+ # Minimize focused window.
+ - commands: ["toggle-minimized"]
+ bindings: ["lwin+m"]
+
+ # Close focused window.
+ - commands: ["close"]
+ bindings: ["lwin+q"]
+
+ # Kill GlazeWM process safely.
+ - commands: ["wm-exit"]
+ bindings: ["alt+shift+e"]
+
+ # Re-evaluate configuration file.
+ - commands: ["wm-reload-config"]
+ bindings: ["alt+shift+r"]
+
+ # Redraw all windows.
+ - commands: ["wm-redraw"]
+ bindings: ["alt+shift+w"]
+
+ # Launch CMD terminal. Alternatively, use `shell-exec wt` or
+ # `shell-exec %ProgramFiles%/Git/git-bash.exe` to start Windows
+ # Terminal and Git Bash respectively.
+ - commands: ["shell-exec wt"]
+ bindings: ["lwin+r"]
+
+ # Focus the next/previous active workspace defined in `workspaces` config.
+ - commands: ["focus --next-active-workspace"]
+ bindings: ["alt+s"]
+ - commands: ["focus --prev-active-workspace"]
+ bindings: ["alt+a"]
+
+ # Focus the workspace that last had focus.
+ - commands: ["focus --recent-workspace"]
+ bindings: ["alt+d"]
+
+ # Change focus to a workspace defined in `workspaces` config.
+ - commands: ["focus --workspace 1"]
+ bindings: ["lwin+1"]
+ - commands: ["focus --workspace 2"]
+ bindings: ["lwin+2"]
+ - commands: ["focus --workspace 3"]
+ bindings: ["lwin+3"]
+ - commands: ["focus --workspace 4"]
+ bindings: ["lwin+4"]
+ - commands: ["focus --workspace 5"]
+ bindings: ["lwin+5"]
+ - commands: ["focus --workspace 6"]
+ bindings: ["lwin+6"]
+ - commands: ["focus --workspace 7"]
+ bindings: ["lwin+7"]
+ - commands: ["focus --workspace 8"]
+ bindings: ["lwin+8"]
+ - commands: ["focus --workspace 9"]
+ bindings: ["lwin+9"]
+
+ # Move the focused window's parent workspace to a monitor in a given
+ # direction.
+ - commands: ["move-workspace --direction left"]
+ bindings: ["alt+shift+a"]
+ - commands: ["move-workspace --direction right"]
+ bindings: ["alt+shift+f"]
+ - commands: ["move-workspace --direction up"]
+ bindings: ["alt+shift+d"]
+ - commands: ["move-workspace --direction down"]
+ bindings: ["alt+shift+s"]
+
+ # Move focused window to a workspace defined in `workspaces` config.
+ - commands: ["move --workspace 1", "focus --workspace 1"]
+ bindings: ["lwin+shift+1"]
+ - commands: ["move --workspace 2", "focus --workspace 2"]
+ bindings: ["lwin+shift+2"]
+ - commands: ["move --workspace 3", "focus --workspace 3"]
+ bindings: ["lwin+shift+3"]
+ - commands: ["move --workspace 4", "focus --workspace 4"]
+ bindings: ["lwin+shift+4"]
+ - commands: ["move --workspace 5", "focus --workspace 5"]
+ bindings: ["lwin+shift+5"]
+ - commands: ["move --workspace 6", "focus --workspace 6"]
+ bindings: ["lwin+shift+6"]
+ - commands: ["move --workspace 7", "focus --workspace 7"]
+ bindings: ["lwin+shift+7"]
+ - commands: ["move --workspace 8", "focus --workspace 8"]
+ bindings: ["lwin+shift+8"]
+ - commands: ["move --workspace 9", "focus --workspace 9"]
+ bindings: ["lwin+shift+9"]
diff --git a/platforms/win/glzr/readme.md b/platforms/win/glzr/readme.md
new file mode 100644
index 0000000..095effb
--- /dev/null
+++ b/platforms/win/glzr/readme.md
@@ -0,0 +1,29 @@
+# GlazeWM Setup
+
+Link the whole `glzr` directory to the user's home directory.
+
+```powershell
+New-Item -ItemType SymbolicLink -Path $Env:UserProfile\.glzr -Target $DOTFILES\platforms\win\glzr -Force
+```
+
+The Zebar config should be downloaded from [this repository](https://github.com/js0ny/neobrutal-zebar) and extracted to the `glzr\zebar` directory.
+
+Or use the minimal setup, by changing `glzr\zebar\settings.json`: `startupConfigs.path` to `minimal/bar.zebar.json`.
+
+```json
+{
+ "$schema": "https://github.com/glzr-io/zebar/raw/v2.4.0/resources/settings-schema.json",
+ "startupConfigs": [
+ {
+ "path": "minimal/bar.zebar.json",
+ "preset": "default"
+ }
+ ]
+}
+```
+
+```powershell
+Invoke-WebRequest -Uri "https://github.com/js0ny/neobrutal-zebar/releases/download/2/neobrutal.zip" -OutFile "$Env:UserProfile\.glzr\zebar\neobrutal.zip"
+Expand-Archive -Path "$Env:UserProfile\.glzr\zebar\neobrutal.zip" -DestinationPath "$Env:UserProfile\.glzr\zebar"
+Remove-Item -Path "$Env:UserProfile\.glzr\zebar\neobrutal.zip"
+```
diff --git a/platforms/win/glzr/zebar/minimal/bar.zebar.json b/platforms/win/glzr/zebar/minimal/bar.zebar.json
new file mode 100644
index 0000000..1dcb03c
--- /dev/null
+++ b/platforms/win/glzr/zebar/minimal/bar.zebar.json
@@ -0,0 +1,22 @@
+{
+ "$schema": "https://github.com/glzr-io/zebar/raw/v2.4.0/resources/widget-schema.json",
+ "htmlPath": "./index.html",
+ "zOrder": "normal",
+ "shownInTaskbar": false,
+ "focused": false,
+ "resizable": false,
+ "transparent": true,
+ "presets": [
+ {
+ "name": "default",
+ "anchor": "top_left",
+ "offsetX": "0px",
+ "offsetY": "0px",
+ "width": "100%",
+ "height": "40px",
+ "monitorSelection": {
+ "type": "all"
+ }
+ }
+ ]
+}
diff --git a/platforms/win/glzr/zebar/minimal/index.html b/platforms/win/glzr/zebar/minimal/index.html
new file mode 100644
index 0000000..b97b52f
--- /dev/null
+++ b/platforms/win/glzr/zebar/minimal/index.html
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/platforms/win/glzr/zebar/minimal/scripts.jsx b/platforms/win/glzr/zebar/minimal/scripts.jsx
new file mode 100644
index 0000000..fbbace9
--- /dev/null
+++ b/platforms/win/glzr/zebar/minimal/scripts.jsx
@@ -0,0 +1,197 @@
+import React, {
+ useState,
+ useEffect,
+} from 'https://esm.sh/react@18?dev';
+import { createRoot } from 'https://esm.sh/react-dom@18/client?dev';
+import * as zebar from 'https://esm.sh/zebar@2';
+
+const providers = zebar.createProviderGroup({
+ // network: { type: 'network' },
+ glazewm: { type: 'glazewm' },
+ cpu: { type: 'cpu' },
+ date: { type: 'date', formatting: 'HH:mm:ss MMM月d日 EEE', locale: 'zh-CN' },
+ battery: { type: 'battery' },
+ memory: { type: 'memory' },
+ weather: { type: 'weather' },
+});
+
+function getNetworkIcon(networkOutput) {
+ switch (networkOutput.defaultInterface?.type) {
+ case 'ethernet':
+ return ;
+ case 'wifi':
+ if (networkOutput.defaultGateway?.signalStrength >= 80) {
+ return ;
+ } else if (
+ networkOutput.defaultGateway?.signalStrength >= 65
+ ) {
+ return ;
+ } else if (
+ networkOutput.defaultGateway?.signalStrength >= 40
+ ) {
+ return ;
+ } else if (
+ networkOutput.defaultGateway?.signalStrength >= 25
+ ) {
+ return ;
+ } else {
+ return ;
+ }
+ default:
+ return (
+
+ );
+ }
+}
+// Get icon to show for how much of the battery is charged.
+function getBatteryIcon(batteryOutput) {
+ if (batteryOutput.chargePercent > 90)
+ return ;
+ if (batteryOutput.chargePercent > 70)
+ return ;
+ if (batteryOutput.chargePercent > 40)
+ return ;
+ if (batteryOutput.chargePercent > 20)
+ return ;
+ return ;
+}
+// Get icon to show for current weather status.
+function getWeatherIcon(weatherOutput) {
+ switch (weatherOutput.status) {
+ case 'clear_day':
+ return ;
+ case 'clear_night':
+ return ;
+ case 'cloudy_day':
+ return ;
+ case 'cloudy_night':
+ return ;
+ case 'light_rain_day':
+ return ;
+ case 'light_rain_night':
+ return ;
+ case 'heavy_rain_day':
+ return ;
+ case 'heavy_rain_night':
+ return ;
+ case 'snow_day':
+ return ;
+ case 'snow_night':
+ return ;
+ case 'thunder_day':
+ return ;
+ case 'thunder_night':
+ return ;
+ }
+}
+
+createRoot(document.getElementById('root')).render();
+
+function App() {
+ const [output, setOutput] = useState(providers.outputMap);
+
+ useEffect(() => {
+ providers.onOutput(() => setOutput(providers.outputMap));
+ }, []);
+
+
+
+ return (
+
+
+
+ {output.glazewm && (
+
+ {output.glazewm.currentWorkspaces.map(workspace => (
+
+ ))}
+
+ )}
+
+
+
{output.date?.formatted}
+
+
+ {output.glazewm && (
+ <>
+ {output.glazewm.bindingModes.map(bindingMode => (
+
+ ))}
+
+
+ >
+ )}
+
+ {output.network && (
+
+ {getNetworkIcon(output.network)}
+ {output.network.defaultGateway?.ssid}
+
+ )}
+
+ {output.memory && (
+
+
+ {Math.round(output.memory.usage)}%
+
+ )}
+
+ {output.cpu && (
+
+
+
+ {/* Change the text color if the CPU usage is high. */}
+ 85 ? 'high-usage' : ''}
+ >
+ {Math.round(output.cpu.usage)}%
+
+
+ )}
+
+ {output.battery && (
+
+ {/* Show icon for whether battery is charging. */}
+ {output.battery.isCharging && (
+
+ )}
+ {getBatteryIcon(output.battery)}
+ {Math.round(output.battery.chargePercent)}%
+
+ )}
+
+ {output.weather && (
+
+ {getWeatherIcon(output.weather)}
+ {Math.round(output.weather.celsiusTemp)}°C
+
+ )}
+
+
+ );
+}
diff --git a/platforms/win/glzr/zebar/minimal/styles.css b/platforms/win/glzr/zebar/minimal/styles.css
new file mode 100644
index 0000000..c28280d
--- /dev/null
+++ b/platforms/win/glzr/zebar/minimal/styles.css
@@ -0,0 +1,115 @@
+/**
+ * Import the Nerdfonts icon font.
+ * Ref https://www.nerdfonts.com/cheat-sheet for a cheatsheet of available Nerdfonts icons.
+ */
+@import 'https://www.nerdfonts.com/assets/css/webfont.css';
+
+i {
+ color: rgb(115 130 175 / 95%);
+ margin-right: 7px;
+}
+
+body {
+ color: rgb(255 255 255 / 90%);
+ font-family: "JetBrainsMono Nerd Font", "LXGW Wenkai", ui-monospace, monospace;
+ font-size: 12px;
+ overflow: hidden;
+}
+
+html,
+body,
+#root {
+ height: 100%;
+}
+
+#root {
+ border-bottom: 1px solid rgb(255 255 255 / 5%);
+ background: linear-gradient(rgb(0 0 0 / 90%), rgb(5 2 20 / 85%));
+}
+
+.app {
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr;
+ align-items: center;
+ height: 100%;
+ padding: 4px 1.5vw;
+}
+
+.left,
+.center,
+.right {
+ display: flex;
+ align-items: center;
+}
+
+.center {
+ justify-self: center;
+}
+
+.right {
+ justify-self: end;
+}
+
+.logo,
+.binding-mode,
+.tiling-direction,
+.network,
+.memory,
+.cpu,
+.battery {
+ margin-right: 20px;
+}
+
+.workspaces {
+ display: flex;
+ align-items: center;
+}
+
+.workspace {
+ background: rgb(255 255 255 / 5%);
+ margin-right: 4px;
+ padding: 4px 8px;
+ color: rgb(255 255 255 / 90%);
+ border: none;
+ border-radius: 2px;
+ cursor: pointer;
+
+ &.displayed {
+ background: rgb(255 255 255 / 15%);
+ }
+
+ &.focused,
+ &:hover {
+ background: rgb(75 115 255 / 50%);
+ }
+}
+
+.binding-mode,
+.tiling-direction {
+ background: rgb(255 255 255 / 15%);
+ color: rgb(255 255 255 / 90%);
+ border-radius: 2px;
+ line-height: 1;
+ padding: 4px 8px;
+ border: 0;
+ cursor: pointer;
+}
+
+.binding-mode {
+ margin-right: 4px;
+}
+
+.cpu .high-usage {
+ color: #900029;
+}
+
+.battery {
+ position: relative;
+}
+
+.battery .charging-icon {
+ position: absolute;
+ font-size: 7px;
+ left: -8px;
+ top: 3px;
+}
diff --git a/platforms/win/glzr/zebar/normalize.css b/platforms/win/glzr/zebar/normalize.css
new file mode 100644
index 0000000..2204e78
--- /dev/null
+++ b/platforms/win/glzr/zebar/normalize.css
@@ -0,0 +1,204 @@
+/**
+ * Base CSS styles for better consistency across platforms.
+ * Yoinked from: https://github.com/sindresorhus/modern-normalize
+ */
+
+/*
+Document
+========
+*/
+
+/**
+Use a better box model (opinionated).
+*/
+
+*,
+::before,
+::after {
+ box-sizing: border-box;
+}
+
+html {
+ /* Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3) */
+ font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif,
+ 'Apple Color Emoji', 'Segoe UI Emoji';
+ line-height: 1.15; /* 1. Correct the line height in all browsers. */
+ -webkit-text-size-adjust: 100%; /* 2. Prevent adjustments of font size after orientation changes in iOS. */
+ tab-size: 4; /* 3. Use a more readable tab size (opinionated). */
+}
+
+/*
+Sections
+========
+*/
+
+body {
+ margin: 0; /* Remove the margin in all browsers. */
+}
+
+/*
+Text-level semantics
+====================
+*/
+
+/**
+Add the correct font weight in Chrome and Safari.
+*/
+
+b,
+strong {
+ font-weight: bolder;
+}
+
+/**
+1. Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3)
+2. Correct the odd 'em' font sizing in all browsers.
+*/
+
+code,
+kbd,
+samp,
+pre {
+ font-family: ui-monospace, SFMono-Regular, Consolas, 'Liberation Mono',
+ Menlo, monospace; /* 1 */
+ font-size: 1em; /* 2 */
+}
+
+/**
+Add the correct font size in all browsers.
+*/
+
+small {
+ font-size: 80%;
+}
+
+/**
+Prevent 'sub' and 'sup' elements from affecting the line height in all browsers.
+*/
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+sup {
+ top: -0.5em;
+}
+
+/*
+Tabular data
+============
+*/
+
+/**
+Correct table border color inheritance in Chrome and Safari. (https://issues.chromium.org/issues/40615503, https://bugs.webkit.org/show_bug.cgi?id=195016)
+*/
+
+table {
+ border-color: currentcolor;
+}
+
+/*
+Forms
+=====
+*/
+
+/**
+1. Change the font styles in all browsers.
+2. Remove the margin in Firefox and Safari.
+*/
+
+button,
+input,
+optgroup,
+select,
+textarea {
+ font-family: inherit; /* 1 */
+ font-size: 100%; /* 1 */
+ line-height: 1.15; /* 1 */
+ margin: 0; /* 2 */
+}
+
+/**
+Correct the inability to style clickable types in iOS and Safari.
+*/
+
+button,
+[type='button'],
+[type='reset'],
+[type='submit'] {
+ -webkit-appearance: button;
+}
+
+/**
+Remove the padding so developers are not caught out when they zero out 'fieldset' elements in all browsers.
+*/
+
+legend {
+ padding: 0;
+}
+
+/**
+Add the correct vertical alignment in Chrome and Firefox.
+*/
+
+progress {
+ vertical-align: baseline;
+}
+
+/**
+Correct the cursor style of increment and decrement buttons in Safari.
+*/
+
+::-webkit-inner-spin-button,
+::-webkit-outer-spin-button {
+ height: auto;
+}
+
+/**
+1. Correct the odd appearance in Chrome and Safari.
+2. Correct the outline style in Safari.
+*/
+
+[type='search'] {
+ -webkit-appearance: textfield; /* 1 */
+ outline-offset: -2px; /* 2 */
+}
+
+/**
+Remove the inner padding in Chrome and Safari on macOS.
+*/
+
+::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+/**
+1. Correct the inability to style clickable types in iOS and Safari.
+2. Change font properties to 'inherit' in Safari.
+*/
+
+::-webkit-file-upload-button {
+ -webkit-appearance: button; /* 1 */
+ font: inherit; /* 2 */
+}
+
+/*
+Interactive
+===========
+*/
+
+/*
+Add the correct display in Chrome and Safari.
+*/
+
+summary {
+ display: list-item;
+}
diff --git a/platforms/win/glzr/zebar/settings.json b/platforms/win/glzr/zebar/settings.json
new file mode 100644
index 0000000..66efb4e
--- /dev/null
+++ b/platforms/win/glzr/zebar/settings.json
@@ -0,0 +1,9 @@
+{
+ "$schema": "https://github.com/glzr-io/zebar/raw/v2.4.0/resources/settings-schema.json",
+ "startupConfigs": [
+ {
+ "path": "neobrutal/bar.zebar.json",
+ "preset": "default"
+ }
+ ]
+}
diff --git a/tools/browser/surfingkeys.js b/tools/browser/surfingkeys.js
index d778b0a..3302020 100644
--- a/tools/browser/surfingkeys.js
+++ b/tools/browser/surfingkeys.js
@@ -73,6 +73,7 @@ const forwardFactory = {
}
}
// #endregion
+
// #region Keymap
const mapLists = {
/// scroll page
@@ -165,7 +166,6 @@ api.addSearchAlias('c', 'ChatGPT', 'https://chatgpt.com/?q=', 's', 'https://duck
// #endregion
// #region Site-specific
-
// chatgpt.com
api.unmap('t', /chatgpt.com/);
api.mapkey('tn', 'New Chat', function () {
@@ -184,245 +184,24 @@ api.mapkey('S', 'Start/Stop Generating', function () {
var btn = document.querySelector('button.h-8:nth-child(2)');
btn.click();
}, { domain: /chatgpt.com/ });
+api.mapkey('an', 'New Chat', function () {
+ var btn = document.querySelector('div.no-draggable:nth-child(3) > span:nth-child(1) > button:nth-child(1)')
+ btn.click();
+}, { domain: /chatgpt.com/ });
+api.mapkey('as', 'Start/Stop Generating', function () {
+ var btn = document.querySelector('button.h-8:nth-child(2)');
+ btn.click();
+}, { domain: /chatgpt.com/ });
+api.mapkey('as', 'Start/Stop Generating', function () {
+ var btn = document.querySelector('button.h-8:nth-child(2)');
+ btn.click();
+}, { domain: /chatgpt.com/ });
//api.mapkey('tm', 'Toggle Model', function () {
// var btn = document.querySelector('#radix -\: r2i\:');
// btn.click();
//}, { domain: /chatgpt.com/ });
+// perplexity.ai
+api.unmap('', /perplexity.ai/);
+
// #endregion
-
-// #region Theme
-// reference to https://github.com/Foldex/surfingkeys-config
-// api.Hints.style('border: solid 2px #4C566A; color:#A3BE8C; background: initial; background-color: #3B4252;');
-// api.Hints.style("border: solid 2px #4C566A !important; padding: 1px !important; color: #E5E9F0 !important; background: #3B4252 !important;", "text");
-// api.Visual.style('marks', 'background-color: #A3BE8C99;');
-// api.Visual.style('cursor', 'background-color: #88C0D0;');
-// settings.theme = `
-// fg: #E5E9F0;
-// bg: #3B4252;
-// bg-dark: #2E3440;
-// border: #4C566A;
-// main-fg: #88C0D0;
-// accent-fg: #A3BE8C;
-// info-fg: #5E81AC;
-// select: #4C566A;
-// /* ---------- Generic ---------- */
-// .sk_theme {
-// background: var(--bg);
-// color: var(--fg);
-// background-color: var(--bg);
-// border-color: var(--border);
-// font-family: var(--font);
-// font-size: var(--font-size);
-// font-weight: var(--font-weight);
-// }
-
-// input {
-// font-family: var(--font);
-// font-weight: var(--font-weight);
-// }
-
-// .sk_theme tbody {
-// color: var(--fg);
-// }
-
-// .sk_theme input {
-// color: var(--fg);
-// }
-
-// /* Hints */
-// #sk_hints .begin {
-// color: var(--accent-fg) !important;
-// }
-
-// #sk_tabs .sk_tab {
-// background: var(--bg-dark);
-// border: 1px solid var(--border);
-// }
-
-// #sk_tabs .sk_tab_title {
-// color: var(--fg);
-// }
-
-// #sk_tabs .sk_tab_url {
-// color: var(--main-fg);
-// }
-
-// #sk_tabs .sk_tab_hint {
-// background: var(--bg);
-// border: 1px solid var(--border);
-// color: var(--accent-fg);
-// }
-
-// .sk_theme #sk_frame {
-// background: var(--bg);
-// opacity: 0.2;
-// color: var(--accent-fg);
-// }
-
-// /* ---------- Omnibar ---------- */
-// /* Uncomment this and use settings.omnibarPosition = 'bottom' for Pentadactyl/Tridactyl style bottom bar */
-// /* .sk_theme#sk_omnibar {
-// width: 100%;
-// left: 0;
-// } */
-
-// .sk_theme .title {
-// color: var(--accent-fg);
-// }
-
-// .sk_theme .url {
-// color: var(--main-fg);
-// }
-
-// .sk_theme .annotation {
-// color: var(--accent-fg);
-// }
-
-// .sk_theme .omnibar_highlight {
-// color: var(--accent-fg);
-// }
-
-// .sk_theme .omnibar_timestamp {
-// color: var(--info-fg);
-// }
-
-// .sk_theme .omnibar_visitcount {
-// color: var(--accent-fg);
-// }
-
-// .sk_theme #sk_omnibarSearchResult ul li:nth-child(odd) {
-// background: var(--bg-dark);
-// }
-
-// .sk_theme #sk_omnibarSearchResult ul li.focused {
-// background: var(--border);
-// }
-
-// .sk_theme #sk_omnibarSearchArea {
-// border-top-color: var(--border);
-// border-bottom-color: var(--border);
-// }
-
-// .sk_theme #sk_omnibarSearchArea input,
-// .sk_theme #sk_omnibarSearchArea span {
-// font-size: var(--font-size);
-// }
-
-// .sk_theme .separator {
-// color: var(--accent-fg);
-// }
-
-// /* ---------- Popup Notification Banner ---------- */
-// #sk_banner {
-// font-family: var(--font);
-// font-size: var(--font-size);
-// font-weight: var(--font-weight);
-// background: var(--bg);
-// border-color: var(--border);
-// color: var(--fg);
-// opacity: 0.9;
-// }
-
-// /* ---------- Popup Keys ---------- */
-// #sk_keystroke {
-// background-color: var(--bg);
-// }
-
-// .sk_theme kbd .candidates {
-// color: var(--info-fg);
-// }
-
-// .sk_theme span.annotation {
-// color: var(--accent-fg);
-// }
-
-// /* ---------- Popup Translation Bubble ---------- */
-// #sk_bubble {
-// background-color: var(--bg) !important;
-// color: var(--fg) !important;
-// border-color: var(--border) !important;
-// }
-
-// #sk_bubble * {
-// color: var(--fg) !important;
-// }
-
-// #sk_bubble div.sk_arrow div:nth-of-type(1) {
-// border-top-color: var(--border) !important;
-// border-bottom-color: var(--border) !important;
-// }
-
-// #sk_bubble div.sk_arrow div:nth-of-type(2) {
-// border-top-color: var(--bg) !important;
-// border-bottom-color: var(--bg) !important;
-// }
-
-// /* ---------- Search ---------- */
-// #sk_status,
-// #sk_find {
-// font-size: var(--font-size);
-// border-color: var(--border);
-// }
-
-// .sk_theme kbd {
-// background: var(--bg-dark);
-// border-color: var(--border);
-// box-shadow: none;
-// color: var(--fg);
-// }
-
-// .sk_theme .feature_name span {
-// color: var(--main-fg);
-// }
-
-// /* ---------- ACE Editor ---------- */
-// #sk_editor {
-// background: var(--bg-dark) !important;
-// height: 50% !important;
-// /* Remove this to restore the default editor size */
-// }
-
-// .ace_dialog-bottom {
-// border-top: 1px solid var(--bg) !important;
-// }
-
-// .ace-chrome .ace_print-margin,
-// .ace_gutter,
-// .ace_gutter-cell,
-// .ace_dialog {
-// background: var(--bg) !important;
-// }
-
-// .ace-chrome {
-// color: var(--fg) !important;
-// }
-
-// .ace_gutter,
-// .ace_dialog {
-// color: var(--fg) !important;
-// }
-
-// .ace_cursor {
-// color: var(--fg) !important;
-// }
-
-// .normal-mode .ace_cursor {
-// background-color: var(--fg) !important;
-// border: var(--fg) !important;
-// opacity: 0.7 !important;
-// }
-
-// .ace_marker-layer .ace_selection {
-// background: var(--select) !important;
-// }
-
-// .ace_editor,
-// .ace_dialog span,
-// .ace_dialog input {
-// font-family: var(--font);
-// font-size: var(--font-size);
-// font-weight: var(--font-weight);
-// }`;
-// click `Save` button to make above settings to take effect.
-// #endregion
diff --git a/tools/powershell/Completions.ps1 b/tools/powershell/Completions.ps1
index 1647b2e..9dd8cb7 100644
--- a/tools/powershell/Completions.ps1
+++ b/tools/powershell/Completions.ps1
@@ -2,9 +2,19 @@ function Invoke-Completion {
param ([string]$command)
switch ($command) {
'docker' { docker completion powershell | Out-String | Invoke-Expression }
+ 'dotnet' {
+ # https://learn.microsoft.com/en-us/dotnet/core/tools/enable-tab-autocomplete#powershell
+ Register-ArgumentCompleter -Native -CommandName dotnet -ScriptBlock {
+ param($wordToComplete, $commandAst, $cursorPosition)
+ dotnet complete --position $cursorPosition "$commandAst" | ForEach-Object {
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
+ }
+ }
+ }
'git' { Import-Module Posh-Git }
'hugo' { hugo completion powershell | Out-String | Invoke-Expression }
'pip' { pip completion --powershell | Out-String | Invoke-Expression }
+ 'rg' { rg --generate complete-powershell | Out-String | Invoke-Expression }
'uv' { uv generate-shell-completion powershell | Out-String | Invoke-Expression }
'wezterm' { wezterm shell-completion --shell power-shell | Out-String | Invoke-Expression }
'winget' {
@@ -26,7 +36,7 @@ Set-Alias "icmp" "Invoke-Completion"
Register-ArgumentCompleter -CommandName Invoke-Completion -ParameterName 'command' -ScriptBlock {
param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)
- $cmds = @('docker', 'git', 'hugo', 'pip', 'uv', 'wezterm', 'winget')
+ $cmds = @('docker', 'dotnet', 'git', 'hugo', 'pip', 'rg', 'uv', 'wezterm', 'winget')
$cmds | Where-Object { $_ -like "$wordToComplete*" }
}
diff --git a/tools/powershell/Config.ps1 b/tools/powershell/Config.ps1
index 4d5ed8c..431131c 100644
--- a/tools/powershell/Config.ps1
+++ b/tools/powershell/Config.ps1
@@ -1,18 +1,8 @@
-# Use XDG Base Directory Specification and its similar structure for Windows
-# wget
-if (Get-Command wget -ErrorAction SilentlyContinue) {
- ${function:wget} = {wget --hsts-file $XDG_CACHE_HOME/wget-hsts $args}
-}
-
-# yarn v1
-if (Get-Command yarn -ErrorAction SilentlyContinue) {
- ${function:yarn} = {yarn --use-yarnrc $XDG_CONFIG_HOME/yarn/config.yaml $args}
-}
-
-if ($Env:WEZTERM) { # Environment variable injected by wezterm/wezterm.lua
- ${function:icat} = {wezterm imgcat $args}
+if ($Env:WEZTERM) {
+ # Environment variable injected by wezterm/wezterm.lua
+ ${function:icat} = { wezterm imgcat $args }
}
elseif ($Env:KITTY) {
- ${function:icat} = {kitty +kitten icat $args}
+ ${function:icat} = { kitty +kitten icat $args }
}