Compare commits

74 Commits
Author SHA1 Message Date
tri 99517bbb6c docs(readme): clone over https
SSH clones need a registered key even for a public repo, so a fresh
machine got "Permission denied (publickey)". HTTPS works anonymously.
2026-11-13 11:13:55 +07:00
tri 1ac77c4045 chore(npm): lower the release-age window to 1 day 2026-11-11 16:39:41 +07:00
tri 61e0ab126f docs(readme): clone over ssh 2026-11-10 16:49:08 +07:00
tri b6b079b8f0 docs(readme): clone from git.trivk.dev 2026-11-10 12:11:28 +07:00
tri f9b35addae feat(zsh): source zshenv.local for per-machine settings 2026-11-06 13:12:29 +07:00
tri 8425ceb709 feat(tray-icons): shrink and recolor the NetBird tray icons
NetBird sends its tray icon as a pixmap, so an icon theme can't
replace it. patch.py rewrites the 48x48 PNGs embedded in netbird-ui in
place: the glyph is scaled to 80% to get Breeze's padding and the
white variants take the panel text color (#dedede). A pacman hook
re-patches the binary after every netbird-ui upgrade, and restore.sh
puts the original back.
2026-11-06 11:20:04 +07:00
tri fa77bc2514 refactor(fastfetch): merge the mac and kde configs into common
One Fastfetch package now serves both platforms. The logo is sent
inline through the kitty graphics protocol from a pre-encoded
albedo.kitty, which works in Ghostty and Kwi alike, so the separate
kitty-direct (mac) and Konsole (kde) variants are no longer needed.
2026-11-06 11:20:04 +07:00
tri 84e96f175c chore(spectacle): mark the desktop launcher as trusted
KDE trusts a .desktop file once it is executable and starts with an
xdg-open shebang, so Plasma launches it without asking first.
2026-11-03 22:18:52 +07:00
tri 09c1e312cb feat(helium): switch to the GTK theme with KWin title buttons
Helium now takes its colors from Breeze GTK instead of a generated
theme extension, which reset the GTK theme on every launch.

- Import window_decorations.css from gtk.css so Helium, which doesn't
  load kde-gtk-config's GTK module, draws the KWin title buttons
  instead of Breeze GTK's round ones.
- Add chromium.css to give the compact layout's address bar and
  button segment the title bar color, so the tab strip is one color.
- Disable WaylandWpColorManagerV1 so KWin doesn't lift Helium's dark
  grays (40 -> 44) and the strip matches KDE title bars.
- Drop the Helium theme from build.py and the helium package.
2026-11-03 22:18:52 +07:00
tri b14133bbec Merge pull request #2 from vokhactri/refactor/add-python-type-hints
Add type hints to KDE Python build scripts
2026-11-02 15:18:44 +07:00
tri 3d1011e17c refactor(kde): add type hints to Python build scripts
- Annotate functions in fastfetch, spectacle and theme scripts
- Add Color and ColorFn type aliases in theme/build.py
- Annotate empty collections and silence optionxform assignment errors
2026-11-02 15:17:49 +07:00
tri 34e978e84c refactor: group stow packages into common, mac and kde
Split the packages by platform so each app stays an opt-in Stow package
under common/, mac/ or kde/. KDE gets its own Fastfetch, Helium and
Spectacle packages, and darwin-breeze becomes kde/theme. The READMEs
document stowing a whole group as well as individual packages.
2026-10-30 21:57:15 +07:00
tri 1e99a15f6c chore: remove aria2, containers and fontconfig packages 2026-10-30 21:57:15 +07:00
tri 26a29b3182 feat(darwin-breeze): add VS Code and Telegram themes
Generate and install a VS Code theme and build an importable Telegram
theme from the color scheme.
2026-10-30 00:21:09 +07:00
triandClaude Opus 5.5 75b1383edf feat(darwin-breeze): unify theme colors across KDE, Helium, T3 Code and Ghostty
Move the Darwin Breeze Dark color scheme and global theme into a stow
package. build.py generates the Helium, T3 Code and Ghostty themes from
DarwinBreezeDark.colors, and apply.sh rebuilds and applies them, so the
colors are edited in one place.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 20:00:16 +07:00
tri d215693df4 feat(tray-icons): shrink qBittorrent tray icon 2026-10-29 00:02:43 +07:00
tri 6423eaa29d feat(tray-icons): add Breeze-style Ngó Sen icons 2026-10-29 00:02:43 +07:00
tri 6f4c331dd4 feat(zsh): replace standalone pnpm with vite-plus 2026-10-16 16:32:44 +07:00
tri 37f4a0391f feat(zsh): replace fnm with standalone pnpm
Install the pnpm native binary from GitHub releases via gh-r and sbin,
matching the existing fnm/starship shim pattern. Node is now managed
by pnpm itself (pnpm runtime), so fnm and its init block are removed.

Drop unzip from the README optional list; only fnm's zip needed it.
2026-09-23 15:52:42 +07:00
tri 829b0de65e feat(zsh): add nbup with progress bar and drop Intel branch 2026-09-15 14:35:40 +07:00
tri 2c5365343e perf(zsh): skip brew --prefix on startup and guard empty XDG_BIN_HOME 2026-09-15 14:35:19 +07:00
tri 39c2dc2ac4 fix(zsh): reap completed jobs before starship prompt 2026-09-15 11:06:53 +07:00
tri 4c90a40ab5 chore(gdfuse): remove obsolete configuration files from gdfuse 2026-09-14 13:57:53 +07:00
tri c98d949ea7 fix(zsh): symlink fastfetch binary 2026-08-22 02:19:12 +07:00
tri dd964df37b fix(zsh): update fastfetch installation to correct asset paths and improve completion handling 2026-08-22 01:32:54 +07:00
tri 55ca1573e5 refactor: remove deprecated Hammerspoon configuration and modules 2026-08-07 10:56:35 +07:00
tri a75a04c814 chore(hammerspoon): unload app name toast 2026-08-03 16:44:59 +07:00
triandClaude d37d12e5d8 fix(hammerspoon): suppress duplicate app name toasts
Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-28 10:52:19 +07:00
tri e7729693df fix(swiftbar): improve safety and readability in script functions 2026-07-17 11:24:22 +07:00
tri bed14dac95 feat(swiftbar): enhance display formatting and add size parameter for icons 2026-07-17 11:01:52 +07:00
tri 1e02f21072 fix: prevent SwiftBar brew actions from overlapping 2026-07-17 10:16:42 +07:00
tri bf71fa6174 feat(swiftbar): add Homebrew updates plugin 2026-07-16 17:44:43 +07:00
tri e78076944a fix: increase frame polling to 60 fps 2026-07-16 16:38:23 +07:00
tri 34989c95ae fix(hammerspoon): simplify window highlight border rendering 2026-07-16 15:49:31 +07:00
tri 4264022a87 fix: preserve window highlight corner radii during resize 2026-07-16 15:19:39 +07:00
tri 2796c820d3 fix: show app name toast on option key 2026-07-16 14:28:24 +07:00
tri 46d240e5cd chore(git): update email address in config 2026-07-15 17:21:28 +07:00
Tri Vo Khac 435a761d22 fix(hammerspoon): refresh highlight after window changes 2026-07-15 13:37:59 +07:00
Tri Vo Khac 6d5b84db51 feat(hammerspoon): show app name on focus and command key
Extract window highlighting into a dedicated module and centralize shared
configuration. Add a configurable app name toast triggered by focus changes
and Command key presses.
2026-07-15 13:19:49 +07:00
Tri Vo Khac 592e4a838c feat(hammerspoon): add active window highlight 2026-07-15 12:59:46 +07:00
Tri Vo Khac 19bc0e3212 chore(opencode): remove local opencode config
Drop tracked opencode.jsonc from the dotfiles tree.
2026-07-14 15:41:49 +07:00
Tri Vo Khac 1b0a6e6d42 chore(zsh): disable Homebrew cask auto-updates on upgrade 2026-07-14 15:33:21 +07:00
Tri Vo Khac 467c2ebf07 feat(zsh): configure claudex model routing 2026-07-14 11:30:43 +07:00
Tri Vo Khac cb026ebe5d feat(zsh): add claudex alias and remove git shortcuts 2026-07-13 17:37:07 +07:00
Tri Vo Khac fe5c70240e fix(zsh): harden shell bootstrap and XDG path setup 2026-07-13 15:55:07 +07:00
Tri Vo Khac 2cee5ce877 fix(zsh): remove zshellcheck from completions list 2026-07-09 11:26:36 +07:00
Tri Vo Khac f62b2b1e4a fix(zsh): apply zshellcheck lint fixes
- use [[ ]] over [ ], quote vars, shallow clone in zinit.zsh
- typeset -A instead of declare -A
- nullglob (N) and path array idiom in bin.zsh/default.zsh
2026-06-24 11:13:22 +07:00
Tri Vo Khac 8f2ece4fb7 feat(zsh): install zshellcheck via zinit 2026-06-24 11:13:00 +07:00
Tri Vo Khac 5830509c0d feat(opencode): enable reasoning models 2026-06-22 15:57:38 +07:00
Tri Vo Khac 6ff9cb4351 feat(opencode): add model context limits 2026-06-22 15:47:59 +07:00
Tri Vo Khac ea6ea60025 feat(opencode): add glm-5.2 model 2026-06-22 15:42:21 +07:00
Tri Vo Khac 7d6f26a6d5 fix(zsh): migrate pnpm PATH to v11 2026-06-22 14:49:51 +07:00
Tri Vo Khac 10a6a8862f fix(zsh): select fnm gh-r asset per OS/arch for aarch64 2026-06-18 10:38:06 +07:00
Tri Vo Khac 76a0ab7891 chore: remove greedy homebrew upgrade and add git ignore 2026-06-17 16:47:51 +07:00
Tri Vo Khac 82c4edd500 feat: add opencode configuration 2026-06-08 14:46:05 +07:00
Tri Vo Khac b046ddb942 chore: fix code formatting in README 2026-05-20 16:38:32 +07:00
Tri Vo Khac 678fb8eb63 chore: remove flameshot configuration file 2026-04-20 14:51:58 +07:00
Tri Vo Khac d3cddc9414 chore: update starship configuration with new symbols and fix whitespace in zshrc 2026-04-17 17:14:54 +07:00
Tri Vo Khac 560e978a34 chore(fastfetch): adopt @ayanrajpoot10 config with albedo pic instead
- Replace box-drawing border layout with a clean, minimal style
- Simplify modules to essential system info with colorized keys
2026-04-17 16:49:58 +07:00
Tri Vo Khac 47f0e4018f chore: update fastfetch configuration modules and display settings 2026-04-17 15:17:01 +07:00
Tri Vo Khac 126a6333a7 feat: add minimum release age configurations for npm and pnpm 2026-03-31 17:49:59 +07:00
Tri Vo Khac c1f1cc13eb feat: Add Flameshot configuration 2026-03-13 16:05:42 +07:00
Tri Vo Khac 576e20682e refactor: Update zinit plugin configurations to use atclone and atpull hooks for initialization and completion generation, and adjust plugin-specific options. 2026-02-27 12:30:57 +07:00
Tri Vo Khac 356ad9d74b feat: enable greedy Homebrew upgrades 2026-02-26 15:59:26 +07:00
Tri Vo Khac 31465ed3f6 fix: Use relative path for fzf executable in zinit atclone hook. 2026-02-23 12:38:23 +07:00
Tri Vo Khac 09e22050e5 feat: add pnpm to PATH. 2026-02-05 14:33:43 +07:00
Tri Vo Khac 1ca097ce6d docs: Add unzip as an optional dependency. 2026-02-05 14:04:47 +07:00
Tri Vo Khac a57e66e31f feat: Update zinit plugin sources and list command, add a global --help alias, and enhance the README documentation. 2026-02-05 13:45:38 +07:00
Tri Vo Khac a943f7893e chore: enhance Git configuration and add .hushlogin file
- Updated Git configuration with new core and advice settings for improved usability.
- Added a new .hushlogin file to suppress login messages in the terminal.
2025-07-11 15:29:48 +07:00
Tri Vo Khac 93f8712adf chore: remove obsolete .gitconfig in favor of .config/git/config 2025-07-02 15:24:21 +07:00
Tri Vo Khac f2b980d1df feat: update starship configuration with new symbols
- Added new symbols for various programming languages and tools including Bun, C++, CMake, Deno, GCloud, Git Commit, and Gradle.
- Updated existing symbols for AWS and Rust.
- Included additional OS symbols for AlmaLinux, CachyOS, Kali, Nobara, and RockyLinux.
2025-06-11 16:02:30 +07:00
Tri Vo Khac dec5f076be feat: enhance Docker alias to support podman fallback
- Replaced the Docker alias with a function that checks for podman availability.
- If podman is installed, it uses podman; otherwise, it defaults to the Docker command.
2025-04-19 04:12:57 +00:00
Tri Vo Khac 05244511c2 chore: update git configuration and remove unused files
- Updated Git user email in `.gitconfig`.
- Removed obsolete Kitty and Topgrade configuration files.
- Cleaned up Zsh configuration by removing unused snippets and scripts, and reorganized plugin loading in `.zshrc`.
2025-04-19 10:54:42 +07:00
Tri Vo Khac aa85f4ff43 feat(zinit): integrate zinit for improved shell configuration (#1) 2025-04-18 20:50:42 +07:00
89 changed files with 8384 additions and 558 deletions

No files matched your search

+44 -18
View File
@@ -1,29 +1,55 @@
# My personal dotfiles
# Personal dotfiles
## Requirement
- **GNU** `stow`
These are my config files for macOS and KDE, managed with GNU Stow. You need `stow` and `zsh` installed.
## Installation
1. clone this repo to your `$HOME` and switch to cloned dir:
```
git -C $HOME clone https://github.com/vokhactri/.dotfiles.git && cd "$(basename "$_" .git)"
```sh
git clone https://git.trivk.dev/tri/.dotfiles.git "$HOME/.dotfiles"
cd "$HOME/.dotfiles"
```
2. use `stow` to symlink configs to `$HOME/.config`:
The packages are split into three groups:
- to symlink all config dirs
```
stow */
```
- to symlink only one config dir, for example `zsh`
```
stow zsh
```
- [common/](common/README.md) has Fastfetch, Git, Micro, mpv, npm, Starship and Zsh.
- [mac/](mac/README.md) has Ghostty.
- [kde/](kde/README.md) has the Darwin Breeze theme, Helium, Spectacle and tray icons.
## Credit
Install all of `common`, then the group for your platform:
```sh
(cd common && stow -t "$HOME" */)
(cd mac && stow -t "$HOME" */) # macOS
(cd kde && stow -t "$HOME" */) # KDE
```
`*/` matches every package in the group. Each line runs in a subshell, so you stay in the repo root and can run them one after another. KDE needs a few more steps after this. They're in [`kde/README.md`](kde/README.md).
### Picking packages
You don't have to install everything. List only the packages you want:
```sh
stow -d common -t "$HOME" git zsh starship
stow -d mac -t "$HOME" ghostty
stow -d kde -t "$HOME" spectacle
```
`-d` tells Stow which group to read from. `-t` puts the symlinks in your home directory. You can mix packages from different groups.
### Previewing and removing
`-n -v` prints what Stow would do and changes nothing. `-D` removes the symlinks. Pass the same `-d` and `-t` you used to install:
```sh
stow -n -v -d kde -t "$HOME" spectacle
stow -D -d kde -t "$HOME" spectacle
```
Once the Zsh config is linked, run `exec zsh` to reload the shell.
## Credits
- [Machfiles](https://github.com/ChristianChiarulli/Machfiles/)
- [zsh_unplugged](https://github.com/mattmc3/zsh_unplugged)
- [ayanrajpoot10/dotfiles](https://github.com/ayanrajpoot10/dotfiles)
-4
View File
@@ -1,4 +0,0 @@
enable-rpc = true
rpc-listen-all = true
dir = ~/Downloads
# rpc-secret = your_password
+18
View File
@@ -0,0 +1,18 @@
# Common packages
Shared configuration for Fastfetch, Git, Micro, mpv, npm, Starship, and Zsh.
From the repository root, install all shared packages:
```sh
(cd common && stow -t "$HOME" */)
```
Or choose individual packages:
```sh
stow -d common -t "$HOME" git
stow -d common -t "$HOME" zsh starship
```
Choose any of `fastfetch`, `git`, `micro`, `mpv`, `npm`, `starship`, and `zsh`.
Reload Zsh with `exec zsh` after installing its configuration.
@@ -0,0 +1 @@
_Ga=T,f=100,t=d,c=20,r=10,q=2,m=1;iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAACXBIWXMAAFxGAABcRgEUlENBAAAgAElEQVR4nOxdB3gU1fc1pPeQ0CFAIAkJCRASWkhCICGFDoKC0hWk6N/eFcvP3it2pIoCFnqTXqQICNJ77wiIAkqZ+//ue/Nm38zOhmR3NkXu+b737aZsm92dc9695957yy0EAsEyKIpyCwDIy0NRFE8AKIc/49+l/8HfVQaAFgDQFwCeA4CvAWAOAPwGAIcA4JyiKNeA4woAnFUU5RQAHACALQCwHAB+UBTlY0VRngSAXoqipOD9KoriYXxMRVHwMT3F38TCvxMIBAKBQCgCDITPSB9JViV/jWABIBAAmgHAfQAwHgDWA8B5KBwUKBrOAcCv+DiKotwLAM0BIMggQLTnaXwNBAKBQCAQCk/8bKdviALUAYABADAJAPY5Infc5SuKchUAcOGO/7q6FIn8FWmJv19Tb3NFuq2pWFAUZZ+iKN8pioLPJ8oQAWCRATkiQEKAQCAQCAQVhnA6LraLNuyskfTvB4CFAHDRZCcvEz0jdIQJ0RcG2m1kGMTBVZP7w+f1MwAMBYAaJkKGogIEAoFAIJjs9nU7ZgAIAICeADADAC4ZyFaQsNjRM7Y2ELjVMN6/EAVX1UiDjAtqhKKdwRtgJwTIK0AgEAiEmwKGnb0gfmboUxeG0l8GgP069lUUJFpth+9msi8sNPGhChARIZCxCQDQMxBWkBAgEAgEAuE/C+OOX3Xzi58bAcBoQ4hfEKqz4fzigmIWGVCfP/+lohwBgGcVRYkwCAEyCxIIBALhvwejCU5yyovfNcZwuRTCR+BuXzbslUbSdwTjc9aiAvgSseRQUZSnsYJAOgYkBAgEAoHw34HB3Gckuhi1dI8RowrZXFfWiN8InRFRFTRyeuAgAAw2SwtQxQCBQCAQyiyMeX7JDIe58LcA4F/Bkg6I/78E+TVdV0sMBVYDQLqjtACBQCAQCGW1c5+XdL0fAByVyE8jfkPZ3n8VRiEgRwQ+AYAQKVKiNT0iIUAgEAiEMlXWJxFYvFojz1lQUa7cZMQvw/h60e8gjgW2Ku5E0QACgUAglAkY69oVRWG7flUAPKEoigj3C3OfXDp3M5G/DNkfoBjSAp8BgJ9JBIWiAQQCgUAoHTDp2S9q+qMBYJlEanK4+2YlfTsYjILXpNLBHQDQVOqVQH0DCAQCgVAqd/6yeQ174/+tEpno2Mc4jsjfoQ6QTZAiGoDHbbiDY1zSbz+BQCAQbjYY6vrlMDVejirJXb/gUfkS1/Xr1+HatWvaunr1qrbk3+P/4TLeXt+mwH1PXzpO8rHDkcaeZikBAoFAIBBKyuznpYqBOuo4XpCm77nd5GdG1DLB43VngCJAvg8hCowCoxgrBXAUcXUSAQQCgUAoETjI9+PQGxyAgzA6/K1nSInsxe6+ILK/fPkyHDlyBLZu3Qq//PILzJkzB3744QeYNGkSTJ48GaZPnw5LliyB3377Dfbt2wfnz583vR8hLGQx4K7ogFlKQFGUEwDQTPQLMJZcEggEAoFQHGY/kQq4T+ItsVt1y65f3n0L0sdLGf/88w9s2LABxo4dCw888AC0bdsW4uPjoUKFCuDh4YEsWeAKCgqCqKgoSE1NhQEDBsBHH30Ey5cvh3PnzukeR358N0YF5ON4RTrGXYQngHoFEAgEAqG4cv6svl/9+U2JrK65g/yNYXexC5dx8OBBRvi9e/eGOnXqFEj05cp5gqenWF7q4j97eJRzeLuqVatCp06dYOTIkbBr1y7d44vogzEd4U5fgKIoQ036LdC3gEAgEAjWwNjcR9r5j3Nnvt9I/Mbd/unTp2HUqFGQn58PgYGBdoTt5cWJvTC7fkcLb4/3YxQGPj4+kJWVBZ9//jmcOnVKe07CSOgGISAfV3nC4FMiIkMigEAgEAiWwoz8AWCaSkBaFzt3Er9MoqtWrYJ77rkHKlasaEr4RhL38faD4MDyUDGiBtSsHgcxdRpD/dgW0CA+HRrWz4CG8RmQUK8l1ItuAlE1E6FqpSgIDakIfr6BDgSBt+53mFq47777YMuWLdpzlP0I7hABajMloYaECKASQQKBQCC4lfxnqSRkudnPGOqXd/wzZ86E3NzcG5J+gH8wVK0cBQn1UiG1SUfITu8FHdreDZ1zh0DnvCHQJX8odMkfBl0NC3/XJW8o+5+OOYMhN7MPpDfvCo0SWkFktVgICixvGh2Qf77jjjuYkVBAjlpYLAQQmghQFKWPPG0RrxMIBAKB4BTMDH8A8KNKPlek/vUus5pMjsJcJ4AO/ZYtW2pE63GLh90uPCQoHKJrJ0HLJh0hv01/RuRI9ILM22ffpa6BbLXDlWVY6t/E/3ZsO4iJBn5fw9jfURDE1k2B0OAI3eN7G54Pmgf37NmjvQb59VgpAtTOgQhstZxoFGsEAoFAIBQJDob6fKiSjbbzdzXsbxbuF8ByvezsbNsOm5n3vHShfQzpI+kjYeMuHgm7Q9tBGtHLhO784uIAowidcu9hj4PXWzbtBDWr1wMvLx8pImETAn5+fvDcc8+xqgQ3RQOMxsBfTHo00CefQCAQCIWHyTS6PirJXLMq5y+ToBzuP378ONx1110OiT8oMIyF93Mye2sheyRk3MXLxI2/E5fOLuN94RKPw6ID+UMhO+MOiK2TDD4+/raIgLdNCMTGxsLcuXO11y1EjgUiwK46QFGUe4w9AggEAoFAKBSkiX7CWV5FUZQ/TEr9nGcuadd/5YptCN5XX30F4eHhuhy/uI5GvkYJmYyAMSTfMWeQXdheJmyrl6PIAKYY8PnkZPZhBkMvT07+WH0gC4Fhw4axhkQIfM0WVQoYKwP2SFMESQAQCAQCwaXd/xcqUV2xkvzlXP+BAwegXbt2pjtof78g5tZH0kWiNdvtu5P4bywEeFQABQk+v6z0XlCjWoxkDvTSShHr1asHa9assYt6WCQCRCqgn2wIJBAIBAKhUDDk/eNNuvs5xVQyycm5/vHjx0NISIjmpC9XjtfcY+19TFQS5LXpZyN+dbdvDM+XxDJLN3AhMJilJlqktGdRCzNR8+GHwk7BhYDx+DgpANgdKYrys/reMfMmgUAgEAiFgmH3/75KLrIIcIr8BUTIH0XA4MGDTQkSa/YzU7urxD9I2/GXBuIvjFcAhUrnvKHset3aDU1TGv369dPI3wJfgCzMLgFAbblBEIFAIBAIBcJQ9hekKMpBlVSuu0r+cr4fB+6kpKSorXnLabt+bNObGNcSOuUMZo770k78NxIBeB1FTPPkdlpjIXytondBixYt4OTJkzph5KIIEFGAXrKQIxAIBAKhQBjqyHNUMhHO/yKzklmJ38KFCyEsLMxuR1whvBrLn3drf6+OUG01+tY6/ItNCKBpMW8oayxUqUKkXcQjMjISNm/ebIUIUKRIzbvy2GACgUAgEAojAEQJ2asqGV11hviNXf0QOLDHLBxerUpdyErvCW1b3ck69+Vm9oV2WQPUuvvhbBfNm/oM0nbXwv1vlo8vDUt+LsIbgK8nOirJTgTgBMKlS5eyY+RopHEhId6r6ep7yLwcBAKBQCAUOgKgKMpciVSKtB01K3F74403NOITIX+bGPDRBu5gGsDXxx+Cg7B/f3WoWSMOEuu1hJZNOkFOq96MRIUg4ESrLwUsTdEBsz4C2EgoKSHTTghhpQBGR4QIcDICINTDGul9pE89gUAgEApdAuinKMoWqd2sU+F/QWIjRoywtfJVS+LwUuTD+aXtuoeH+XQ+FAaYKqhXN4V1AMQoARcDQ/lO20QIlAYxYEwJoAhITemgdREUkQCcMOiKABCtgRVFwZyCD/UCIBAIBEKhgM1/VNKoCAAnnDUAymH/t99+W2f2K/qIXuz976VLGdgG/4RArRrxzGQnxABGCGxpgtIjBMxEQFqzLuBZztYnAGcesAN+/bpTRkBpNsBGRVG8SQAQCAQCoVCQKgBqAMCfglecICKNwNDkxnr3+9h65uPCjn9YCdClSxfo378/KwnEFsC33347mwEQFxenmQWNy2wKYGBACCu5y2jRjacJRFTApJKgfduSEQNGrwIOLsJG\_Gm=1;R+I1tGnTxpUIALupermOJgMSCAQCocgRAEVRUABcUMncKQEgIgA4GU8z+1WrBo888gjLdf/xh+gubA7cBZ8+fRpWr14No0ePhnvvvReSk5PB39/Wc1902jOKAUwTNG7QRosKsLbBpaSkUJs2mDOYVT14e/tqEYBOnTq5JACkCMByagdMIBAIBGciAJUA4KQrPQAEgV26dIl1vhs5ciScPXvWlOiR8LBMEC9vRH67du2CMWPGsEhBpUqVDJEBb53BMDAgFOJjmrESvNIkBPAxMUqRmdqDmR/Fc8YIiIsmQFEFME/u6UAgEAgEQmEFQAAAbBcc7UoVgBFI9GI0rkgVOFpGcWC8P4wQfPvtt3DrrbeyUjpblYEneEkTBNE8iBP7cGCPo7bCxSsAsFPgEDZSWK4EePrpp7Vj5GQKQEwFnCJXdBAIBAKBUJROgD+rZHK1qGkAYx8AmfTlv9/obo3lhEIUCEEg49ChQ/DOO+9Aw4YN7aIC4jqO7MWIAEsNqK16izsaICYJ4uMnJbbWPccvvvjCFQGgSAObvlD7AFAjIAKBQCAUeQ7A2yqZFLkRkBmRuzDtzu6+xKWZGMDfz5o1Czp27OhQCGBqIKVhtq65UHFGAjD6gJEIjErIfRHmzp1rNyypaIdGa9r0P2oFTCAQCARnBUBHlUxEHwBrGNwiGKMM8nhhARy927NnT10PAjk1gB0Ic1v3ZYa84hIBokSxS/5QqFa5jvZc/Pz8YNu2ba6UAcqNgIaRACAQCASCsymA8gBw3NVhQMUBo3fAGBVYv3498wnIZYTCeY8dB9EkKEcC3C0AhA8gJChce05YLnn58mXt9ThxDGQB0E54AOjjTyAQCARLine truncated
Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

@@ -0,0 +1,80 @@
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/master/doc/json_schema.json",
"display": {
"key": {
"width": 10
},
"size": {
"binaryPrefix": "jedec"
},
"separator": ""
},
"logo": {
"type": "raw",
"source": "~/.config/fastfetch/albedo.kitty",
"width": 20,
"height": 10
},
"modules": [
"break",
{
"type": "os",
"key": "os",
"keyColor": "yellow",
"format": "{name}"
},
{
"type": "kernel",
"key": "ker",
"keyColor": "green"
},
{
"type": "packages",
"key": "pkgs",
"keyColor": "cyan"
},
{
"type": "shell",
"key": "sh",
"keyColor": "blue",
"format": "{pretty-name}"
},
{
"type": "wm",
"key": "wm",
"keyColor": "red",
"format": "{pretty-name}"
},
{
"type": "uptime",
"key": "up",
"keyColor": "green"
},
{
"type": "cpu",
"key": "cpu",
"keyColor": "red",
"format": "{name}"
},
{
"type": "memory",
"key": "ram",
"keyColor": "yellow",
"format": "{used} / {total}"
},
{
"type": "disk",
"key": "disk",
"keyColor": "cyan",
"folders": [
"/"
],
"format": "{size-used} / {size-total}"
},
"break",
{
"type": "custom",
"format": "\u001b[33m󰮯 \u001b[32m󰊠 \u001b[34m󰊠 \u001b[31m󰊠 \u001b[36m󰊠 \u001b[35m󰊠 \u001b[37m󰊠 \u001b[97m󰊠"
}
]
}
+3
View File
@@ -0,0 +1,3 @@
^/README.*
^/build\.py
__pycache__
+17
View File
@@ -0,0 +1,17 @@
# Fastfetch
```sh
stow -d common -t "$HOME" fastfetch
```
The logo is `albedo.png`, sent inline through the kitty graphics protocol from
the pre-encoded `albedo.kitty`. This works in Ghostty and Kwi. The
`kitty-direct` logo type is not used because Kwi ignores images passed as a
file path.
After changing `albedo.png` or the logo size in `config.jsonc`, regenerate the
logo from the repository root:
```sh
python3 common/fastfetch/build.py
```
+33
View File
@@ -0,0 +1,33 @@
#!/usr/bin/env python3
"""Encode albedo.png as kitty graphics escapes for fastfetch's "raw" logo.
fastfetch's "kitty-direct" logo sends the terminal a file path (t=f), which
Kwi ignores. This file carries the PNG inline (t=d) instead, so it works in
any terminal with the kitty graphics protocol, Ghostty and Kwi included. q=2
keeps the terminal from answering. Rerun after changing the image or the
logo size.
"""
import base64
from pathlib import Path
DIR = Path(__file__).resolve().parent / ".config/fastfetch"
# Logo size in cells; keep in sync with "width" and "height" in config.jsonc.
COLS, ROWS = 20, 10
def encode(png: bytes) -> bytes:
data = base64.b64encode(png)
chunks = [data[i : i + 4096] for i in range(0, len(data), 4096)]
out = bytearray()
for n, chunk in enumerate(chunks):
more = int(n < len(chunks) - 1)
if n == 0:
keys = b"a=T,f=100,t=d,c=%d,r=%d,q=2,m=%d" % (COLS, ROWS, more)
else:
keys = b"m=%d" % more
out += b"\x1b_G" + keys + b";" + chunk + b"\x1b\\"
return bytes(out)
(DIR / "albedo.kitty").write_bytes(encode((DIR / "albedo.png").read_bytes()))
+22
View File
@@ -0,0 +1,22 @@
[init]
defaultBranch = main
[user]
name = Tri Vo Khac
email = git@trivk.dev
[core]
compression = 9
whitespace = error
preloadindex = true
[advice]
addEmptyPathspec = false
pushNonFastForward = false
statusHints = false
[push]
autoSetupRemote = true
[url "git@github.com:"]
insteadOf = "gh:"
+1
View File
@@ -0,0 +1 @@
**/.claude/settings.local.json
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+2
View File
@@ -0,0 +1,2 @@
min-release-age=1 ; 1 day for npm
minimum-release-age=1440 ; 1 day in minutes for pnpm
@@ -5,14 +5,23 @@ add_newline = false
success_symbol = "[➜](bold green)" # The "success_symbol" segment is being set to "➜" with the color "bold green"
[aws]
symbol = " "
symbol = " "
[buf]
symbol = " "
[bun]
symbol = " "
[c]
symbol = " "
[cpp]
symbol = " "
[cmake]
symbol = " "
[conda]
symbol = " "
@@ -22,6 +31,9 @@ symbol = " "
[dart]
symbol = " "
[deno]
symbol = " "
[directory]
read_only = " 󰌾"
@@ -37,15 +49,27 @@ symbol = " "
[fennel]
symbol = " "
[fortran]
symbol = " "
[fossil_branch]
symbol = " "
[gcloud]
symbol = " "
[git_branch]
symbol = " "
[git_commit]
tag_symbol = '  '
[golang]
symbol = " "
[gradle]
symbol = " "
[guix_shell]
symbol = " "
@@ -94,13 +118,17 @@ symbol = " "
[os.symbols]
Alpaquita = " "
Alpine = " "
AlmaLinux = " "
Amazon = " "
Android = " "
AOSC = " "
Arch = " "
Artix = " "
CachyOS = " "
CentOS = " "
Debian = " "
DragonFly = " "
Elementary = " "
Emscripten = " "
EndeavourOS = " "
Fedora = " "
@@ -109,6 +137,8 @@ Garuda = "󰛓 "
Gentoo = " "
HardenedBSD = "󰞌 "
Illumos = "󰈸 "
Ios = "󰀷 "
Kali = " "
Linux = " "
Mabox = " "
Macos = " "
@@ -118,6 +148,7 @@ MidnightBSD = " "
Mint = " "
NetBSD = " "
NixOS = " "
Nobara = " "
OpenBSD = "󰈺 "
openSUSE = " "
OracleLinux = "󰌷 "
@@ -125,12 +156,15 @@ Pop = " "
Raspbian = " "
Redhat = " "
RedHatEnterprise = " "
RockyLinux = " "
Redox = "󰀘 "
Solus = "󰠳 "
SUSE = " "
Ubuntu = " "
Unknown = " "
Void = " "
Windows = "󰍲 "
Zorin = " "
[package]
symbol = "󰏗 "
@@ -144,6 +178,9 @@ symbol = " "
[pijul_channel]
symbol = " "
[pixi]
symbol = "󰏗 "
[python]
symbol = " "
@@ -154,13 +191,19 @@ symbol = "󰟔 "
symbol = " "
[rust]
symbol = " "
symbol = "󱘗 "
[scala]
symbol = " "
[status]
symbol = " "
[swift]
symbol = " "
[xmake]
symbol = " "
[zig]
symbol = " "
@@ -2,3 +2,4 @@
.zsh_history
.zcompcache/
.zsh_sessions/
config/secrets.zsh
+75
View File
@@ -0,0 +1,75 @@
# install zinit
if ! source "$ZDOTDIR/zinit.zsh"; then
print -u2 "zinit: failed to initialize; skipping plugin configuration"
return 1
fi
zinit light zdharma-continuum/zinit-annex-bin-gem-node
zinit light zdharma-continuum/zinit-annex-binary-symlink
zinit wait lucid light-mode id-as depth'1' for \
wintermi/zsh-brew \
hlissner/zsh-autopair \
Aloxaf/fzf-tab \
atinit'zicompinit; zicdreplay -q' \
zdharma-continuum/fast-syntax-highlighting \
atload'_zsh_autosuggest_start' \
zsh-users/zsh-autosuggestions
zinit id-as from'gh-r' lbin'!' completions for \
lsd-rs/lsd \
micro-editor/micro \
mv'**/bat.zsh -> _bat' \
@sharkdp/bat
zinit for \
id-as \
as'completion' \
from'gh-r' \
mv'**/_fastfetch -> _fastfetch' \
atpull'%atclone' \
lbin'!**bin/fastfetch -> fastfetch' \
@fastfetch-cli/fastfetch
zinit for \
id-as \
from'gh-r' \
atclone'./zoxide init zsh > init.zsh' \
atpull'%atclone' \
lbin'!' \
@ajeetdsouza/zoxide
zinit for \
id-as \
from'gh-r' \
atclone'
VP_SELF_SETUP_NO_MODIFY_PATH=1 ./vp env setup --refresh > /dev/null; \
./vp env on > /dev/null; \
VP_COMPLETE=zsh "$XDG_DATA_HOME/vite-plus/bin/vp" > init.zsh;
' \
atpull'%atclone' \
atload'source "$XDG_CONFIG_HOME/vite-plus/env"' \
@voidzero-dev/vite-plus
zinit for \
id-as \
from'gh-r' \
atclone'
./starship init zsh > init.zsh; \
./starship completions zsh > _starship;
' \
atpull'%atclone' \
sbin'starship' \
@starship/starship
zinit for \
id-as \
from'gh-r' \
atclone'./fzf --zsh > init.zsh' \
atpull'%atclone' \
lbin'!fzf' \
@junegunn/fzf
for script in $ZDOTDIR/config/*.zsh; do
source "$script"
done
@@ -8,13 +8,13 @@ alias tree='lsd --tree'
alias nano='micro'
alias fetch='fastfetch'
# Git shortcuts
alias g='git'
alias gs='git status -sb'
alias ga='git add'
alias gc='git commit'
alias gp='git push'
alias gl='git pull'
# Global alias
alias \-g -- --help="--help | bat -plhelp"
# Docker shortcuts
alias docker='podman'
docker() {
if command -v podman >/dev/null 2>&1; then
podman "$@"
else
command docker "$@"
fi
}
+48
View File
@@ -0,0 +1,48 @@
#!/usr/bin/env zsh
local brew_prefix="${HOMEBREW_PREFIX:-}"
# `brew --prefix` costs ~12 ms because it runs Ruby. Check the standard
# Apple Silicon location first, then fall back for anything else.
if [[ -z "$brew_prefix" ]]; then
[[ -x /opt/homebrew/bin/brew ]] && brew_prefix=/opt/homebrew
fi
if [[ -z "$brew_prefix" ]] && command -v brew >/dev/null 2>&1; then
brew_prefix="$(brew --prefix 2>/dev/null)"
fi
if [[ -n "$brew_prefix" ]]; then
gnu_tools=(
"coreutils"
"findutils"
"gnu-tar"
"gnu-sed"
"gawk"
"gnu-indent"
"grep"
)
if [[ -n "$XDG_BIN_HOME" ]] && mkdir -p "$XDG_BIN_HOME"; then
for tool in $gnu_tools; do
gnubin="$brew_prefix/opt/$tool/libexec/gnubin"
if [[ -d "$gnubin" ]]; then
for bin in "$gnubin"/*(N); do
target="$XDG_BIN_HOME/${bin:t}"
[[ "$target" -ef "$bin" ]] || ln -sf "$bin" "$target"
done
fi
done
fi
fi
local bin_paths=(
"$XDG_BIN_HOME"
"${brew_prefix:+$brew_prefix/opt/gnu-getopt/bin}"
)
for bin_path in "${bin_paths[@]}"; do
if [[ -d "$bin_path" ]]; then
case ":$PATH:" in
*":$bin_path:"*) ;;
*) path=("$bin_path" $path) ;;
esac
fi
done
@@ -6,6 +6,6 @@ export EDITOR="micro"
export PAGER="bat"
export VISUAL="micro"
export SUDO_EDITOR="micro"
export COMPANY_DIR="$HOME/Documents/work/company/"
export STARSHIP_CONFIG="$XDG_CONFIG_HOME"/starship/starship.toml
export HOMEBREW_NO_UPGRADE_AUTO_UPDATES_CASKS=1
+31
View File
@@ -0,0 +1,31 @@
#!/usr/bin/env zsh
# NetBird is installed from the official signed .pkg, not Homebrew: the brew
# cask removed the launchd plist in uninstall_preflight and then ran the app's
# installer.sh against the missing service, leaving the daemon crash-looping.
# The pkg's preinstall aborts if the brew formula is present, so keep it out.
nbup() {
local pkg tmp
tmp="$(mktemp -d)" || return 1
pkg="$tmp/netbird.pkg"
print "netbird: downloading arm64 pkg"
curl -fL --progress-bar -o "$pkg" "https://pkgs.netbird.io/macos/arm64" || { rm -rf "${tmp:?}"; return 1; }
if ! pkgutil --check-signature "$pkg" | grep -q "NetBird GmbH"; then
print -u2 "netbird: unexpected pkg signature, refusing to install"
rm -rf "${tmp:?}"
return 1
fi
sudo installer -pkg "$pkg" -target / || { rm -rf "${tmp:?}"; return 1; }
rm -rf "${tmp:?}"
local i
for i in {1..30}; do
[[ -S /var/run/netbird.sock ]] && break
sleep 1
done
/usr/local/bin/netbird status 2>/dev/null |
grep -E '^(Daemon version|CLI version|Management|Signal|NetBird IP):'
}
@@ -28,3 +28,15 @@ HISTSIZE=5000000
SAVEHIST=5000000
zstyle ':fzf-tab:complete:cd:*' fzf-preview 'lsd -1 --color=always --icon=always $realpath'
# Starship counts every entry in jobstates, including completed jobs that zsh
# hasn't reaped yet. Run jobs before Starship's precmd hook so parallel Zinit
# updates don't leave a stale job badge in the prompt.
autoload -Uz add-zsh-hook
_zinit_reap_done_jobs() {
jobs -p >/dev/null 2>&1
}
add-zsh-hook -d precmd _zinit_reap_done_jobs 2>/dev/null || true
precmd_functions=( _zinit_reap_done_jobs ${precmd_functions:#_zinit_reap_done_jobs} )
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/env zsh
ZINIT_HOME="${XDG_DATA_HOME:-${HOME}/.local/share}/zinit/zinit.git"
if [[ ! -d "$ZINIT_HOME/.git" ]]; then
mkdir -p "$(dirname "$ZINIT_HOME")" || return 1
git clone --depth 1 https://github.com/zdharma-continuum/zinit.git "$ZINIT_HOME" || return 1
fi
if [[ ! -r "$ZINIT_HOME/zinit.zsh" ]]; then
print -u2 "zinit: bootstrap is incomplete at $ZINIT_HOME"
return 1
fi
# not to use aliases: zi or zini
typeset -A ZINIT
ZINIT[NO_ALIASES]=1
ZINIT[LIST_COMMAND]='lsd --tree'
source "${ZINIT_HOME}/zinit.zsh"
View File
Whitespace-only changes.
+10
View File
@@ -0,0 +1,10 @@
export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
export XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"
export XDG_STATE_HOME="${XDG_STATE_HOME:-$HOME/.local/state}"
XDG_BIN_HOME="${XDG_BIN_HOME:-$HOME/.local/bin}"
ZDOTDIR="$XDG_CONFIG_HOME/zsh"
# Per-machine settings that stay out of the repo, like PATH entries for a VPS.
[ -r "$XDG_CONFIG_HOME/zshenv.local" ] && . "$XDG_CONFIG_HOME/zshenv.local"
@@ -1,2 +0,0 @@
[engine]
compose_warning_logs = false
-42
View File
@@ -1,42 +0,0 @@
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": {
"type": "builtin",
"source": "arch"
},
"modules": [
"title",
"separator",
{
"type": "os",
"format": "Arch Linux ({12})"
},
"host",
"kernel",
"uptime",
{
"type": "packages",
"format": "{} (pacman)"
},
"shell",
"display",
"de",
"wm",
"wmtheme",
"theme",
"icons",
"font",
"cursor",
"terminal",
"terminalfont",
"cpu",
"gpu",
"memory",
"disk",
"battery",
"poweradapter",
"locale",
"break",
"colors"
]
}
-49
View File
@@ -1,49 +0,0 @@
<?xml version='1.0'?>
<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
<fontconfig>
<alias>
<family>sans-serif</family>
<prefer>
<family>Arial</family>
<family>JoyPixels</family>
# <family>Noto Color Emoji</family>
# <family>Noto Emoji</family>
</prefer>
</alias>
<alias>
<family>serif</family>
<prefer>
<family>Times New Roman</family>
<family>JoyPixels</family>
# <family>Noto Color Emoji</family>
# <family>Noto Emoji</family>
</prefer>
</alias>
<alias>
<family>monospace</family>
<prefer>
<family>Consolas</family>
<family>JoyPixels</family>
# <family>Noto Color Emoji</family>
# <family>Noto Emoji</family>
</prefer>
</alias>
<match target="font">
<edit name="hinting" mode="assign">
<bool>true</bool>
</edit>
</match>
<match target="font">
<edit name="hintstyle" mode="assign">
<const>hintslight</const>
</edit>
</match>
<dir>~/.fonts</dir>
<selectfont>
<rejectfont>
<patelt name="family">
<string>Segoe UI Emoji</string>
</patelt>
</rejectfont>
</selectfont>
</fontconfig>
-69
View File
@@ -1,69 +0,0 @@
acknowledge_abuse=false
apps_script_format=desktop
apps_script_icon=
async_upload_queue=false
async_upload_queue_max_length=0
async_upload_threads=10
autodetect_mime=true
background_folder_fetching=false
cache_directory=
client_id=
client_secret=
connect_timeout_ms=5000
curl_debug_off=false
data_directory=
debug_buffers=false
delete_forever_in_trash_folder=false
desktop_entry_as_html=false
desktop_entry_exec=
disable_trash=false
docs_file_extension=true
document_format=desktop
document_icon=
download_docs=true
drawing_format=desktop
drawing_icon=
form_format=desktop
form_icon=
fusion_table_format=desktop
fusion_table_icon=
keep_duplicates=false
large_file_read_only=true
large_file_threshold_mb=16
log_directory=
log_to=
lost_and_found=false
low_speed_limit=0
low_speed_time=0
map_format=desktop
map_icon=
max_cache_size_mb=512000
max_download_speed=0
max_memory_cache_size=10737418240
max_retries=8
max_upload_chunk_size=1099511627776
max_upload_speed=0
memory_buffer_size=8388608
metadata_cache_time=60
metadata_memory_cache=true
metadata_memory_cache_saving_interval=30
mv_keep_target=false
oauth2_loopback=false
oauth2_loopback_port=8080
presentation_format=desktop
presentation_icon=
read_ahead_buffers=5
read_only=false
redirect_uri=
root_folder=
scope=
service_account_credentials_path=
service_account_user_to_impersonate=
spreadsheet_format=desktop
spreadsheet_icon=
sqlite3_busy_timeout=5000
stream_large_files=true
team_drive_id=
umask=0o022
verification_code=
write_buffers=false
-69
View File
@@ -1,69 +0,0 @@
acknowledge_abuse=false
apps_script_format=desktop
apps_script_icon=
async_upload_queue=false
async_upload_queue_max_length=0
async_upload_threads=10
autodetect_mime=true
background_folder_fetching=true
cache_directory=
client_id=
client_secret=
connect_timeout_ms=5000
curl_debug_off=false
data_directory=
debug_buffers=false
delete_forever_in_trash_folder=false
desktop_entry_as_html=false
desktop_entry_exec=
disable_trash=false
docs_file_extension=true
document_format=desktop
document_icon=
download_docs=true
drawing_format=desktop
drawing_icon=
form_format=desktop
form_icon=
fusion_table_format=desktop
fusion_table_icon=
keep_duplicates=false
large_file_read_only=true
large_file_threshold_mb=16
log_directory=
log_to=
lost_and_found=false
low_speed_limit=0
low_speed_time=0
map_format=desktop
map_icon=
max_cache_size_mb=512000
max_download_speed=0
max_memory_cache_size=5368709120
max_retries=8
max_upload_chunk_size=1099511627776
max_upload_speed=0
memory_buffer_size=8388608
metadata_cache_time=60
metadata_memory_cache=true
metadata_memory_cache_saving_interval=30
mv_keep_target=false
oauth2_loopback=false
oauth2_loopback_port=8080
presentation_format=desktop
presentation_icon=
read_ahead_buffers=5
read_only=false
redirect_uri=
root_folder=
scope=
service_account_credentials_path=
service_account_user_to_impersonate=
spreadsheet_format=desktop
spreadsheet_icon=
sqlite3_busy_timeout=5000
stream_large_files=true
team_drive_id=0AH4Ykx7cpiF6Uk9PVA
umask=0o022
verification_code=
write_buffers=false
-69
View File
@@ -1,69 +0,0 @@
acknowledge_abuse=false
apps_script_format=desktop
apps_script_icon=
async_upload_queue=false
async_upload_queue_max_length=0
async_upload_threads=10
autodetect_mime=true
background_folder_fetching=true
cache_directory=
client_id=
client_secret=
connect_timeout_ms=5000
curl_debug_off=false
data_directory=
debug_buffers=false
delete_forever_in_trash_folder=false
desktop_entry_as_html=false
desktop_entry_exec=
disable_trash=false
docs_file_extension=true
document_format=desktop
document_icon=
download_docs=true
drawing_format=desktop
drawing_icon=
form_format=desktop
form_icon=
fusion_table_format=desktop
fusion_table_icon=
keep_duplicates=false
large_file_read_only=true
large_file_threshold_mb=16
log_directory=
log_to=
lost_and_found=false
low_speed_limit=0
low_speed_time=0
map_format=desktop
map_icon=
max_cache_size_mb=512000
max_download_speed=0
max_memory_cache_size=10737418240
max_retries=8
max_upload_chunk_size=1099511627776
max_upload_speed=0
memory_buffer_size=8388608
metadata_cache_time=60
metadata_memory_cache=true
metadata_memory_cache_saving_interval=30
mv_keep_target=false
oauth2_loopback=false
oauth2_loopback_port=8080
presentation_format=desktop
presentation_icon=
read_ahead_buffers=5
read_only=false
redirect_uri=
root_folder=
scope=
service_account_credentials_path=
service_account_user_to_impersonate=
spreadsheet_format=desktop
spreadsheet_icon=
sqlite3_busy_timeout=5000
stream_large_files=true
team_drive_id=0AIwrATJm5KEtUk9PVA
umask=0o022
verification_code=
write_buffers=false
-12
View File
@@ -1,12 +0,0 @@
[init]
defaultBranch = main
[user]
name = Tri Vo Khac
email = 33442340+vokhactri@users.noreply.github.com
[filter "lfs"]
required = true
clean = git-lfs clean -- %f
smudge = git-lfs smudge -- %f
process = git-lfs filter-process
[push]
autoSetupRemote = true
+35
View File
@@ -0,0 +1,35 @@
# KDE Plasma packages
From the repository root, install all KDE packages:
```sh
(cd kde && stow -t "$HOME" */)
```
Or choose individual packages:
```sh
stow -d kde -t "$HOME" spectacle helium
```
| Package | Details |
| ---------------------------------- | -------------------------------------------------------- |
| [theme](theme/README.md) | Darwin Breeze KDE colors and generated app themes |
| [helium](helium/README.md) | Browser flags; colors come from GTK |
| [spectacle](spectacle/README.md) | Screenshots to clipboard with a notification, no preview |
| [tray-icons](tray-icons/README.md) | Ngó Sen, NetBird and qBittorrent tray icons |
Theme and Spectacle need an additional apply step after stowing their package:
```sh
# If you selected theme:
./kde/theme/apply.sh
# If you selected spectacle:
./kde/spectacle/apply.py
```
The apply scripts require a running KDE Plasma 6 session. Ngó Sen and NetBird
icons need an additional install step described in the tray-icons README.
Packages can be selected independently; Helium follows the Darwin Breeze
colors only when the theme is applied.
@@ -0,0 +1,8 @@
# Hardware video acceleration (VA-API, AMD radeonsi) on Wayland
--ozone-platform-hint=auto
--enable-features=AcceleratedVideoDecodeLinuxGL,AcceleratedVideoDecodeLinuxZeroCopyGL,AcceleratedVideoEncoder
# Don't tag surfaces as sRGB. KWin shows tagged sRGB through a gamma 2.2
# curve, which lifts dark grays (40 -> 44), so the tab strip would come out
# lighter than KDE title bars.
--disable-features=WaylandWpColorManagerV1
+14
View File
@@ -0,0 +1,14 @@
# Helium
Browser flags for hardware video decoding on Wayland and for colors that
match KDE apps. From the repository root:
```sh
stow -d kde -t "$HOME" helium
```
Helium takes its colors and window buttons from GTK. In Settings →
Appearance, set Theme to GTK and turn off "Use system title bar and borders".
With the KDE `theme` package applied, GTK follows the Darwin Breeze colors and
the window buttons match KWin's; see
[Darwin Breeze → Helium notes](../theme/README.md#helium-notes).
@@ -0,0 +1,62 @@
#!/usr/bin/env xdg-open
[Desktop Entry]
GenericName=Screenshot Capture Utility
Name=Spectacle
Comment=Take screenshots and screen recordings
Categories=Qt;KDE;Utility;
Keywords=snapshot;capture;print;screenshot;snipping;snipping tool;snip;
Exec=/usr/bin/spectacle --background --region --copy-image
Icon=spectacle
Type=Application
StartupNotify=false
Actions=FullScreenScreenShot;CurrentMonitorScreenShot;ActiveWindowScreenShot;RectangularRegionScreenShot;WindowUnderCursorScreenShot;RecordRegion;RecordScreen;RecordWindow;OpenWithoutScreenshot;
DBusActivatable=false
X-DBUS-StartupType=Unique
X-DBUS-ServiceName=org.kde.Spectacle
X-KDE-Shortcuts=Print,Meta+Shift+S
X-KDE-DBUS-Restricted-Interfaces=org.kde.KWin.ScreenShot2
X-KDE-Wayland-Interfaces=org_kde_plasma_window_management,zkde_screencast_unstable_v1
[Desktop Action FullScreenScreenShot]
Name=Capture Entire Desktop
Exec=/usr/bin/spectacle --background --copy-image -f
X-KDE-Shortcuts=Shift+Print
[Desktop Action CurrentMonitorScreenShot]
Name=Capture Current Monitor
Exec=/usr/bin/spectacle --background --copy-image -m
[Desktop Action ActiveWindowScreenShot]
Name=Capture Active Window
Exec=/usr/bin/spectacle --background --copy-image -a
X-KDE-Shortcuts=Meta+Print
[Desktop Action RectangularRegionScreenShot]
Name=Capture Rectangular Region
Exec=/usr/bin/spectacle --background --copy-image -r
X-KDE-Shortcuts=Meta+Shift+Print
[Desktop Action WindowUnderCursorScreenShot]
Name=Capture Window Under Cursor
Exec=/usr/bin/spectacle --background --copy-image -u
X-KDE-Shortcuts=Meta+Ctrl+Print
[Desktop Action RecordRegion]
Name=Start/Stop Region Recording
Exec=/usr/bin/spectacle -R region
X-KDE-Shortcuts=Meta+Shift+R,Meta+R
[Desktop Action RecordScreen]
Name=Start/Stop Screen Recording
Exec=/usr/bin/spectacle -R screen
X-KDE-Shortcuts=Meta+Alt+R
[Desktop Action RecordWindow]
Name=Start/Stop Window Recording
Exec=/usr/bin/spectacle -R window
X-KDE-Shortcuts=Meta+Ctrl+R
[Desktop Action OpenWithoutScreenshot]
Name=Launch without taking a screenshot
Exec=/usr/bin/spectacle -l
@@ -0,0 +1 @@
../applications/org.kde.spectacle.desktop
+4
View File
@@ -0,0 +1,4 @@
^/README.*
^/apply\.py
^/settings
__pycache__
+28
View File
@@ -0,0 +1,28 @@
# Spectacle
Capture screenshots in the background, copy the image to the clipboard, and
show a completion notification. Screenshots are not automatically saved.
```sh
stow -d kde -t "$HOME" spectacle
./kde/spectacle/apply.py
```
Requires Spectacle, KDE Plasma 6, GNU Stow, Python 3, `kwriteconfig6`,
`kbuildsycoca6`, `qdbus6`, and `gdbus`. Run the apply script in your KDE session.
Move any existing files reported as conflicts by Stow out of the way first.
- **Print** / **Meta+Shift+S**: select a rectangular region.
- **Shift+Print**: entire desktop.
- **Meta+Print**: active window.
- **Meta+Shift+Print**: select a rectangular region.
- **Meta+Ctrl+Print**: window under the cursor.
The desktop launcher and shortcut entry are managed by Stow. The files in
`settings/` are merged into `~/.config/spectaclerc` and `~/.config/klipperrc`
by `apply.py`, preserving unrelated preferences and window state. Klipper's
`SaveImages=true` keeps captured images available after Spectacle exits.
After editing settings or launcher commands, run `apply.py` again. It rebuilds
the cache using the KDE session's environment and reloads only Spectacle's
shortcut component, preserving custom key bindings.
+86
View File
@@ -0,0 +1,86 @@
#!/usr/bin/env python3
"""Apply screenshot preferences and reload Spectacle's KDE shortcuts."""
import ast
import configparser
import os
from pathlib import Path
import re
import subprocess
from typing import Any
HERE = Path(__file__).resolve().parent
COMPONENT = "org.kde.spectacle.desktop"
ACCEL = "/component/org_kde_spectacle_desktop"
def run(*args: str, **kwargs: Any) -> subprocess.CompletedProcess[str]:
return subprocess.run(args, check=True, text=True, **kwargs)
def accel(path: str, method: str, *args: str) -> str:
return run(
"gdbus", "call", "--session", "--dest", "org.kde.kglobalaccel",
"--object-path", path, "--method", method, *args,
capture_output=True,
).stdout
def main() -> None:
for name in ("spectaclerc", "klipperrc"):
config = configparser.ConfigParser(interpolation=None)
config.optionxform = str # type: ignore[method-assign,assignment]
config.read(HERE / "settings" / name)
for group in config.sections():
for key, value in config[group].items():
run("kwriteconfig6", "--file", name, "--group", group,
"--key", key, value)
# T3's locale and XDG_DATA_DIRS can differ from the running KDE session.
# Build the cache KDE actually reads, rather than an app-specific cache.
session: dict[str, str] = dict(
line.split("=", 1) for line in
run("systemctl", "--user", "show-environment", capture_output=True)
.stdout.splitlines() if "=" in line
)
env = os.environ.copy()
for key in ("LANG", "LANGUAGE", "XDG_DATA_DIRS", "XDG_DATA_HOME",
"XDG_CACHE_HOME", "XDG_CONFIG_HOME"):
env.pop(key, None)
if key in session:
env[key] = session[key]
for key in set(env) | set(session):
if key.startswith("LC_"):
env.pop(key, None)
if key in session:
env[key] = session[key]
run("kbuildsycoca6", "--noincremental", env=env)
# Existing shortcut components retain their old Exec commands. Recreate
# only Spectacle's component, preserving any customized key bindings.
try:
output = accel(ACCEL, "org.kde.kglobalaccel.Component.allShortcutInfos")
except subprocess.CalledProcessError:
shortcuts: list[Any] = [] # Component has not been registered yet.
else:
shortcuts = ast.literal_eval(re.sub(r"@a[is] ", "", output))[0]
accel(ACCEL, "org.kde.kglobalaccel.Component.cleanUp")
action = [COMPONENT, "_reload_config", "Spectacle", "Reload configuration"]
accel("/kglobalaccel", "org.kde.KGlobalAccel.doRegister", repr(action))
accel("/kglobalaccel", "org.kde.KGlobalAccel.unregister",
COMPONENT, "_reload_config")
for name, label, component, friendly, context, _, keys, defaults in shortcuts:
if keys != defaults:
identity = component if context == "default" else f"{component}|{context}"
accel("/kglobalaccel", "org.kde.KGlobalAccel.setForeignShortcut",
repr([identity, name, friendly, label]), repr(keys))
run("qdbus6", "org.kde.klipper", "/klipper",
"org.kde.klipper.klipper.reloadConfig")
print("Applied Spectacle: copy to clipboard with a notification, no preview.")
if __name__ == "__main__":
main()
+2
View File
@@ -0,0 +1,2 @@
[General]
SaveImages=true
+3
View File
@@ -0,0 +1,3 @@
[General]
autoSaveImage=false
clipboardGroup=PostScreenshotCopyImage
+12
View File
@@ -0,0 +1,12 @@
/* Helium (Chromium) with its GTK theme. Chromium adds a "chromium" class to
every node of the GTK style contexts it reads colors from, so these rules
reach Helium and no other GTK app.
In the compact layout, the address bar takes the text field color and the
segment with the extension and window buttons takes the window color,
which Chromium resolves to the darker view color. Both get the title bar
color, so the strip reads as one bar like a KDE title bar. */
window.background.chromium,
textview.view.chromium {
background-color: @theme_bg_color_breeze;
}
+4
View File
@@ -0,0 +1,4 @@
__pycache__/
# Binary packages built by build.py.
*.vsix
*.tdesktop-theme
@@ -0,0 +1,165 @@
# macOS-inspired colors for Breeze (dark variant).
# Header and Window share one color so the title bar merges into the toolbar.
[ColorEffects:Disabled]
Color=56,56,56
ColorAmount=0
ColorEffect=0
ContrastAmount=0.65
ContrastEffect=1
IntensityAmount=0.1
IntensityEffect=2
[ColorEffects:Inactive]
ChangeSelectionColor=true
Color=112,111,110
ColorAmount=0.025
ColorEffect=2
ContrastAmount=0.1
ContrastEffect=2
Enable=false
IntensityAmount=0
IntensityEffect=0
[Colors:Button]
BackgroundAlternate=109,109,109
BackgroundNormal=93,93,93
DecorationFocus=0,122,255
DecorationHover=0,122,255
ForegroundActive=65,156,255
ForegroundInactive=154,154,154
ForegroundLink=65,156,255
ForegroundNegative=255,74,76
ForegroundNeutral=255,146,48
ForegroundNormal=230,230,230
ForegroundPositive=48,209,88
ForegroundVisited=191,90,242
[Colors:Complementary]
BackgroundAlternate=40,40,40
BackgroundNormal=30,30,30
DecorationFocus=0,122,255
DecorationHover=0,122,255
ForegroundActive=65,156,255
ForegroundInactive=154,154,154
ForegroundLink=65,156,255
ForegroundNegative=255,74,76
ForegroundNeutral=255,146,48
ForegroundNormal=221,221,221
ForegroundPositive=48,209,88
ForegroundVisited=191,90,242
[Colors:Header]
BackgroundAlternate=40,40,40
BackgroundNormal=40,40,40
DecorationFocus=0,122,255
DecorationHover=0,122,255
ForegroundActive=65,156,255
ForegroundInactive=154,154,154
ForegroundLink=65,156,255
ForegroundNegative=255,74,76
ForegroundNeutral=255,146,48
ForegroundNormal=222,222,222
ForegroundPositive=48,209,88
ForegroundVisited=191,90,242
[Colors:Header][Inactive]
BackgroundAlternate=36,36,36
BackgroundNormal=36,36,36
DecorationFocus=0,122,255
DecorationHover=0,122,255
ForegroundActive=65,156,255
ForegroundInactive=128,128,128
ForegroundLink=65,156,255
ForegroundNegative=255,74,76
ForegroundNeutral=255,146,48
ForegroundNormal=154,154,154
ForegroundPositive=48,209,88
ForegroundVisited=191,90,242
[Colors:Selection]
BackgroundAlternate=25,135,255
BackgroundNormal=0,122,255
DecorationFocus=0,122,255
DecorationHover=0,122,255
ForegroundActive=255,255,255
ForegroundInactive=222,222,222
ForegroundLink=255,255,255
ForegroundNegative=255,200,200
ForegroundNeutral=255,220,180
ForegroundNormal=255,255,255
ForegroundPositive=200,255,210
ForegroundVisited=230,210,255
# macOS turns the selection gray when the window loses focus.
[Colors:Selection][Inactive]
BackgroundAlternate=70,70,70
BackgroundNormal=70,70,70
DecorationFocus=0,122,255
DecorationHover=0,122,255
ForegroundActive=255,255,255
ForegroundInactive=222,222,222
ForegroundLink=255,255,255
ForegroundNegative=255,74,76
ForegroundNeutral=255,146,48
ForegroundNormal=255,255,255
ForegroundPositive=48,209,88
ForegroundVisited=191,90,242
[Colors:Tooltip]
BackgroundAlternate=46,46,46
BackgroundNormal=40,40,40
DecorationFocus=0,122,255
DecorationHover=0,122,255
ForegroundActive=65,156,255
ForegroundInactive=154,154,154
ForegroundLink=65,156,255
ForegroundNegative=255,74,76
ForegroundNeutral=255,146,48
ForegroundNormal=222,222,222
ForegroundPositive=48,209,88
ForegroundVisited=191,90,242
[Colors:View]
BackgroundAlternate=37,37,37
BackgroundNormal=30,30,30
DecorationFocus=0,122,255
DecorationHover=0,122,255
ForegroundActive=65,156,255
ForegroundInactive=154,154,154
ForegroundLink=65,156,255
ForegroundNegative=255,74,76
ForegroundNeutral=255,146,48
ForegroundNormal=221,221,221
ForegroundPositive=48,209,88
ForegroundVisited=191,90,242
[Colors:Window]
BackgroundAlternate=46,46,46
BackgroundNormal=40,40,40
DecorationFocus=0,122,255
DecorationHover=0,122,255
ForegroundActive=65,156,255
ForegroundInactive=154,154,154
ForegroundLink=65,156,255
ForegroundNegative=255,74,76
ForegroundNeutral=255,146,48
ForegroundNormal=222,222,222
ForegroundPositive=48,209,88
ForegroundVisited=191,90,242
[General]
ColorScheme=DarwinBreezeDark
Name=Darwin Breeze Dark
shadeSortColumn=true
[KDE]
contrast=4
[WM]
activeBackground=40,40,40
activeBlend=40,40,40
activeForeground=222,222,222
inactiveBackground=36,36,36
inactiveBlend=36,36,36
inactiveForeground=154,154,154
@@ -0,0 +1,24 @@
[kdeglobals][KDE]
widgetStyle=Breeze
[kdeglobals][General]
ColorScheme=DarwinBreezeDark
[kdeglobals][Icons]
Theme=breeze-dark
[plasmarc][Theme]
name=default
[kcminputrc][Mouse]
cursorTheme=breeze_cursors
[kwinrc][WindowSwitcher]
LayoutName=org.kde.breeze.desktop
[kwinrc][DesktopSwitcher]
LayoutName=org.kde.breeze.desktop
[kwinrc][org.kde.kdecoration2]
library=org.kde.breeze
theme=Breeze
@@ -0,0 +1,17 @@
{
"KPackageStructure": "Plasma/LookAndFeel",
"KPlugin": {
"Authors": [
{
"Name": "trivk"
}
],
"Category": "",
"Description": "Breeze in macOS-inspired colors (dark)",
"Id": "dev.trivk.darwinbreeze.dark",
"License": "GPL-2.0-or-later",
"Name": "Darwin Breeze Dark",
"Version": "1.0"
},
"X-Plasma-APIVersion": "2"
}
+8
View File
@@ -0,0 +1,8 @@
^/README.*
^/\.gitignore
^/apply\.sh
^/build\.py
^/t3
^/telegram
^/vscode
__pycache__
+133
View File
@@ -0,0 +1,133 @@
# Darwin Breeze
Breeze for KDE Plasma 6 in the macOS dark system colors, with Helium, T3 Code,
VS Code and Telegram themed from the same colors.
Only the colors change. Breeze still draws the widgets and the title bar, and
the window buttons stay on the right.
- Selection and focus rings use the macOS blue, `#007AFF`.
- The title bar has the same color as the toolbar below it, so the two read as
one strip.
- When a window loses focus, its selection turns gray, as on macOS.
- Errors, warnings, success text and links use Apple's system red, orange,
green, blue and purple.
## Install
From `~/.dotfiles`:
```sh
stow -d kde -t "$HOME" theme
./kde/theme/apply.sh
```
`apply.sh` regenerates the app themes, applies the global theme, hides the
line under the title bar, turns off the wallpaper accent color, gives Helium
the KWin title buttons and an even tab strip, publishes the T3 Code theme and
installs the VS Code extension. Restart Helium afterwards; T3 Code switches on its own. In VS
Code, pick "Darwin Breeze Dark" once under Preferences → Color Theme; after
later color changes, run Developer: Reload Window.
Telegram has to import its theme by hand: Settings → Chat Settings → Chat
background → Choose from file, then pick
`kde/theme/telegram/DarwinBreezeDark.tdesktop-theme` and Apply. Import it
again after the colors change.
## Changing colors
The color scheme is the only place colors are defined:
```
kde/theme/.local/share/color-schemes/DarwinBreezeDark.colors
```
Edit it, then run `./kde/theme/apply.sh` again. Everything else follows:
| App | How it gets the colors |
| --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| Qt / KDE apps | the color scheme itself |
| GTK apps | Breeze GTK, which `kde-gtk-config` syncs from the scheme |
| Tray icons in `kde/tray-icons/` | `ColorScheme-Text`, recolored by Plasma |
| Helium | Breeze GTK, through Helium's GTK theme (see [Helium notes](#helium-notes)) |
| T3 Code | `t3/darwin-breeze.json`, generated by `build.py` and published with `t3 theme set` |
| VS Code | `vscode/package.json` and `vscode/themes/`, generated by `build.py`, packed into `darwin-breeze.vsix` and installed by `apply.sh` |
| Telegram | `telegram/DarwinBreezeDark.tdesktop-theme`, built by `build.py` and imported by hand |
The generated text files are committed so that `stow` alone gives a working
setup; the binary packages (Telegram's `.tdesktop-theme`, VS Code's `.vsix`)
are built by `build.py` instead. Don't edit generated files by hand.
## T3 Code notes
- T3 Code ignores symlinked theme files, so the theme isn't stowed;
`apply.sh` publishes a copy into `~/.t3/userdata/themes/`.
- Every slot of the T3 theme maps to a role in the color scheme (see `t3()` in
`build.py`), so a new slot or a different mapping is a change there, not a
hand-edited color.
## VS Code notes
- The workbench colors start from VS Code's own default dark theme, Dark 2026
(vendored in `vscode/base/` with the themes it includes). It already lays
out its grays as the scheme does: the editor darkest, the chrome around it
lighter, widgets lighter still. Each of those becomes the matching scheme
gray and the grays between them are interpolated. Other colors take the
hue of the matching Apple color and keep their lightness and saturation.
Keys with an exact role, such as buttons, badges, the active tab's top
border and the git colors, are set directly (`vscode()` in `build.py`).
- Syntax colors are Pierre Dark's, the theme T3 Code highlights code with
(`vscode/base/pierre-dark.json`, taken from T3 Code). They are used as they
are, without gamma compensation, so code looks the same in both apps.
- The terminal palette is generated from the color scheme.
- VS Code is Electron, so its workbench colors get the same gamma
compensation as T3 Code.
- The `.vsix` isn't committed; `build.py` packs it from `vscode/`.
## Telegram notes
- Telegram has some 600 color keys and the scheme has roles for only a few
dozen of them (`telegram()` in `build.py`). The rest start from Telegram's
own night theme, vendored as `telegram/night.tdesktop-palette`: its
blue-tinted grays become scheme grays of the same brightness and its blues
take the macOS blue's hue. Other colors, such as the reds, greens and name
colors, are kept as night has them.
- The chat list, top bar and compose bar use the window color; the chat
behind the bubbles and the folder strip use the darker view color.
- Telegram is a Qt app, so unlike T3 Code and VS Code it needs no gamma
compensation.
- The `.tdesktop-theme` is a zip, so it isn't committed; `build.py` builds it
from the night palette and the color scheme.
## Helium notes
- Helium uses the GTK theme (Settings → Appearance → Theme: GTK) with "Use
system title bar and borders" off, so the tab strip doubles as the title
bar. Its colors come from Breeze GTK, which `kde-gtk-config` syncs from
the scheme; there is no Helium theme to generate.
- With the system title bar off, Helium draws the window buttons through
GTK. `kde-gtk-config` renders the KWin buttons into
`~/.config/gtk-3.0/window_decorations.css`, but hands that file to GTK apps
through a GTK module that Helium doesn't load, so Helium would show Breeze
GTK's own round buttons instead. `apply.sh` imports the file from `gtk.css`
so Helium picks it up too.
- In the compact layout, the address bar takes GTK's text field color and the
segment with the extension and window buttons takes the window color, which
Chromium resolves to the darker view color. `.config/gtk-3.0/chromium.css`
gives both the title bar color, and `apply.sh` imports it from `gtk.css`.
Chromium adds a `chromium` class to every GTK node it reads colors from, so
the rules reach Helium and no other GTK app.
- Chromium tags its output as sRGB and KWin shows it with a gamma 2.2 curve,
which lifts dark grays (40 becomes 44). T3 Code and VS Code get
pre-compensated colors from `build.py`; Helium instead runs with
`--disable-features=WaylandWpColorManagerV1`, so its surfaces go untagged
and show the GTK colors as they are.
## When the colors don't show up
- In System Settings → Colors, take the accent color from the color scheme. A
custom accent, or one taken from the wallpaper, replaces the blue.
- Use the Plasma style called "Breeze". "Breeze Dark" and "Breeze Light" carry
their own colors, so panels and popups ignore the scheme.
- GTK apps follow the scheme only with the Breeze GTK theme. Flatpak apps also
need `org.gtk.Gtk3theme.Breeze` installed.
+64
View File
@@ -0,0 +1,64 @@
#!/usr/bin/env bash
# Regenerate the app themes from the color scheme and apply Darwin Breeze.
#
# Run `stow -d kde -t "$HOME" theme` from the repo root first.
set -euo pipefail
here="$(cd "$(dirname "$0")" && pwd)"
data="${XDG_DATA_HOME:-$HOME/.local/share}"
if [ ! -e "$data/color-schemes/DarwinBreezeDark.colors" ]; then
echo 'DarwinBreezeDark.colors is not installed; run: stow -d kde -t "$HOME" theme' >&2
exit 1
fi
python3 -I "$here/build.py"
plasma-apply-lookandfeel --apply dev.trivk.darwinbreeze.dark
# plasma-apply-colorscheme skips a scheme that is already active, so edits
# to the .colors file would not be picked up. Bounce through stock Breeze.
plasma-apply-colorscheme BreezeClassic >/dev/null
plasma-apply-colorscheme DarwinBreezeDark >/dev/null
# kde-gtk-config writes gtk.css; add our imports to it.
gtk_import() {
local css="${XDG_CONFIG_HOME:-$HOME/.config}/$1/gtk.css"
if [ -e "$css" ] && ! grep -qF "'$2'" "$css"; then
sed -i "\$a @import '$2';" "$css"
fi
}
# kde-gtk-config gives GTK apps the KWin title buttons through a GTK module,
# which Helium doesn't load, so it would fall back to Breeze GTK's own
# buttons. Importing the same CSS from gtk.css reaches Helium too.
gtk_import gtk-3.0 window_decorations.css
gtk_import gtk-4.0 window_decorations.css
# Helium's tab strip colors (see chromium.css).
gtk_import gtk-3.0 chromium.css
# Drop the line under the title bar so it blends into the toolbar.
kwriteconfig6 --file breezerc --group Windeco --key DrawTitleBarSeparator false
# A wallpaper-derived accent color would override the blue from the scheme.
kwriteconfig6 --file kdeglobals --group General --key AccentColor --delete
kwriteconfig6 --file kdeglobals --group General --key accentColorFromWallpaper false
qdbus6 org.kde.KWin /KWin reconfigure 2>/dev/null \
|| dbus-send --session --type=signal /KWin org.kde.KWin.reloadConfig
# T3 Code skips symlinked theme files, so publish a copy instead of stowing it.
t3="$(command -v t3 || echo "$HOME/.t3/bin/t3")"
if [ -x "$t3" ]; then
"$t3" theme set "$here/t3/darwin-breeze.json" >/dev/null
fi
# VS Code only loads themes from installed extensions. --force reinstalls the
# same version, so color changes land without a version bump.
if command -v code >/dev/null; then
code --install-extension "$here/vscode/darwin-breeze.vsix" --force >/dev/null 2>&1
fi
echo "Applied Darwin Breeze"
if pgrep -x helium >/dev/null; then
echo "Restart Helium to pick up the new colors"
fi
+617
View File
@@ -0,0 +1,617 @@
#!/usr/bin/env python3
"""Generate app themes from the Darwin Breeze KDE color scheme.
.local/share/color-schemes/DarwinBreezeDark.colors is the only place colors
are defined. This script derives from it:
t3/darwin-breeze.json (published to T3 Code by apply.sh)
telegram/DarwinBreezeDark.tdesktop-theme (not committed; imported into Telegram by hand)
vscode/ (packed into vscode/darwin-breeze.vsix, installed by apply.sh)
"""
import colorsys
import configparser
import io
import json
import re
import struct
import zipfile
import zlib
from collections.abc import Callable, Mapping, Sequence
from pathlib import Path
HERE = Path(__file__).resolve().parent
PKG = HERE
SCHEME = PKG / ".local/share/color-schemes/DarwinBreezeDark.colors"
T3 = HERE / "t3/darwin-breeze.json"
# Telegram Desktop's built-in night theme, used as the base for every key the
# scheme has no role for: the colors file from telegramdesktop/tdesktop at
# 837b256, Telegram/Resources/night.tdesktop-theme.
TELEGRAM_BASE = HERE / "telegram/night.tdesktop-palette"
TELEGRAM = HERE / "telegram/DarwinBreezeDark.tdesktop-theme"
VSCODE = HERE / "vscode"
VSCODE_THEME = "themes/DarwinBreezeDark-color-theme.json"
# VS Code's default dark theme, Dark 2026 (which includes Dark Modern, Dark+
# and Visual Studio Dark), from Code - OSS 1.138 extensions/theme-defaults.
# The workbench colors start from it.
VSCODE_UI = VSCODE / "base/2026-dark.json"
# Pierre Dark, the syntax theme T3 Code highlights code with (from T3 Code
# 0.1.4). The editor uses its token colors as they are.
VSCODE_SYNTAX = VSCODE / "base/pierre-dark.json"
# An RGB or RGBA color, 0-255 per channel.
type Color = tuple[int, ...]
# Looks up a color in the scheme by group and key.
type ColorFn = Callable[[str, str], Color]
WHITE = (255, 255, 255)
# Apple systemCyan; the KDE scheme has no cyan role.
CYAN = (100, 210, 255)
# Apple systemYellow; search highlights in T3 Code.
YELLOW = (255, 255, 0)
def load() -> ColorFn:
cp = configparser.ConfigParser(interpolation=None, strict=False)
cp.optionxform = str # type: ignore[method-assign,assignment]
cp.read(SCHEME)
def color(group: str, key: str) -> Color:
return tuple(int(v) for v in cp[f"Colors:{group}"][key].split(","))
return color
def mix(a: Sequence[int], b: Sequence[int], t: float) -> Color:
return tuple(round(x + (y - x) * t) for x, y in zip(a, b))
def hexc(c: Sequence[int]) -> str:
"""#rrggbb, or #rrggbbaa when c carries an alpha."""
return "#" + "".join(f"{v:02x}" for v in c)
def kwin_compensate(c: Sequence[int]) -> list[int]:
"""Pre-distort a color for Chromium on KWin.
Chromium tags its surfaces as sRGB, KWin shows them with a gamma 2.2
curve, so dark grays come out lighter (40 -> 44). Encoding the target
with the inverse makes Chromium apps land on the same values as native
apps.
"""
def ch(v: int) -> int:
lin: float = (v / 255) ** 2.2
enc = 12.92 * lin if lin <= 0.0031308 else 1.055 * lin ** (1 / 2.4) - 0.055
return round(enc * 255)
return [ch(v) for v in c]
def ansi(color: ColorFn) -> list[Color]:
"""The 16 colors for the VS Code terminal."""
bg = color("View", "BackgroundNormal")
fg = color("View", "ForegroundNormal")
normal = [
mix(bg, fg, 0.15),
color("View", "ForegroundNegative"),
color("View", "ForegroundPositive"),
color("View", "ForegroundNeutral"),
color("View", "ForegroundLink"),
color("View", "ForegroundVisited"),
CYAN,
fg,
]
bright = [
mix(bg, fg, 0.45),
*(mix(c, WHITE, 0.25) for c in normal[1:7]),
mix(fg, WHITE, 0.6),
]
return normal + bright
def t3(color: ColorFn) -> dict[str, str]:
"""Every color slot of a T3 Code theme, mapped onto a scheme role."""
window, window_text = color("Window", "BackgroundNormal"), color("Window", "ForegroundNormal")
view, view_text = color("View", "BackgroundNormal"), color("View", "ForegroundNormal")
header, header_text = color("Header", "BackgroundNormal"), color("Header", "ForegroundNormal")
button, button_text = color("Button", "BackgroundNormal"), color("Button", "ForegroundNormal")
accent, accent_text = color("Selection", "BackgroundNormal"), color("Selection", "ForegroundNormal")
unfocused = color("Selection][Inactive", "BackgroundNormal")
unfocused_text = color("Selection][Inactive", "ForegroundNormal")
muted = color("View", "ForegroundInactive")
negative = color("View", "ForegroundNegative")
neutral = color("View", "ForegroundNeutral")
link = color("View", "ForegroundLink")
window_line = mix(window, window_text, 0.115)
colors = {
"canvas": view,
"chrome": header,
"toolbar": header,
"toolbarForeground": header_text,
"toolbarBorder": mix(header, header_text, 0.115),
"toolbarControl": button,
"toolbarControlForeground": button_text,
"toolbarControlHover": color("Button", "BackgroundAlternate"),
"surface": view,
"surfaceRaised": window,
"surfaceOverlay": window,
"text": view_text,
"textMuted": muted,
"border": mix(view, view_text, 0.115),
"input": mix(view, view_text, 0.3),
"focus": mix(view, accent, 0.5),
"accent": accent,
"accentForeground": accent_text,
"secondary": button,
"secondaryForeground": button_text,
"muted": window,
"mutedForeground": color("Window", "ForegroundInactive"),
"placeholder": muted,
"secondaryLabel": muted,
"iconMuted": muted,
"error": negative,
"errorForeground": negative,
"errorSurface": mix(view, negative, 0.1),
"warning": neutral,
"warningForeground": neutral,
"warningSurface": mix(view, neutral, 0.1),
"update": link,
"updateForeground": link,
"updateSurface": mix(view, link, 0.12),
"accentSurface": unfocused,
"accentSurfaceForeground": unfocused_text,
"messageSurface": window,
"messageForeground": window_text,
"messageAction": accent,
"messageActionForeground": accent_text,
"messageActionHover": color("Selection", "BackgroundAlternate"),
"codeBackground": window,
"codeForeground": WHITE,
"searchMatchBackground": mix(view, YELLOW, 0.25),
"searchMatchForeground": view_text,
"searchMatchActiveBackground": YELLOW,
"searchMatchActiveForeground": (0, 0, 0),
"sidebar": window,
"sidebarForeground": window_text,
"sidebarMutedForeground": color("Window", "ForegroundInactive"),
"sidebarControlSurface": button,
"sidebarRowHover": window_line,
"sidebarRowActive": unfocused,
"sidebarRowSelected": unfocused,
"sidebarBorder": window_line,
"terminalBackground": view,
"terminalForeground": WHITE,
"terminalCursor": WHITE,
"terminalSelection": mix(view, accent, 0.4),
"terminalScrollbar": mix(view, view_text, 0.3),
"terminalScrollbarHover": muted,
}
# T3 Code runs on Chromium too, so it needs the same KWin compensation.
return {k: hexc(kwin_compensate(v)) for k, v in colors.items()}
def telegram(color: ColorFn) -> dict[str, Color]:
"""Telegram keys mapped onto a scheme role; the rest come from night."""
window, window_text = color("Window", "BackgroundNormal"), color("Window", "ForegroundNormal")
view, view_text = color("View", "BackgroundNormal"), color("View", "ForegroundNormal")
header, header_text = color("Header", "BackgroundNormal"), color("Header", "ForegroundNormal")
title_inactive = color("Header][Inactive", "BackgroundNormal")
title_inactive_text = color("Header][Inactive", "ForegroundNormal")
tooltip, tooltip_text = color("Tooltip", "BackgroundNormal"), color("Tooltip", "ForegroundNormal")
accent, accent_text = color("Selection", "BackgroundNormal"), color("Selection", "ForegroundNormal")
accent_hover = color("Selection", "BackgroundAlternate")
muted = color("Window", "ForegroundInactive")
negative = color("Window", "ForegroundNegative")
positive = color("Window", "ForegroundPositive")
link = color("Window", "ForegroundLink")
hover = mix(window, window_text, 0.115)
ripple = mix(window, window_text, 0.18)
control = mix(window, window_text, 0.3)
msg_in = mix(view, view_text, 0.1)
msg_out = mix(view, accent, 0.5)
return {
"windowBg": window,
"windowFg": window_text,
"windowBgOver": hover,
"windowBgRipple": ripple,
"windowFgOver": window_text,
"windowSubTextFg": muted,
"windowSubTextFgOver": mix(muted, window_text, 0.2),
"windowBoldFg": window_text,
"windowBoldFgOver": window_text,
"windowBgActive": accent,
"windowFgActive": accent_text,
"windowActiveTextFg": link,
"windowShadowFgFallback": window,
"activeButtonBg": accent,
"activeButtonBgOver": accent_hover,
"activeButtonBgRipple": mix(accent, WHITE, 0.2),
"activeButtonFg": accent_text,
"activeButtonFgOver": accent_text,
"activeButtonSecondaryFg": mix(accent, accent_text, 0.75),
"activeLineFg": accent,
"activeLineFgError": negative,
"lightButtonBg": window,
"lightButtonBgOver": mix(window, accent, 0.12),
"lightButtonBgRipple": mix(window, accent, 0.2),
"lightButtonFg": link,
"attentionButtonFg": negative,
"attentionButtonFgOver": negative,
"attentionButtonBgOver": mix(window, negative, 0.12),
"attentionButtonBgRipple": mix(window, negative, 0.2),
"outlineButtonOutlineFg": accent,
"menuBg": window,
"menuBgOver": hover,
"menuBgRipple": ripple,
"menuIconFg": muted,
"menuIconFgOver": mix(muted, window_text, 0.3),
"menuSubmenuArrowFg": muted,
"menuFgDisabled": control,
"menuSeparatorFg": hover,
"checkboxFg": muted,
"sliderBgInactive": control,
"sliderBgActive": accent,
"inputBorderFg": control,
# Breeze draws text fields in the view color with a blue focus ring.
"filterInputActiveBg": view,
"filterInputInactiveBg": view,
"filterInputBorderFg": accent,
"tooltipBg": tooltip,
"tooltipFg": tooltip_text,
"tooltipBorderFg": mix(tooltip, tooltip_text, 0.115),
"titleBg": title_inactive,
"titleBgActive": header,
"titleFg": title_inactive_text,
"titleFgActive": header_text,
"topBarBg": header,
"boxBg": window,
"boxTitleFg": window_text,
"boxTextFgGood": positive,
"boxTextFgError": negative,
# Folder strip in the view color, so the selected folder merges into
# the chat list next to it.
"sideBarBg": view,
"sideBarBgActive": window,
"sideBarBgRipple": mix(view, window_text, 0.1),
"sideBarTextFg": muted,
"sideBarTextFgActive": link,
"sideBarIconFg": muted,
"sideBarIconFgActive": link,
"sideBarBadgeBg": accent,
"sideBarBadgeBgMuted": control,
"sideBarBadgeFg": accent_text,
"dialogsBg": window,
"dialogsBgOver": hover,
"dialogsRippleBg": ripple,
"dialogsBgActive": accent,
"dialogsRippleBgActive": accent_hover,
"dialogsNameFg": window_text,
"dialogsTextFg": muted,
"dialogsTextFgOver": muted,
"dialogsTextFgService": link,
"dialogsTextFgServiceOver": link,
"dialogsDateFg": muted,
"dialogsDateFgOver": muted,
"dialogsDraftFg": negative,
"dialogsOnlineBadgeFg": positive,
"dialogsVerifiedIconBg": link,
"dialogsVerifiedIconFg": window,
"dialogsUnreadBg": accent,
"dialogsUnreadBgOver": accent,
"dialogsUnreadFg": accent_text,
"dialogsUnreadBgMuted": control,
"dialogsUnreadBgMutedOver": mix(window, window_text, 0.35),
"dialogsUnreadBgActive": accent_text,
"dialogsUnreadFgActive": accent,
"dialogsUnreadBgMutedActive": mix(accent, accent_text, 0.55),
"historyComposeAreaBg": window,
"historyComposeAreaFg": window_text,
"historyComposeButtonBgOver": hover,
"historyComposeButtonBgRipple": ripple,
"historyTextInFg": view_text,
"historyTextOutFg": view_text,
"historyLinkInFg": link,
"msgInBg": msg_in,
"msgInBgSelected": mix(msg_in, accent, 0.3),
"msgOutBg": msg_out,
"msgOutBgSelected": mix(msg_out, accent, 0.3),
"msgInDateFg": muted,
"msgOutDateFg": mix(msg_out, WHITE, 0.55),
"msgSelectOverlay": (*accent, 0x4C),
"msgStickerOverlay": (*accent, 0x7F),
}
def luma(c: Sequence[int]) -> float:
return 0.299 * c[0] + 0.587 * c[1] + 0.114 * c[2]
def interp(points: Sequence[tuple[float, float]], x: float) -> float:
for (x0, y0), (x1, y1) in zip(points, points[1:]):
if x <= x1:
return y0 + (y1 - y0) * (x - x0) / (x1 - x0)
return points[-1][1]
def parse_hex(v: str) -> Color:
h = v[1:]
if len(h) in (3, 4):
h = "".join(ch * 2 for ch in h)
return tuple(int(h[i:i + 2], 16) for i in range(0, len(h), 2))
def telegram_theme(color: ColorFn) -> str:
"""The night theme, recolored onto the scheme.
Night tints everything blue. Its tinted grays become scheme grays of
matching brightness, its blues take the accent's hue and saturation, and
other hues (reds, greens, name colors) stay. telegram() then pins every
key that has a scheme role.
"""
base = TELEGRAM_BASE.read_text()
line_re = re.compile(r"^(\w+):\s*(#[0-9a-fA-F]+)\s*;")
night = {m[1]: parse_hex(m[2]) for m in map(line_re.match, base.splitlines()) if m}
window, muted = color("Window", "BackgroundNormal"), color("Window", "ForegroundInactive")
grays = sorted({
(0, 0),
(luma(night["windowBg"]), window[0]),
(luma(night["windowSubTextFg"]), muted[0]),
(255, 255),
})
accent_h, _, accent_s = colorsys.rgb_to_hls(*(v / 255 for v in color("Selection", "BackgroundNormal")))
def recolor(c: Color) -> Color:
rgb, alpha = c[:3], c[3:]
chroma = max(rgb) - min(rgb)
h, l, _ = colorsys.rgb_to_hls(*(v / 255 for v in rgb))
if chroma <= 4 or not 195 <= h * 360 <= 225:
return c
if chroma <= 55:
g = round(interp(grays, luma(rgb)))
return (g, g, g, *alpha)
return (*(round(v * 255) for v in colorsys.hls_to_rgb(accent_h, l, accent_s)), *alpha)
pinned = telegram(color)
seen: set[str] = set()
out = [f"// Generated by kde/theme/build.py from {SCHEME.name}"]
for line in base.splitlines():
m = line_re.match(line)
if m:
key = m[1]
seen.add(key)
c = pinned[key] if key in pinned else recolor(night[key])
line = f"{key}: {hexc(c)};" + line[m.end():]
elif re.match(r"^(\w+):", line) and line.split(":")[0] in pinned:
key = line.split(":")[0]
seen.add(key)
line = f"{key}: {hexc(pinned[key])};"
out.append(line)
out += [f"{k}: {hexc(c)};" for k, c in pinned.items() if k not in seen]
return "\n".join(out) + "\n"
def vscode_base_colors() -> dict[str, Color]:
"""Dark 2026's colors with its include chain resolved."""
chain: list[dict[str, str]] = []
path: Path | None = VSCODE_UI
while path:
theme = json.loads(path.read_text())
chain.append(theme.get("colors", {}))
path = path.parent / theme["include"] if "include" in theme else None
colors: dict[str, str] = {}
for layer in reversed(chain):
colors.update(layer)
return {k: parse_hex(v) for k, v in colors.items()}
def vscode(color: ColorFn) -> dict[str, str]:
"""Workbench colors: Dark 2026, recolored onto the scheme.
Dark 2026 lays out its grays the way the scheme does: the chrome lighter
than the editor, widgets lighter still. Each of those grays becomes the
scheme gray in the same place, and the grays in between are interpolated.
Each hue takes the hue of the matching scheme color but keeps its own
lightness and saturation, so a muted dark red background stays one. pins
then sets the keys that have an exact scheme role, which is where the full
macOS blue shows.
"""
window, window_text = color("Window", "BackgroundNormal"), color("Window", "ForegroundNormal")
view, view_text = color("View", "BackgroundNormal"), color("View", "ForegroundNormal")
accent, accent_text = color("Selection", "BackgroundNormal"), color("Selection", "ForegroundNormal")
muted = color("Window", "ForegroundInactive")
negative = color("View", "ForegroundNegative")
neutral = color("View", "ForegroundNeutral")
positive = color("View", "ForegroundPositive")
link = color("View", "ForegroundLink")
base = vscode_base_colors()
grays = sorted({
(0, 0),
(luma(base["editor.background"]), view[0]),
(luma(base["sideBar.background"]), window[0]),
(luma(base["editorWidget.background"]), color("Window", "BackgroundAlternate")[0]),
(luma(base["sideBar.border"]), mix(window, window_text, 0.115)[0]),
(luma(base["descriptionForeground"]), muted[0]),
(luma(base["foreground"]), window_text[0]),
(255, 255),
})
assert all(a[1] <= b[1] for a, b in zip(grays, grays[1:])), grays
def hls(c: Sequence[int]) -> tuple[float, float, float]:
return colorsys.rgb_to_hls(*(v / 255 for v in c))
# (hue range in degrees, scheme color whose hue it takes)
families: list[tuple[tuple[int, int], Color]] = [
((0, 15), negative),
((15, 70), neutral),
((70, 170), positive),
((170, 250), accent),
((250, 330), color("View", "ForegroundVisited")),
((330, 360), negative),
]
def recolor(c: Color) -> Color:
rgb, alpha = c[:3], c[3:]
if max(rgb) - min(rgb) <= 10:
g = round(interp(grays, luma(rgb)))
return (g, g, g, *alpha)
h, l, sat = hls(rgb)
target = next(t for (lo, hi), t in families if lo <= h * 360 < hi)
return (*(round(v * 255) for v in colorsys.hls_to_rgb(hls(target)[0], l, sat)), *alpha)
pins: dict[str, Color] = {
"editor.background": view,
"editor.foreground": view_text,
"titleBar.inactiveBackground": color("Header][Inactive", "BackgroundNormal"),
"titleBar.inactiveForeground": color("Header][Inactive", "ForegroundNormal"),
"focusBorder": (*accent, 0xB3),
"quickInputList.focusBackground": accent,
"button.background": accent,
"button.border": accent,
"button.hoverBackground": color("Selection", "BackgroundAlternate"),
"button.foreground": accent_text,
"badge.background": accent,
"badge.foreground": accent_text,
"activityBarBadge.background": accent,
"activityBarBadge.foreground": accent_text,
"tab.activeBorderTop": accent,
"panelTitle.activeBorder": accent,
"textLink.foreground": link,
"textLink.activeForeground": link,
}
names = ["Black", "Red", "Green", "Yellow", "Blue", "Magenta", "Cyan", "White"]
for i, c in enumerate(ansi(color)):
pins[f"terminal.ansi{'Bright' if i >= 8 else ''}{names[i % 8]}"] = c
colors = {k: pins.get(k) or recolor(c) for k, c in base.items()}
colors.update(pins)
# Electron is Chromium, so it needs the KWin compensation.
return {k: hexc(kwin_compensate(c[:3]) + list(c[3:])) for k, c in sorted(colors.items())}
def vscode_files(color: ColorFn) -> dict[str, str]:
"""The extension files, keyed by their path inside it."""
name = "Darwin Breeze Dark"
# Syntax colors as T3 Code shows them. T3 Code doesn't compensate them
# either, so the two render the same.
syntax = json.loads(VSCODE_SYNTAX.read_text())
theme = {
"$schema": "vscode://schemas/color-theme",
"name": name,
"type": "dark",
"semanticHighlighting": True,
"colors": vscode(color),
"tokenColors": syntax["tokenColors"],
"semanticTokenColors": syntax["semanticTokenColors"],
}
package = {
"name": "darwin-breeze",
"displayName": "Darwin Breeze",
"description": f"Generated by kde/theme/build.py from {SCHEME.name}",
"publisher": "trivk",
"version": "1.0.0",
"engines": {"vscode": "^1.70.0"},
"categories": ["Themes"],
"contributes": {
"themes": [{"label": name, "uiTheme": "vs-dark", "path": f"./{VSCODE_THEME}"}],
},
}
return {
"package.json": json.dumps(package, indent=2) + "\n",
VSCODE_THEME: json.dumps(theme, indent=2) + "\n",
}
def vsix(files: Mapping[str, str]) -> bytes:
"""Pack the extension the way vsce does, for code --install-extension."""
manifest = """<?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
<Metadata>
<Identity Language="en-US" Id="darwin-breeze" Version="1.0.0" Publisher="trivk"/>
<DisplayName>Darwin Breeze</DisplayName>
<Description xml:space="preserve">Darwin Breeze Dark color theme</Description>
<Categories>Themes</Categories>
<Properties>
<Property Id="Microsoft.VisualStudio.Code.Engine" Value="^1.70.0"/>
</Properties>
</Metadata>
<Installation>
<InstallationTarget Id="Microsoft.VisualStudio.Code"/>
</Installation>
<Dependencies/>
<Assets>
<Asset Type="Microsoft.VisualStudio.Code.Manifest" Path="extension/package.json" Addressable="true"/>
</Assets>
</PackageManifest>
"""
content_types = """<?xml version="1.0" encoding="utf-8"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension=".json" ContentType="application/json"/><Default Extension=".vsixmanifest" ContentType="text/xml"/></Types>
"""
return zip_bytes({
"[Content_Types].xml": content_types,
"extension.vsixmanifest": manifest,
**{f"extension/{path}": text for path, text in files.items()},
})
def solid_png(c: Sequence[int]) -> bytes:
"""A 1x1 PNG; Telegram stretches it over the chat as a plain background."""
def chunk(kind: bytes, data: bytes) -> bytes:
return struct.pack(">I", len(data)) + kind + data + struct.pack(">I", zlib.crc32(kind + data))
return (
b"\x89PNG\r\n\x1a\n"
+ chunk(b"IHDR", struct.pack(">IIBBBBB", 1, 1, 8, 2, 0, 0, 0))
+ chunk(b"IDAT", zlib.compress(bytes([0, *c])))
+ chunk(b"IEND", b"")
)
def zip_bytes(files: Mapping[str, str | bytes]) -> bytes:
"""A zip with fixed timestamps, so an unchanged theme rebuilds byte-identical."""
buf = io.BytesIO()
with zipfile.ZipFile(buf, "w", zipfile.ZIP_DEFLATED) as z:
for name, data in files.items():
info = zipfile.ZipInfo(name, (1980, 1, 1, 0, 0, 0))
info.compress_type = zipfile.ZIP_DEFLATED
info.external_attr = 0o644 << 16
z.writestr(info, data)
return buf.getvalue()
def write(path: Path, data: str | bytes) -> bool:
path.parent.mkdir(parents=True, exist_ok=True)
if isinstance(data, str):
data = data.encode()
if path.exists() and path.read_bytes() == data:
return False
path.write_bytes(data)
print(f"wrote {path.relative_to(PKG.parent)}")
return True
def main() -> None:
color = load()
theme = {"version": 1, "name": "Darwin Breeze", "appearance": "dark", "colors": t3(color)}
write(T3, json.dumps(theme, indent=2) + "\n")
write(TELEGRAM, zip_bytes({
"colors.tdesktop-theme": telegram_theme(color),
"background.png": solid_png(color("View", "BackgroundNormal")),
}))
files = vscode_files(color)
for path, text in files.items():
write(VSCODE / path, text)
write(VSCODE / "darwin-breeze.vsix", vsix(files))
if __name__ == "__main__":
main()
+68
View File
@@ -0,0 +1,68 @@
{
"version": 1,
"name": "Darwin Breeze",
"appearance": "dark",
"colors": {
"canvas": "#181818",
"chrome": "#232323",
"toolbar": "#232323",
"toolbarForeground": "#dfdfdf",
"toolbarBorder": "#3a3a3a",
"toolbarControl": "#5d5d5d",
"toolbarControlForeground": "#e7e7e7",
"toolbarControlHover": "#6d6d6d",
"surface": "#181818",
"surfaceRaised": "#232323",
"surfaceOverlay": "#232323",
"text": "#dedede",
"textMuted": "#9b9b9b",
"border": "#313131",
"input": "#565656",
"focus": "#064b8f",
"accent": "#007bff",
"accentForeground": "#ffffff",
"secondary": "#5d5d5d",
"secondaryForeground": "#e7e7e7",
"muted": "#232323",
"mutedForeground": "#9b9b9b",
"placeholder": "#9b9b9b",
"secondaryLabel": "#9b9b9b",
"iconMuted": "#9b9b9b",
"error": "#ff494b",
"errorForeground": "#ff494b",
"errorSurface": "#311c1e",
"warning": "#ff932c",
"warningForeground": "#ff932c",
"warningSurface": "#31251a",
"update": "#3f9dff",
"updateForeground": "#3f9dff",
"updateSurface": "#1c2936",
"accentSurface": "#444444",
"accentSurfaceForeground": "#ffffff",
"messageSurface": "#232323",
"messageForeground": "#dfdfdf",
"messageAction": "#007bff",
"messageActionForeground": "#ffffff",
"messageActionHover": "#1288ff",
"codeBackground": "#232323",
"codeForeground": "#ffffff",
"searchMatchBackground": "#55550e",
"searchMatchForeground": "#dedede",
"searchMatchActiveBackground": "#ffff00",
"searchMatchActiveForeground": "#000000",
"sidebar": "#232323",
"sidebarForeground": "#dfdfdf",
"sidebarMutedForeground": "#9b9b9b",
"sidebarControlSurface": "#5d5d5d",
"sidebarRowHover": "#3a3a3a",
"sidebarRowActive": "#444444",
"sidebarRowSelected": "#444444",
"sidebarBorder": "#3a3a3a",
"terminalBackground": "#181818",
"terminalForeground": "#ffffff",
"terminalCursor": "#ffffff",
"terminalSelection": "#0a4179",
"terminalScrollbar": "#565656",
"terminalScrollbarHover": "#9b9b9b"
}
}
+467
View File
@@ -0,0 +1,467 @@
windowBg: #17212b; // white: fallback for background
windowFg: #f5f5f5; // black: fallback for text
windowBgOver: #232e3c; // light gray: fallback for background with mouse over
windowBgRipple: #24303d; // darker gray: fallback for ripple effect
windowFgOver: #e9ecf0; // black: fallback for text with mouse over
windowSubTextFg: #708499; // gray: fallback for additional text
windowSubTextFgOver: #7c90a4; // darker gray: fallback for additional text with mouse over
windowBoldFg: #e9e8e8; // dark gray: fallback for bold text
windowBoldFgOver: #e9e9e9; // dark gray: fallback for bold text with mouse over
windowBgActive: #5288c1; // bright blue: fallback for blue filled active areas
windowFgActive: #ffffff; // white: fallback for text on active areas
windowActiveTextFg: #6ab3f3; // online blue: fallback for active text like online status
windowShadowFg: #000000; // black: fallback for shadow
windowShadowFgFallback: #17212b; // gray: fallback for shadow without opacity
shadowFg: #04080e56; // most shadows (including opacity)
slideFadeOutBg: #0000003c; // slide animation (chat to profile) fade out filling
slideFadeOutShadowFg: windowShadowFg; // slide animation (chat to profile) fade out right section shadow
imageBg: #000000; // image background fallback (when photo size is less than minimum allowed)
imageBgTransparent: #ffffff; // image background when displaying an image with opacity where no opacity is needed
activeButtonBg: #2f6ea5; // default active button background
activeButtonBgOver: #3476ab; // default active button background with mouse over
activeButtonBgRipple: #3b7cb1; // default active button ripple effect
activeButtonFg: #ffffff; // default active button text
activeButtonFgOver: #ffffff; // default active button text with mouse over
activeButtonSecondaryFg: #9abfe7; // default active button additional text (selected messages counter in forward / delete buttons)
activeButtonSecondaryFgOver: activeButtonSecondaryFg; // default active button additional text with mouse over
activeLineFg: #6396cb; // default active line (like code input field bottom border when you log in and field is focused)
activeLineFgError: #ef5959; // default active line for error state (like code input field bottom border when you log in and you've entered incorrect code)
lightButtonBg: #17212b; // default light button background (like buttons in boxes)
lightButtonBgOver: #1d2a39; // default light button background with mouse over
lightButtonBgRipple: #223143; // default light button ripple effect
lightButtonFg: #6ab2f2; // default light button text
lightButtonFgOver: lightButtonFg; // default light button text with mouse over
attentionButtonFg: #ec3942; // default attention button text (like confirm button on log out)
attentionButtonFgOver: #ec3942; // default attention button text with mouse over
attentionButtonBgOver: #592a2a64; // default attention button background with mouse over
attentionButtonBgRipple: #68323264; // default attention button ripple effect
outlineButtonBg: windowBg; // default left outlined button background (like shared media links in profiles)
outlineButtonBgOver: #202b37; // default left outlined button background with mouse over
outlineButtonOutlineFg: #3983c3; // default left outlined button left outline border
outlineButtonBgRipple: #27323f; // default left outlined button ripple effect
menuBg: #17212b; // default popup menu background
menuBgOver: #ffffff; // default popup menu item background with mouse over
menuBgRipple: #1f2934; // default popup menu item ripple effect
menuIconFg: #6c7883; // default popup menu item icon (like main menu)
menuIconFgOver: #dcdcdc; // default popup menu item icon with mouse over
menuSubmenuArrowFg: #637c95; // default popup menu submenu arrow icon (like in message field context menu in case of RTL system language)
menuFgDisabled: #3d4e5c; // default popup menu item disabled text (like unavailable items in message field context menu)
menuSeparatorFg: #232f39; // default popup menu separator (like in message field context menu)
scrollBarBg: #ffffff53; // default scroll bar current rectangle, the bar itself (like in chats list)
scrollBarBgOver: #ffffff7a; // default scroll bar current rectangle with mouse over it
scrollBg: #ffffff1a; // default scroll bar background
scrollBgOver: #ffffff2c; // default scroll bar background with mouse over the scroll bar
smallCloseIconFg: #55616c; // small X icon (like in Show all sessions box to the right for sessions termination)
smallCloseIconFgOver: #a3a3a3; // small X icon with mouse over
radialFg: windowFgActive; // default radial loader line (like in Media Viewer when loading a photo)
radialBg: #00000056; // default radial loader background (like in Media Viewer when loading a photo)
placeholderFg: #6d7883; // default input field placeholder when field is not focused (like in phone input field when you log in)
placeholderFgActive: #4f5b67; // default input field placeholder when field is focused
inputBorderFg: #313c49; // default input field bottom border (like in code input field when you log in and field is not focused)
filterInputBorderFg: #242f3d; // default rounded input field border (like in chats list search field when field is focused)
filterInputInactiveBg: #242f3d; // default rounded input field background (like in chats list search field when field is inactive)
checkboxFg: #4f6276; // default unchecked checkbox rounded rectangle (and also emoji category icons)
sliderBgInactive: #364554; // default slider not active bar (like in Settings when you choose interface scale or custom notifications count)
sliderBgActive: #4a81bc; // default slider active bar (like in Settings when you choose interface scale or custom notifications count)
tooltipBg: #16222d; // tooltip background (like when you put mouse over the message timestamp and wait)
tooltipFg: #d4e0ea; // tooltip text
tooltipBorderFg: #16222d; // tooltip border
titleShadow: #00000000; // one pixel line shadow at the bottom of custom window title
titleBg: #1f2936; // custom window title background when window is inactive
titleBgActive: #242f3d; // custom window title background when window is active
titleButtonBg: titleBg; // custom window title minimize/maximize/restore button background when window is inactive (Windows only)
titleButtonFg: #576673; // custom window title minimize/maximize/restore button icon when window is inactive (Windows only)
titleButtonBgOver: #25303e; // custom window title minimize/maximize/restore button background with mouse over when window is inactive (Windows only)
titleButtonFgOver: #e0e0e0; // custom window title minimize/maximize/restore button icon with mouse over when window is inactive (Windows only)
titleButtonBgActive: #242f3d; // custom window title minimize/maximize/restore button background when window is active (Windows only)
titleButtonFgActive: titleButtonFg; // custom window title minimize/maximize/restore button icon when window is active (Windows only)
titleButtonBgActiveOver: #2c3847; // custom window title minimize/maximize/restore button background with mouse over when window is active (Windows only)
titleButtonFgActiveOver: titleButtonFgOver; // custom window title minimize/maximize/restore button icon with mouse over when window is active (Windows only)
titleButtonCloseBg: titleButtonBg; // custom window title close button background when window is inactive (Windows only)
titleButtonCloseFg: titleButtonFg; // custom window title close button icon when window is inactive (Windows only)
titleButtonCloseBgOver: #e92539; // custom window title close button background with mouse over when window is inactive (Windows only)
titleButtonCloseFgOver: windowFgActive; // custom window title close button icon with mouse over when window is inactive (Windows only)
titleButtonCloseBgActive: #242f3d; // custom window title close button background when window is active (Windows only)
titleButtonCloseFgActive: titleButtonCloseFg; // custom window title close button icon when window is active (Windows only)
titleButtonCloseBgActiveOver: #e92539; // custom window title close button background with mouse over when window is active (Windows only)
titleButtonCloseFgActiveOver: titleButtonCloseFgOver; // custom window title close button icon with mouse over when window is active (Windows only)
titleFg: #6a7680; // custom window title text when window is inactive (macOS only)
titleFgActive: #91a3b3; // custom window title text when window is active (macOS only)
trayCounterBg: #f23c34; // tray icon counter background
trayCounterBgMute: #888888; // tray icon counter background if all unread messages are muted
trayCounterFg: #ffffff; // tray icon counter text
trayCounterBgMacInvert: #ffffff; // tray icon counter background when tray icon is pressed or when dark theme of macOS is used (macOS only)
trayCounterFgMacInvert: #ffffff01; // tray icon counter text when tray icon is pressed or when dark theme of macOS is used (macOS only)
layerBg: #0000007f; // box and main menu background layer fade
cancelIconFg: #737e87; // default for settings close icon and box search cancel icon
cancelIconFgOver: #dcdcdc; // default for settings close icon and box search cancel icon with mouse over
boxBg: #17212b; // box background
boxTextFg: windowFg; // box text
boxTextFgGood: #5598db; // accepted box text (like when choosing username that is not occupied)
boxTextFgError: #dc3d3d; // rejecting box text (like when choosing username that is occupied)
boxTitleFg: #ebebeb; // box title text
boxSearchBg: #17212b; // box search field background (like in contacts box)
boxTitleAdditionalFg: #6d7f8f; // box title additional text (like in create group box when you see chosen members count)
boxTitleCloseFg: cancelIconFg; // settings close icon and box search cancel icon (like in contacts box)
boxTitleCloseFgOver: cancelIconFgOver; // settings close icon and box search cancel icon (like in contacts box) with mouse over
membersAboutLimitFg: #677a8b; // text in channel members box about the limit (max 200 last members are shown)
contactsBg: #17212b; // contacts (and some other) box row background
contactsBgOver: #1f2c39; // contacts (and some other) box row background with mouse over
contactsNameFg: boxTextFg; // contacts (and some other) box row name text
contactsStatusFg: #677a8b; // contacts (and some other) box row additional text (like last seen stamp)
contactsStatusFgOver: #677a8b; // contacts (and some other) box row additional text (like last seen stamp) with mouse over
contactsStatusFgOnline: #559be0; // contacts (and some other) box row active additional text (like online status)
photoCropFadeBg: layerBg; // avatar crop box fade background (when choosing a new photo in Settings or for a group)
photoCropPointFg: #ffffff7f; // avatar crop box corner rectangles (when choosing a new photo in Settings or for a group)
callArrowFg: #49a2f0; // received phone call arrow (in calls list box)
callArrowMissedFg: #ed5050; // missed phone call arrow (in calls list box)
introBg: windowBg; // login background
introTitleFg: #eeeeee; // login title text
introDescriptionFg: #72879b; // login description text
introErrorFg: #e94040; // login error text (like when providing a wrong log in code)
introCoverTopBg: #124a82; // intro gradient top (from)
introCoverBottomBg: #23659f; // intro gradient bottom (to)
introCoverIconsFg: #3b7cbd; // intro cloud graphics
introCoverPlaneTrace: #3870a8; // intro plane traces
introCoverPlaneInner: #ced9e2; // intro plane part
introCoverPlaneOuter: #97a9b5; // intro plane part
introCoverPlaneTop: #ffffff; // intro plane part
dialogsMenuIconFg: menuIconFg; // main menu and lock telegram icon
dialogsMenuIconFgOver: menuIconFgOver; // main menu and lock telegram icon with mouse over
dialogsBg: windowBg; // chat list background
dialogsNameFg: #f5f5f5; // chat list name text
dialogsChatIconFg: dialogsNameFg; // chat list group or channel icon
dialogsDateFg: #8696a8; // chat list date text
dialogsTextFg: #7f91a4; // chat list message text
dialogsTextFgService: #73b9f5; // chat list group sender name text (or media message type text)
dialogsDraftFg: #ff525d; // chat list draft label
dialogsVerifiedIconBg: #6ab3f3; // chat list verified icon background
dialogsVerifiedIconFg: #17212b; // chat list verified icon check
dialogsSendingIconFg: #647d96; // chat list sending message icon (clock)
dialogsSentIconFg: #72bcfd; // chat list sent message tick / double tick icon
dialogsUnreadBg: #4082bc; // chat list unread badge background for not muted chat
dialogsUnreadBgMuted: #3e546a; // chat list unread badge background for muted chat
dialogsUnreadFg: #ffffff; // chat list unread badge text
dialogsBgOver: #202b36; // chat list background with mouse over
dialogsOnlineBadgeFg: #63b6ff; // chat list online status
dialogsNameFgOver: windowBoldFgOver; // chat list name text with mouse over
dialogsChatIconFgOver: dialogsNameFgOver; // chat list group or channel icon with mouse over
dialogsDateFgOver: #8495a9; // chat list date text with mouse over
dialogsTextFgOver: #91a3b5; // chat list message text with mouse over
dialogsTextFgServiceOver: #73b9f5; // chat list group sender name text with mouse over
dialogsDraftFgOver: dialogsDraftFg; // chat list draft label with mouse over
dialogsVerifiedIconBgOver: #6ab3f3; // chat list verified icon background with mouse over
dialogsVerifiedIconFgOver: dialogsVerifiedIconFg; // chat list verified icon check with mouse over
dialogsSendingIconFgOver: dialogsSendingIconFg; // chat list sending message icon (clock) with mouse over
dialogsSentIconFgOver: #72bcfd; // chat list sent message tick / double tick icon with mouse over
dialogsUnreadBgOver: #4082bc; // chat list unread badge background for not muted chat with mouse over
dialogsUnreadBgMutedOver: #4d5762; // chat list unread badge background for muted chat with mouse over
dialogsUnreadFgOver: dialogsUnreadFg; // chat list unread badge text with mouse over
dialogsBgActive: #2b5278; // chat list background for current (active) chat
dialogsNameFgActive: windowFgActive; // chat list name text for current (active) chat
dialogsChatIconFgActive: dialogsNameFgActive; // chat list group or channel icon for current (active) chat
dialogsDateFgActive: windowFgActive; // chat list date text for current (active) chat
dialogsTextFgActive: windowFgActive; // chat list message text for current (active) chat
dialogsTextFgServiceActive: dialogsTextFgActive; // chat list group sender name text for current (active) chat
dialogsDraftFgActive: #a9caf0; // chat list draft label for current (active) chat
dialogsVerifiedIconBgActive: dialogsTextFgActive; // chat list verified icon background for current (active) chat
dialogsVerifiedIconFgActive: dialogsBgActive; // chat list verified icon check for current (active) chat
dialogsSendingIconFgActive: #ffffff99; // chat list sending message icon (clock) for current (active) chat
dialogsSentIconFgActive: dialogsTextFgActive; // chat list sent message tick / double tick icon for current (active) chat
dialogsUnreadBgActive: dialogsTextFgActive; // chat list unread badge background for not muted chat for current (active) chat
dialogsUnreadBgMutedActive: #7aa3ca; // chat list unread badge background for muted chat for current (active) chat
dialogsUnreadFgActive: #2a5378; // chat list unread badge text for current (active) chat
dialogsOnlineBadgeFgActive: #ffffff; // chat list online status for current (active) chat
dialogsRippleBg: #25313d; //
dialogsRippleBgActive: #315a80; //
dialogsForwardBg: dialogsBgActive; // forwarding panel background (when forwarding messages in the smallest window size)
dialogsForwardFg: dialogsNameFgActive; // forwarding panel text (when forwarding messages in the smallest window size)
searchedBarBg: #202b38; // search results bar background (in chats list, contacts box..)
searchedBarFg: #8c98a4; // search results bar text (in chats list, contacts box..)
topBarBg: #17212b; // top bar background (in chat view, media overview..)
emojiPanBg: windowBg; // emoji panel background
emojiPanCategories: #17212b; // emoji panel categories background
emojiPanHeaderFg: #7c8d9e; // emoji panel section header text
emojiPanHeaderBg: #fffffff2; // emoji panel section header background
stickerPanDeleteBg: #000000cc; // delete X button background for custom sent stickers in stickers panel (legacy)
stickerPanDeleteFg: windowFgActive; // delete X button icon for custom sent stickers in stickers panel (legacy)
stickerPreviewBg: #000000b0; // sticker and GIF preview background (when you press and hold on a sticker)
historyTextInFg: windowFg; // inbox message text
historyTextInFgSelected: #ffffff; // inbox message selected text or text in a selected message
historyTextOutFg: #e4ecf2; // outbox message text
historyTextOutFgSelected: #ffffff; // outbox message selected text or text in a selected message
historyLinkInFg: #70baf5; // inbox message link
historyLinkInFgSelected: #aadcff; // inbox message link in a selected text or message
historyLinkOutFg: #83caff; // outbox message link
historyLinkOutFgSelected: #aadcff; // outbox message link in a selected text or message
historyFileNameInFg: historyTextInFg; // inbox media filename text
historyFileNameInFgSelected: #ffffff; // inbox media filename text in a selected message
historyFileNameOutFg: historyTextOutFg; // outbox media filename text
historyFileNameOutFgSelected: #ffffff; // outbox media filename text in a selected message
historyOutIconFg: #6bbfff; // outbox message tick / double tick icon
historyOutIconFgSelected: #ffffff; // outbox message tick / double tick icon in a selected message
historyIconFgInverted: #ffffffe5; // media message tick / double tick icon (like in sent photo)
historySendingOutIconFg: #70a4d2; // outbox sending message icon (clock)
historySendingInIconFg: #76838b; // inbox sending message icon (clock) (like in sent messages to yourself or in sent messages to a channel)
historySendingInvertedIconFg: #ffffffc8; // media sending message icon (clock) (like in sent photo)
historyCallArrowInFg: #5093d6; // received phone call arrow
historyCallArrowInFgSelected: #ffffff; // received phone call arrow in a selected message
historyCallArrowMissedInFg: callArrowMissedFg; // missed phone call arrow
historyCallArrowMissedInFgSelected: #ffffff; // missed phone call arrow in a selected message
historyCallArrowOutFg: #ffffff; // outgoing phone call arrow
historyCallArrowOutFgSelected: #ffffff; // outgoing phone call arrow
historyUnreadBarBg: #182433; // new unread messages bar background
historyUnreadBarBorder: #03080d00; // new unread messages bar shadow
historyUnreadBarFg: #ffffff; // new unread messages bar text
historyForwardChooseBg: #0000004c; // forwarding messages in a large window size "choose recipient" background
historyForwardChooseFg: windowFgActive; // forwarding messages in a large window size "choose recipient" text
historyPeer1NameFg: #fb6169; // red group member name
historyPeer1NameFgSelected: #ffffff; // red group member name in a selected message
historyPeer1UserpicBg: #ff845e; // red userpic background
historyPeer2NameFg: #85de85; // green group member name
historyPeer2NameFgSelected: #ffffff; // green group member name in a selected message
historyPeer2UserpicBg: #9ad164; // green userpic background
historyPeer3NameFg: #f3bc5c; // yellow group member name
historyPeer3NameFgSelected: #ffffff; // yellow group member name in a selected message
historyPeer3UserpicBg: #e5ca77; // yellow userpic background (actually unused)
historyPeer4NameFg: #65bdf3; // blue group member name
historyPeer4NameFgSelected: #ffffff; // blue group member name in a selected message
historyPeer4UserpicBg: #5caffa; // blue userpic background
historyPeer5NameFg: #b48bf2; // purple group member name
historyPeer5NameFgSelected: #ffffff; // purple group member name in a selected message
historyPeer5UserpicBg: #b694f9; // purple userpic background
historyPeer6NameFg: #ff5694; // pink group member name
historyPeer6NameFgSelected: #ffffff; // pink group member name in a selected message
historyPeer6UserpicBg: #ff8aac; // pink userpic background
historyPeer7NameFg: #62d4e3; // sea group member name
historyPeer7NameFgSelected: #ffffff; // sea group member name in a selected message
historyPeer7UserpicBg: #5bcbe3; // sea userpic background
historyPeer8NameFg: #faa357; // orange group member name
historyPeer8NameFgSelected: #ffffff; // orange group member name in a selected message
historyPeer8UserpicBg: #febb5b; // orange userpic background
historyPeerUserpicFg: windowFgActive; // default userpic initials
historyPeer1UserpicBg2: #d45246; // the second red userpic background
historyPeer2UserpicBg2: #46ba43; // the second green userpic background
historyPeer3UserpicBg2: #e5ca77; // the second yellow userpic background (actually unused)
historyPeer4UserpicBg2: #408acf; // the second blue userpic background
historyPeer5UserpicBg2: #6c61df; // the second purple userpic background
historyPeer6UserpicBg2: #d95574; // the second pink userpic background
historyPeer7UserpicBg2: #359ad4; // the second sea userpic background
historyPeer8UserpicBg2: #f68136; // the second orange userpic background
historyPeerSavedMessagesBg2: historyPeer4UserpicBg2; // the second saved messages userpic background
historyScrollBarBg: #7f84897a; // scroll bar current rectangle, the bar itself in the chat view (adjusted)
historyScrollBarBgOver: #64686cbc; // scroll bar current rectangle with mouse over it in the chat view (adjusted)
historyScrollBg: #565a5e4c; // scroll bar background (adjusted)
historyScrollBgOver: #5a5d616b; // scroll bar background with mouse over the scroll bar (adjusted)
msgInBg: #182533; // inbox message background
msgInBgSelected: #2e70a5; // inbox selected message background (and background of selected text in those messages)
msgOutBg: #2b5278; // outbox message background
msgOutBgSelected: #2e70a5; // outbox selected message background (and background of selected text in those messages)
msgSelectOverlay: #3585d44c; // overlay which is filling the media parts of selected messages (like in selected photo message)
msgStickerOverlay: #3585d47f; // overlay which is filling the selected sticker message
msgInServiceFg: #71bafa; // inbox message information text (like information about a forwarded message original sender)
msgInServiceFgSelected: #ffffff; // inbox selected message information text (like information about a forwarded message original sender)
msgOutServiceFg: #90caff; // outbox message information text (like information about a forwarded message original sender)
msgOutServiceFgSelected: #ffffff; // outbox message information text (like information about a forwarded message original sender)
msgInShadow: #748ea200; // inbox message shadow (below the bubble)
msgInShadowSelected: #538ebb00; // inbox selected message shadow (below the bubble)
msgOutShadow: #00000000; // outbox message shadow (below the bubble)
msgOutShadowSelected: #366ea600; // outbox selected message shadow (below the bubble)
msgInDateFg: #6d7f8f; // inbox message time text
msgInDateFgSelected: #ffffff; // inbox selected message time text
msgOutDateFg: #7da8d3; // outbox message time text
msgOutDateFgSelected: #ffffff; // outbox selected message time text
msgServiceFg: windowFgActive; // service message text (like date dividers or service message about the group title being changed)
msgServiceBg: #213040d5; // service message background (like in a service message about group title being changed) (adjusted)
msgServiceBgSelected: #2e7ab4; // service message selected text background (like in a service message about group title being changed) (adjusted)
msgInReplyBarColor: #429bdb; // inbox message reply outline
msgInReplyBarSelColor: #ffffff; // inbox selected message reply outline
msgOutReplyBarColor: #65b9f4; // outbox message reply outline
msgOutReplyBarSelColor: #ffffff; // outbox selected message reply outline
msgImgReplyBarColor: msgServiceFg; // sticker message reply outline
msgInMonoFg: #5a8cb7; // inbox message monospace text (like a message sent with `test` text)
msgOutMonoFg: #aed1f3; // outbox message monospace text
msgInMonoFgSelected: #a3cdf7; // inbox message monospace text in a selected text or message
msgOutMonoFgSelected: #a3cdf7; // outbox message monospace text in a selected text or message
msgDateImgFg: #fffffff2; // media message time text (like time text in a sent photo)
msgDateImgBg: #00000054; // media message time bubble background (like time bubble in a sent photo) or file with thumbnail download icon circle background
msgDateImgBgOver: #00000074; // media message download icon circle background with mouse over (like file with thumbnail download icon)
msgDateImgBgSelected: #204f7887; // selected media message time bubble background
msgFileThumbLinkInFg: lightButtonFg; // inbox media file message with thumbnail download / open with button text
msgFileThumbLinkInFgSelected: #ffffff; // inbox selected media file message with thumbnail download / open with button text
msgFileThumbLinkOutFg: #6c9ecf; // outbox media file message with thumbnail download / open with button text
msgFileThumbLinkOutFgSelected: #ffffff; // outbox selected media file message with thumbnail download / open with button text
msgFileInBg: #3f96d0; // inbox audio file download circle background
msgFileInBgOver: #489ed7; // inbox audio file download circle background with mouse over
msgFileInBgSelected: #6ab4f4; // inbox selected audio file download circle background
msgFileOutBg: #4c9ce2; // outbox audio file download circle background
msgFileOutBgOver: #54a4e9; // outbox audio file download circle background with mouse over
msgFileOutBgSelected: #58abf3; // outbox selected audio file download circle background
msgFile1Bg: #3e7eba; // blue shared links / files without image square thumbnail
msgFile1BgDark: #24679e; // blue shared files without image download circle background
msgFile1BgOver: #1d5e93; // blue shared files without image download circle background with mouse over
msgFile1BgSelected: #ffffff; // blue shared files without image download circle background if file is selected
msgFile2Bg: #3ea34a; // green shared links / shared files without image square thumbnail
msgFile2BgDark: #298835; // green shared files without image download circle background
msgFile2BgOver: #1b7725; // green shared files without image download circle background with mouse over
msgFile2BgSelected: #1b7725; // green shared files without image download circle background if file is selected
msgFile3Bg: #d6454c; // red shared links / shared files without image square thumbnail
msgFile3BgDark: #bf333a; // red shared files without image download circle background
msgFile3BgOver: #b2282f; // red shared files without image download circle background with mouse over
msgFile3BgSelected: #b2282f; // red shared files without image download circle background if file is selected
msgFile4Bg: #d99546; // yellow shared links / shared files without image square thumbnail
msgFile4BgDark: #c17d39; // yellow shared files without image download circle background
msgFile4BgOver: #ac6b29; // yellow shared files without image download circle background with mouse over
msgFile4BgSelected: #ac6b29; // yellow shared files without image download circle background if file is selected
historyFileInIconFg: #ffffff; // inbox file without thumbnail (like audio file) download arrow icon
historyFileInIconFgSelected: #ffffff; // inbox selected file without thumbnail (like audio file) download arrow icon
historyFileInRadialFg: #ffffff; // inbox file without thumbnail (like audio file) radial download animation line
historyFileInRadialFgSelected: historyFileInIconFgSelected; // inbox selected file without thumbnail (like audio file) radial download animation line
historyFileOutIconFg: #ffffff; // outbox file without thumbnail (like audio file) download arrow icon
historyFileOutIconFgSelected: #ffffff; // outbox selected file without thumbnail (like audio file) download arrow icon
historyFileOutRadialFg: #ffffff; // outbox file without thumbnail (like audio file) radial download animation line
historyFileOutRadialFgSelected: #ffffff; // outbox selected file without thumbnail (like audio file) radial download animation line
historyFileThumbIconFg: #efefef; // file with thumbnail (or photo / video) download arrow icon
historyFileThumbIconFgSelected: #ffffff; // selected file with thumbnail (or photo / video) download arrow icon
historyFileThumbRadialFg: historyFileThumbIconFg; // file with thumbnail (or photo / video) radial download animation line
historyFileThumbRadialFgSelected: #ffffff; // selected file with thumbnail (or photo / video) radial download animation line
historyVideoMessageProgressFg: historyFileThumbIconFg; // radial playback progress in round video messages
msgWaveformInActive: #549cd7; // inbox voice message active waveform lines (like played part of currently playing voice message)
msgWaveformInActiveSelected: #ffffff; // inbox selected voice message active waveform lines (like played part of currently playing voice message)
msgWaveformInInactive: #3a4d61; // inbox voice message inactive waveform lines (like upcoming part of currently playing voice message)
msgWaveformInInactiveSelected: #6fa5d4; // inbox selected voice message inactive waveform lines (like upcoming part of currently playing voice message)
msgWaveformOutActive: #62b2fd; // outbox voice message active waveform lines (like played part of currently playing voice message)
msgWaveformOutActiveSelected: #ffffff; // outbox selected voice message active waveform lines (like played part of currently playing voice message)
msgWaveformOutInactive: #4b7fb3; // outbox voice message inactive waveform lines (like upcoming part of currently playing voice message)
msgWaveformOutInactiveSelected: #6fa5d4; // outbox selected voice message inactive waveform lines (like upcoming part of currently playing voice message)
msgBotKbOverBgAdd: #80b1db0f; // this is painted over a bot inline keyboard button (which has msgServiceBg background) when mouse is over that button
msgBotKbIconFg: msgServiceFg; // bot inline keyboard button icon in the top-right corner (like in @vote bot when a poll is ready to be shared)
msgBotKbRippleBg: #92c0e50b; // bot inline keyboard button ripple effect
mediaInFg: msgInDateFg; // inbox media message status text (like in file that is being downloaded)
mediaInFgSelected: msgInDateFgSelected; // inbox selected media message status text (like in file that is being downloaded)
mediaOutFg: msgOutDateFg; // outbox media message status text (like in file that is being downloaded)
mediaOutFgSelected: msgOutDateFgSelected; // outbox selected media message status text (like in file that is being downloaded)
youtubePlayIconBg: #e83131c8; // youtube play icon background (when a link to a youtube video with a webpage preview is sent)
youtubePlayIconFg: windowFgActive; // youtube play icon arrow (when a link to a youtube video with a webpage preview is sent)
videoPlayIconBg: #0000007f; // other video play icon background (like when a link to a vimeo video with a webpage preview is sent)
videoPlayIconFg: #ffffff; // other video play icon arrow (like when a link to a vimeo video with a webpage preview is sent)
toastBg: #000000b2; // toast notification background (like when you click on your t.me link when editing your username)
toastFg: windowFgActive; // toast notification text (like when you click on your t.me link when editing your username)
reportSpamBg: #363c42; // report spam panel background (like a non contact user writes your for the first time)
reportSpamFg: windowFg; // report spam panel text (when you send a report from that panel)
historyToDownBg: #1d2b3a; // arrow button background (to scroll to the end of the viewed chat)
historyToDownBgOver: #243446; // arrow button background with mouse over
historyToDownBgRipple: #2b3c4f; // arrow button ripple effect
historyToDownFg: #adb4ba; // arrow button icon
historyToDownFgOver: menuIconFgOver; // arrow button icon with mouse over
historyToDownShadow: #00000040; // arrow button shadow
historyComposeAreaBg: #17212b; // history compose area background (message write area / reply information / forwarding information)
historyComposeAreaFg: historyTextInFg; // history compose area text
historyComposeAreaFgService: msgInDateFg; // history compose area text when replying to a media message
historyComposeIconFg: menuIconFg; // history compose area icon (like emoji, attach, bot command..)
historyComposeIconFgOver: menuIconFgOver; // history compose area icon with mouse over
historySendIconFg: windowBgActive; // send message icon
historySendIconFgOver: windowBgActive; // send message icon with mouse over
historyPinnedBg: #1b2734; // pinned message area background
historyReplyBg: historyComposeAreaBg; // reply / forward / edit message area background
historyReplyIconFg: windowBgActive; // reply / forward / edit message left icon
historyReplyCancelFg: cancelIconFg; // reply / forward / edit message cancel button
historyReplyCancelFgOver: cancelIconFgOver; // reply / forward / edit message cancel button with mouse over
historyComposeButtonBg: historyComposeAreaBg; // unblock / join channel / mute channel button background
historyComposeButtonBgOver: #1c2835; // unblock / join channel / mute channel button background with mouse over
historyComposeButtonBgRipple: #222f3e; // unblock / join channel / mute channel button ripple effect
overviewCheckBg: #00000040; // shared files / links checkbox background for not selected rows when some rows are selected
overviewCheckFg: #ffffff; // shared files / links checkbox icon for not selected rows when some rows are selected
overviewCheckFgActive: #ffffff; // shared files / links checkbox icon for selected rows
overviewPhotoSelectOverlay: #3fa2e333; // shared photos / videos / links fill for selected rows
profileStatusFgOver: #677a8b; // group members list in group profile user last seen text with mouse over
profileVerifiedCheckBg: windowBgActive; // profile verified check icon background
profileVerifiedCheckFg: #ffffff; // profile verified check icon tick
profileAdminStartFg: #62a9e6; // group members list admin star icon
notificationsBoxMonitorFg: windowFg; // custom notifications settings box monitor color
notificationsBoxScreenBg: dialogsBgActive; // #6389a8; // custom notifications settings box monitor screen background
notificationSampleUserpicFg: windowBgActive; // custom notifications settings box small sample userpic placeholder
notificationSampleCloseFg: #d7d7d7; // custom notifications settings box small sample close button placeholder
notificationSampleTextFg: #d7d7d7; // custom notifications settings box small sample text placeholder
notificationSampleNameFg: #939393; // custom notifications settings box small sample name placeholder
changePhoneSimcardFrom: notificationSampleTextFg; // change phone number box left simcard icon
changePhoneSimcardTo: notificationSampleNameFg; // change phone number box right simcard and plane icons
mainMenuBg: windowBg; // main menu background
mainMenuCoverBg: #276899; // main menu top cover background
mainMenuCoverFg: windowFgActive; // main menu top cover text
mainMenuCloudFg: activeButtonFg; //
mainMenuCloudBg: #185680; //
mediaPlayerBg: windowBg; // audio file player background
mediaPlayerActiveFg: windowBgActive; // audio file player playback progress already played part
mediaPlayerInactiveFg: sliderBgInactive; // audio file player playback progress upcoming (not played yet) part with mouse over
mediaPlayerDisabledFg: #9dd1ef; // audio file player loading progress (when you're playing an audio file and switch to the previous one which is not loaded yet)
mediaviewFileBg: windowBg; // file rectangle background (when you view a png file in Media Viewer and go to a previous, not loaded yet, file)
mediaviewFileNameFg: windowFg; // file name in file rectangle
mediaviewFileSizeFg: windowSubTextFg; // file size text in file rectangle
mediaviewFileRedCornerFg: #d55959; // red file thumbnail placeholder corner in file rectangle (for a file without thumbnail, like .pdf)
mediaviewFileYellowCornerFg: #e8a659; // yellow file thumbnail placeholder corner in file rectangle (for a file without thumbnail, like .zip)
mediaviewFileGreenCornerFg: #49a957; // green file thumbnail placeholder corner in file rectangle (for a file without thumbnail, like .exe)
mediaviewFileBlueCornerFg: #599dcf; // blue file thumbnail placeholder corner in file rectangle (for a file without thumbnail, like .dmg)
mediaviewFileExtFg: activeButtonFg; // file extension text in file thumbnail placeholder in file rectangle
mediaviewMenuBg: #383838; // context menu in Media Viewer background
mediaviewMenuBgOver: #505050; // context menu item background with mouse over
mediaviewMenuBgRipple: #676767; // context menu item ripple effect
mediaviewMenuFg: windowFgActive; // context menu item text
mediaviewBg: #222222eb; // Media Viewer background
mediaviewVideoBg: imageBg; // Media Viewer background when viewing a video in full screen
mediaviewControlBg: #0000003c; // controls background (like next photo / previous photo)
mediaviewControlFg: windowFgActive; // controls icon (like next photo / previous photo)
mediaviewCaptionBg: #11111180; // caption text background (when viewing photo with caption)
mediaviewCaptionFg: mediaviewControlFg; // caption text
mediaviewTextLinkFg: #70baf5; // caption text link
mediaviewSaveMsgBg: toastBg; // save to file toast message background in Media Viewer
mediaviewSaveMsgFg: toastFg; // save to file toast message text
mediaviewPlaybackActive: #c7c7c7; // video playback progress already played part
mediaviewPlaybackInactive: #252525; // video playback progress upcoming (not played yet) part
mediaviewPlaybackActiveOver: #ffffff; // video playback progress already played part with mouse over
mediaviewPlaybackInactiveOver: #474747; // video playback progress upcoming (not played yet) part with mouse over
mediaviewPlaybackProgressFg: #ffffffc7; // video playback progress text
mediaviewPlaybackIconFg: mediaviewPlaybackActive; // video playback controls icon
mediaviewPlaybackIconFgOver: mediaviewPlaybackActiveOver; // video playback controls icon with mouse over
mediaviewTransparentBg: #ffffff; // transparent filling part (when viewing a transparent .png file in Media Viewer)
mediaviewTransparentFg: #cccccc; // another transparent filling part
notificationBg: windowBg; // custom notification window background
callBg: #14191ff5; // phone call popup background
callNameFg: #ffffff; // phone call popup name text
callFingerprintBg: #00000066; // phone call popup emoji fingerprint background
callStatusFg: #aaabac; // phone call popup status text
callIconFg: #ffffff; // phone call popup answer, hangup and mute mic icon
callAnswerBg: #488fc9; // phone call popup answer button background
callAnswerRipple: #4286c2; // phone call popup answer button ripple effect
callAnswerBgOuter: #3f95eb26; // phone call popup answer button outer ripple effect
callHangupBg: #cc4646; // phone call popup hangup button background
callHangupRipple: #ca4141; // phone call popup hangup button ripple effect
callCancelBg: #ffffff; // phone call popup line busy cancel button background
callCancelFg: #536271; // phone call popup line busy cancel button icon
callCancelRipple: #435363; // phone call popup line busy cancel button ripple effect
callMuteRipple: #ffffff12; // phone call popup mute mic ripple effect
callBarBg: #366693; // active phone call bar background
callBarMuteRipple: #4b7dab; // active phone call bar mute and hangup button ripple effect
callBarBgMuted: #35495d; // phone call bar with muted mic background
callBarUnmuteRipple: #435b73; // phone call bar with muted mic mute and hangup button ripple effect
callBarFg: dialogsNameFgActive; // phone call bar text and icons
importantTooltipBg: toastBg; //
importantTooltipFg: toastFg; //
importantTooltipFgLink: #65b6fc; //
filterInputActiveBg: #242f3d; // default rounded input field active background (like in chats list search field when field is focused)
botKbBg: #242f3d; // bot keyboard button background
botKbDownBg: #2d3a49; // bot keyboard button ripple effect
emojiIconFg: #6c7883; // emoji category icon
emojiIconFgActive: #51a0e5; // active emoji category icon
overviewCheckBorder: #e4eaef; // shared media round checkbox border
sideBarBg: #0e1621; // filters side bar background
sideBarBgActive: #25303e; // filters side bar active background
sideBarBgRipple: #1e2733; // filters side bar ripple effect
sideBarTextFg: #768c9e; // filters side bar text
sideBarTextFgActive: #64b9fa; // filters side bar active item text
sideBarIconFg: #768c9e; // filters side bar icon
sideBarIconFgActive: #5eb5f7; // filters side bar active item icon
sideBarBadgeBg: #5eb5f7; // filters side bar badge background
sideBarBadgeBgMuted: #768c9e; // filters side bar unimportant badge background
statisticsChartInactive: #313d4cc8; // inactive area in footer of statistic charts
statisticsChartActive: #526679d8; // sides in footer of statistic charts
+710
View File
@@ -0,0 +1,710 @@
{
"$schema": "vscode://schemas/color-theme",
"name": "2026 Dark",
"include": "./dark_modern.json",
"type": "dark",
"colors": {
"foreground": "#bfbfbf",
"disabledForeground": "#555555",
"errorForeground": "#f48771",
"descriptionForeground": "#8C8C8C",
"icon.foreground": "#8C8C8C",
"focusBorder": "#3994BCB3",
"textBlockQuote.background": "#242526",
"textBlockQuote.border": "#2A2B2C",
"textCodeBlock.background": "#242526",
"textLink.foreground": "#48A0C7",
"textLink.activeForeground": "#53A5CA",
"textPreformat.background": "#262626",
"textPreformat.foreground": "#8C8C8C",
"textSeparator.foreground": "#2a2a2a",
"button.background": "#297AA0",
"button.foreground": "#FFFFFF",
"button.hoverBackground": "#2B7DA3",
"button.border": "#297AA0",
"button.secondaryHoverBackground": "#FFFFFF10",
"button.secondaryBorder": "#333536",
"checkbox.background": "#242526",
"checkbox.border": "#707070",
"checkbox.foreground": "#8C8C8C",
"dropdown.background": "#191A1B",
"dropdown.border": "#333536",
"dropdown.foreground": "#bfbfbf",
"dropdown.listBackground": "#191A1B",
"input.background": "#191A1B",
"input.border": "#333536",
"input.foreground": "#bfbfbf",
"input.placeholderForeground": "#555555",
"inputOption.activeBackground": "#313233",
"inputOption.activeForeground": "#bfbfbf",
"inputOption.activeBorder": "#2A2B2C",
"inputValidation.infoBackground": "#1E3A47",
"inputValidation.infoBorder": "#3994BC",
"inputValidation.infoForeground": "#bfbfbf",
"inputValidation.warningBackground": "#352A05",
"inputValidation.warningBorder": "#B89500",
"inputValidation.warningForeground": "#bfbfbf",
"inputValidation.errorBackground": "#3A1D1D",
"inputValidation.errorBorder": "#BE1100",
"inputValidation.errorForeground": "#bfbfbf",
"scrollbar.shadow": "#191B1D4D",
"scrollbarSlider.background": "#A8A9AA85",
"scrollbarSlider.hoverBackground": "#A8A9AA90",
"scrollbarSlider.activeBackground": "#A8A9AA9C",
"badge.background": "#307E9F",
"badge.foreground": "#FFFFFF",
"progressBar.background": "#878889",
"list.activeSelectionBackground": "#FFFFFF22",
"list.activeSelectionForeground": "#ededed",
"list.inactiveSelectionBackground": "#2C2D2E",
"list.inactiveSelectionForeground": "#ededed",
"list.hoverBackground": "#FFFFFF14",
"list.hoverForeground": "#bfbfbf",
"list.dropBackground": "#3994BC1A",
"toolbar.activeBackground": "#FFFFFF33",
"list.focusBackground": "#FFFFFF22",
"list.focusForeground": "#bfbfbf",
"list.focusOutline": "#3994BCB3",
"list.highlightForeground": "#48A0C7",
"list.invalidItemForeground": "#444444",
"list.errorForeground": "#f48771",
"list.warningForeground": "#e5ba7d",
"activityBar.background": "#191A1B",
"activityBar.foreground": "#bfbfbf",
"activityBar.inactiveForeground": "#8C8C8C",
"activityBar.activeBackground": "#313233",
"activityBar.border": "#2A2B2C",
"activityBar.activeBorder": "#bfbfbf",
"activityBar.activeFocusBorder": "#3994BCB3",
"activityBarBadge.background": "#307E9F",
"activityBarBadge.foreground": "#FFFFFF",
"activityBarTop.activeBorder": "#bfbfbf",
"sideBar.background": "#191A1B",
"sideBar.foreground": "#bfbfbf",
"sideBar.border": "#2A2B2C",
"sideBarTitle.foreground": "#bfbfbf",
"sideBarSectionHeader.background": "#191A1B",
"sideBarSectionHeader.foreground": "#bfbfbf",
"sideBarSectionHeader.border": "#2A2B2C",
"titleBar.activeBackground": "#191A1B",
"titleBar.activeForeground": "#8C8C8C",
"titleBar.inactiveBackground": "#121314",
"titleBar.inactiveForeground": "#8C8C8C",
"titleBar.border": "#2A2B2C",
"menubar.selectionBackground": "#242526",
"menubar.selectionForeground": "#bfbfbf",
"menu.background": "#202122",
"menu.foreground": "#bfbfbf",
"menu.selectionBackground": "#3994BC26",
"menu.selectionForeground": "#bfbfbf",
"menu.selectionBorder": "#3994BC",
"menu.separatorBackground": "#2A2B2C",
"menu.border": "#2A2B2C",
"commandCenter.foreground": "#bfbfbf",
"commandCenter.activeForeground": "#bfbfbf",
"commandCenter.background": "#191A1B",
"commandCenter.activeBackground": "#FFFFFF0F",
"commandCenter.border": "#2E3031",
"editor.background": "#121314",
"editor.foreground": "#BBBEBF",
"editorStickyScroll.background": "#121314",
"editorStickyScrollHover.background": "#202122",
"editorStickyScroll.border": "#2A2B2C",
"editorLineNumber.foreground": "#858889",
"editorLineNumber.activeForeground": "#BBBEBF",
"editorCursor.foreground": "#BBBEBF",
"editor.selectionBackground": "#276782dd",
"editor.inactiveSelectionBackground": "#27678260",
"editor.selectionHighlightBackground": "#27678260",
"editor.wordHighlightBackground": "#27678250",
"editor.wordHighlightStrongBackground": "#27678280",
"editor.findMatchBackground": "#27678290",
"editor.findMatchHighlightBackground": "#27678280",
"editor.findRangeHighlightBackground": "#FFFFFF13",
"editor.hoverHighlightBackground": "#FFFFFF13",
"editor.lineHighlightBackground": "#242526",
"editor.rangeHighlightBackground": "#FFFFFF13",
"editorLink.activeForeground": "#3a94bc",
"editorWhitespace.foreground": "#8C8C8C4D",
"editorIndentGuide.background1": "#8384854D",
"editorIndentGuide.activeBackground1": "#838485",
"editorRuler.foreground": "#848484",
"editorCodeLens.foreground": "#8C8C8C",
"editorBracketMatch.background": "#3994BC55",
"editorBracketMatch.border": "#2A2B2C",
"editorWidget.background": "#202122",
"editorWidget.border": "#2A2B2C",
"editorWidget.foreground": "#bfbfbf",
"editorSuggestWidget.background": "#202122",
"editorSuggestWidget.border": "#2A2B2C",
"editorSuggestWidget.foreground": "#bfbfbf",
"editorSuggestWidget.highlightForeground": "#bfbfbf",
"editorSuggestWidget.selectedBackground": "#FFFFFF26",
"editorSuggestWidget.focusOutline": "#3994BCB3",
"editorHoverWidget.background": "#202122",
"editorHoverWidget.border": "#2A2B2C",
"widget.border": "#2A2B2C",
"peekView.border": "#2A2B2C",
"peekViewEditor.background": "#191A1B",
"peekViewEditor.matchHighlightBackground": "#3994BC33",
"peekViewResult.background": "#191A1B",
"peekViewResult.fileForeground": "#bfbfbf",
"peekViewResult.lineForeground": "#8C8C8C",
"peekViewResult.matchHighlightBackground": "#3994BC33",
"peekViewResult.selectionBackground": "#3994BC26",
"peekViewResult.selectionForeground": "#bfbfbf",
"peekViewTitle.background": "#242526",
"peekViewTitleDescription.foreground": "#8C8C8C",
"peekViewTitleLabel.foreground": "#bfbfbf",
"editorGutter.background": "#121314",
"editorGutter.addedBackground": "#72C892",
"editorGutter.deletedBackground": "#F28772",
"diffEditor.insertedLineBackground": "#347d3926",
"diffEditor.insertedTextBackground": "#57ab5a4d",
"diffEditor.removedLineBackground": "#c93c3726",
"diffEditor.removedTextBackground": "#f470674d",
"editorOverviewRuler.border": "#2A2B2C",
"editorOverviewRuler.findMatchForeground": "#3a94bc99",
"editorOverviewRuler.modifiedForeground": "#6ab890",
"editorOverviewRuler.addedForeground": "#73c991",
"editorOverviewRuler.deletedForeground": "#f48771",
"editorOverviewRuler.errorForeground": "#f48771",
"editorOverviewRuler.warningForeground": "#e5ba7d",
"panel.background": "#191A1B",
"panel.border": "#2A2B2C",
"panelSection.border": "#2A2B2C",
"panelSectionHeader.border": "#2A2B2C",
"panelTitle.activeBorder": "#3994BC",
"panelTitle.activeForeground": "#bfbfbf",
"panelTitle.inactiveForeground": "#8C8C8C",
"statusBar.background": "#191A1B",
"statusBar.inactiveBackground": "#121314",
"statusBar.foreground": "#8C8C8C",
"statusBar.border": "#2A2B2C",
"statusBar.focusBorder": "#3994BCB3",
"statusBar.debuggingBackground": "#3994BC",
"statusBar.debuggingForeground": "#FFFFFF",
"statusBar.noFolderBackground": "#191A1B",
"statusBar.noFolderForeground": "#8C8C8C",
"statusBarItem.activeBackground": "#4B4C4D",
"statusBarItem.hoverBackground": "#323233",
"statusBarItem.focusBorder": "#3994BCB3",
"statusBarItem.prominentBackground": "#3994BC",
"statusBarItem.prominentForeground": "#FFFFFF",
"statusBarItem.prominentHoverBackground": "#3994BC",
"tab.activeBackground": "#121314",
"tab.activeForeground": "#bfbfbf",
"tab.inactiveBackground": "#191A1B",
"tab.inactiveForeground": "#8C8C8C",
"tab.border": "#2A2B2C",
"tab.lastPinnedBorder": "#2A2B2C",
"tab.activeBorderTop": "#3994BC",
"tab.hoverBackground": "#121314",
"tab.hoverForeground": "#bfbfbf",
"tab.unfocusedActiveBackground": "#121314",
"tab.unfocusedActiveForeground": "#8C8C8C",
"tab.unfocusedInactiveBackground": "#191A1B",
"tab.unfocusedInactiveForeground": "#444444",
"editorGroupHeader.tabsBackground": "#191A1B",
"tab.activeBorder": "#121314",
"editorGroupHeader.tabsBorder": "#2A2B2C",
"breadcrumb.foreground": "#8C8C8C",
"breadcrumb.background": "#121314",
"breadcrumb.focusForeground": "#bfbfbf",
"breadcrumb.activeSelectionForeground": "#bfbfbf",
"breadcrumbPicker.background": "#202122",
"notificationCenter.border": "#2A2B2C",
"notificationCenterHeader.foreground": "#bfbfbf",
"notificationCenterHeader.background": "#242526",
"notificationToast.border": "#2A2B2C",
"notifications.foreground": "#bfbfbf",
"notifications.background": "#202122",
"notifications.border": "#2A2B2C",
"notificationLink.foreground": "#3a94bc",
"notificationsWarningIcon.foreground": "#CCA700",
"notificationsErrorIcon.foreground": "#f48771",
"notificationsInfoIcon.foreground": "#3a94bc",
"activityWarningBadge.foreground": "#202020",
"activityWarningBadge.background": "#CCA700",
"activityErrorBadge.foreground": "#FFFFFF",
"activityErrorBadge.background": "#f48771",
"extensionButton.prominentBackground": "#297AA0",
"extensionButton.prominentForeground": "#FFFFFF",
"extensionButton.prominentHoverBackground": "#2B7DA3",
"pickerGroup.border": "#2A2B2C",
"pickerGroup.foreground": "#bfbfbf",
"quickInput.background": "#202122",
"quickInput.foreground": "#bfbfbf",
"quickInputList.focusBackground": "#297AA0",
"quickInputList.focusForeground": "#FFFFFF",
"quickInputList.focusIconForeground": "#FFFFFF",
"quickInputList.focusHighlightForeground": "#FFFFFF",
"terminal.selectionBackground": "#3994BC33",
"terminal.background": "#191A1B",
"terminal.border": "#2A2B2C",
"terminal.tab.activeBorder": "#3994BC00",
"terminalCursor.foreground": "#bfbfbf",
"terminalCursor.background": "#191A1B",
"gitDecoration.addedResourceForeground": "#73c991",
"gitDecoration.modifiedResourceForeground": "#e5ba7d",
"gitDecoration.deletedResourceForeground": "#f48771",
"gitDecoration.untrackedResourceForeground": "#73c991",
"gitDecoration.ignoredResourceForeground": "#8C8C8C",
"gitDecoration.conflictingResourceForeground": "#f48771",
"gitDecoration.stageModifiedResourceForeground": "#e5ba7d",
"gitDecoration.stageDeletedResourceForeground": "#f48771",
"quickInputTitle.background": "#202122",
"commandCenter.activeBorder": "#333536",
"chat.requestBubbleBackground": "#ffffff13",
"chat.requestBubbleHoverBackground": "#ffffff22",
"chat.inputWorkingBorderColor1": "#297AA0",
"editorCommentsWidget.rangeBackground": "#488FAE26",
"editorCommentsWidget.rangeActiveBackground": "#488FAE46",
"charts.foreground": "#CCCCCC",
"charts.lines": "#C8CACC80",
"charts.blue": "#57A3F8",
"charts.red": "#EF8773",
"charts.yellow": "#E0B97F",
"charts.orange": "#CD861A",
"charts.green": "#86CF86",
"charts.purple": "#AD80D7",
"inlineChat.border": "#00000000",
"minimapSlider.background": "#A8A9AA85",
"minimapSlider.hoverBackground": "#A8A9AA90",
"minimapSlider.activeBackground": "#A8A9AA9C",
"agents.background": "#121314",
"agentsPanel.background": "#191A1B",
"agentsPanel.foreground": "#bfbfbf",
"agentsPanel.border": "#2A2B2C",
"surface.background": "#191A1B",
"surface.foreground": "#bfbfbf",
"surface.border": "#2A2B2C",
"agentsGradient.tintColor": "#297AA0",
"agentsChatInput.background": "#202122",
"agentsChatInput.foreground": "#bfbfbf",
"agentsChatInput.border": "#333536",
"agentsChatInput.focusBorder": "#3994BCB3",
"agentsChatInput.placeholderForeground": "#555555",
"agentsNewSessionButton.background": "#00000000",
"agentsNewSessionButton.foreground": "#bfbfbf",
"agentsNewSessionButton.border": "#333536",
"agentsNewSessionButton.hoverBackground": "#FFFFFF18",
"agentsBadge.background": "#307E9F",
"agentsBadge.foreground": "#FFFFFF",
"agentsUnreadBadge.background": "#307E9F",
"agentsUnreadBadge.foreground": "#FFFFFF",
"agentsBottomPanel.border": "#00000000"
},
"tokenColors": [
{
"scope": [
"comment",
"punctuation.definition.comment",
"string.comment"
],
"settings": {
"foreground": "#8b949e"
}
},
{
"scope": [
"constant.other.placeholder",
"constant.character"
],
"settings": {
"foreground": "#ff7b72"
}
},
{
"scope": [
"constant",
"entity.name.constant",
"variable.other.constant",
"variable.other.enummember",
"variable.language",
"entity"
],
"settings": {
"foreground": "#79c0ff"
}
},
{
"scope": [
"entity.name",
"meta.export.default",
"meta.definition.variable"
],
"settings": {
"foreground": "#ffa657"
}
},
{
"scope": [
"variable.parameter.function",
"meta.jsx.children",
"meta.block",
"meta.tag.attributes",
"entity.name.constant",
"meta.object.member",
"meta.embedded.expression"
],
"settings": {
"foreground": "#c9d1d9"
}
},
{
"scope": "entity.name.function",
"settings": {
"foreground": "#d2a8ff"
}
},
{
"scope": [
"entity.name.tag",
"support.class.component"
],
"settings": {
"foreground": "#7ee787"
}
},
{
"scope": "keyword",
"settings": {
"foreground": "#ff7b72"
}
},
{
"scope": [
"storage",
"storage.type"
],
"settings": {
"foreground": "#ff7b72"
}
},
{
"scope": [
"storage.modifier.package",
"storage.modifier.import",
"storage.type.java"
],
"settings": {
"foreground": "#c9d1d9"
}
},
{
"scope": [
"string",
"string punctuation.section.embedded source"
],
"settings": {
"foreground": "#a5d6ff"
}
},
{
"scope": "support",
"settings": {
"foreground": "#79c0ff"
}
},
{
"scope": "meta.property-name",
"settings": {
"foreground": "#79c0ff"
}
},
{
"scope": "variable",
"settings": {
"foreground": "#ffa657"
}
},
{
"scope": "variable.other",
"settings": {
"foreground": "#c9d1d9"
}
},
{
"scope": "invalid.broken",
"settings": {
"foreground": "#ffa198",
"fontStyle": "italic"
}
},
{
"scope": "invalid.deprecated",
"settings": {
"foreground": "#ffa198",
"fontStyle": "italic"
}
},
{
"scope": "invalid.illegal",
"settings": {
"foreground": "#ffa198",
"fontStyle": "italic"
}
},
{
"scope": "invalid.unimplemented",
"settings": {
"foreground": "#ffa198",
"fontStyle": "italic"
}
},
{
"scope": "carriage-return",
"settings": {
"foreground": "#f0f6fc",
"fontStyle": "italic underline"
}
},
{
"scope": "message.error",
"settings": {
"foreground": "#ffa198"
}
},
{
"scope": "string variable",
"settings": {
"foreground": "#79c0ff"
}
},
{
"scope": [
"source.regexp",
"string.regexp"
],
"settings": {
"foreground": "#a5d6ff"
}
},
{
"scope": [
"string.regexp.character-class",
"string.regexp constant.character.escape",
"string.regexp source.ruby.embedded",
"string.regexp string.regexp.arbitrary-repitition"
],
"settings": {
"foreground": "#a5d6ff"
}
},
{
"scope": "string.regexp constant.character.escape",
"settings": {
"foreground": "#7ee787",
"fontStyle": "bold"
}
},
{
"scope": "support.constant",
"settings": {
"foreground": "#79c0ff"
}
},
{
"scope": "support.variable",
"settings": {
"foreground": "#79c0ff"
}
},
{
"scope": "support.type.property-name.json",
"settings": {
"foreground": "#7ee787"
}
},
{
"scope": "meta.module-reference",
"settings": {
"foreground": "#79c0ff"
}
},
{
"scope": "punctuation.definition.list.begin.markdown",
"settings": {
"foreground": "#ffa657"
}
},
{
"scope": [
"markup.heading",
"markup.heading entity.name"
],
"settings": {
"foreground": "#79c0ff",
"fontStyle": "bold"
}
},
{
"scope": "markup.quote",
"settings": {
"foreground": "#7ee787"
}
},
{
"scope": "markup.italic",
"settings": {
"foreground": "#c9d1d9",
"fontStyle": "italic"
}
},
{
"scope": "markup.bold",
"settings": {
"foreground": "#c9d1d9",
"fontStyle": "bold"
}
},
{
"scope": [
"markup.underline"
],
"settings": {
"fontStyle": "underline"
}
},
{
"scope": [
"markup.strikethrough"
],
"settings": {
"fontStyle": "strikethrough"
}
},
{
"scope": "markup.inline.raw",
"settings": {
"foreground": "#79c0ff"
}
},
{
"scope": [
"markup.deleted",
"meta.diff.header.from-file",
"punctuation.definition.deleted"
],
"settings": {
"foreground": "#ffa198"
}
},
{
"scope": [
"punctuation.section.embedded"
],
"settings": {
"foreground": "#ff7b72"
}
},
{
"scope": [
"markup.inserted",
"meta.diff.header.to-file",
"punctuation.definition.inserted"
],
"settings": {
"foreground": "#7ee787"
}
},
{
"scope": [
"markup.changed",
"punctuation.definition.changed"
],
"settings": {
"foreground": "#ffa657"
}
},
{
"scope": [
"markup.ignored",
"markup.untracked"
],
"settings": {
"foreground": "#0d1117"
}
},
{
"scope": "meta.diff.range",
"settings": {
"foreground": "#d2a8ff",
"fontStyle": "bold"
}
},
{
"scope": "meta.diff.header",
"settings": {
"foreground": "#79c0ff"
}
},
{
"scope": "meta.separator",
"settings": {
"foreground": "#79c0ff",
"fontStyle": "bold"
}
},
{
"scope": "meta.output",
"settings": {
"foreground": "#79c0ff"
}
},
{
"scope": [
"brackethighlighter.tag",
"brackethighlighter.curly",
"brackethighlighter.round",
"brackethighlighter.square",
"brackethighlighter.angle",
"brackethighlighter.quote"
],
"settings": {
"foreground": "#8b949e"
}
},
{
"scope": "brackethighlighter.unmatched",
"settings": {
"foreground": "#ffa198"
}
},
{
"scope": [
"constant.other.reference.link",
"string.other.link"
],
"settings": {
"foreground": "#a5d6ff"
}
},
{
"scope": "token.info-token",
"settings": {
"foreground": "#6796E6"
}
},
{
"scope": "token.warn-token",
"settings": {
"foreground": "#CD9731"
}
},
{
"scope": "token.error-token",
"settings": {
"foreground": "#F44747"
}
},
{
"scope": "token.debug-token",
"settings": {
"foreground": "#B267E6"
}
}
],
"semanticHighlighting": true
}
+137
View File
@@ -0,0 +1,137 @@
{
"$schema": "vscode://schemas/color-theme",
"name": "Dark Modern",
"include": "./dark_plus.json",
"colors": {
"activityBar.activeBorder": "#0078D4",
"activityBar.background": "#181818",
"activityBar.border": "#2B2B2B",
"activityBar.foreground": "#D7D7D7",
"activityBar.inactiveForeground": "#868686",
"activityBarBadge.background": "#0078D4",
"activityBarBadge.foreground": "#FFFFFF",
"badge.background": "#616161",
"badge.foreground": "#F8F8F8",
"button.background": "#0078D4",
"button.border": "#ffffff1a",
"button.foreground": "#FFFFFF",
"button.hoverBackground": "#026EC1",
"button.secondaryBackground": "#00000000",
"button.secondaryForeground": "#CCCCCC",
"button.secondaryHoverBackground": "#2B2B2B",
"chat.slashCommandBackground": "#26477866",
"chat.slashCommandForeground": "#85B6FF",
"chat.editedFileForeground": "#E2C08D",
"checkbox.background": "#313131",
"checkbox.border": "#3C3C3C",
"debugToolBar.background": "#181818",
"descriptionForeground": "#9D9D9D",
"dropdown.background": "#313131",
"dropdown.border": "#3C3C3C",
"dropdown.foreground": "#CCCCCC",
"dropdown.listBackground": "#1F1F1F",
"editor.background": "#1F1F1F",
"editor.findMatchBackground": "#9E6A03",
"editor.foreground": "#CCCCCC",
"editorGroup.border": "#FFFFFF17",
"editorGroupHeader.tabsBackground": "#181818",
"editorGroupHeader.tabsBorder": "#2B2B2B",
"editorGutter.addedBackground": "#2EA043",
"editorGutter.deletedBackground": "#F85149",
"editorGutter.modifiedBackground": "#0078D4",
"editorLineNumber.activeForeground": "#CCCCCC",
"editorLineNumber.foreground": "#6E7681",
"editorOverviewRuler.border": "#010409",
"editorWidget.background": "#202020",
"errorForeground": "#F85149",
"focusBorder": "#0078D4",
"foreground": "#CCCCCC",
"icon.foreground": "#CCCCCC",
"input.background": "#313131",
"input.border": "#3C3C3C",
"input.foreground": "#CCCCCC",
"input.placeholderForeground": "#989898",
"inputOption.activeBackground": "#2489DB82",
"inputOption.activeBorder": "#2488DB",
"keybindingLabel.foreground": "#CCCCCC",
"menu.background": "#1F1F1F",
"menu.selectionBackground": "#0078d4",
"notificationCenterHeader.background": "#1F1F1F",
"notificationCenterHeader.foreground": "#CCCCCC",
"notifications.background": "#1F1F1F",
"notifications.border": "#2B2B2B",
"notifications.foreground": "#CCCCCC",
"panel.background": "#181818",
"panel.border": "#2B2B2B",
"panelInput.border": "#2B2B2B",
"panelTitle.activeBorder": "#0078D4",
"panelTitle.activeForeground": "#CCCCCC",
"panelTitle.inactiveForeground": "#9D9D9D",
"peekViewEditor.background": "#1F1F1F",
"peekViewEditor.matchHighlightBackground": "#BB800966",
"peekViewResult.background": "#1F1F1F",
"peekViewResult.matchHighlightBackground": "#BB800966",
"pickerGroup.border": "#3C3C3C",
"progressBar.background": "#0078D4",
"quickInput.background": "#222222",
"quickInput.foreground": "#CCCCCC",
"settings.dropdownBackground": "#313131",
"settings.dropdownBorder": "#3C3C3C",
"settings.headerForeground": "#FFFFFF",
"settings.modifiedItemIndicator": "#BB800966",
"sideBar.background": "#181818",
"sideBar.border": "#2B2B2B",
"sideBar.foreground": "#CCCCCC",
"sideBarSectionHeader.background": "#181818",
"sideBarSectionHeader.border": "#2B2B2B",
"sideBarSectionHeader.foreground": "#CCCCCC",
"sideBarTitle.foreground": "#CCCCCC",
"statusBar.background": "#181818",
"statusBar.inactiveBackground": "#1F1F1F",
"statusBar.border": "#2B2B2B",
"statusBarItem.hoverBackground": "#F1F1F133",
"statusBarItem.hoverForeground": "#FFFFFF",
"statusBar.debuggingBackground": "#0078D4",
"statusBar.debuggingForeground": "#FFFFFF",
"statusBar.focusBorder": "#0078D4",
"statusBar.foreground": "#CCCCCC",
"statusBar.noFolderBackground": "#1F1F1F",
"statusBarItem.focusBorder": "#0078D4",
"statusBarItem.prominentBackground": "#6E768166",
"statusBarItem.remoteBackground": "#0078D4",
"statusBarItem.remoteForeground": "#FFFFFF",
"tab.activeBackground": "#1F1F1F",
"tab.activeBorder": "#1F1F1F",
"tab.activeBorderTop": "#0078D4",
"tab.activeForeground": "#FFFFFF",
"tab.selectedBorderTop": "#6caddf",
"tab.border": "#2B2B2B",
"tab.hoverBackground": "#1F1F1F",
"tab.inactiveBackground": "#181818",
"tab.inactiveForeground": "#9D9D9D",
"tab.unfocusedActiveBorder": "#1F1F1F",
"tab.unfocusedActiveBorderTop": "#2B2B2B",
"tab.unfocusedHoverBackground": "#1F1F1F",
"terminal.foreground": "#CCCCCC",
"terminal.tab.activeBorder": "#0078D4",
"textBlockQuote.background": "#2B2B2B",
"textBlockQuote.border": "#616161",
"textCodeBlock.background": "#2B2B2B",
"textLink.activeForeground": "#4daafc",
"textLink.foreground": "#4daafc",
"textPreformat.foreground": "#D0D0D0",
"textPreformat.background": "#3C3C3C",
"textSeparator.foreground": "#21262D",
"titleBar.activeBackground": "#181818",
"titleBar.activeForeground": "#CCCCCC",
"titleBar.border": "#2B2B2B",
"titleBar.inactiveBackground": "#1F1F1F",
"titleBar.inactiveForeground": "#9D9D9D",
"welcomePage.tileBackground": "#2B2B2B",
"welcomePage.progress.foreground": "#0078D4",
"widget.border": "#313131",
"modernActivityBarItem.activeBackground": "#FFFFFF22",
"modernActivityBarItem.hoverBackground": "#FFFFFF11",
"modernActivityBar.border": "#252526"
}
}
+205
View File
@@ -0,0 +1,205 @@
{
"$schema": "vscode://schemas/color-theme",
"name": "Dark+",
"include": "./dark_vs.json",
"tokenColors": [
{
"name": "Function declarations",
"scope": [
"entity.name.function",
"support.function",
"support.constant.handlebars",
"source.powershell variable.other.member",
"entity.name.operator.custom-literal"
],
"settings": {
"foreground": "#DCDCAA"
}
},
{
"name": "Types declaration and references",
"scope": [
"support.class",
"support.type",
"entity.name.type",
"entity.name.namespace",
"entity.other.attribute",
"entity.name.scope-resolution",
"entity.name.class",
"storage.type.numeric.go",
"storage.type.byte.go",
"storage.type.boolean.go",
"storage.type.string.go",
"storage.type.uintptr.go",
"storage.type.error.go",
"storage.type.rune.go",
"storage.type.cs",
"storage.type.generic.cs",
"storage.type.modifier.cs",
"storage.type.variable.cs",
"storage.type.annotation.java",
"storage.type.generic.java",
"storage.type.java",
"storage.type.object.array.java",
"storage.type.primitive.array.java",
"storage.type.primitive.java",
"storage.type.token.java",
"storage.type.groovy",
"storage.type.annotation.groovy",
"storage.type.parameters.groovy",
"storage.type.generic.groovy",
"storage.type.object.array.groovy",
"storage.type.primitive.array.groovy",
"storage.type.primitive.groovy"
],
"settings": {
"foreground": "#4EC9B0"
}
},
{
"name": "Types declaration and references, TS grammar specific",
"scope": [
"meta.type.cast.expr",
"meta.type.new.expr",
"support.constant.math",
"support.constant.dom",
"support.constant.json",
"entity.other.inherited-class",
"punctuation.separator.namespace.ruby"
],
"settings": {
"foreground": "#4EC9B0"
}
},
{
"name": "Control flow / Special keywords",
"scope": [
"keyword.control",
"source.cpp keyword.operator.new",
"keyword.operator.delete",
"keyword.other.using",
"keyword.other.directive.using",
"keyword.other.operator",
"entity.name.operator"
],
"settings": {
"foreground": "#C586C0"
}
},
{
"name": "Variable and parameter name",
"scope": [
"variable",
"meta.definition.variable.name",
"support.variable",
"entity.name.variable",
"constant.other.placeholder"
],
"settings": {
"foreground": "#9CDCFE"
}
},
{
"name": "Constants and enums",
"scope": [
"variable.other.constant",
"variable.other.enummember"
],
"settings": {
"foreground": "#4FC1FF"
}
},
{
"name": "Object keys, TS grammar specific",
"scope": [
"meta.object-literal.key"
],
"settings": {
"foreground": "#9CDCFE"
}
},
{
"name": "CSS property value",
"scope": [
"support.constant.property-value",
"support.constant.font-name",
"support.constant.media-type",
"support.constant.media",
"constant.other.color.rgb-value",
"constant.other.rgb-value",
"support.constant.color"
],
"settings": {
"foreground": "#CE9178"
}
},
{
"name": "Regular expression groups",
"scope": [
"punctuation.definition.group.regexp",
"punctuation.definition.group.assertion.regexp",
"punctuation.definition.character-class.regexp",
"punctuation.character.set.begin.regexp",
"punctuation.character.set.end.regexp",
"keyword.operator.negation.regexp",
"support.other.parenthesis.regexp"
],
"settings": {
"foreground": "#CE9178"
}
},
{
"scope": [
"constant.character.character-class.regexp",
"constant.other.character-class.set.regexp",
"constant.other.character-class.regexp",
"constant.character.set.regexp"
],
"settings": {
"foreground": "#d16969"
}
},
{
"scope": [
"keyword.operator.or.regexp",
"keyword.control.anchor.regexp"
],
"settings": {
"foreground": "#DCDCAA"
}
},
{
"scope": "keyword.operator.quantifier.regexp",
"settings": {
"foreground": "#d7ba7d"
}
},
{
"scope": [
"constant.character",
"constant.other.option"
],
"settings": {
"foreground": "#569cd6"
}
},
{
"scope": "constant.character.escape",
"settings": {
"foreground": "#d7ba7d"
}
},
{
"scope": "entity.name.label",
"settings": {
"foreground": "#C8C8C8"
}
}
],
"semanticTokenColors": {
"newOperator": "#C586C0",
"stringLiteral": "#ce9178",
"customLiteral": "#DCDCAA",
"numberLiteral": "#b5cea8"
}
}
+423
View File
@@ -0,0 +1,423 @@
{
"$schema": "vscode://schemas/color-theme",
"name": "Dark (Visual Studio)",
"colors": {
"checkbox.border": "#6B6B6B",
"editor.background": "#1E1E1E",
"editor.foreground": "#D4D4D4",
"editor.inactiveSelectionBackground": "#3A3D41",
"editorIndentGuide.background1": "#404040",
"editorIndentGuide.activeBackground1": "#707070",
"editor.selectionHighlightBackground": "#ADD6FF26",
"list.dropBackground": "#383B3D",
"activityBarBadge.background": "#007ACC",
"sideBarTitle.foreground": "#BBBBBB",
"input.placeholderForeground": "#A6A6A6",
"menu.background": "#252526",
"menu.foreground": "#CCCCCC",
"menu.separatorBackground": "#454545",
"menu.border": "#454545",
"menu.selectionBackground": "#0078d4",
"statusBarItem.remoteForeground": "#FFF",
"statusBarItem.remoteBackground": "#16825D",
"statusBar.inactiveBackground": "#1476B8",
"titleBar.inactiveBackground": "#323233",
"ports.iconRunningProcessForeground": "#369432",
"sideBarSectionHeader.background": "#0000",
"sideBarSectionHeader.border": "#ccc3",
"tab.selectedBackground": "#37373D",
"tab.selectedForeground": "#FFFFFF",
"tab.lastPinnedBorder": "#ccc3",
"list.activeSelectionIconForeground": "#FFF",
"terminal.inactiveSelectionBackground": "#3A3D41",
"widget.border": "#303031",
"actionBar.toggledBackground": "#383a49",
"agentsPanel.border": "#303031",
"agentsCard.border": "#00000000",
"agentsChatInput.border": "#303031",
"agentsChatInput.focusBorder": "#007ACC",
"agentsNewSessionButton.border": "#303031",
"surface.border": "#252526",
"modernActivityBarItem.activeBackground": "#1E1E1E",
"modernActivityBarItem.hoverBackground": "#1E1E1E66",
"modernActivityBar.border": "#252526"
},
"tokenColors": [
{
"scope": [
"meta.embedded",
"source.groovy.embedded",
"string meta.image.inline.markdown",
"variable.legacy.builtin.python"
],
"settings": {
"foreground": "#D4D4D4"
}
},
{
"scope": "emphasis",
"settings": {
"fontStyle": "italic"
}
},
{
"scope": "strong",
"settings": {
"fontStyle": "bold"
}
},
{
"scope": "header",
"settings": {
"foreground": "#000080"
}
},
{
"scope": "comment",
"settings": {
"foreground": "#6A9955"
}
},
{
"scope": "constant.language",
"settings": {
"foreground": "#569cd6"
}
},
{
"scope": [
"constant.numeric",
"variable.other.enummember",
"keyword.operator.plus.exponent",
"keyword.operator.minus.exponent"
],
"settings": {
"foreground": "#b5cea8"
}
},
{
"scope": "constant.regexp",
"settings": {
"foreground": "#646695"
}
},
{
"scope": "entity.name.tag",
"settings": {
"foreground": "#569cd6"
}
},
{
"scope": [
"entity.name.tag.css",
"entity.name.tag.less"
],
"settings": {
"foreground": "#d7ba7d"
}
},
{
"scope": "entity.other.attribute-name",
"settings": {
"foreground": "#9cdcfe"
}
},
{
"scope": [
"entity.other.attribute-name.class.css",
"source.css entity.other.attribute-name.class",
"entity.other.attribute-name.id.css",
"entity.other.attribute-name.parent-selector.css",
"entity.other.attribute-name.parent.less",
"source.css entity.other.attribute-name.pseudo-class",
"entity.other.attribute-name.pseudo-element.css",
"source.css.less entity.other.attribute-name.id",
"entity.other.attribute-name.scss"
],
"settings": {
"foreground": "#d7ba7d"
}
},
{
"scope": "invalid",
"settings": {
"foreground": "#f44747"
}
},
{
"scope": "markup.underline",
"settings": {
"fontStyle": "underline"
}
},
{
"scope": "markup.bold",
"settings": {
"fontStyle": "bold",
"foreground": "#569cd6"
}
},
{
"scope": "markup.heading",
"settings": {
"fontStyle": "bold",
"foreground": "#569cd6"
}
},
{
"scope": "markup.italic",
"settings": {
"fontStyle": "italic",
"foreground": "#C586C0"
}
},
{
"scope": "markup.strikethrough",
"settings": {
"fontStyle": "strikethrough"
}
},
{
"scope": "markup.inserted",
"settings": {
"foreground": "#b5cea8"
}
},
{
"scope": "markup.deleted",
"settings": {
"foreground": "#ce9178"
}
},
{
"scope": "markup.changed",
"settings": {
"foreground": "#569cd6"
}
},
{
"scope": "punctuation.definition.quote.begin.markdown",
"settings": {
"foreground": "#6A9955"
}
},
{
"scope": "punctuation.definition.list.begin.markdown",
"settings": {
"foreground": "#6796e6"
}
},
{
"scope": "markup.inline.raw",
"settings": {
"foreground": "#ce9178"
}
},
{
"name": "brackets of XML/HTML tags",
"scope": "punctuation.definition.tag",
"settings": {
"foreground": "#808080"
}
},
{
"scope": [
"meta.preprocessor",
"entity.name.function.preprocessor"
],
"settings": {
"foreground": "#569cd6"
}
},
{
"scope": "meta.preprocessor.string",
"settings": {
"foreground": "#ce9178"
}
},
{
"scope": "meta.preprocessor.numeric",
"settings": {
"foreground": "#b5cea8"
}
},
{
"scope": "meta.structure.dictionary.key.python",
"settings": {
"foreground": "#9cdcfe"
}
},
{
"scope": "meta.diff.header",
"settings": {
"foreground": "#569cd6"
}
},
{
"scope": "storage",
"settings": {
"foreground": "#569cd6"
}
},
{
"scope": "storage.type",
"settings": {
"foreground": "#569cd6"
}
},
{
"scope": [
"storage.modifier",
"keyword.operator.noexcept"
],
"settings": {
"foreground": "#569cd6"
}
},
{
"scope": [
"string",
"meta.embedded.assembly"
],
"settings": {
"foreground": "#ce9178"
}
},
{
"scope": "string.tag",
"settings": {
"foreground": "#ce9178"
}
},
{
"scope": "string.value",
"settings": {
"foreground": "#ce9178"
}
},
{
"scope": "string.regexp",
"settings": {
"foreground": "#d16969"
}
},
{
"name": "String interpolation",
"scope": [
"punctuation.definition.template-expression.begin",
"punctuation.definition.template-expression.end",
"punctuation.section.embedded"
],
"settings": {
"foreground": "#569cd6"
}
},
{
"name": "Reset JavaScript string interpolation expression",
"scope": [
"meta.template.expression"
],
"settings": {
"foreground": "#d4d4d4"
}
},
{
"scope": [
"support.type.vendored.property-name",
"support.type.property-name",
"source.css variable",
"source.coffee.embedded"
],
"settings": {
"foreground": "#9cdcfe"
}
},
{
"scope": "keyword",
"settings": {
"foreground": "#569cd6"
}
},
{
"scope": "keyword.control",
"settings": {
"foreground": "#569cd6"
}
},
{
"scope": "keyword.operator",
"settings": {
"foreground": "#d4d4d4"
}
},
{
"scope": [
"keyword.operator.new",
"keyword.operator.expression",
"keyword.operator.cast",
"keyword.operator.sizeof",
"keyword.operator.alignof",
"keyword.operator.typeid",
"keyword.operator.alignas",
"keyword.operator.instanceof",
"keyword.operator.logical.python",
"keyword.operator.wordlike"
],
"settings": {
"foreground": "#569cd6"
}
},
{
"scope": "keyword.other.unit",
"settings": {
"foreground": "#b5cea8"
}
},
{
"scope": [
"punctuation.section.embedded.begin.php",
"punctuation.section.embedded.end.php"
],
"settings": {
"foreground": "#569cd6"
}
},
{
"scope": "support.function.git-rebase",
"settings": {
"foreground": "#9cdcfe"
}
},
{
"scope": "constant.sha.git-rebase",
"settings": {
"foreground": "#b5cea8"
}
},
{
"name": "coloring of the Java import and package identifiers",
"scope": [
"storage.modifier.import.java",
"variable.language.wildcard.java",
"storage.modifier.package.java"
],
"settings": {
"foreground": "#d4d4d4"
}
},
{
"name": "this.self",
"scope": "variable.language",
"settings": {
"foreground": "#569cd6"
}
}
],
"semanticHighlighting": true,
"semanticTokenColors": {
"newOperator": "#d4d4d4",
"stringLiteral": "#ce9178",
"customLiteral": "#D4D4D4",
"numberLiteral": "#b5cea8"
}
}
File diff suppressed because it is too large. Load diff
+22
View File
@@ -0,0 +1,22 @@
{
"name": "darwin-breeze",
"displayName": "Darwin Breeze",
"description": "Generated by kde/theme/build.py from DarwinBreezeDark.colors",
"publisher": "trivk",
"version": "1.0.0",
"engines": {
"vscode": "^1.70.0"
},
"categories": [
"Themes"
],
"contributes": {
"themes": [
{
"label": "Darwin Breeze Dark",
"uiTheme": "vs-dark",
"path": "./themes/DarwinBreezeDark-color-theme.json"
}
]
}
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1 @@
<svg height="32" viewBox="0 0 32 32" width="32" xmlns="http://www.w3.org/2000/svg"><g transform="matrix(0.78 0 0 0.78 3.52 3.52)"><g transform="matrix(.99917103 0 0 .9988667 .023961 .026876)"><path d="m29.946 15.942c.354 9.205-9.874 16.514-18.469 13.197-8.505-2.569-12.285-13.93-7.003-21.077 4.9-7.801 17.469-8.068 22.695-.48a13.97 13.97 0 0 1 2.777 8.36z" fill="none" opacity=".95" stroke="#f5f5f5" stroke-width="2.093"/><path d="m12.758 26.311v-5.725c-.282.433-.679.792-1.19 1.079a3.216 3.216 0 0 1 -1.613.43c-1.27 0-2.366-.555-3.287-1.663-.914-1.109-1.371-2.628-1.371-4.559 0-1.174.185-2.227.555-3.16.376-.932.917-1.636 1.623-2.114a4.074 4.074 0 0 1 2.34-.726c1.323 0 2.365.609 3.125 1.827v-1.563h1.633v16.174zm-5.596-10.36c0 1.504.29 2.635.867 3.39.579.75 1.27 1.124 2.078 1.124.773 0 1.438-.356 1.996-1.068.558-.72.837-1.81.837-3.27 0-1.557-.296-2.727-.887-3.513-.585-.785-1.274-1.178-2.067-1.178-.787 0-1.456.367-2.007 1.101-.544.727-.817 1.865-.817 3.413m11.938 5.88h-1.683v-16.141h1.815v5.758c.766-1.05 1.744-1.574 2.934-1.574.658 0 1.28.147 1.865.44a3.768 3.768 0 0 1 1.452 1.222c.383.521.682 1.153.897 1.894s.323 1.534.323 2.378c0 2.004-.454 3.553-1.361 4.647-.908 1.093-1.997 1.64-3.267 1.64-1.264 0-2.255-.576-2.974-1.728v1.464m-.02-5.935c0 1.402.174 2.415.524 3.04.571 1.02 1.344 1.53 2.319 1.53.793 0 1.479-.375 2.057-1.123.578-.756.867-1.88.867-3.37 0-1.526-.28-2.653-.837-3.38-.551-.726-1.22-1.09-2.007-1.09-.793 0-1.478.378-2.057 1.134-.578.75-.867 1.835-.867 3.26" fill="#fafafa"/></g></g></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+16
View File
@@ -0,0 +1,16 @@
#!/bin/bash
# Patch netbird-ui's tray icons to Breeze proportions.
# Runs as root; the pacman hook re-runs it after every netbird-ui install/upgrade.
set -euo pipefail
here=$(cd "$(dirname "$0")" && pwd)
ROOT=${ROOT:-} # for dry-run testing only
bin=$ROOT/usr/bin/netbird-ui
[[ -f $bin ]] || exit 0
# Still the file the package installed: keep it as the original for restore.sh
sum=$(zcat "$ROOT"/var/lib/pacman/local/netbird-ui*/mtree 2>/dev/null \
| grep -F './usr/bin/netbird-ui ' | grep -o 'sha256digest=[0-9a-f]*' | cut -d= -f2 || true)
if [[ -n $sum && $(sha256sum <"$bin" | cut -d' ' -f1) == "$sum" ]]; then
install -Dm755 "$bin" "$here/orig/netbird-ui"
fi
python3 -I "$here/patch.py" "$bin"
@@ -0,0 +1,15 @@
#!/bin/bash
# Install the netbird-ui tray icon patch and its pacman hook. Usage: sudo ./install.sh
set -euo pipefail
here=$(cd "$(dirname "$0")" && pwd)
ROOT=${ROOT:-} # for dry-run testing only
[[ $EUID -eq 0 || -n $ROOT ]] || { echo "Must be run with sudo"; exit 1; }
dest=$ROOT/usr/local/share/netbird-breeze-icons
install -Dm755 "$here/patch.py" "$dest/patch.py"
install -m755 "$here/apply.sh" "$dest/apply.sh"
install -Dm644 "$here/netbird-breeze-icons.hook" "$ROOT/etc/pacman.d/hooks/netbird-breeze-icons.hook"
ROOT=$ROOT "$dest/apply.sh"
echo "Done. Restart the NetBird UI (without sudo):"
echo " pkill -x netbird-ui; setsid -f netbird-ui --daemon-addr unix:///var/run/netbird/main.sock >/dev/null 2>&1"
@@ -0,0 +1,11 @@
[Trigger]
Operation = Install
Operation = Upgrade
Type = Package
Target = netbird-ui
Target = netbird-ui-bin
[Action]
Description = Patching NetBird tray icons to match Breeze...
When = PostTransaction
Exec = /usr/local/share/netbird-breeze-icons/apply.sh
+183
View File
@@ -0,0 +1,183 @@
#!/usr/bin/env python3
"""Shrink and recolor the tray icons embedded in the netbird-ui binary.
NetBird sends its tray icon as a pixmap, so an icon theme can't replace it.
This rewrites the 48x48 monochrome PNGs inside the binary in place: the
glyph is scaled to SCALE so it gets the padding of a Breeze status icon,
and the white variants take the panel's text color. Each new PNG must fit
in the bytes of the old one; the rest is zero-filled, which Go's PNG
decoder never reads because it stops at IEND.
Usage: patch.py BINARY [--check]
"""
import argparse
import os
from pathlib import Path
import struct
import sys
import tempfile
import zlib
SIZE = 48
SCALE = 0.8
# DarwinBreezeDark ForegroundNormal, as the other tray icons are drawn
LIGHT = (222, 222, 222)
# A glyph narrower than this already has padding (already patched)
MAX_PADDED_WIDTH = round(SIZE * 0.9)
SIG = b"\x89PNG\r\n\x1a\n"
Pixels = list[list[float]] # rows of premultiplied RGBA floats
def decode(png: bytes) -> tuple[int, int, bytes] | None:
"""Return (width, height, RGBA rows) for an 8-bit RGBA PNG, else None."""
pos, idat, ihdr = 8, b"", b""
while pos < len(png):
(length,) = struct.unpack(">I", png[pos:pos + 4])
kind, body = png[pos + 4:pos + 8], png[pos + 8:pos + 8 + length]
if kind == b"IHDR":
ihdr = body
elif kind == b"IDAT":
idat += body
elif kind == b"IEND":
break
pos += 12 + length
w, h, depth, color, _, _, interlace = struct.unpack(">IIBBBBB", ihdr)
if (depth, color, interlace) != (8, 6, 0):
return None
raw, stride, out = zlib.decompress(idat), w * 4, bytearray()
prev = bytearray(stride)
for y in range(h):
ftype = raw[y * (stride + 1)]
line = bytearray(raw[y * (stride + 1) + 1:(y + 1) * (stride + 1)])
for i in range(stride):
a = line[i - 4] if i >= 4 else 0
b = prev[i]
c = prev[i - 4] if i >= 4 else 0
if ftype == 1:
line[i] = (line[i] + a) & 0xFF
elif ftype == 2:
line[i] = (line[i] + b) & 0xFF
elif ftype == 3:
line[i] = (line[i] + (a + b) // 2) & 0xFF
elif ftype == 4:
p = a + b - c
pa, pb, pc = abs(p - a), abs(p - b), abs(p - c)
pred = a if pa <= pb and pa <= pc else b if pb <= pc else c
line[i] = (line[i] + pred) & 0xFF
out += line
prev = line
return w, h, bytes(out)
def encode(w: int, h: int, rgba: bytes) -> bytes:
def chunk(kind: bytes, body: bytes) -> bytes:
crc = zlib.crc32(kind + body)
return struct.pack(">I", len(body)) + kind + body + struct.pack(">I", crc)
raw = b"".join(b"\0" + rgba[y * w * 4:(y + 1) * w * 4] for y in range(h))
return (SIG + chunk(b"IHDR", struct.pack(">IIBBBBB", w, h, 8, 6, 0, 0, 0))
+ chunk(b"IDAT", zlib.compress(raw, 9)) + chunk(b"IEND", b""))
def glyph_width(rgba: bytes) -> int:
xs = [i // 4 % SIZE for i in range(3, len(rgba), 4) if rgba[i] > 16]
return max(xs) - min(xs) + 1 if xs else 0
def is_light(rgba: bytes) -> bool | None:
"""True for a white glyph, False for black, None if not monochrome."""
lum = [rgba[i - 3] for i in range(3, len(rgba), 4) if rgba[i] > 200]
if not lum or any(abs(rgba[i - 3] - rgba[i - 2]) > 8 for i in range(3, len(rgba), 4)
if rgba[i] > 200):
return None
if all(v > 230 for v in lum):
return True
if all(v < 25 for v in lum):
return False
return None
def shrink(rgba: bytes, light: bool) -> bytes:
"""Box-filter the image to SCALE, centered on a SIZE canvas."""
src: Pixels = []
for y in range(SIZE):
row: list[float] = []
for x in range(SIZE):
r, g, b, a = rgba[(y * SIZE + x) * 4:(y * SIZE + x) * 4 + 4]
row += [r * a, g * a, b * a, a]
src.append(row)
inner = SIZE * SCALE
off = (SIZE - inner) / 2
step = 1 / SCALE
out = bytearray(SIZE * SIZE * 4)
def spans(o: int) -> list[tuple[int, float]]:
lo = (o - off) * step
hi = lo + step
res = []
for s in range(max(0, int(lo)), min(SIZE, int(hi) + 1)):
cover = min(hi, s + 1) - max(lo, s)
if cover > 0:
res.append((s, cover))
return res
for oy in range(SIZE):
ys = spans(oy)
for ox in range(SIZE):
acc = [0.0] * 4
for sy, wy in ys:
for sx, wx in spans(ox):
k = wy * wx
for c in range(4):
acc[c] += src[sy][sx * 4 + c] * k
area = step * step
a = acc[3] / area
if a < 0.5:
continue
color = LIGHT if light else tuple(round(acc[c] / acc[3]) for c in range(3))
out[(oy * SIZE + ox) * 4:(oy * SIZE + ox) * 4 + 4] = bytes(
[*color, min(255, round(a))])
return bytes(out)
def patch(data: bytearray) -> int:
count, pos = 0, 0
while (pos := data.find(SIG, pos)) >= 0:
end = data.find(b"IEND", pos) + 8
old = bytes(data[pos:end])
img = decode(old) if old[16:24] == struct.pack(">II", SIZE, SIZE) else None
if img is not None:
light = is_light(img[2])
if light is not None and glyph_width(img[2]) > MAX_PADDED_WIDTH:
new = encode(SIZE, SIZE, shrink(img[2], light))
if len(new) > len(old):
sys.exit(f"Patched icon at {pos} is larger than the original")
data[pos:end] = new + bytes(len(old) - len(new))
count += 1
pos = end
return count
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
parser.add_argument("binary", type=Path)
parser.add_argument("--check", action="store_true",
help="only print how many icons would be patched")
args = parser.parse_args()
data = bytearray(args.binary.read_bytes())
count = patch(data)
print(f"{args.binary}: {count} tray icons {'to patch' if args.check else 'patched'}")
if args.check or not count:
return
mode = args.binary.stat().st_mode
fd, tmp = tempfile.mkstemp(dir=args.binary.parent, prefix=".netbird-ui.")
with os.fdopen(fd, "wb") as f:
f.write(data)
os.chmod(tmp, mode & 0o7777)
os.replace(tmp, args.binary)
if __name__ == "__main__":
main()
@@ -0,0 +1,12 @@
#!/bin/bash
# Put the original netbird-ui back and remove the hook. Usage: sudo ./restore.sh
set -euo pipefail
ROOT=${ROOT:-} # for dry-run testing only
[[ $EUID -eq 0 || -n $ROOT ]] || { echo "Must be run with sudo"; exit 1; }
dest=$ROOT/usr/local/share/netbird-breeze-icons
[[ -f $dest/orig/netbird-ui ]] || { echo "No original binary in $dest/orig"; exit 1; }
install -m755 "$dest/orig/netbird-ui" "$ROOT/usr/bin/netbird-ui"
rm -f "$ROOT/etc/pacman.d/hooks/netbird-breeze-icons.hook"
rm -rf "$dest"
echo "Restored. Restart the NetBird UI (without sudo):"
echo " pkill -x netbird-ui; setsid -f netbird-ui --daemon-addr unix:///var/run/netbird/main.sock >/dev/null 2>&1"
+24
View File
@@ -0,0 +1,24 @@
#!/bin/bash
# Copy the Breeze-style icons over Ngó Sen's monochrome tray icons.
# Runs as root; the pacman hook re-runs it after every fcitx5-ngosen install/upgrade.
set -euo pipefail
here=$(cd "$(dirname "$0")" && pwd)
ROOT=${ROOT:-} # for dry-run testing only
# Ngó Sen points at hicolor, but Plasma looks the icon up by name in breeze/breeze-dark
dirs=(usr/share/icons/hicolor/scalable/{apps,status}
usr/share/icons/breeze{,-dark}/status/{22,24})
mtree=$(zcat "$ROOT"/var/lib/pacman/local/fcitx5-ngosen-*/mtree 2>/dev/null || true)
for d in "${dirs[@]}"; do
for f in "$here"/icons/*.svg; do
n=$(basename "$f"); t=$ROOT/$d/$n
[[ -f $t ]] || continue
# Still the file the package installed: keep it as the original for restore.sh
sum=$(grep -F "./$d/$n " <<<"$mtree" | grep -o 'sha256digest=[0-9a-f]*' | cut -d= -f2 || true)
if [[ -n $sum && $(sha256sum <"$t" | cut -d' ' -f1) == "$sum" ]]; then
install -Dm644 "$t" "$here/orig/$d/$n"
fi
install -m644 "$f" "$t"
done
done
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22" width="22" height="22">
<style id="current-color-scheme" type="text/css">.ColorScheme-Text { color: #232629; }</style>
<g class="ColorScheme-Text" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.3">
<rect x="3.5" y="3.5" width="15" height="15" rx="2.5" stroke-width="1"/><path d="M8.3 7.5 11 14.5l2.7-7"/>
</g></svg>

After

Width:  |  Height:  |  Size: 426 B

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22" width="22" height="22">
<style id="current-color-scheme" type="text/css">.ColorScheme-Text { color: #fcfcfc; }</style>
<g class="ColorScheme-Text" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.3">
<rect x="3.5" y="3.5" width="15" height="15" rx="2.5" stroke-width="1"/><path d="M8.3 7.5 11 14.5l2.7-7"/>
</g></svg>

After

Width:  |  Height:  |  Size: 426 B

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22" width="22" height="22">
<style id="current-color-scheme" type="text/css">.ColorScheme-Text { color: #232629; }</style>
<g class="ColorScheme-Text" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1">
<circle cx="11" cy="11" r="7.5"/><path d="M7.8 12.6q3.2 3.2 6.4 0"/><path d="M8.6 8.6v.6M13.4 8.6v.6" stroke-width="1.6"/>
</g></svg>

After

Width:  |  Height:  |  Size: 440 B

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22" width="22" height="22">
<style id="current-color-scheme" type="text/css">.ColorScheme-Text { color: #fcfcfc; }</style>
<g class="ColorScheme-Text" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1">
<circle cx="11" cy="11" r="7.5"/><path d="M7.8 12.6q3.2 3.2 6.4 0"/><path d="M8.6 8.6v.6M13.4 8.6v.6" stroke-width="1.6"/>
</g></svg>

After

Width:  |  Height:  |  Size: 440 B

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22" width="22" height="22">
<style id="current-color-scheme" type="text/css">.ColorScheme-Text { color: #232629; }</style>
<g class="ColorScheme-Text" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.3">
<rect x="3.5" y="3.5" width="15" height="15" rx="2.5" stroke-width="1"/><path d="M13.3 7.5H8.8v7h4.5M8.8 11h3.7"/>
</g></svg>

After

Width:  |  Height:  |  Size: 434 B

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22" width="22" height="22">
<style id="current-color-scheme" type="text/css">.ColorScheme-Text { color: #fcfcfc; }</style>
<g class="ColorScheme-Text" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.3">
<rect x="3.5" y="3.5" width="15" height="15" rx="2.5" stroke-width="1"/><path d="M13.3 7.5H8.8v7h4.5M8.8 11h3.7"/>
</g></svg>

After

Width:  |  Height:  |  Size: 434 B

+33
View File
@@ -0,0 +1,33 @@
#!/bin/bash
# Install Breeze-style tray icons for Ngó Sen. Usage: sudo ./install.sh
set -euo pipefail
here=$(cd "$(dirname "$0")" && pwd)
ROOT=${ROOT:-} # for dry-run testing only
[[ $EUID -eq 0 || -n $ROOT ]] || { echo "Must be run with sudo"; exit 1; }
owner=${SUDO_USER:-$(id -un "${PKEXEC_UID:-0}")}
dest=$ROOT/usr/local/share/ngosen-breeze-icons
install -d "$dest/icons"
install -m644 "$here"/icons/*.svg "$dest/icons/"
install -m755 "$here/apply.sh" "$dest/apply.sh"
install -Dm644 "$here/ngosen-breeze-icons.hook" "$ROOT/etc/pacman.d/hooks/ngosen-breeze-icons.hook"
# Older versions used NoUpgrade in pacman.conf; the hook replaces it
sed -i '/^# ngosen-breeze-icons$/,+1d' "$ROOT/etc/pacman.conf"
ROOT=$ROOT "$dest/apply.sh"
# Ngó Sen: use the monochrome icons (not the lotus ones), white for a dark panel
conf=$ROOT$(getent passwd "$owner" | cut -d: -f6)/.config/fcitx5/conf/ngosen.conf
as_owner() { if [[ -n $ROOT ]]; then "$@"; else runuser -u "$owner" -- "$@"; fi; }
if [[ -f $conf ]]; then
for kv in UseLotusIcons=False IconTheme=Dark; do
k=${kv%%=*}
if grep -q "^$k=" "$conf"; then as_owner sed -i "s/^$k=.*/$kv/" "$conf"
elif grep -q "^# $k=" "$conf"; then as_owner sed -i "s/^# $k=.*/$kv/" "$conf"
else as_owner sh -c "echo '$kv' >> '$conf'"; fi
done
else
as_owner install -Dm600 /dev/stdin "$conf" <<<$'UseLotusIcons=False\nIconTheme=Dark'
fi
echo "Done. Restart fcitx5 and plasmashell (without sudo):"
echo " $here/restart-fcitx5.sh; systemctl --user restart plasma-plasmashell"
@@ -0,0 +1,10 @@
[Trigger]
Operation = Install
Operation = Upgrade
Type = Package
Target = fcitx5-ngosen
[Action]
Description = Applying Breeze-style tray icons for Ngó Sen...
When = PostTransaction
Exec = /usr/local/share/ngosen-breeze-icons/apply.sh
@@ -0,0 +1,7 @@
#!/bin/bash
# Restart fcitx5 through KWin (KDE Wayland) so it keeps the Wayland input method frontend.
L=$(kreadconfig6 --file kwinrc --group Wayland --key InputMethod)
[[ -n $L ]] || L=/usr/share/applications/fcitx5-wayland-launcher.desktop
pkill -x fcitx5; sleep 1
kwriteconfig6 --notify --file kwinrc --group Wayland --key InputMethod --delete; sleep 1
kwriteconfig6 --notify --file kwinrc --group Wayland --key InputMethod "$L"
+14
View File
@@ -0,0 +1,14 @@
#!/bin/bash
# Put Ngó Sen's original icons back and remove the hook. Usage: sudo ./restore.sh
set -euo pipefail
ROOT=${ROOT:-} # for dry-run testing only
[[ $EUID -eq 0 || -n $ROOT ]] || { echo "Must be run with sudo"; exit 1; }
dest=$ROOT/usr/local/share/ngosen-breeze-icons
[[ -d $dest/orig/usr ]] || { echo "No original icons in $dest/orig"; exit 1; }
(cd "$dest/orig" && find usr -name '*.svg' -print0) | while IFS= read -r -d '' f; do
install -m644 "$dest/orig/$f" "$ROOT/$f"
done
rm -f "$ROOT/etc/pacman.d/hooks/ngosen-breeze-icons.hook"
rm -rf "$dest"
echo "Restored. To get the lotus icons back, turn them on in Ngó Sen Settings."
echo "Restart plasmashell (without sudo): systemctl --user restart plasma-plasmashell"
+76
View File
@@ -0,0 +1,76 @@
# Tray icons that match Breeze
```sh
stow -d kde -t "$HOME" tray-icons
```
Some icons need one more step after stowing; see below.
## Ngó Sen (fcitx5-ngosen)
Replaces Ngó Sen's monochrome tray icons with a V/E inside a rounded frame.
```sh
sudo ~/.local/share/ngosen-breeze-icons/install.sh
~/.local/share/ngosen-breeze-icons/restart-fcitx5.sh
systemctl --user restart plasma-plasmashell
```
- Ngó Sen points the tray at `/usr/share/icons/hicolor`, but Plasma looks
the icon up by name in the `breeze`/`breeze-dark` themes under
`/usr/share` and ignores `~/.local/share/icons`, so the system files have
to be replaced.
- `install.sh` copies the icons and `apply.sh` to
`/usr/local/share/ngosen-breeze-icons/`, installs the pacman hook
`/etc/pacman.d/hooks/ngosen-breeze-icons.hook` to re-apply them after
every package upgrade, and sets `UseLotusIcons=False` and
`IconTheme=Dark` in `~/.config/fcitx5/conf/ngosen.conf`.
- The original icons are kept in `/usr/local/share/ngosen-breeze-icons/orig/`;
`sudo ~/.local/share/ngosen-breeze-icons/restore.sh` puts them back and
removes the hook.
- On KDE Wayland don't start fcitx5 with `fcitx5 -d`; use
`restart-fcitx5.sh` so KWin launches it.
## NetBird (netbird-ui)
Scales NetBird's tray icons down to 80% so they get the padding of Breeze
status icons, and draws the white ones in the panel's text color
(`#dedede`) instead of pure white.
```sh
sudo ~/.local/share/netbird-breeze-icons/install.sh
pkill -x netbird-ui; setsid -f netbird-ui --daemon-addr unix:///var/run/netbird/main.sock >/dev/null 2>&1
```
- NetBird sends the tray icon as raw pixels, not an icon name, so an icon
theme can't replace it. `patch.py` rewrites the 48x48 PNGs embedded in
`/usr/bin/netbird-ui` in place instead; each new PNG fits in the bytes
of the old one.
- `install.sh` copies `patch.py` and `apply.sh` to
`/usr/local/share/netbird-breeze-icons/` and installs the pacman hook
`/etc/pacman.d/hooks/netbird-breeze-icons.hook` to re-patch the binary
after every `netbird-ui`/`netbird-ui-bin` upgrade.
- The original binary is kept in `/usr/local/share/netbird-breeze-icons/orig/`;
`sudo ~/.local/share/netbird-breeze-icons/restore.sh` puts it back and
removes the hook.
## qBittorrent
`qbittorrent-tray-mono.svg` is qBittorrent's monochrome tray icon scaled
down to 78%, so it has the same padding as Breeze status icons instead of
filling the whole tray slot.
qBittorrent 5.x only looks the tray icon up in the icon theme when "Use
icons from system theme" is on, so also set (qBittorrent closed, or via
Tools > Options > Behavior):
```ini
# ~/.config/qBittorrent/qBittorrent.conf
[Appearance]
TrayIconStyle=Monochrome
[Preferences]
Advanced\useSystemIconTheme=true
```
`qBittorrent.conf` itself isn't stowed: qBittorrent rewrites it on exit.
Binary file not shown.
-18
View File
@@ -1,18 +0,0 @@
# vim:fileencoding=utf-8:foldmethod=marker
font_family JetBrainsMono Nerd Font Regular
bold_font JetBrainsMono Nerd Font Bold
italic_font JetBrainsMono Nerd Font Italic
bold_italic_font JetBrainsMono Nerd Font Bold Italic
font_size 13.0
background_opacity 0.85
allow_hyperlinks yes
shell_integration enabled
macos_option_as_alt yes
# include ./mocha.conf
+15
View File
@@ -0,0 +1,15 @@
# macOS packages
From the repository root, install all macOS packages:
```sh
(cd mac && stow -t "$HOME" */)
```
Install the package:
```sh
stow -d mac -t "$HOME" ghostty
```
- `ghostty`: JetBrainsMono Nerd Font and Ghostty's bundled SpaceGray Eighties theme.
File renamed without changes.
-104
View File
@@ -1,104 +0,0 @@
# Don't ask for confirmations
#assume_yes = true
# Disable specific steps - same options as the command line flag
disable = ["system", "emacs", "gem", "node", "pnpm", "pip3", "micro", "containers"]
display_preamble = false
# Ignore failures for these steps
#ignore_failures = ["powershell"]
# Run specific steps - same options as the command line flag
#only = ["system", "emacs"]
# Do not ask to retry failed steps (default: false)
#no_retry = true
# Run inside tmux
#run_in_tmux = true
# List of remote machines with Topgrade installed on them
#remote_topgrades = ["toothless", "pi", "parnas"]
# Arguments to pass SSH when upgrading remote systems
#ssh_arguments = "-o ConnectTimeout=2"
# Path to Topgrade executable on remote machines
#remote_topgrade_path = ".cargo/bin/topgrade"
# Arguments to pass tmux when pulling Repositories
#tmux_arguments = "-S /var/tmux.sock"
# Do not set the terminal title
#set_title = false
# Display the time in step titles
# display_time = true
# Cleanup temporary or old files
#cleanup = true
[git]
#max_concurrency = 5
# Additional git repositories to pull
#repos = [
# "~/src/*/",
# "~/.config/something"
#]
# Don't pull the predefined git repos
#pull_predefined = false
# Arguments to pass Git when pulling Repositories
#arguments = "--rebase --autostash"
[composer]
#self_update = true
# Commands to run before anything
[pre_commands]
#"Emacs Snapshot" = "rm -rf ~/.emacs.d/elpa.bak && cp -rl ~/.emacs.d/elpa ~/.emacs.d/elpa.bak"
# Custom commands
[commands]
#"Python Environment" = "~/dev/.env/bin/pip install -i https://pypi.python.org/simple -U --upgrade-strategy eager jupyter"
[brew]
#greedy_cask = true
[linux]
# Arch Package Manager to use. Allowed values: autodetect, trizen, paru, yay, pikaur, pacman.
#arch_package_manager = "pacman"
# Arguments to pass yay (or paru) when updating packages
#yay_arguments = "--nodevel"
#show_arch_news = true
#trizen_arguments = "--devel"
#pikaur_arguments = ""
#enable_tlmgr = true
#emerge_sync_flags = "-q"
#emerge_update_flags = "-uDNa --with-bdeps=y world"
#redhat_distro_sync = false
#rpm_ostree = false
[windows]
# Manually select Windows updates
#accept_all_updates = false
#open_remotes_in_new_terminal = true
# Causes Topgrade to rename itself during the run to allow package managers
# to upgrade it. Use this only if you installed Topgrade by using a package
# manager such as Scoop to Cargo
#self_rename = true
[npm]
# Use sudo if the NPM directory isn't owned by the current user
#use_sudo = true
[firmware]
# Offer to update firmware; if false just check for and display available updates
#upgrade = true
[flatpak]
# Use sudo for updating the system-wide installation
#use_sudo = true
-38
View File
@@ -1,38 +0,0 @@
# install zinit
source $ZDOTDIR/zinit
# load remote plugins
zinit wait lucid light-mode id-as depth"1" for \
wintermi/zsh-brew \
hlissner/zsh-autopair \
Aloxaf/fzf-tab \
atinit"zicompinit; zicdreplay -q" \
zdharma-continuum/fast-syntax-highlighting \
atload"_zsh_autosuggest_start" \
zsh-users/zsh-autosuggestions
# load prompt theme
zinit ice as"command" from"gh-r" id-as \
atclone"./starship init zsh > init.zsh; ./starship completions zsh > _starship" \
atpull"%atclone" src"init.zsh"
zinit light starship/starship
# load binaries
zinit as"command" wait lucid light-mode from"gh-r" id-as for \
extract"!" lsd-rs/lsd \
extract"!" zyedidia/micro \
extract"!" cp"autocomplete/bat.zsh -> _bat" @sharkdp/bat \
extract"!" pick"usr/bin/fastfetch" \
fastfetch-cli/fastfetch \
atclone"./zoxide init zsh > init.zsh" atpull"%atclone" src"init.zsh" \
ajeetdsouza/zoxide \
atclone"./fzf --zsh > init.zsh" atpull="%atclone" src"init.zsh" \
junegunn/fzf \
atclone"./fnm env --use-on-cd --shell zsh > init.zsh; ./fnm completions --shell zsh > _fnm" atpull"%atclone" src"init.zsh" Schniz/fnm
# load local scripts
zinit is-snippet id-as for \
$ZDOTDIR/snippets/exports \
$ZDOTDIR/snippets/aliases \
$ZDOTDIR/snippets/options \
$ZDOTDIR/snippets/bin
-37
View File
@@ -1,37 +0,0 @@
#!/usr/bin/env zsh
# Add GNU tools to PATH without 'g' prefix
local gnu_tools=(
"coreutils"
"findutils"
"gnu-tar"
"gnu-sed"
"gawk"
"gnu-indent"
"grep"
)
for tool in $gnu_tools; do
local gnubin="/opt/homebrew/opt/$tool/libexec/gnubin"
if [ -d "$gnubin" ]; then
case ":$PATH:" in
*":$gnubin:"*) ;;
*) export PATH="$gnubin:$PATH" ;;
esac
fi
done
# Add other bins separately since they have a different path structure
local bin_paths=(
"$HOME/.local/bin"
"/opt/homebrew/opt/gnu-getopt/bin"
)
for bin_path in $bin_paths; do
if [ -d "$bin_path" ]; then
case ":$PATH:" in
*":$bin_path:"*) ;;
*) export PATH="$bin_path:$PATH" ;;
esac
fi
done
-12
View File
@@ -1,12 +0,0 @@
#!/usr/bin/env zsh
ZINIT_HOME="${XDG_DATA_HOME:-${HOME}/.local/share}/zinit/zinit.git"
[ ! -d $ZINIT_HOME ] && mkdir -p "$(dirname $ZINIT_HOME)"
[ ! -d $ZINIT_HOME/.git ] && git clone https://github.com/zdharma-continuum/zinit.git "$ZINIT_HOME"
# not to use aliases: zi or zini
declare -A ZINIT
ZINIT[NO_ALIASES]=1
ZINIT[LIST_COMMAND]='lsd --tree'
source "${ZINIT_HOME}/zinit.zsh"
-3
View File
@@ -1,3 +0,0 @@
export XDG_CONFIG_HOME="${HOME}/.config"
export ZDOTDIR="${XDG_CONFIG_HOME}/zsh"
export SHELL_SESSIONS_DISABLE=1