85 Commits
Author SHA1 Message Date
nvrl 08146fe16f final theme 2026-08-11 02:05:46 +02:00
nvrl 105cf6b3a8 updated theme 2026-08-11 01:53:26 +02:00
nvrl 0a439d951e updated style 2026-08-11 00:22:59 +02:00
nvrl 47ff5233bd added quickshell 2026-08-10 23:57:26 +02:00
nvrl cbaf55cfc5 updated 2026-08-10 22:36:16 +02:00
nvrl ad1b8fe3a9 update 2026-05-09 07:21:33 +02:00
nvrl 667e42ba15 updated keybinds and window rules 2026-05-01 20:56:23 +02:00
nvrl 5e6d48b30a added window rules and services 2026-04-29 13:37:25 +02:00
nvrl 9e8411a176 updated configs 2026-04-06 01:17:40 +02:00
nvrl 6d5d2caeca added fluxo and hyprlock conf 2026-04-04 16:44:12 +02:00
nvrl 86c964c274 fixed style css and updated config 2026-04-04 14:42:56 +02:00
nvrl 7958f17951 updated waybar + fluxo 2026-04-04 14:07:35 +02:00
nvrl 9365615f06 updated waybar config 2026-04-04 05:10:21 +02:00
nvrl f910af8dce removed splash and increased refresh intervals 2026-04-02 18:47:11 +02:00
nvrl 74945d45e9 updated hyprlock 2026-04-02 13:46:16 +02:00
nvrl eadaaa5d52 updated themes, waybar 2026-04-02 13:10:37 +02:00
nvrl 70842dc108 changen clock color 2026-04-01 17:44:08 +02:00
nvrl 1e811035a5 updated waybar + hypr rules 2026-03-31 10:20:16 +02:00
nvrl 9dda38ceee fire/ice theme 2026-03-24 23:47:28 +01:00
nvrl f2c432ff2c fixed brightness ctrl and max volume 2026-03-24 14:40:58 +01:00
nvrl 233ef1e291 fixed gamemode style 2026-03-23 17:26:36 +01:00
nvrl db7d5d17a6 added nvim submodule 2026-03-22 14:05:27 +01:00
nvrl 70de42923c removed nvim repo 2026-03-22 14:03:13 +01:00
nvrl dae66e3608 updated icons of nvim config 2026-03-20 13:52:27 +01:00
nvrl 2fb95b16e8 updated neovim config 2026-03-20 13:14:03 +01:00
nvrl 89ce9ab548 updated neovim config 2026-03-20 10:05:56 +01:00
nvrl 146429f594 fixed some waybar styling 2026-03-14 15:02:08 +01:00
nvrl 13bc86f713 fixed lid handling with lidstate file 2026-03-14 15:01:31 +01:00
nvrl e8ef6712af updated gitignore and waybar 2026-03-13 17:53:30 +01:00
nvrl d7c1b0e733 updated waybar 2026-03-13 17:38:40 +01:00
nvrl 20ea9cc4d1 updated hypr config 2026-03-13 17:28:56 +01:00
nvrl bc9e2b7c19 added fluxo 2026-03-13 17:28:37 +01:00
nvrl 85feb977a1 updated dotfiles 2026-02-24 22:44:05 +01:00
nvrl 5356157750 updated waybar script to not crash with my usb c hub 2026-02-13 19:39:31 +01:00
nvrl 2f31b86e65 updated nvim and fish config 2026-02-13 19:17:39 +01:00
nvrl 6acb9b9aaa updated user systemd services 2026-02-13 19:17:22 +01:00
nvrl 918c52f6f3 added gitzip + hypr config 2026-02-07 04:02:48 +01:00
nvrl c93e9cf826 updated hypr dots + fixed waybar cpu style 2026-01-28 12:49:34 +01:00
nvrl 8c8ca7b0f2 updated dots 2026-01-14 11:28:55 +01:00
nvrl fe2e971850 updated some stuff 2025-11-25 00:29:47 +01:00
nvrl fb67c05bb6 added zen browser + window rule for opening workspaces 2025-10-22 15:31:01 +02:00
nvrl edcfc9d911 updated hyprland config + gdrive mount 2025-10-21 13:10:45 +02:00
nvrl 801d990154 added systemd service for gdrive 2025-09-11 13:44:08 +02:00
nvrl 9679cb29f0 updated hypr conf 2025-09-11 13:39:55 +02:00
nvrl 7d16572181 rearranged modules 2025-09-09 10:38:59 +02:00
nvrl d835a4c4ab fixed waybar 2025-09-09 09:53:57 +02:00
nvrl 6af5a295b1 added input module 2025-09-09 09:33:04 +02:00
nvrl 8e5a15395a updated network script 2025-09-08 03:17:41 +02:00
nvrl 653591289d updated nvim init.lua and waybar network module 2025-08-29 14:38:51 +02:00
nvrl 251b5a5eeb upadted waybar + hypr theme 2025-08-29 01:12:56 +02:00
nvrl 02e48b7d1e updated waybar 2025-08-29 00:58:18 +02:00
nvrl 52cc37a102 fixed buds script 2025-08-15 18:06:04 +02:00
nvrl b81c6e2228 updated the not connected string for pixelbuds 2025-08-15 17:23:03 +02:00
nvrl 1b88c5cc71 updated status bar 2025-08-15 16:36:05 +02:00
nvrl 6a3de0df23 updated 2025-08-15 12:59:28 +02:00
nvrl 2a3f8f7294 chnages 2025-08-07 06:06:53 +02:00
nvrl 5599be8150 added fish_vars to ignore 2025-08-04 07:31:22 +02:00
nvrl 5696aeed8d updated hyprland confs 2025-08-02 00:16:14 +02:00
nvrl bc2cabece3 refactored hyprland conf for better maintainability 2025-08-01 10:03:02 +02:00
nvrl bab1718ea5 added wallpapers 2025-08-01 09:45:23 +02:00
nvrl 9f31f26325 added different wallpapers 2025-07-31 10:53:09 +02:00
nvrl c6d9cfc270 added packages + fuzzel 2025-07-30 12:08:36 +02:00
nvrl 7850c7bb0e added fish config 2025-07-30 11:46:46 +02:00
nvrl 44b40bc8e7 added updated rice pics 2025-07-23 23:37:08 +02:00
nvrl 53b1b5bc27 added btop 2025-07-23 23:04:08 +02:00
nvrl 0244eef63d added submodules 2025-07-23 23:01:04 +02:00
nvrl e32ff37a24 removed waybar catppuccin git 2025-07-23 22:30:40 +02:00
nvrl dc30bbe28d added btop 2025-07-23 22:23:45 +02:00
nvrl 97b5d87d30 added pixel buds control 2025-07-23 20:58:55 +02:00
nvrl 23e2f7492e updated font and lock 2025-07-23 14:14:05 +02:00
nvrl a4434d7f97 fixed battery display 2025-07-23 12:46:08 +02:00
nvrl 1ed4ef0963 fixed deprecation in nvim 2025-07-23 12:23:52 +02:00
nvrl ec15fc0bcd edited dunstrc 2025-07-23 11:43:05 +02:00
nvrl beaf8a4547 updated screenshot 2025-07-23 11:24:52 +02:00
nvrl 6ddc32b262 some tweaks 2025-07-23 11:22:08 +02:00
nvrl c7e388d153 added readme 2025-07-23 10:53:43 +02:00
nvrl 7d06bfd2c1 wallpaper 2025-07-23 10:52:01 +02:00
nvrl 99ffef8803 added protonvpn and change waybar style 2025-07-23 10:28:32 +02:00
nvrl 090a0186f9 updated waybar and uswm for hyprland 2025-07-23 10:03:41 +02:00
nvrl 569cfeb68f added chromium and brave flags 2025-07-19 13:51:47 +02:00
nvrl a5327dd263 updatde alacritty and nvim 2025-07-19 13:50:57 +02:00
nvrl c7cda90e07 added fuzzel 2025-07-12 14:16:59 +02:00
nvrl 976842b66e added zathura and mineapps 2025-07-12 11:33:23 +02:00
nvrl 3eb06362a9 added files 2025-07-12 11:31:54 +02:00
nvrl c8b5f931f9 added gitignore 2025-07-12 11:30:13 +02:00
177 changed files with 12846 additions and 2375 deletions
+4
View File
@@ -6,7 +6,9 @@
!alacritty/
!dunst/
!hypr/
!hyprpanel/
!nvim/
!quickshell/
!waybar/
!zathura/
!mimeapps.list
@@ -23,3 +25,5 @@
!wireplumber/
!systemd/
fish/fish_variables
waybar/fluxo-rs
!fluxo/
+15 -12
View File
@@ -1,12 +1,3 @@
[submodule "zathura/catppuccin-zathura"]
path = zathura/catppuccin-zathura
url = https://github.com/catppuccin/zathura.git
[submodule "nvim/pack/nvim/start/mini.nvim"]
path = nvim/pack/nvim/start/mini.nvim
url = https://github.com/echasnovski/mini.nvim
[submodule "nvim/pack/nvim/start/nvim-lspconfig"]
path = nvim/pack/nvim/start/nvim-lspconfig
url = https://github.com/neovim/nvim-lspconfig
[submodule "waybar/catppuccin-waybar"]
path = waybar/catppuccin-waybar
url = https://github.com/catppuccin/waybar.git
@@ -16,9 +7,21 @@
[submodule "hypr/catppuccin-hyprlock"]
path = hypr/catppuccin-hyprlock
url = https://github.com/catppuccin/hyprlock.git
[submodule "fuzzel/catppuccin-fuzzel"]
path = fuzzel/catppuccin-fuzzel
url = https://github.com/catppuccin/fuzzel.git
[submodule "zathura/catppuccin-zathura"]
path = zathura/catppuccin-zathura
url = https://github.com/catppuccin/zathura.git
[submodule "nvim/pack/nvim/start/mini.nvim"]
path = nvim/pack/nvim/start/mini.nvim
url = https://github.com/echasnovski/mini.nvim
[submodule "nvim/pack/nvim/start/nvim-lspconfig"]
path = nvim/pack/nvim/start/nvim-lspconfig
url = https://github.com/neovim/nvim-lspconfig
[submodule "btop/catppuccin-btop"]
path = btop/catppuccin-btop
url = https://github.com/catppuccin/btop.git
[submodule "fuzzel/catppuccin-fuzzel"]
path = fuzzel/catppuccin-fuzzel
url = https://github.com/catppuccin/fuzzel.git
[submodule "nvim"]
path = nvim
url = https://git.narl.io/nvrl/nvim-config.git
+3 -1
View File
@@ -1,3 +1,5 @@
# desktop rice
# My dotfiles
![image not found](./rice.png)
![image not found](./rice-2.png)
![image not found](./rice-3.png)
+14 -5
View File
@@ -12,7 +12,10 @@ WINIT_X11_SCALE_FACTOR = "1.0"
position = "None"
dynamic_padding = true
decorations = "None"
opacity = 0.9
## Fully opaque, no blur. Persona surfaces are flat ink on flat ground —
## glass and translucency read as a different design language entirely.
opacity = 1.0
blur = false
startup_mode = "Windowed"
dynamic_title = true
@@ -24,10 +27,11 @@ decorations_theme_variant = "None"
columns = 82
lines = 24
## Blank space added around the window in pixels.
## Blank space added around the window in pixels. Roomier than the old 3/0 —
## the text needs to sit inside the crimson border, not against it.
[window.padding]
x = 30
y = 30
x = 12
y = 8
## SCROLLING ------------------------------------------------------
[scrolling]
@@ -103,4 +107,9 @@ ipc_socket = true
## GENERAL --------------------------------------------------------
## Import additional configuration files.
import = ["~/.config/alacritty/colors.toml", "~/.config/alacritty/fonts.toml"]
import = ["~/.config/alacritty/takemi.toml", "~/.config/alacritty/fonts.toml"]
[[keyboard.bindings]]
key = "Return"
mods = "Shift"
chars = "\u001B\r"
+5 -5
View File
@@ -4,26 +4,26 @@
[font]
## Font size in points.
size = 14
size = 10
## When true, Alacritty will use a custom built-in font for box drawing characters and powerline symbols.
builtin_box_drawing = true
## Normal font family.
[font.normal]
family = "Fira Mono"
family = "0xProto Nerd Font Mono"
## If the family is not specified, it will fall back to the value specified for the normal font.
[font.bold]
family = "Fira Mono"
family = "0xProto Nerd Font Mono"
## If the family is not specified, it will fall back to the value specified for the normal font.
[font.italic]
family = "Fira Mono"
family = "0xProto Nerd Font Mono"
## If the family is not specified, it will fall back to the value specified for the normal font.
[font.bold_italic]
family = "Fira Mono"
family = "0xProto Nerd Font Mono"
## Offset is the extra space around each character.
## 'y' can be thought of as modifying the line spacing, and 'x' as modifying the letter spacing.
+86
View File
@@ -0,0 +1,86 @@
## Takemi — matched to ~/.config/quickshell/config/Theme.qml and
## ~/.config/hypr/modules/takemi.conf.
##
## Near-black ground, white text, crimson as the only saturated colour. The
## sixteen ANSI slots still have to be told apart by syntax highlighters, so the
## non-crimson hues survive — but every one of them is pulled down and
## desaturated so nothing competes with the accent. Nothing here is neon.
[colors.primary]
background = "#0a0a0c"
foreground = "#ffffff"
dim_foreground = "#6b6b70"
bright_foreground = "#ffffff"
## Crimson block cursor, black text punched out of it.
[colors.cursor]
text = "#000000"
cursor = "#ff2d40"
[colors.vi_mode_cursor]
text = "#000000"
cursor = "#ffffff"
## Selection is a solid crimson block — the same "active" signal the shell uses.
[colors.selection]
text = "#000000"
background = "#ff2d40"
[colors.search.matches]
foreground = "#000000"
background = "#c8c8ce"
[colors.search.focused_match]
foreground = "#000000"
background = "#ff2d40"
[colors.footer_bar]
foreground = "#000000"
background = "#c8c8ce"
[colors.hints.start]
foreground = "#000000"
background = "#ff2d40"
[colors.hints.end]
foreground = "#000000"
background = "#c8c8ce"
## Red is the accent, exactly. The rest are muted enough to sit behind it.
[colors.normal]
black = "#14141a"
red = "#ff2d40"
green = "#7f9b6a"
yellow = "#d6a24a"
blue = "#6f7d99"
magenta = "#c0566d"
cyan = "#7f9aa0"
white = "#c8c8ce"
[colors.bright]
black = "#3a3a44"
red = "#ff6b78"
green = "#9bb886"
yellow = "#f0c070"
blue = "#8d9bb8"
magenta = "#e07a8e"
cyan = "#9db8bd"
white = "#ffffff"
[colors.dim]
black = "#0f0f13"
red = "#8f1826"
green = "#5c704d"
yellow = "#9c7635"
blue = "#515c70"
magenta = "#8c3f4f"
cyan = "#5c7075"
white = "#6b6b70"
[[colors.indexed_colors]]
index = 16
color = "#ff6b78"
[[colors.indexed_colors]]
index = 17
color = "#ffffff"
+80 -51
View File
@@ -1,18 +1,23 @@
#? Config file for btop v. 1.4.5
#? Config file for btop v.1.4.7
#* Name of a btop++/bpytop/bashtop formatted ".theme" file, "Default" and "TTY" for builtin themes.
#* Themes should be placed in "../share/btop/themes" relative to binary or "$HOME/.config/btop/themes"
color_theme = "/home/narl/.config/btop/themes/catppuccin_mocha.theme"
#* If the theme set background should be shown, set to False if you want terminal background transparency.
theme_background = False
theme_background = false
#* Sets if 24-bit truecolor should be used, will convert 24-bit colors to 256 color (6x6x6 color cube) if false.
truecolor = True
truecolor = true
#* Set to true to force tty mode regardless if a real tty has been detected or not.
#* Will force 16-color mode and TTY theme, set all graph symbols to "tty" and swap out other non tty friendly symbols.
force_tty = False
force_tty = false
#* Option to disable presets. Either the default preset, custom presets, or all presets.
#* "Off" All presets are enabled.
#* "Default" preset is disabled.#* "Custom" presets are disabled.#* "All" presets are disabled.
disable_presets = "Off"
#* Define presets for the layout of the boxes. Preset 0 is always all boxes shown with default settings. Max 9 presets.
#* Format: "box_name:P:G,box_name:P:G" P=(0 or 1) for alternate positions, G=graph symbol to use for box.
@@ -22,10 +27,16 @@ presets = "cpu:1:default,proc:0:default cpu:0:default,mem:0:default,net:0:defaul
#* Set to True to enable "h,j,k,l,g,G" keys for directional control in lists.
#* Conflicting keys for h:"help" and k:"kill" is accessible while holding shift.
vim_keys = True
vim_keys = true
#* Disable all mouse events.
disable_mouse = false
#* Rounded corners on boxes, is ignored if TTY mode is ON.
rounded_corners = True
rounded_corners = true
#* Use terminal synchronized output sequences to reduce flickering on supported terminals.
terminal_sync = true
#* Default symbols to use for graph creation, "braille", "block" or "tty".
#* "braille" offers the highest resolution but might not be included in all fonts.
@@ -53,44 +64,50 @@ graph_symbol_proc = "default"
shown_boxes = "cpu mem net proc"
#* Update time in milliseconds, recommended 2000 ms or above for better sample times for graphs.
update_ms = 2000
update_ms = 1000
#* Processes sorting, "pid" "program" "arguments" "threads" "user" "memory" "cpu lazy" "cpu direct",
#* "cpu lazy" sorts top process over time (easier to follow), "cpu direct" updates top process directly.
proc_sorting = "cpu direct"
proc_sorting = "memory"
#* Reverse sorting order, True or False.
proc_reversed = False
proc_reversed = false
#* Show processes as a tree.
proc_tree = True
proc_tree = true
#* Use the cpu graph colors in the process list.
proc_colors = True
proc_colors = true
#* Use a darkening gradient in the process list.
proc_gradient = True
proc_gradient = true
#* If process cpu usage should be of the core it's running on or usage of the total available cpu power.
proc_per_core = True
proc_per_core = false
#* Show process memory as bytes instead of percent.
proc_mem_bytes = True
proc_mem_bytes = true
#* Show cpu graph for each process.
proc_cpu_graphs = True
proc_cpu_graphs = true
#* Use /proc/[pid]/smaps for memory information in the process info box (very slow but more accurate)
proc_info_smaps = False
proc_info_smaps = false
#* Show proc box on left side of screen instead of right.
proc_left = False
proc_left = false
#* (Linux) Filter processes tied to the Linux kernel(similar behavior to htop).
proc_filter_kernel = False
proc_filter_kernel = false
#* Should the process list follow the selected process when detailed view is open.
proc_follow_detailed = true
#* In tree-view, always accumulate child process resources in the parent process.
proc_aggregate = False
proc_aggregate = false
#* Should cpu and memory usage display be preserved for dead processes when paused.
keep_dead_proc_usage = false
#* Sets the CPU stat shown in upper half of the CPU graph, "total" is always available.
#* Select from a list of detected attributes from the options menu.
@@ -104,28 +121,28 @@ cpu_graph_lower = "Auto"
show_gpu_info = "Auto"
#* Toggles if the lower CPU graph should be inverted.
cpu_invert_lower = True
cpu_invert_lower = true
#* Set to True to completely disable the lower CPU graph.
cpu_single_graph = False
cpu_single_graph = false
#* Show cpu box at bottom of screen instead of top.
cpu_bottom = False
cpu_bottom = false
#* Shows the system uptime in the CPU box.
show_uptime = True
show_uptime = true
#* Shows the CPU package current power consumption in watts. Requires running `make setcap` or `make setuid` or running with sudo.
show_cpu_watts = True
show_cpu_watts = true
#* Show cpu temperature.
check_temp = True
check_temp = true
#* Which sensor to use for cpu temperature, use options menu to select from list of available sensors.
cpu_sensor = "Auto"
#* Show temperatures for cpu cores also if check_temp is True and sensors has been found.
show_coretemp = True
show_coretemp = true
#* Set a custom mapping between core and coretemp, can be needed on certain cpus to get correct temperature for correct core.
#* Use lm-sensors or similar to see which cores are reporting temperatures on your machine.
@@ -137,17 +154,20 @@ cpu_core_map = ""
temp_scale = "celsius"
#* Use base 10 for bits/bytes sizes, KB = 1000 instead of KiB = 1024.
base_10_sizes = False
base_10_sizes = false
#* Show CPU frequency.
show_cpu_freq = True
show_cpu_freq = true
#* How to calculate CPU frequency, available values: "first", "range", "lowest", "highest" and "average".
freq_mode = "first"
#* Draw a clock at top of screen, formatting according to strftime, empty string to disable.
#* Special formatting: /host = hostname | /user = username | /uptime = system uptime
clock_format = "%X"
#* Update main ui in background when menus are showing, set this to false if the menus is flickering too much for comfort.
background_update = True
background_update = true
#* Custom cpu model name, empty string to disable.
custom_cpu_name = ""
@@ -157,58 +177,61 @@ custom_cpu_name = ""
disks_filter = ""
#* Show graphs instead of meters for memory values.
mem_graphs = True
mem_graphs = true
#* Show mem box below net box instead of above.
mem_below_net = False
mem_below_net = false
#* Count ZFS ARC in cached and available memory.
zfs_arc_cached = True
zfs_arc_cached = true
#* If swap memory should be shown in memory box.
show_swap = True
show_swap = true
#* Show swap as a disk, ignores show_swap value above, inserts itself after first disk.
swap_disk = True
swap_disk = true
#* If mem box should be split to also show disks info.
show_disks = True
show_disks = true
#* Filter out non physical disks. Set this to False to include network disks, RAM disks and similar.
only_physical = True
only_physical = true
#* Read disks list from /etc/fstab. This also disables only_physical.
use_fstab = True
use_fstab = true
#* Setting this to True will hide all datasets, and only show ZFS pools. (IO stats will be calculated per-pool)
zfs_hide_datasets = False
zfs_hide_datasets = false
#* Set to true to show available disk space for privileged users.
disk_free_priv = False
disk_free_priv = false
#* Toggles if io activity % (disk busy time) should be shown in regular disk usage view.
show_io_stat = True
show_io_stat = true
#* Toggles io mode for disks, showing big graphs for disk read/write speeds.
io_mode = False
io_mode = false
#* Set to True to show combined read/write io graphs in io mode.
io_graph_combined = False
io_graph_combined = false
#* Set the top speed for the io graphs in MiB/s (100 by default), use format "mountpoint:speed" separate disks with whitespace " ".
#* Example: "/mnt/media:100 /:20 /boot:1".
io_graph_speeds = ""
#* Swap the positions of the upload and download speed graphs. When true, upload will be on top.
swap_upload_download = false
#* Set fixed values for network graphs in Mebibits. Is only used if net_auto is also set to False.
net_download = 100
net_upload = 100
#* Use network graphs auto rescaling mode, ignores any values set above and rescales down to 10 Kibibytes at the lowest.
net_auto = True
net_auto = true
#* Sync the auto scaling for download and upload to whichever currently has the highest scale.
net_sync = True
net_sync = true
#* Starts with the Network Interface specified here.
net_iface = ""
@@ -217,29 +240,35 @@ net_iface = ""
base_10_bitrate = "Auto"
#* Show battery stats in top right if battery is present.
show_battery = True
show_battery = true
#* Which battery to use if multiple are present. "Auto" for auto detection.
selected_battery = "Auto"
#* Show power stats of battery next to charge indicator.
show_battery_watts = True
show_battery_watts = true
#* Set loglevel for "~/.config/btop/btop.log" levels are: "ERROR" "WARNING" "INFO" "DEBUG".
#* Set loglevel for "~/.local/state/btop.log" levels are: "ERROR" "WARNING" "INFO" "DEBUG".
#* The level set includes all lower levels, i.e. "DEBUG" will show all logging info.
log_level = "WARNING"
#* Automatically save current settings to config file on exit.
save_config_on_exit = true
#* Measure PCIe throughput on NVIDIA cards, may impact performance on certain cards.
nvml_measure_pcie_speeds = True
nvml_measure_pcie_speeds = true
#* Measure PCIe throughput on AMD cards, may impact performance on certain cards.
rsmi_measure_pcie_speeds = True
rsmi_measure_pcie_speeds = true
#* Horizontally mirror the GPU graph.
gpu_mirror_graph = True
gpu_mirror_graph = true
#* Set which GPU vendors to show. Available values are "nvidia amd intel apple"
shown_gpus = "nvidia amd intel"
#* Custom gpu0 model name, empty string to disable.
custom_gpu_name0 = ""
custom_gpu_name0 = "Radeon Vega"
#* Custom gpu1 model name, empty string to disable.
custom_gpu_name1 = ""
+3
View File
@@ -0,0 +1,3 @@
--enable-features=AcceleratedVideoDecodeLinuxGL,DefaultANGLEVulkan,VaapiIgnoreDriverChecks,Vulkan,VulkanFromANGLE,AcceleratedVideoDecodeLinuxGL,AcceleratedVideoDecodeLinuxZeroCopyGL,AcceleratedVideoEncoder
--use-angle=vulkan
--use-gl=angle
+2 -2
View File
@@ -1,10 +1,10 @@
[global]
corner_radius = 4
transparency = 90
frame_color = "#94e2d5"
frame_color = "#f38ba8"
frame_width = 1
separator_color= frame
highlight = "#89b4fa"
highlight = "#89dceb"
[urgency_low]
background = "#1e1e2e"
+14
View File
@@ -0,0 +1,14 @@
# This file was created by fish when upgrading to version 4.3, to migrate
# the 'fish_key_bindings' variable from its old default scope (universal)
# to its new default scope (global). We recommend you delete this file
# and configure key bindings in ~/.config/fish/config.fish if needed.
set --global fish_key_bindings fish_vi_key_bindings
# Prior to version 4.3, fish shipped an event handler that runs
# `set --universal fish_key_bindings fish_default_key_bindings`
# whenever the fish_key_bindings variable is erased.
# This means that as long as any fish < 4.3 is still running on this system,
# we cannot complete the migration.
# As a workaround, erase the universal variable at every shell startup.
set --erase --universal fish_key_bindings
+7
View File
@@ -0,0 +1,7 @@
# Path to Oh My Fish install.
set -q XDG_DATA_HOME
and set -gx OMF_PATH "$XDG_DATA_HOME/omf"
or set -gx OMF_PATH "$HOME/.local/share/omf"
# Load Oh My Fish configuration.
source $OMF_PATH/init.fish
+50
View File
@@ -0,0 +1,50 @@
# Takemi — matched to ~/.config/quickshell/config/Theme.qml,
# ~/.config/alacritty/takemi.toml and ~/.config/nvim/lua/takemi.lua.
#
# Replaces the catppuccin fish_frozen_theme.fish that fish 4.3 generated on
# upgrade. Same content as themes/Takemi.theme — that copy exists only so
# `fish_config` can preview it; this one is what actually loads.
#
# Note that `fish_config` writing a theme from the web UI will recreate
# fish_frozen_theme.fish, which sorts before this file and so would lose.
set --global fish_color_normal ffffff
set --global fish_color_command ffffff --bold
set --global fish_color_keyword ff2d40
set --global fish_color_param c8c8ce
set --global fish_color_option 8d9bb8
set --global fish_color_quote 7f9b6a
set --global fish_color_escape 9db8bd
set --global fish_color_operator c8c8ce
set --global fish_color_redirection ff6b78
set --global fish_color_end 6b6b70
set --global fish_color_comment 6b6b70 --italics
set --global fish_color_error ff2d40 --bold
set --global fish_color_cancel ff2d40
set --global fish_color_gray 6b6b70
set --global fish_color_autosuggestion 4a4a52
set --global fish_color_selection 000000 --background=ff2d40
set --global fish_color_search_match 000000 --background=c8c8ce
set --global fish_color_match 000000 --background=ff2d40
set --global fish_color_history_current --bold
set --global fish_color_valid_path --underline
set --global fish_color_cwd ffffff --bold
set --global fish_color_cwd_root ff2d40 --bold
set --global fish_color_user c8c8ce
set --global fish_color_host ffffff --bold
set --global fish_color_host_remote ff6b78
set --global fish_color_status ff2d40
set --global fish_pager_color_progress 6b6b70 --background=141418
set --global fish_pager_color_background
set --global fish_pager_color_prefix ffffff --bold
set --global fish_pager_color_completion c8c8ce
set --global fish_pager_color_description 6b6b70
set --global fish_pager_color_secondary_background --background=0d0d10
set --global fish_pager_color_secondary_completion c8c8ce
set --global fish_pager_color_secondary_description 6b6b70
set --global fish_pager_color_secondary_prefix ffffff --bold
set --global fish_pager_color_selected_background --background=ff2d40
set --global fish_pager_color_selected_completion 000000
set --global fish_pager_color_selected_description 000000
set --global fish_pager_color_selected_prefix 000000 --bold
+34
View File
@@ -1,9 +1,43 @@
if status is-interactive
# Commands to run in interactive sessions can go here
end
# set SPACESHIP_PROMPT_ADD_NEWLINE false
# set SPACESHIP_TIME_SHOW false
# set SPACESHIP_USER_SHOW always
# set SPACESHIP_HOST_SHOW true
# set SPACESHIP_CHAR_SYMBOL ""
# set SPACESHIP_CHAR_SYMBOL=" "
# set SPACESHIP_VI_MODE_INSERT 
# set SPACESHIP_VI_MODE_NORMAL 
# Set the cursor shapes for the different vi modes.
set fish_cursor_default block blink
set fish_cursor_insert line blink
set fish_cursor_replace_one underscore blink
set fish_cursor_visual block
# starship init fish | source
fish_vi_key_bindings
if test -e ~/.cache/wal/colors.fish
source ~/.cache/wal/colors.fish
end
zoxide init --cmd cd fish | source
set -gx PATH ~/.local/bin $PATH
# if not pgrep --full ssh-agent | string collect > /dev/null
# eval (ssh-agent -c)
# set -Ux SSH_AGENT_PID $SSH_AGENT_PID
# set -Ux SSH_AUTH_SOCK $SSH_AUTH_SOCK
# end
# Set SSH_AUTH_SOCK for GNOME Keyring / systemd
# The socket path is predictable
set -l GCR_SSH_SOCK $XDG_RUNTIME_DIR/gcr/ssh
if test -S "$GCR_SSH_SOCK"
set -gx SSH_AUTH_SOCK "$GCR_SSH_SOCK"
end
if status is-login && test -z "$DISPLAY" -a -z "$WAYLAND_DISPLAY"
if uwsm check may-start && uwsm select
exec uwsm start default
end
end
# Claude environments
alias claude="CLAUDE_CONFIG_DIR=~/.claude command claude"
alias claude-work="CLAUDE_CONFIG_DIR=~/.claude-work command claude"
-1
View File
@@ -1,3 +1,2 @@
franciscolourenco/done
jorgebucaran/autopair.fish
catppuccin/fish
-130
View File
@@ -1,130 +0,0 @@
# This file contains fish universal variable definitions.
# VERSION: 3.0
SETUVAR CUDAToolkit_ROOT:/opt/cuda/
SETUVAR DATABASE_URL:sqlite\x3adatabase\x2esqlite
SETUVAR GLFW_IM_MODULE:ibus
SETUVAR MANPAGER:sh\x20\x2dc\x20\x27col\x20\x2dbx\x20\x7c\x20bat\x20\x2dl\x20man\x20\x2dp\x27
SETUVAR RUST_LOG:debug
SETUVAR --export SSH_AGENT_PID:967
SETUVAR --export SSH_AUTH_SOCK:/tmp/ssh\x2dXXXXXX7Ck8nI/agent\x2e966
SETUVAR SXHKD_SHELL:/usr/bin/bash
SETUVAR ZO_CMD:zo
SETUVAR Z_CMD:z
SETUVAR Z_DATA:/home/narl/\x2elocal/share/z/data
SETUVAR Z_DATA_DIR:/home/narl/\x2elocal/share/z
SETUVAR Z_EXCLUDE:\x5e/home/narl\x24
SETUVAR __done_min_cmd_duration:5000
SETUVAR __fish_initialized:3800
SETUVAR _fisher_catppuccin_2F_fish_files:\x7e/\x2econfig/fish/themes/Catppuccin\x20Frappe\x2etheme\x1e\x7e/\x2econfig/fish/themes/Catppuccin\x20Latte\x2etheme\x1e\x7e/\x2econfig/fish/themes/Catppuccin\x20Macchiato\x2etheme\x1e\x7e/\x2econfig/fish/themes/Catppuccin\x20Mocha\x2etheme
SETUVAR _fisher_franciscolourenco_2F_done_files:/home/niru/\x2econfig/fish/conf\x2ed/done\x2efish
SETUVAR _fisher_jorgebucaran_2F_autopair_2E_fish_files:/home/niru/\x2econfig/fish/functions/_autopair_backspace\x2efish\x1e/home/niru/\x2econfig/fish/functions/_autopair_insert_left\x2efish\x1e/home/niru/\x2econfig/fish/functions/_autopair_insert_right\x2efish\x1e/home/niru/\x2econfig/fish/functions/_autopair_insert_same\x2efish\x1e/home/niru/\x2econfig/fish/functions/_autopair_tab\x2efish\x1e/home/niru/\x2econfig/fish/conf\x2ed/autopair\x2efish
SETUVAR _fisher_plugins:franciscolourenco/done\x1ejorgebucaran/autopair\x2efish\x1ecatppuccin/fish
SETUVAR _fisher_upgraded_to_4_4:\x1d
SETUVAR fish_color_autosuggestion:6c7086
SETUVAR fish_color_cancel:f38ba8
SETUVAR fish_color_command:89b4fa
SETUVAR fish_color_comment:7f849c
SETUVAR fish_color_cwd:f9e2af
SETUVAR fish_color_cwd_root:red
SETUVAR fish_color_end:fab387
SETUVAR fish_color_error:f38ba8
SETUVAR fish_color_escape:eba0ac
SETUVAR fish_color_gray:6c7086
SETUVAR fish_color_history_current:\x2d\x2dbold
SETUVAR fish_color_host:89b4fa
SETUVAR fish_color_host_remote:a6e3a1
SETUVAR fish_color_keyword:f38ba8
SETUVAR fish_color_match:\x2d\x2dbackground\x3dbrblue
SETUVAR fish_color_normal:cdd6f4
SETUVAR fish_color_operator:f5c2e7
SETUVAR fish_color_option:a6e3a1
SETUVAR fish_color_param:f2cdcd
SETUVAR fish_color_quote:a6e3a1
SETUVAR fish_color_redirection:f5c2e7
SETUVAR fish_color_search_match:\x2d\x2dbackground\x3d313244
SETUVAR fish_color_selection:\x2d\x2dbackground\x3d313244
SETUVAR fish_color_status:f38ba8
SETUVAR fish_color_user:94e2d5
SETUVAR fish_color_valid_path:\x2d\x2dunderline
SETUVAR fish_greeting:\x1d
SETUVAR fish_key_bindings:fish_vi_key_bindings
SETUVAR fish_pager_color_background:\x1d
SETUVAR fish_pager_color_completion:cdd6f4
SETUVAR fish_pager_color_description:6c7086
SETUVAR fish_pager_color_prefix:f5c2e7
SETUVAR fish_pager_color_progress:6c7086
SETUVAR fish_pager_color_secondary_background:\x1d
SETUVAR fish_pager_color_secondary_completion:\x1d
SETUVAR fish_pager_color_secondary_description:\x1d
SETUVAR fish_pager_color_secondary_prefix:\x1d
SETUVAR fish_pager_color_selected_background:\x1d
SETUVAR fish_pager_color_selected_completion:\x1d
SETUVAR fish_pager_color_selected_description:\x1d
SETUVAR fish_pager_color_selected_prefix:\x1d
SETUVAR fish_user_paths:/home/narl/\x2elocal/share/nvim/mason/bin\x1e/home/niru/\x2escripts\x1e/home/niru/Documents/rust\x2ddev/practice\x2drs/target/release\x1e/opt/cuda/bin\x1e/home/niru/\x2e
SETUVAR pure_begin_prompt_with_current_directory:true
SETUVAR pure_check_for_new_release:false
SETUVAR pure_color_at_sign:pure_color_mute
SETUVAR pure_color_aws_profile:pure_color_warning
SETUVAR pure_color_command_duration:pure_color_warning
SETUVAR pure_color_current_directory:pure_color_primary
SETUVAR pure_color_danger:red
SETUVAR pure_color_dark:black
SETUVAR pure_color_git_branch:pure_color_mute
SETUVAR pure_color_git_dirty:pure_color_mute
SETUVAR pure_color_git_stash:pure_color_info
SETUVAR pure_color_git_unpulled_commits:pure_color_info
SETUVAR pure_color_git_unpushed_commits:pure_color_info
SETUVAR pure_color_hostname:pure_color_mute
SETUVAR pure_color_info:cyan
SETUVAR pure_color_jobs:pure_color_normal
SETUVAR pure_color_k8s_context:pure_color_success
SETUVAR pure_color_k8s_namespace:pure_color_primary
SETUVAR pure_color_k8s_prefix:pure_color_info
SETUVAR pure_color_light:white
SETUVAR pure_color_mute:brblack
SETUVAR pure_color_nixdevshell_prefix:pure_color_info
SETUVAR pure_color_nixdevshell_symbol:pure_color_mute
SETUVAR pure_color_normal:normal
SETUVAR pure_color_prefix_root_prompt:pure_color_danger
SETUVAR pure_color_primary:blue
SETUVAR pure_color_prompt_on_error:pure_color_danger
SETUVAR pure_color_prompt_on_success:pure_color_success
SETUVAR pure_color_success:magenta
SETUVAR pure_color_system_time:pure_color_mute
SETUVAR pure_color_username_normal:pure_color_mute
SETUVAR pure_color_username_root:pure_color_light
SETUVAR pure_color_virtualenv:pure_color_mute
SETUVAR pure_color_warning:yellow
SETUVAR pure_enable_aws_profile:true
SETUVAR pure_enable_container_detection:true
SETUVAR pure_enable_git:true
SETUVAR pure_enable_k8s:false
SETUVAR pure_enable_nixdevshell:false
SETUVAR pure_enable_single_line_prompt:false
SETUVAR pure_enable_virtualenv:true
SETUVAR pure_reverse_prompt_symbol_in_vimode:true
SETUVAR pure_separate_prompt_on_error:false
SETUVAR pure_shorten_prompt_current_directory_length:0
SETUVAR pure_shorten_window_title_current_directory_length:0
SETUVAR pure_show_jobs:true
SETUVAR pure_show_prefix_root_prompt:false
SETUVAR pure_show_subsecond_command_duration:false
SETUVAR pure_show_system_time:false
SETUVAR pure_symbol_aws_profile_prefix:
SETUVAR pure_symbol_container_prefix:
SETUVAR pure_symbol_git_dirty:\x2a
SETUVAR pure_symbol_git_stash:\u2261
SETUVAR pure_symbol_git_unpulled_commits:\u21e3
SETUVAR pure_symbol_git_unpushed_commits:\u21e1
SETUVAR pure_symbol_k8s_prefix:\u2638
SETUVAR pure_symbol_nixdevshell_prefix:\u2744\ufe0f
SETUVAR pure_symbol_prefix_root_prompt:\x23
SETUVAR pure_symbol_prompt:\x3e_
SETUVAR pure_symbol_reverse_prompt:\x7c_
SETUVAR pure_symbol_ssh_prefix:
SETUVAR pure_symbol_title_bar_separator:\x2d
SETUVAR pure_symbol_virtualenv_prefix:
SETUVAR pure_threshold_command_duration:5
SETUVAR pure_truncate_prompt_current_directory_keeps:\x2d1
SETUVAR pure_truncate_window_title_current_directory_keeps:\x2d1
-3
View File
@@ -1,3 +0,0 @@
function convert_discord --wraps='ffmpeg -i <source> -s 1280x720 <source>-discord.mp4' --description 'alias convert_discord=ffmpeg -i <source> -s 1280x720 <source>-discord.mp4'
ffmpeg -hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -i $argv[1] -s 1280x720 (string split -r -m1 . $argv[1])[1]-discord.mp4;
end
+3
View File
@@ -0,0 +1,3 @@
function feh --description 'alias feh=feh -.'
command feh -. $argv
end
+34
View File
@@ -0,0 +1,34 @@
function fish_prompt --description 'Write out the prompt'
set -l last_status $status
set -l normal (set_color normal)
# White at rest, crimson when the last command failed — the prompt
# arrow is the one place the shell says "something is wrong", so it is
# the one place that earns the accent. Was brgreen/brpurple, which
# spent colour on states that are not worth any.
set -l status_color (set_color ffffff)
set -l cwd_color (set_color $fish_color_cwd)
set -l vcs_color (set_color 6b6b70)
set -l prompt_status ""
# Since we display the prompt on a new line allow the directory names to be longer.
set -q fish_prompt_pwd_dir_length
or set -lx fish_prompt_pwd_dir_length 0
# Color the prompt differently when we're root
set -l suffix ''
if functions -q fish_is_root_user; and fish_is_root_user
if set -q fish_color_cwd_root
set cwd_color (set_color $fish_color_cwd_root)
end
set suffix '#'
end
# Color the prompt in red on error
if test $last_status -ne 0
set status_color (set_color $fish_color_error)
set prompt_status $status_color "[" $last_status "]" $normal
end
echo -s (prompt_login) ' ' $cwd_color (prompt_pwd) $vcs_color (fish_vcs_prompt) $normal ' ' $prompt_status
echo -n -s $status_color $suffix ' ' $normal
end
-3
View File
@@ -1,3 +0,0 @@
function get_open_ports --wraps='netstat -tunlp' --description 'alias get_open_ports=netstat -tunlp'
netstat -tunlp $argv;
end
+3
View File
@@ -0,0 +1,3 @@
function gitzip
git archive HEAD -o (basename $PWD).zip
end
+1 -1
View File
@@ -1,3 +1,3 @@
function ls --wraps='exa --long --color=auto' --description 'alias ls=exa --long --color=auto'
exa --long --color=auto $argv;
exa -l --color=auto $argv;
end
-3
View File
@@ -1,3 +0,0 @@
function mpv_vr --wraps='mpv --script=360plugin.lua --script-opts=360plugin-enabled=yes' --description 'alias mpv_vr=mpv --script=360plugin.lua --script-opts=360plugin-enabled=yes'
mpv --script=~/.config/mpv/scripts/360plugin.lua --script-opts=360plugin-enabled=yes $argv;
end
+3
View File
@@ -0,0 +1,3 @@
function open -d "Open an application detached from the terminal"
nohup $argv >/dev/null 2>&1 &
end
+52
View File
@@ -0,0 +1,52 @@
# name: 'Takemi'
# url: 'local — matched to ~/.config/quickshell/config/Theme.qml'
# preferred_background: 0a0a0c
# Same rules as the shell and the editor: white does the work, crimson is the
# only saturated colour and it means either "load-bearing" (keyword, prefix,
# selected) or "wrong" (error, status, root). Everything else is grey, or a hue
# pulled far enough down that it reads as grey with a temperature.
#
# Kept in sync by hand with conf.d/takemi_theme.fish, which is what actually
# takes effect at startup. This file exists so `fish_config` can preview it.
fish_color_normal ffffff
fish_color_command ffffff --bold
fish_color_keyword ff2d40
fish_color_param c8c8ce
fish_color_option 8d9bb8
fish_color_quote 7f9b6a
fish_color_escape 9db8bd
fish_color_operator c8c8ce
fish_color_redirection ff6b78
fish_color_end 6b6b70
fish_color_comment 6b6b70 --italics
fish_color_error ff2d40 --bold
fish_color_cancel ff2d40
fish_color_gray 6b6b70
fish_color_autosuggestion 4a4a52
fish_color_selection 000000 --background=ff2d40
fish_color_search_match 000000 --background=c8c8ce
fish_color_match 000000 --background=ff2d40
fish_color_history_current --bold
fish_color_valid_path --underline
fish_color_cwd ffffff --bold
fish_color_cwd_root ff2d40 --bold
fish_color_user c8c8ce
fish_color_host ffffff --bold
fish_color_host_remote ff6b78
fish_color_status ff2d40
fish_pager_color_progress 6b6b70 --background=141418
fish_pager_color_background
fish_pager_color_prefix ffffff --bold
fish_pager_color_completion c8c8ce
fish_pager_color_description 6b6b70
fish_pager_color_secondary_background --background=0d0d10
fish_pager_color_secondary_completion c8c8ce
fish_pager_color_secondary_description 6b6b70
fish_pager_color_secondary_prefix ffffff --bold
fish_pager_color_selected_background --background=ff2d40
fish_pager_color_selected_completion 000000
fish_pager_color_selected_description 000000
fish_pager_color_selected_prefix 000000 --bold
+90
View File
@@ -0,0 +1,90 @@
# fluxo-rs configuration
# Location: ~/.config/fluxo/config.toml
#
# The hardware modules below emit raw pipe-delimited values rather than display
# strings. The Quickshell config (~/.config/quickshell/services/Sys.qml) parses
# them and does its own formatting. The previous human-readable Waybar formats
# are preserved in config.toml.waybar-bak.
[general]
menu_command = "fuzzel --dmenu --prompt \"$FLUXO_PROMPT\""
[signals]
network = 1
cpu = 2
memory = 3
gpu = 4
sys = 5
disk = 6
game = 7
audio = 8
bt = 9
power = 10
mpris = 11
backlight = 12
dnd = 13
[network]
format = "{interface}|{ip}|{rx:.3}|{tx:.3}"
[cpu]
format = "{usage:.1}|{temp:.1}"
[memory]
format = "{used:.2}|{total:.2}"
[sys]
format = "{uptime}|{load1:.2}|{load5:.2}|{load15:.2}"
[disk]
format = "{mount}|{used:.1}|{total:.1}"
[power]
format = "{percentage}"
[audio]
format_sink_unmuted = "{name} {volume:>3}% <span size='large'>{icon}</span>"
format_sink_muted = "{name} <span size='large'> {icon}</span>"
format_source_unmuted = "{name} {volume:>3}% <span size='large'>{icon}</span>"
format_source_muted = "{name} <span size='large'>{icon}</span>"
[bt]
format_plugin = "{alias} [{left}|{right}] {anc} <span size='large'>󰂰</span>"
format_connected = "{alias} <span size='large'>󰂰</span>"
format_disconnected = "Disconnected <span size='large'>󰂯</span>"
format_disabled = "<span size='large'>󰂲</span>"
[game]
format_active = "<span size='large'>󰊖</span>"
format_inactive = "<span size='large'></span>"
[mpris]
format = "{artist} - {title}"
max_length = 20
scroll = true
scroll_speed = 500
scroll_separator = " /// "
[pool]
enabled = false
format = "{used:>4.0}G / {total:>4.0}G"
[gpu]
enabled = true
format_amd = "{usage:.0}|{vram_used:.2}|{vram_total:.2}|{temp:.1}"
format_intel = "{usage:.0}|0|0|0"
format_nvidia = "{usage:.0}|{vram_used:.2}|{vram_total:.2}|{temp:.1}"
[keyboard]
enabled = false
format = "{layout}"
[backlight]
enable = true
format = "{percentage}"
[dnd]
enabled = true
format_dnd = "<span size='large'>󰂛</span>"
format_normal = "<span size='large'>󰂚</span>"
+85
View File
@@ -0,0 +1,85 @@
# fluxo-rs configuration
# Location: ~/.config/fluxo/config.toml
[general]
menu_command = "fuzzel --dmenu --prompt \"$FLUXO_PROMPT\""
[signals]
network = 1
cpu = 2
memory = 3
gpu = 4
sys = 5
disk = 6
game = 7
audio = 8
bt = 9
power = 10
mpris = 11
backlight = 12
dnd = 13
[network]
format = "{interface} ({ip}):  {rx:^4.1} MB/s  {tx:^4.1} MB/s"
[cpu]
format = "CPU: {usage:^4.1}% {temp:^4.1}C"
[memory]
format = "MEM: {used:^4.1}/{total:^4.1}GB"
[sys]
format = "UP: {uptime} LOAD: {load1:^3.1} "
[disk]
format = "{mount} {used:^3.0}/{total:^3.0}G"
[power]
format = "{percentage:>3}% {icon}"
[audio]
format_sink_unmuted = "{name} {volume:>3}% <span size='large'>{icon}</span>"
format_sink_muted = "{name} <span size='large'> {icon}</span>"
format_source_unmuted = "{name} {volume:>3}% <span size='large'>{icon}</span>"
format_source_muted = "{name} <span size='large'>{icon}</span>"
[bt]
format_plugin = "{alias} [{left}|{right}] {anc} <span size='large'>󰂰</span>"
format_connected = "{alias} <span size='large'>󰂰</span>"
format_disconnected = "Disconnected <span size='large'>󰂯</span>"
format_disabled = "<span size='large'>󰂲</span>"
[game]
format_active = "<span size='large'>󰊖</span>"
format_inactive = "<span size='large'></span>"
[mpris]
format = "{artist} - {title}"
max_length = 20
scroll = true
scroll_speed = 500
scroll_separator = " /// "
[pool]
enabled = false
format = "{used:>4.0}G / {total:>4.0}G"
[gpu]
enabled = false
format_amd = "AMD: {usage:>3.0}% {vram_used:>4.1}/{vram_total:>4.1}GB {temp:>4.1}C"
format_intel = "iGPU: {usage:>3.0}%"
format_nvidia = "NV: {usage:>3.0}% {vram_used:>4.1}/{vram_total:>4.1}GB {temp:>4.1}C"
[keyboard]
enabled = false
format = "{layout}"
[backlight]
enable = true
format = " {icon} {percentage}"
[dnd]
enabled = true
format_dnd = "<span size='large'>󰂛</span>"
format_normal = "<span size='large'>󰂚</span>"
+14 -8
View File
@@ -1,13 +1,19 @@
include=~/.config/fuzzel/catppuccin-fuzzel/themes/catppuccin-mocha/mauve.ini
include=~/.config/fuzzel/takemi.ini
[main]
font=FiraCode Nerd Font:size=14
# JetBrainsMono to match Theme.fontMono, so the launcher and the bar are
# visibly the same typeface.
font=JetBrainsMono Nerd Font:size=14
terminal=alacritty
dpi-aware=no
prompt="> "
icon-theme=Papirus-Dark
show-actions=yes
[border]
radius=4
width=2
width=45
lines=8
horizontal-pad=20
vertical-pad=20
inner-pad=10
prompt=" "
show-actions=no
layer=overlay
+37
View File
@@ -0,0 +1,37 @@
# Takemi — matched to ~/.config/quickshell/config/Theme.qml,
# ~/.config/alacritty/takemi.toml and ~/.config/nvim/lua/takemi.lua.
#
# Near-black ground, white text, crimson as the only saturated colour. The
# selection is a solid crimson block with the text punched out of it in black,
# which is the same "active" signal the bar and the terminal use.
[colors]
# Flat and fully opaque. The Persona surfaces are ink on ground — translucency
# and blur read as a different design language, so the alpha stays at ff.
background=0a0a0cff
text=c8c8ceff
input=ffffffff
placeholder=6b6b70ff
prompt=ff2d40ff
# Fuzzy-match characters in an unselected row: crimson, since they are the
# reason the row is on screen at all.
match=ff2d40ff
selection=ff2d40ff
selection-text=000000ff
# White rather than black, so the matched characters still read as marked once
# the row is already crimson.
selection-match=ffffffff
# Deliberately the same as the background — hides the match counter.
counter=0a0a0cff
border=ff2d40ff
[border]
# Square. Every corner in this style is either a right angle or a hard chamfer;
# nothing in the shell is rounded.
radius=0
# Theme.stroke.
width=2
+83
View File
@@ -0,0 +1,83 @@
<div align="center">
<h1>✦ Google-ish Hyprlock Theme ✦</h1>
<h3></h3>
</div>
## ▶️ Preview
<details>
<summary><b>Without Profile & User Info</b></summary>
<img src="https://github.com/user-attachments/assets/7bbacd47-b0d7-4132-9951-53dc0ead604c" alt="Hyprlock-Without-Profile" width="1280">
</details>
<details>
<summary><b>With Profile & User Info</b></summary>
<img src="https://github.com/user-attachments/assets/9a58a6e2-a71f-4b28-998a-8a45c8950aaf" alt="Hyprlock-With-Profile" width="1280">
</details>
<details>
<summary><b>With Profile & User Info [12H Format]</b></summary>
<img src="https://github.com/user-attachments/assets/e0049860-7511-432e-8814-8d17d448182b" alt="Hyprlock-With-Profile" width="1280">
</details>
## 📦 Installation
><i><b>❗ This configuration is based on a 1080p display, if you are using a higher screen resolution,</br>you may need to reconfigure the sizes and recoordinate all the components.</b></i>
<b>Auto-Installation :</b>
```bash
sh -c "$(curl -fsSL https://raw.githubusercontent.com/Tamarindtype/googlish-hyprlock-theme/main/install.sh)"
```
</br><b>Manual Installation :</b>
```bash
# Backup your current Hyprlock config first!
# Clone the repository
git clone https://github.com/Tamarindtype/googlish-hyprlock-theme.git
# Move all the files to the hyprland config folder
mv ./googlish-hyprlock-theme/* ~/.config/hypr/
# Go to script folder
cd $HOME/.config/hypr/hyprlock/
# Change all the scripts permission to make them executable
chmod +x *.sh
# Run the Hyprlock
hyprlock
```
## 🗄️ Directory Structure
```md
$HOME
└── .config
└── hypr
├── hyprlock
│ ├── assets
│ ├── battery.sh
│ ├── bluetooth.sh
│ ├── change_wallpaper.sh
│ ├── greeting.sh
│ ├── network.sh
│ ├── medianotif.sh
│ └── weatherinfo.sh
└── hyprlock.conf
```
## 🗨️ FAQ
| Question | Answer |
| --- | --- |
| Profile & User info does not appear? | By default, it set without profile and user info. You can enable it by uncomment the `image` @PROFILE PICTURE and `label` @USER INFO in `hyprlock.conf` |
| Battery percentage number does not appear? | Change your battery module in `battery.sh`. The default is `BAT0`, you can check it by running this command `ls /sys/class/power_supply/` |
| How to change the 24H Format to 12H Format? | Comment the 24H format and uncomment the 12H format. also uncomment the AM/PM `label` & `shape` in `hyprlock.conf` |
| null location or Unable to determine your location? | Change the IP Geolocation provider in `weatherinfo.sh` |
## 🏅 Recommendations
| Type | Name | Links |
| --- | --- | --- |
| Regular | PP Neue Machina | [Pangram Pangram](https://pangrampangram.com/products/neue-machina) |
| Nerd Font | Geist & Space Mono | [Nerd Fonts](https://github.com/ryanoasis/nerd-fonts/releases) |
| Emoji | Apple Emoji | [apple-emoji-linux](https://github.com/samuelngs/apple-emoji-linux) |
## ✨ Special Thanks & Credits
| Details | Credit |
| --- | --- |
| Battery & Playerctl Widget Scripts | @ashish-kus [minimal Hyprlock](https://gist.github.com/ashish-kus/dd562b0bf5e8488a09e0b9c289f4574c) |
| Helped Me Create Dynamic WiFi, Bluetooth, Weathercast and Greeting Widget | @OPENAI [ChatGPT](https://chatgpt.com/)|
-2
View File
@@ -1,6 +1,5 @@
# narls hyprland dotfiles
source = ~/.config/hypr/modules/plugins.conf
source = ~/.config/hypr/modules/monitors.conf
@@ -17,4 +16,3 @@ source = ~/.config/hypr/modules/input.conf
source = ~/.config/hypr/modules/keybinds.conf
source = ~/.config/hypr/modules/window_rules.conf
+507 -62
View File
@@ -1,100 +1,545 @@
source = $HOME/.config/hypr/catppuccin-hyprland/themes/mocha.conf
# For more information visit https://wiki.hyprland.org/Hypr-Ecosystem/hyprlock/
source = ~/.config/hypr/catppuccin-hyprland/themes/mocha.conf
$scrPath = ~/.config/hypr/hyprlock/
$imgPath = ~/.config/hypr/hyprlock/assets/
$USER = narl # Your Alias
$host = uname -n #Your Alias
$wifi-mode = false # Change the WiFi output. true = show SSID, false = Connected.
$bt-mode = false # Change the Bluetooth output. true = show Device name, false = Connected.
# Default geolocation provider is IP-API.COM, hardcode it if the location does not match the current location.
# Hardcode your location (If hardcode does not recognize your City, change it to IP Geolocation provider in weatherinfo.sh)
$CITY =
$COUNTRY =
# WALLPAPER
# Just comment and uncomment to select
$wallpaper = screenshot
#$wallpaper = ~/your/wallpaper-path.png
$blur = 2
# ADJUST HERE
$rounding = 12
$shape-rd = -1
$font-text = GeistMono Nerd Font Bold
$font-text0 = GeistMono Nerd Font
$font-display = PP Neue Machina Ultra-Bold
$font-symbol = JetBrainsMono Nerd Font Mono
# Input Var
$weight = 2
$inner-color = rgba($baseAlpha80)
$border-color = rgba($mauveAlpha80)
# Colors
$clock-color = $text
$fg0 = $text
$fg1 = $base
$shape-col0 = $mauve
$shape-col1 = rgba($surface0Alpha80)
$shape-col2 = rgba($surface1Alpha80)
$shadow-pass = 2
$shadow-size = 3
$shadow-color = $crust
$shadow-boost = 1.2
$text-shadow-pass = 1
$text-shadow-boost = 0.5
$accent = $mauve
$accentAlpha = $mauveAlpha
$font = JetBrainsMono Nerd Font
# GENERAL
general {
no_fade_in = true
grace = 1
disable_loading_bar = false
hide_cursor = true
ignore_empty_input = true
text_trim = true
}
#BACKGROUND
background {
monitor =
path = $HOME/Pictures/wallpapers/rem-latte.jpg
blur_passes = 0
color = $base
path = $wallpaper
blur_passes = $blur
contrast = 0.8916
brightness = 0.7172
vibrancy = 0.1696
vibrancy_darkness = 0
}
# LAYOUT
# PROFILE PICTURE
image {
monitor =
path = $imgPath/profile.jpg
size = 120 # lesser side if not 1:1 ratio
opacity = 0.25
shadow_pass = $shadow-pass
shadow_size = $shadow-size
shadow_color = $shadow-color
shadow_boost = $shadow-boost
rounding = $rounding # negative values mean circle
border_size = 4
border_color = $mauve
rotate = 0 # degrees, counter-clockwise
position = 20, -20
halign = left
valign = top
zindex = 1
}
# USER INFO
label {
monitor =
text = Layout: $LAYOUT
color = $text
font_size = 25
font_family = $font
position = 30, -30
text = cmd[update:1000] echo -e "$USER\n󰁥 $($host)\n\n$(uname -r)\nPackages: $(pacman -Q | wc -l) pacman"
shadow_passes = 1
shadow_boost = 0.5
color = $fg0
font_size = 11
font_family = $font-text
position = 170, -35
halign = left
valign = top
}
# TIME
# WEATHERCAST & LOCATION
label {
monitor =
text = $TIME
color = $text
font_size = 90
font_family = $font
position = -30, 0
halign = right
valign = top
}
text = cmd[update:1000] echo "$(bash $scrPath/weatherinfo.sh)"
# DATE
label {
monitor =
text = cmd[update:43200000] date +"%A, %d %B %Y"
color = $text
font_size = 25
font_family = $font
position = -30, -150
halign = right
valign = top
}
shadow_passes = 1
shadow_boost = 0.5
# FINGERPRINT
{
monitor = "";
text = "$FPRINTPROMPT";
color = "$text";
font_size = 14;
font_family = $font;
position = "0, -107";
halign = "center";
valign = "center";
}
color = $fg0
font_size = 11
font_family = $font-text
# USER AVATAR
image {
monitor =
path = $HOME/.face
size = 100
border_color = $accent
position = 0, 75
position = 0, -20
halign = center
valign = center
valign = top
}
# INPUT FIELD
input-field {
monitor =
size = 300, 60
outline_thickness = 4
dots_size = 0.2
dots_spacing = 0.2
size = 275, 55
rounding = $rounding
outline_thickness = $weight
outer_color = $border-color
dots_size = 0.1 # Scale of input-field height, 0.2 - 0.8
dots_spacing = 1 # Scale of dots' absolute size, 0.0 - 1.0
dots_center = true
outer_color = $accent
inner_color = $surface0
font_color = $text
inner_color = $inner-color
font_color = $fg0
fade_on_empty = false
placeholder_text = <span foreground="##$textAlpha"><i>󰌾 Logged in as </i><span foreground="##$accentAlpha">$USER</span></span>
font_family = $font-text
placeholder_text = <span foreground="##$textAlpha">󰢏 $USER</span>
hide_input = false
check_color = $accent
check_color = $mauve
fail_color = $red
fail_text = <i>$FAIL <b>($ATTEMPTS)</b></i>
capslock_color = $yellow
position = 0, -47
position = 0, -240
halign = center
valign = center
zindex = 10
}
# TIME HR
label {
monitor =
text = cmd[update:1000] echo -e "$(date +"%H")" # 24-Hour Format
#text = cmd[update:1000] echo -e "$(date +"%I")" # 12-Hour Format
color = $clock-color
shadow_pass = $shadow-pass
shadow_size = $shadow-size
shadow_color = $shadow-color
shadow_boost = $shadow-boost
font_size = 150
font_family = $font-display
position = 0, -155
halign = center
valign = top
}
# TIME MM
label {
monitor =
text = cmd[update:1000] echo -e "$(date +"%M")"
color = $clock-color
shadow_pass = $shadow-pass
shadow_size = $shadow-size
shadow_color = $shadow-color
shadow_boost = $shadow-boost
font_size = 150
font_family = $font-display
position = 0, -325
halign = center
valign = top
}
# AM/PM for 12-Hour Format
#label {
monitor =
text = cmd[update:1000] echo -e "$(date +"%p")"
color = $clock-color
shadow_pass = $shadow-pass
shadow_size = $shadow-size
shadow_color = $shadow-color
shadow_boost = $shadow-boost
font_size = 16
font_family = $font-display
position = 0, 17
halign = center
valign = center
zindex = 5
}
# AM/PM BG
#shape {
monitor =
size = 70, 40
shadow_passes = $text-shadow-pass
shadow_boost = $text-shadow-boost
color = $shape-col2
rounding = $rounding
border_size =
border_color =
position = 0, 20
halign = center
valign = center
zindex = 1
}
# GREETING
label {
monitor =
text = cmd[update:1000] echo "$(bash $scrPath/greeting.sh)"
shadow_passes = $text-shadow-pass
shadow_boost = $text-shadow-boost
color = $fg0
font_size = 11
font_family = $font-text
position = 0, -55
halign = center
valign = center
}
# TODAY IS
label {
monitor =
text = cmd[update:1000] bash -c 'day=$(date +%A); echo "Today is $day"'
shadow_passes = $text-shadow-pass
shadow_boost = $text-shadow-boost
color = $fg0
font_size = 11
font_family = $font-text
position = 0, -75
halign = center
valign = center
}
# DATE
label {
monitor =
text = cmd[update:1000] bash -c 'day=$(date +%d); case "$day" in 1) suffix="st";; 2) suffix="nd";; 3) suffix="rd";; *) suffix="th";; esac; echo -e "$(date +"%B %e")'$day'$suffix, $(date +%Y)"'
shadow_passes = $text-shadow-pass
shadow_boost = $text-shadow-boost
color = $fg0
font_size = 14
font_family = $font-text
position = 0, -115
halign = center
valign = center
}
# BATTERY
label {
monitor =
text = cmd[update:1000] echo -e "$($scrPath/battery.sh)"
color = $fg1
font_size = 12
font_family = $font-text
position = -37, 29
halign = right
valign = bottom
zindex = 5
}
# NETWORK
label {
monitor =
text = cmd[update:1000] echo -e "$($scrPath/network.sh)"
color = $fg1
font_size = 12
font_family = $font-text
position = 37, 29
halign = left
valign = bottom
zindex = 5
}
# BLUETOOTH
label {
monitor =
text = cmd[update:1000] echo -e "$(~/.config/hypr/hyprlock/bluetooth.sh)"
color = $fg1
font_size = 12
font_family = $font-text
position = 37, 85
halign = left
valign = bottom
zindex = 5
}
# BATTERY BG
shape {
monitor =
size = 90, 40
shadow_passes = $text-shadow-pass
shadow_boost = $text-shadow-boost
color = $shape-col0
rounding = $shape-rd
border_size =
border_color =
position = -20, 20
halign = right
valign = bottom
zindex = 1
}
# NETWORK BG
shape {
monitor =
size = 150, 40
shadow_passes = $text-shadow-pass
shadow_boost = $text-shadow-boost
color = $shape-col0
rounding = $shape-rd
border_size =
border_color =
position = 20, 20
halign = left
valign = bottom
zindex = 1
}
# BLUETOOTH BG
shape {
monitor =
size = 150, 40
shadow_passes = $text-shadow-pass
shadow_boost = $text-shadow-boost
color = $shape-col0
rounding = $shape-rd
border_size =
border_color =
position = 20, 75
halign = left
valign = bottom
zindex = 1
}
# MEDIA BG
image {
monitor =
path = $imgPath/media-bg-dark-25.png
size = 8%
opacity = 0.25
rounding = 5
border_size = 0
rotate = 0
position = 0, -10%
halign = center
valign = center
zindex = 1
}
shape {
monitor =
size = 35%, 8%
shadow_passes = $text-shadow-pass
shadow_boost = $text-shadow-boost
color = $shape-col1
rounding = $rounding
border_size =
border_color =
position = 0, 5%
halign = center
valign = bottom
zindex = 1
}
# PLAYER TITLE
label {
monitor =
text = cmd[update:1000] echo "$($scrPath/playerctl.sh --title)"
color = $fg0
font_size = 14
font_family = $font-text
position = 0, -40%
halign = center
valign = center
zindex = 5
}
# PLAYER ARTIST
label {
monitor =
text = cmd[update:1000] echo "$($scrPath/playerctl.sh --artist)"
color = $fg0
font_size = 11
font_family = $font-text
position = 0, -42%
halign = center
valign = center
zindex = 5
}
# PLAYER ALBUM
label {
monitor =
text = cmd[update:1000] echo "$($scrPath/playerctl.sh --album)"
color = $fg0
font_size = 11
font_family = $font-text0
position = 0, -44%
halign = center
valign = center
zindex = 5
}
# PLAYER STATUS SYMBOL
label {
monitor =
text = cmd[update:1000] echo "$($scrPath/playerctl.sh --status-symbol)"
color = $fg0
font_size = 16
font_family = $font-symbol
position = 33.5%, -38%
halign = left
valign = center
zindex = 5
}
# PLAYER STATUS
label {
monitor =
text = cmd[update:1000] echo "$($scrPath/playerctl.sh --status)"
color = $fg0
font_size = 10
font_family = $font-text
position = 35%, -38%
halign = left
valign = center
zindex = 5
}
# PLAYER SOURCE SYMBOL
label {
monitor =
text = cmd[update:1000] echo "$($scrPath/playerctl.sh --source-symbol)"
color = rgba($subtext0Alpha99)
font_size = 16
font_family = $font-symbol
position = -33.5%, -38%
halign = right
valign = center
zindex = 5
}
# PLAYER SOURCE
label {
monitor =
text = cmd[update:1000] echo "$($scrPath/playerctl.sh --source)"
color = rgba($subtext0Alpha99)
font_size = 10
font_family = $font-text
position = -35%, -38%
halign = right
valign = center
zindex = 5
}
label {
monitor =
text =
color = $fg0
font_size = 24
font_family = $font-symbol
position = 0, 1%
halign = center
valign = bottom
}
+155
View File
@@ -0,0 +1,155 @@
source = $HOME/.config/hypr/catppuccin-hyprland/themes/mocha.conf
$accent = $mauve
$accentAlpha = $mauveAlpha
$font = JetBrainsMono Nerd Font
# GENERAL
general {
hide_cursor = true
no_fade_in = false
grace = 0
disable_loading_bar = true
}
# BACKGROUND
background {
monitor =
path = $HOME/Pictures/reze/reze.png
blur_passes = 3
blur_size = 7
noise = 0.0117
contrast = 0.8916
brightness = 0.8172
vibrancy = 0.1696
vibrancy_darkness = 0.0
color = $base
}
# TIME
label {
monitor =
text = $TIME
color = $text
font_size = 120
font_family = $font
position = 0, 300
halign = center
valign = center
}
# DATE
label {
monitor =
text = cmd[update:43200000] date +"%A, %d %B %Y"
color = $text
font_size = 30
font_family = $font
position = 0, 200
halign = center
valign = center
}
# USER AVATAR (Center)
image {
monitor =
path = $HOME/.face
size = 120
border_color = rgba(255, 255, 255, 0.1)
position = 0, 50
halign = center
valign = center
}
# INPUT FIELD (Center)
input-field {
monitor =
size = 300, 60
outline_thickness = 2
dots_size = 0.2
dots_spacing = 0.2
dots_center = true
outer_color = rgba(255, 255, 255, 0.1)
inner_color = rgba(0, 0, 0, 0.2)
font_color = $text
fade_on_empty = false
placeholder_text = <span foreground="##$textAlpha"><i>󰌾 Logged in as </i><span foreground="##$accentAlpha">$USER</span></span>
hide_input = false
check_color = $accent
fail_color = $red
fail_text = <i>$FAIL <b>($ATTEMPTS)</b></i>
capslock_color = $yellow
position = 0, -60
halign = center
valign = center
}
# --- MUSIC DASHBOARD (TOP RIGHT) ---
# ALBUM ART (At the very top right, 80px high, adjusted -3px for perfect alignment)
image {
monitor =
path = /tmp/hyprlock_art.png
size = 80
rounding = 15
border_color = rgba(255, 255, 255, 0.1)
reload_time = 2
reload_cmd = ~/.config/hypr/scripts/album_art.sh
position = -20, -17
halign = right
valign = top
}
# MUSIC TEXT BOX (To the left of the image, same height)
shape {
monitor =
size = 300, 80
color = rgba(0, 0, 0, 0.3)
rounding = 15
border_size = 1
border_color = rgba(255, 255, 255, 0.1)
position = -110, -20
halign = right
valign = top
}
# MUSIC TEXT (Right aligned and vertically centered inside the 80px box)
label {
monitor =
text = cmd[update:1000] ~/.config/hypr/scripts/songdetail.sh
color = $text
font_size = 14
font_family = $font
position = -125, -37
halign = right
valign = top
text_align = right
}
# --- STATUS DASHBOARD (BOTTOM RIGHT) ---
# SYSTEM INFO BOX (Vertical stack container)
shape {
monitor =
size = 300, 100
color = rgba(0, 0, 0, 0.3)
rounding = 15
border_size = 1
border_color = rgba(255, 255, 255, 0.1)
position = -20, 20
halign = right
valign = bottom
}
# SYSTEM INFO TEXT (3 lines, top of each other, right aligned)
label {
monitor =
text = cmd[update:5000] ~/.config/hypr/scripts/status_info.sh
color = $text
font_size = 14
font_family = $font
position = -35, 35
halign = right
valign = bottom
text_align = right
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

+33
View File
@@ -0,0 +1,33 @@
#!/bin/bash
# Get the current battery percentage
battery_percentage=$(cat /sys/class/power_supply/BAT0/capacity)
# Get the battery status (Charging or Discharging)
battery_status=$(cat /sys/class/power_supply/BAT0/status)
# Define the battery icons for each 10% segment
battery_icons=("󰂃" "󰁺" "󰁻" "󰁼" "󰁽" "󰁾" "󰁿" "󰂀" "󰂁" "󰁹")
# Define the charging icon
charging_icon="󰂄"
# Calculate the index for the icon array
# Ensure the index is within bounds (0 to 9) for battery percentages 0 to 100
icon_index=$((battery_percentage / 10))
# If the battery is 100%, use the last icon (index 9)
if [ "$battery_percentage" -eq 100 ]; then
icon_index=9
fi
# Get the corresponding icon
battery_icon=${battery_icons[$icon_index]}
# Check if the battery is charging
if [ "$battery_status" = "Charging" ]; then
battery_icon="$charging_icon"
fi
# Output the battery percentage and icon
echo "$battery_percentage% $battery_icon"
+47
View File
@@ -0,0 +1,47 @@
#!/bin/bash
# Path to the Hyprland configuration file
config_file="$HOME/.config/hypr/hyprlock.conf"
# Read the bt-mode value from the configuration file
bt_mode=$(grep -oP '^\$bt-mode\s*=\s*\K\S+' ~/.config/hypr/hyprlock.conf)
# Get Bluetooth power status
bluetooth_status=$(bluetoothctl show | grep "Powered:" | awk '{print $2}')
# Check if Bluetooth is powered on
if [ "$bluetooth_status" != "yes" ]; then
echo "󰂯 Bluetooth Off"
exit 0
fi
# Initialize connected devices
connected_devices=$(echo "$connected_devices" | sed 's/[[:space:]]*$//')
# Process Bluetooth devices
while read -r line; do
echo "Processing line: $line" >&2
device_mac=$(echo "$line" | awk '{print $2}')
device_name=$(echo "$line" | cut -d' ' -f3-)
echo "Device MAC: $device_mac" >&2
echo "Device Name: $device_name" >&2
if bluetoothctl info "$device_mac" | grep -q "Connected: yes"; then
connected_devices+="$device_name "
fi
echo "Finished processing $device_mac" >&2
echo "---" >&2
done < <(bluetoothctl devices)
# If no connected devices, show "No Devices"
if [ -z "$connected_devices" ]; then
echo "󰂲 No Devices"
exit 0
fi
# Display output based on bt-mode
if [ "$bt_mode" = "true" ]; then
echo "󰂯 $connected_devices"
else
echo "󰂯 Connected"
fi
+22
View File
@@ -0,0 +1,22 @@
#!/bin/bash
# Only works if you use SWWW for your wallpapers
SWWW_DIR="$HOME/.cache/swww/"
HYPRLOCK="$HOME/.config/hypr/hyprlock.conf"
# Get a Monitor Cache File
FIRST_FILE=$(find "$SWWW_DIR" -type f | head -n 1)
# Check if SWWW file exists
if [ -n "$FIRST_FILE" ] && [ -f "$FIRST_FILE" ]; then
WALLPAPER=$(sed -n '2p' "$FIRST_FILE")
sed -i "s|^\(\$wallpaper[[:space:]]*=[[:space:]]*\).*|\1$WALLPAPER # (screenshot or /path/to/your/wallpaper.jpg)|" "$HYPRLOCK"
echo "Wallpaper path updated to $WALLPAPER"
exit 0
fi
# Error
echo "Fehler: kein Wallpaper gefunden."
exit 1
+32
View File
@@ -0,0 +1,32 @@
#!/bin/bash
# Set your Username
# username="TamarindX"
# Read the username alias from hyprlock.conf
username=$(grep -oP '^\$USER\s*=\s*\K\S+' ~/.config/hypr/hyprlock.conf)
# Check if the username was successfully extracted
if [ -z "$username" ]; then
echo "Username not found in hyprlock.conf."
exit 1
fi
# Get the current hour
hour=$(date +%H)
# Determine the greeting based on the time
if [ "$hour" -ge 5 ] && [ "$hour" -lt 12 ]; then
greeting="Good Morning"
elif [ "$hour" -ge 12 ] && [ "$hour" -lt 17 ]; then
greeting="Good Afternoon"
elif [ "$hour" -ge 17 ] && [ "$hour" -lt 21 ]; then
greeting="Good Evening"
elif [ "$hour" -ge 21 ] && [ "$hour" -lt 24 ]; then
greeting="Good Night"
else
greeting="GO TO SLEEP!"
fi
# Output the combined text
echo -e "Hello, $username! $greeting"
+65
View File
@@ -0,0 +1,65 @@
#!/bin/bash
# Set this variable to control the output
# Set to "true" to show SSID, "false" to show "Connected"
# show_ssid=false
# Read the wifi-mode alias from hyprlock.conf
show_ssid=$(grep -oP '^\$wifi-mode\s*=\s*\K\S+' ~/.config/hypr/hyprlock.conf)
# Check if the SSID was successfully extracted else fallback?!
if [ -z "$show_ssid" ]; then
show_ssid=false
fi
# Check if any Ethernet connection is active
ethernet_connected=$(nmcli -t -f DEVICE,TYPE,STATE dev | grep -E 'ethernet:connected')
# If Ethernet
if [ -n "$ethernet_connected" ]; then
echo "󰈀 Ethernet"
exit 0
fi
# Get Wi-Fi connection status
wifi_status=$(nmcli -t -f WIFI g)
# Check if Wi-Fi is enabled
if [ "$wifi_status" != "enabled" ]; then
echo "󰤮 Wi-Fi Off"
exit 0
fi
# Get active Wi-Fi connection details
wifi_info=$(nmcli -t -f ACTIVE,SSID,SIGNAL dev wifi | grep '^yes')
# If no active connection, show "Disconnected"
if [ -z "$wifi_info" ]; then
echo "󰤮 No Wi-Fi"
exit 0
fi
# Extract SSID
ssid=$(echo "$wifi_info" | cut -d':' -f2)
# Extract signal strength
signal_strength=$(echo "$wifi_info" | cut -d':' -f3)
# Define Wi-Fi icons based on signal strength
wifi_icons=("󰤯" "󰤟" "󰤢" "󰤥" "󰤨") # From low to high signal
# Clamp signal strength between 0 and 100
signal_strength=$((signal_strength < 0 ? 0 : (signal_strength > 100 ? 100 : signal_strength)))
# Calculate the icon index based on signal strength
icon_index=$((signal_strength / 25))
# Get the corresponding icon
wifi_icon=${wifi_icons[$icon_index]}
# Output based on show_ssid variable
if [ "$show_ssid" = true ]; then
echo "$wifi_icon $ssid"
else
echo "$wifi_icon Connected"
fi
+116
View File
@@ -0,0 +1,116 @@
#!/bin/bash
if [ $# -eq 0 ]; then
echo "Usage: $0 --title | --artist | --album | --source | --source-symbol"
exit 1
fi
# Function to get metadata using playerctl
get_metadata() {
key=$1
playerctl metadata --player=%any,chromium,firefox --format "{{ $key }}" 2>/dev/null
}
# Check for arguments
# Function to determine the source and return an icon and text
get_source_info_symbol() {
trackid=$(get_metadata "mpris:trackid")
if [[ "$trackid" == *"firefox"* ]]; then
echo -e "󰈹"
elif [[ "$trackid" == *"spotify"* ]]; then
echo -e ""
elif [[ "$trackid" == *"chromium"* ]]; then
echo -e ""
else
echo ""
fi
}
get_source_info() {
trackid=$(get_metadata "mpris:trackid")
if [[ "$trackid" == *"firefox"* ]]; then
echo -e "Firefox"
elif [[ "$trackid" == *"spotify"* ]]; then
echo -e "Spotify"
elif [[ "$trackid" == *"chromium"* ]]; then
echo -e "Chrome"
else
echo ""
fi
}
# Function to truncate text with ellipsis if necessary
truncate_with_ellipsis() {
text=$1
max_length=$2
if [ ${#text} -gt $max_length ]; then
echo "${text:0:$((max_length - 3))}..."
else
echo "$text"
fi
}
# Parse the argument
case "$1" in
--title)
title=$(get_metadata "xesam:title")
if [ -z "$title" ]; then
echo ""
else
truncate_with_ellipsis "$title" 28 # Limit the output to 50 characters
fi
;;
--artist)
artist=$(get_metadata "xesam:artist")
if [ -z "$artist" ]; then
echo ""
else
truncate_with_ellipsis "$artist" 28 # Limit the output to 50 characters
fi
;;
--status-symbol)
status=$(playerctl status 2>/dev/null)
if [[ $status == "Playing" ]]; then
echo "󰎆"
elif [[ $status == "Paused" ]]; then
echo "󰏥"
else
echo ""
fi
;;
--status)
status=$(playerctl status 2>/dev/null)
if [[ $status == "Playing" ]]; then
echo "Playing Now"
elif [[ $status == "Paused" ]]; then
echo "Paused"
else
echo ""
fi
;;
--album)
album=$(playerctl metadata --player=%any,chromium,firefox --format "{{ xesam:album }}" 2>/dev/null)
if [[ -n $album ]]; then
echo "$album"
else
status=$(playerctl status 2>/dev/null)
if [[ -n $status ]]; then
echo "Not album"
else
truncate_with_ellipsis "$album" 28 # Limit the output to 50 characters
fi
fi
;;
--source-symbol)
get_source_info_symbol
;;
--source)
get_source_info
;;
*)
echo "Invalid option: $1"
echo "Usage: $0 --title | --artist | --album | --source | --source-symbol"
exit 1
;;
esac
+39
View File
@@ -0,0 +1,39 @@
#!/bin/bash
# Get location data using IP Geolocation
# Recommended with API, but you can try w/o API [IPINFO.IO]
# API_TOKEN="YOUR_API_TOKEN"
# location_data=$(curl -s "https://ipinfo.io?token=$API_TOKEN" 2>/dev/null)
# location_data=$(curl -s https://ipinfo.io 2>/dev/null) #[Limited requests. Require API to send 50k request/month]
# Extract city and country code (ISO 3166-1 alpha-2 code)
# CITY=$(echo "$location_data" | jq -r '.city // empty')
# COUNTRY=$(echo "$location_data" | jq -r '.country // empty')
# IPINFO Alternative [IP-API.COM]
location_data=$(curl -s "http://ip-api.com/json/" 2>/dev/null)
# Extract city and country code
CITY=$(echo "$location_data" | jq -r '.city // empty')
COUNTRY=$(echo "$location_data" | jq -r '.countryCode // empty')
# Visit http://ip-api.com/json/ to find other variables
# HARDCODE Location
# CITY=$(grep -oP '^\$CITY\s*=\s*\K.+' ~/.config/hypr/hyprlock.conf)
# COUNTRY=$(grep -oP '^\$COUNTRY\s*=\s*\K.+' ~/.config/hypr/hyprlock.conf)
# Check if CITY and COUNTRY are valid
if [[ -n "$CITY" && -n "$COUNTRY" ]]; then
# Fetch weather info for the detected city from wttr.in
weather_info=$(curl -s "wttr.in/$CITY?format=%c+%C+%t" 2>/dev/null)
# Check if the weather info is valid
if [[ -n "$weather_info" ]]; then
echo "$COUNTRY, $CITY: $weather_info"
else
echo "Weather info unavailable for $COUNTRY, $CITY"
fi
else
echo "Unable to determine your location"
fi
+7 -4
View File
@@ -1,4 +1,7 @@
# preload = ~/Pictures/red_moon/red_moon-latte.jpg
preload = ~/Pictures/wallpapers/rem.jpg
# wallpaper = ,~/Pictures/red_moon/red_moon-latte.jpg
wallpaper = ,~/Pictures/wallpapers/rem.jpg
wallpaper {
monitor =
path = ~/.wallpapers/takemi_1.jpg
fit_mode = cover
}
splash = false
-3
View File
@@ -1,3 +0,0 @@
color_scheme=/usr/share/qt6ct/colors/catppuccin-mocha-maroon.conf
icon_theme=Papirus
style=Fusion
+97
View File
@@ -0,0 +1,97 @@
#!/bin/bash
# Set paths
CONFIG_DIR="$HOME/.config/hypr"
BACKUP_DIR="$CONFIG_DIR/hyprlock-backup-$(date +%Y%m%d%H%M%S)"
REPO_URL="https://github.com/Tamarindtype/googlish-hyprlock-theme.git"
TEMP_DIR="$(mktemp -d)"
read -p "Do you want to see every command executed? [y/N]: " choice
choice=${choice,,}
if [[ "$choice" == "y" ]]; then
SHOW_COMMANDS=true
else
SHOW_COMMANDS=false
fi
run_cmd() {
local desc="$1"
local cmd="$2"
if [[ "$SHOW_COMMANDS" == true ]]; then
echo -e "\n$desc"
echo "-> $cmd"
read -p "Run command? [Y/n]: " confirm
confirm=${confirm,,}
if [[ "$confirm" == "n" ]]; then
echo "⏭ Skipped."
else
eval "$cmd"
fi
else
eval "$cmd"
fi
}
# Backup existing config
if [ -d "$CONFIG_DIR/hyprlock" ] || [ -f "$CONFIG_DIR/hyprlock.conf" ]; then
read -p "Do you want to create a backup of your config? [Y/n]: " choice
choice=${choice,,}
if [[ "$choice" != "n" ]]; then
run_cmd "Creating backup folder" "mkdir -p \"$BACKUP_DIR\""
if [ -d "$CONFIG_DIR/hyprlock" ]; then
run_cmd "Backing up folder" "mv \"$CONFIG_DIR/hyprlock\" \"$BACKUP_DIR/\""
fi
if [ -f "$CONFIG_DIR/hyprlock.conf" ]; then
run_cmd "Backing up file" "mv \"$CONFIG_DIR/hyprlock.conf\" \"$BACKUP_DIR/\""
fi
fi
else
echo "No existing hyprlock config found. Skipping backup."
fi
# Clone the repo
run_cmd "Cloning repository..." "git clone \"$REPO_URL\" \"$TEMP_DIR\""
# Move files
run_cmd "Creating config directory" "mkdir -p \"$CONFIG_DIR\""
if [ -d "$TEMP_DIR/hyprlock" ]; then
run_cmd "Moving hyprlock folder" "mv \"$TEMP_DIR/hyprlock\" \"$CONFIG_DIR/\""
fi
if [ -f "$TEMP_DIR/hyprlock.conf" ]; then
run_cmd "Moving hyprlock.conf" "mv \"$TEMP_DIR/hyprlock.conf\" \"$CONFIG_DIR/\""
fi
# Make scripts executable
if [ -d "$CONFIG_DIR/hyprlock" ]; then
run_cmd "Making scripts executable..." "chmod +x \"$CONFIG_DIR/hyprlock\"/*.sh"
fi
# Optional: Run hyprlock
run_cmd "Running Hyprlock" "hyprlock"
read -p "Do you want to install the 'hyprlock-change-wallpaper' command? [Y/n]: " choice
choice=${choice,,}
if [[ "$choice" != "n" ]]; then
run_cmd "Installing hyprlock-change-wallpaper shortcut" "sudo ln -sf $CONFIG_DIR/hyprlock/change_wallpaper.sh /usr/local/bin/hyprlock-change-wallpaper"
run_cmd "Make command runable" "chmod +x $CONFIG_DIR/hyprlock/change_wallpaper.sh"
if command -v hyprlock-change-wallpaper &>/dev/null; then
echo "hyprlock-change-wallpaper was succesfully installed"
else
echo "Error while installing hyprlock-change-wallpaper."
fi
else
echo "⏭ installation of hyprlock-change-wallpaper skipped"
fi
# Cleanup
run_cmd "Cleaning up temp files..." "rm -rf \"$TEMP_DIR\""
+1
View File
@@ -0,0 +1 @@
+8 -2
View File
@@ -2,14 +2,20 @@
# Autostart necessary processes (like notifications daemons, status bars, etc.)
# Or execute your favorite apps at launch like this:
# Takemi shell — bar, popouts, notifications, OSD, power menu and lock screen.
# Config lives in ~/.config/quickshell. It owns org.freedesktop.Notifications,
# so dunst must stay masked (systemctl --user mask dunst.service).
exec-once = uwsm app -- qs
# exec-once = uwsm app -- waybar
# exec-once = uwsm app -- hyprpanel
# exec-once = uwsm app -- nextcloud --background
exec-once = uwsm app -- nm-applet --indicator
# exec-once = uwsm app -- rclone mount google_drive: ~/gdrive
exec-once = uwsm app -- protonvpn-app
# exec-once = uwsm app -- protonvpn-app
exec-once = uwsm app -- hyprpaper
# exec-once = uwsm app -- /usr/bin/discord --enable-features=UseOzonePlatform --ozone-platform=wayland --start-minimized &> /dev/null
exec-once = sleep 5 && ~/.config/hypr/scripts/replay-ctrl.sh start
# exec-once = sleep 5 && ~/.config/hypr/scripts/replay-ctrl.sh start
# exec-once = uwsm app -- /usr/lib/xdg-desktop-portal-hyprland
exec-once = wl-paste --type text --watch cliphist store # Stores only text data
exec-once = wl-paste --type image --watch cliphist store # Stores only image data
+5 -4
View File
@@ -1,17 +1,18 @@
# See https://wiki.hyprland.org/Configuring/Environment-variables/
# env = INTEL_DEBUG,noccs
# env = WLR_DRM_NO_ATOMIC,1
env = HYPRCURSOR_THEME,Bibata-Modern-Classic
env = HYPRCURSOR_SIZE,24
env = XCURSOR_SIZE,24
env = XCURSOR_THEME,Bibata-Modern-Classic
env = XDG_CURRENT_DESKTOP,Hyprland
env = debug:full_cm_proto,true
# env = debug:full_cm_proto,true
env = QT_QPA_PLATFORMTHEME,qt6ct
env = LIBVA_DRIVER_NAME,radeonsi
env = VDPAU_DRIVER,radeonsi
env = AMD_VULKAN_ICD,RADV
env = MOZ_ENABLE_WAYLAND,1
env = ELECTRON_OZONE_PLATFORM_HINT,wayland
env = AMD_VULKAN_ICD,RADV
env = WLR_NO_HARDWARE_CURSORS,0
env = QT_QPA_PLATFORMTHEME,hyprqt6engine
env = EDITOR,nvim
+17 -4
View File
@@ -1,12 +1,13 @@
# https://wiki.hyprland.org/Configuring/Variables/#input
input {
kb_layout = us
# kb_variant = dvorak-intl, intl
kb_variant = intl
# index 0 = dvorak-intl (default), index 1 = us-intl
# switch with $mainMod ALT, SPACE (see keybinds.conf)
kb_layout = us,us
kb_variant = dvorak-intl,intl
kb_model =
kb_options =
kb_rules =
kb_options = caps:backspace
follow_mouse = 0
@@ -17,3 +18,15 @@ input {
natural_scroll = false
}
}
# Layouts are inherited from the global input block so that layout
# switching applies to these too. Only bind resolution differs here.
device {
name = at-translated-set-2-keyboard
resolve_binds_by_sym = 1
}
device {
name = topre-corporation-hhkb-professional
resolve_binds_by_sym = 1
}
+26 -13
View File
@@ -1,22 +1,37 @@
$mainMod = SUPER # Sets "Windows" key as main modifier
bindl=,switch:on:Lid Switch,exec,~/.config/hypr/scripts/lid_handler.sh close
bindl=,switch:off:Lid Switch,exec,~/.config/hypr/scripts/lid_handler.sh open
bindr = ALT, m, exec, cliphist list | fuzzel --dmenu | cliphist decode | wl-copy
bind = , PRINT, exec, grim -g "$(slurp)" - | wl-copy
bind = SHIFT, PRINT, exec, grim -g "$(slurp)" ~/Pictures/Screenshots/$(date +'%Y-%m-%d_%H-%M-%S').png
bind = CTRL, PRINT, exec, ~/.config/hypr/scripts/screenshot_window.sh copy
bind = CTRL SHIFT, PRINT, exec, ~/.config/hypr/scripts/screenshot_window.sh save
bindr = ALT SHIFT, z, exec, ~/.config/hypr/scripts/replay-ctrl.sh save
bindr = ALT, z, exec, ~/.config/hypr/scripts/replay-ctrl.sh toggle
bindr = ALT SHIFT, c, exec, ~/.config/hypr/scripts/droidcam-ctrl.sh toggle
# general binds
bind = $mainMod, M, exec, pdfs-prompt
bind = $mainMod, B, exec, fluxo bt menu
bind = $mainMod, RETURN, exec, $terminal
bind = $mainMod SHIFT, Q, killactive,
bind = $mainMod CTRL, L, exec, hyprlock
bind = $mainMod CTRL, L, exec, qs ipc call shell lock
bind = $mainMod, E, exec, $fileManager
bind = $mainMod, V, togglefloating,
bind = $mainMod, F, fullscreen,
bind = $mainMod, SPACE, exec, $menu
bind = $mainMod, P, exec, ~/.config/hypr/scripts/powermenu.sh
bind = $mainMod, t, togglesplit, # dwindle
bind = $mainMod, P, exec, qs ipc call shell power
# Takemi shell
bind = $mainMod SHIFT, N, exec, qs ipc call shell toggleDnd
bind = $mainMod CTRL SHIFT, N, exec, qs ipc call shell clearNotifications
bind = $mainMod SHIFT, R, exec, qs ipc call shell reloadConfig
# cycle keyboard layout (dvorak-intl <-> us-intl)
bind = $mainMod ALT, SPACE, exec, hyprctl switchxkblayout all next
# bind = $mainMod, t, togglesplit, # dwindle
bind = $mainMod, n, togglegroup
# Move focus with mainMod + arrow keys
@@ -60,8 +75,8 @@ bind = ALT, Tab, changegroupactive, next
# Example special workspace (scratchpad)
bind = $mainMod, S, togglespecialworkspace, magic
bind = $mainMod SHIFT, S, movetoworkspace, special:magic
bind = $mainMod, S, togglespecialworkspace, virtual
bind = $mainMod SHIFT, S, movetoworkspace, special:virtual
bind = $mainMod, D, togglespecialworkspace, discord
bind = $mainMod SHIFT, D, movetoworkspace, special:discord
@@ -74,17 +89,15 @@ bindm = $mainMod, mouse:272, movewindow
bindm = $mainMod, mouse:273, resizewindow
# Laptop multimedia keys for volume and LCD brightness
bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+
bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle
bindel = ,XF86MonBrightnessUp, exec, brightnessctl -e4 -n2 set 5%+
bindel = ,XF86MonBrightnessDown, exec, brightnessctl -e4 -n2 set 5%-
bindel = ,XF86AudioRaiseVolume, exec, fluxo vol up 5
bindel = ,XF86AudioLowerVolume, exec, fluxo vol down 5
bindel = ,XF86AudioMute, exec, fluxo vol mute
bindel = ,XF86AudioMicMute, exec, fluxo mic mute
bindel = ,XF86MonBrightnessUp, exec, brightnessctl s +10%
bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%-
# Requires playerctl
bindl = , XF86AudioNext, exec, playerctl next
bindl = , XF86AudioPause, exec, playerctl play-pause
bindl = , XF86AudioPlay, exec, playerctl play-pause
bindl = , XF86AudioPrev, exec, playerctl previous
bindel = ,XF86MonBrightnessUp, exec, brightnessctl s 10%+
bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%-
+12 -9
View File
@@ -1,10 +1,13 @@
monitor = desc:Samsung Electric Company LC27G7xT H4ZRA00734, 2560x1440@240, 0x0, 1
# monitorv2 {
# desc = Samsung Electric Company LC27G7xT H4ZRA00734
# mode = 2560x1440@240
# position = 0x0
# scale = 1
# bitdepth = 10
# cm = wide
# }
# laptop screen
monitor = eDP-1, 1920x1080@60, 0x0, 1
# samsung home monitor
# monitor = desc:Samsung Electric Company LC27G7xT H4ZRA00734, 1280x720@240, 0x0, 1
monitor = desc:Samsung Electric Company LC27G7xT H4ZRA00734, 2560x1440@240, -2560x0, 1
# monitor = desc:Samsung Electric Company LC27G7xT H4ZRA00734, 2560x1440@144, 0x0, 1
# monitor = desc:Samsung Electric Company LC27G7xT H4ZRA00734, 1920x1080@144, 0x0, 1
# monitor = desc:Samsung Electric Company LC27G7xT H4ZRA00734, 2560x1440@60, 0x0, 1
# lid_state fallback
source = ~/.config/hypr/lid_state.conf
-38
View File
@@ -1,38 +0,0 @@
exec-once = hyprpm reload -n
# plugin:hyprfocus {
# enabled = yes
# animate_floating = yes
# animate_workspacechange = yes
# focus_animation = shrink
# # Beziers for focus animations
# bezier = bezIn, 0.5,0.0,1.0,0.5
# bezier = bezOut, 0.0,0.5,0.5,1.0
# bezier = overshot, 0.05, 0.9, 0.1, 1.05
# bezier = smoothOut, 0.36, 0, 0.66, -0.56
# bezier = smoothIn, 0.25, 1, 0.5, 1
# bezier = realsmooth, 0.28,0.29,.69,1.08
# # Flash settings
# flash {
# flash_opacity = 0.95
# in_bezier = realsmooth
# in_speed = 0.5
# out_bezier = realsmooth
# out_speed = 3
# }
# # Shrink settings
# shrink {
# shrink_percentage = 0.95
# in_bezier = realsmooth
# in_speed = 1
# out_bezier = realsmooth
# out_speed = 2
# }
# }
#
# plugin:csgo-vulkan-fix {
# res_w = 1280
# res_h = 960
# class = gamescope
# fix_mouse = true
# }
+39
View File
@@ -0,0 +1,39 @@
# Takemi palette — kept in step with ~/.config/quickshell/config/Theme.qml.
#
# Crimson, black, white. Nothing else carries hue.
# ----------------------------------------------------------------- THE KNOB
# The one colour in this setup. Change this line and the window borders,
# group indicators and focus states all recolour with it.
#
# Keep it in step with `readonly property color accent` in
# ~/.config/quickshell/config/Theme.qml, which is what colours the shell.
# Those are the only two places the colour is written.
$accent = rgb(ff2d40)
$accentDim = rgb(8f1826)
$accentSoft = rgb(ff6b78)
# ------------------------------------------------------------------ neutrals
$ink = rgb(000000)
$base = rgb(0a0a0c)
$mantle = rgb(0d0d10)
$surface = rgb(141418)
$surfaceAlt = rgb(1c1c22)
$overlay = rgb(26262e)
$outline = rgb(3a3a44)
$text = rgb(ffffff)
$subtext = rgb(c8c8ce)
$muted = rgb(6b6b70)
# Retired hues, kept as aliases so existing references resolve. The shell has
# no teal any more — the wallpaper is the colour in the composition.
$primary = $text
$primaryDim = rgb(9a9aa2)
$glow = $accent
$blue = $primaryDim
$deep = $surfaceAlt
$warn = $accentSoft
$ok = $text
+83 -59
View File
@@ -1,90 +1,96 @@
# catppuccin mocha theme
source = ~/.config/hypr/catppuccin-hyprland/themes/mocha.conf
# Takemi — Persona 5 flavoured theme, matched to ~/.config/quickshell.
source = ~/.config/hypr/modules/takemi.conf
# Refer to https://wiki.hyprland.org/Configuring/Variables/
# https://wiki.hyprland.org/Configuring/Variables/#general
general {
gaps_in = 5
gaps_out = 5, 5, 5, 5
gaps_out = 6, 8, 8, 8
border_size = 3
border_size = 2
# https://wiki.hyprland.org/Configuring/Variables/#variable-types for info about colors
# col.active_border = rgba(cba6f7ee) rgba(f38ba8ee) 45deg
col.active_border = rgb($mauveAlpha) rgb($blueAlpha) 30deg
col.inactive_border = rgb($surface2Alpha)
# Crimson into its own shadow, on the diagonal. The accent is the only hue
# here — a gradient into a second colour is what put blue in the border.
col.active_border = $accent $accentDim 135deg
col.inactive_border = $outline
# Set to true enable resizing windows by clicking and dragging on borders and gaps
resize_on_border = false
# Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on
allow_tearing = true
allow_tearing = false
layout = dwindle
}
# https://wiki.hyprland.org/Configuring/Variables/#decoration
decoration {
rounding = 4
rounding_power = 1
# Persona 5 has no rounded corners. Neither do we.
rounding = 0
# Change transparency of focused and unfocused windows
# Fully opaque, both states. Flat ink on flat ground.
active_opacity = 1.0
inactive_opacity = 1.0
shadow {
enabled = true
range = 4
range = 18
render_power = 3
color = rgba(1a1a1aee)
offset = 0 4
color = rgba(000000ee)
color_inactive = rgba(00000088)
}
# https://wiki.hyprland.org/Configuring/Variables/#blur
#
# Off. Blur is the signature of the glass-and-frost look, which is the
# opposite of what this theme is doing — every surface here is opaque, flat
# and hard-edged. With nothing translucent left to blur it also costs three
# render passes for no visible result.
blur {
enabled = true
size = 3
passes = 1
vibrancy = 0.1696
enabled = false
}
}
# https://wiki.hyprland.org/Configuring/Variables/#animations
# https://wiki.hyprland.org/Configuring/Animations/
# Quick and clean. Motion should get out of the way, not perform.
#
# The previous pass overdid it: a 1.56 overshoot on every window, an 88% popin
# scale, and a borderangle looping forever so the focused border was in constant
# motion. The bounce is dialled back to a hint, the popin barely scales, and the
# border angle no longer animates at all.
animations {
enabled = yes, please :)
# Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more
bezier = easeOutQuint,0.23,1,0.32,1
bezier = easeInOutCubic,0.65,0.05,0.36,1
bezier = snap, 0.16, 1.00, 0.30, 1.00
bezier = overshoot, 0.34, 1.12, 0.64, 1.00
bezier = hard, 0.55, 0.00, 0.90, 0.35
bezier = linear, 0, 0, 1, 1
bezier = almostLinear,0.5,0.5,0.75,1.0
bezier = quick,0.15,0,0.1,1
animation = global, 1, 10, default
animation = border, 1, 5.39, easeOutQuint
animation = windows, 1, 4.79, easeOutQuint
animation = windowsIn, 1, 4.1, easeOutQuint, popin 87%
animation = windowsOut, 1, 1.49, linear, popin 87%
animation = fadeIn, 1, 1.73, almostLinear
animation = fadeOut, 1, 1.46, almostLinear
animation = fade, 1, 3.03, quick
animation = layers, 1, 3.81, easeOutQuint
animation = layersIn, 1, 4, easeOutQuint, fade
animation = layersOut, 1, 1.5, linear, fade
animation = fadeLayersIn, 1, 1.79, almostLinear
animation = fadeLayersOut, 1, 1.39, almostLinear
animation = workspaces, 1, 1.94, almostLinear, fade
animation = workspacesIn, 1, 1.21, almostLinear, fade
animation = workspacesOut, 1, 1.94, almostLinear, fade
}
animation = global, 1, 4, snap
animation = border, 1, 5, snap
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
dwindle {
pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below
preserve_split = true # You probably want this
animation = windows, 1, 4, snap
animation = windowsIn, 1, 4, overshoot, popin 96%
animation = windowsOut, 1, 2.6, hard, popin 97%
animation = windowsMove, 1, 3.6, snap
animation = fade, 1, 3, snap
animation = fadeIn, 1, 2.4, snap
animation = fadeOut, 1, 1.8, hard
animation = fadeSwitch, 1, 2, snap
animation = fadeShadow, 1, 3, snap
animation = fadeDim, 1, 2.4, snap
animation = layers, 1, 3, snap
animation = layersIn, 1, 3, snap, slide
animation = layersOut, 1, 2, hard, slide
animation = workspaces, 1, 3, snap, slidevert
animation = workspacesIn, 1, 3, snap, slidevert
animation = workspacesOut, 1, 2.4, hard, slidevert
animation = specialWorkspace, 1, 3, snap, slidevert
}
# See https://wiki.hyprland.org/Configuring/Master-Layout/ for more
@@ -92,22 +98,40 @@ master {
new_status = master
}
dwindle {
preserve_split = true
}
# https://wiki.hyprland.org/Configuring/Variables/#misc
misc {
force_default_wallpaper = 0 # Set to 0 or 1 to disable the anime mascot wallpapers
disable_hyprland_logo = true # If true disables the random hyprland logo / anime girl background. :(
vrr = 0
force_default_wallpaper = 0
disable_hyprland_logo = true
# 0 = off, 1 = always, 2 = fullscreen only (G7 is a 240Hz VRR panel)
vrr = 2
font_family = FiraCode Nerd Font
background_color = $base
focus_on_activate = true
}
group {
col.border_active = $accent $accentDim 135deg
col.border_inactive = $outline
groupbar {
font_size = 14
text_color = $text
text_color_inactive = $text
col.active = $maroon
col.inactive = $surface2
font_family = JetBrainsMono Nerd Font
font_size = 11
height = 24
gradients = false
# --- Active Tab ---
col.active = $accent
text_color = $ink
# --- Inactive Tab ---
col.inactive = $surface
text_color_inactive = $muted
indicator_height = 3
}
col.border_active = $maroon $teal 30deg
col.border_inactive = $surface2
}
+71 -69
View File
@@ -1,87 +1,89 @@
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
# See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules
# ==========================================
# VARIABLES
# ==========================================
# Dialogs and utility apps that should float in the center
$dialog_titles = ^(Open Form|Open File|Select a File|Choose a file|Open Workspace|Choose Directory.*|Save As.*|Save File.*|branchdialog|pinentry-gtk-2|Confirm to replace files|File Operation Progress|Open Files.*|Anmelden.*|File Upload.*|TRuDI-Export laden)$
$dialog_classes = ^(pavucontrol|blueman-manager|nm-connection-editor|org.pulseaudio.pavucontrol|io.narl.proton-drive-linux-prompt)$
# App classes
$steam = ^(steam)$
$gamescope = ^(gamescope)$
# ==========================================
# GENERAL & FIXES
# ==========================================
# Ignore maximize requests from apps. You'll probably like this.
windowrule = suppressevent maximize, class:.*
# windowrule = suppress_event maximize, match:class .*
# Fix some dragging issues with XWayland
windowrule = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0
windowrulev2=noblur,class:^()$,title:^()$
# windowrule = no_focus 1, match:class ^$, match:title ^$, match:xwayland 1, match:floating 1, match:fullscreen 0, match:pinned 0
windowrule = no_blur 1, match:class ^$, match:title ^$
# games for tearing add the immediate rule
# ==========================================
# FLOATING & CENTERED DIALOGS
# ==========================================
# Make them float
windowrule = float 1, match:title $dialog_titles
windowrule = float 1, match:class $dialog_classes
# Float Windows
windowrulev2=float,title:^(Open File)$
windowrulev2=float,title:^(Select a File)$
windowrulev2=float,title:^(Select Folder)$
windowrulev2=float,title:^(Choose a file)$
windowrulev2=float,title:^(Save As)$
windowrulev2=float,title:^(Save File)$
windowrulev2=float,title:^(branchdialog)$
windowrulev2=float,title:^(pinentry-gtk-2)$
windowrulev2=float,title:^(Confirm to replace files)$
windowrulev2=float,title:^(File Operation Progress)$
windowrulev2=float,class:^(pavucontrol|blueman-manager|nm-connection-editor)$
# Set to 800x600
windowrule = size 800 600, match:title $dialog_titles
windowrule = size 800 600, match:class $dialog_classes
# Center and Resize Windows
windowrulev2=size 800 600,title:^(Open File)$
windowrulev2=size 800 600,title:^(Select a File)$
windowrulev2=size 800 600,title:^(Choose a file)$
windowrulev2=size 800 600,title:^(Save As)$
windowrulev2=size 800 600,title:^(Save File)$
windowrulev2=size 800 600,title:^(branchdialog)$
windowrulev2=size 800 600,title:^(pinentry-gtk-2)$
windowrulev2=size 800 600,title:^(Confirm to replace files)$
windowrulev2=size 800 600,title:^(File Operation Progress)$
windowrulev2=size 800 600,class:^(pavucontrol|blueman-manager|nm-connection-editor)$
windowrulev2=center,title:^(Open File)$
windowrulev2=center,title:^(Select a File)$
windowrulev2=center,title:^(Choose a file)$
windowrulev2=center,title:^(Save As)$
windowrulev2=center,title:^(Save File)$
windowrulev2=center,title:^(branchdialog)$
windowrulev2=center,title:^(pinentry-gtk-2)$
windowrulev2=center,title:^(Confirm to replace files)$
windowrulev2=center,title:^(File Operation Progress)$
windowrulev2=center,class:^(pavucontrol|blueman-manager|nm-connection-editor)$
windowrulev2=noblur,title:^(Open File)$
windowrulev2=noblur,title:^(Select a File)$
windowrulev2=noblur,title:^(Choose a file)$
windowrulev2=noblur,title:^(Save As)$
windowrulev2=noblur,title:^(Save File)$
windowrulev2=noblur,title:^(branchdialog)$
windowrulev2=noblur,title:^(pinentry-gtk-2)$
windowrulev2=noblur,title:^(Confirm to replace files)$
windowrulev2=noblur,title:^(File Operation Progress)$
windowrulev2=noblur,class:^(pavucontrol|blueman-manager|nm-connection-editor)$
# Center them on the screen
windowrule = center 1, match:title $dialog_titles
windowrule = center 1, match:class $dialog_classes
# Workspace Rules
# windowrule=workspace 1,class:^(firefox)$
# windowrule=workspace 2,class:^(kitty)$
# windowrule=workspace 3,class:^(Code)$
# Disable blur
windowrule = no_blur 1, match:title $dialog_titles
windowrule = no_blur 1, match:class $dialog_classes
windowrulev2=workspace special:magic,class:^(Spotify)$
windowrulev2=workspace special:magic,class:^(spotify)$
windowrulev2=workspace special:discord,class:^(discord|vesktop)$
# windowrulev2=workspace 2, class:^(brave-browser)$
# ==========================================
# WORKSPACE ASSIGNMENTS
# ==========================================
# Normal Workspaces
# windowrule = workspace 1, match:class ^(firefox)$
# windowrule = workspace 2, match:class ^(kitty)$
# windowrule = workspace 3, match:class ^(Code)$
windowrule = workspace 1, match:class $gamescope
# steam rules
# Special Workspaces
windowrule = workspace special:virtual, match:class ^(Spotify|spotify)$
windowrule = workspace special:discord, match:class ^(discord|vesktop)$
windowrulev2=workspace 3 silent, class:^(steam)$, title:^(Steam)$
windowrulev2=workspace 4, class:^(gamescope)$
# fixed sizes for different windows
windowrulev2=size 400 800,title:^(Friends List)$ class:^(steam)$
windowrulev2=size 1000 800,title:^(Steam Settings)$ class:^(steam)$
windowrulev2=size 1000 800,title:^(Add Non-Steam Game)$ class:^(steam)$
# ==========================================
# APP-SPECIFIC RULES: STEAM & GAMING
# ==========================================
# windowrule = workspace 3 silent, match:class $steam, match:title ^(Steam)$
# float windows that arent the main steam window
windowrulev2 = float, class:^(steam)$, title:negative:^(Steam)$
windowrulev2 = noblur, class:^(steam)$, title:negative:^(Steam)$
# windowrulev2 = center, class:^(steam)$, title:negative:^(Steam)$
# Fixed sizes for specific Steam windows
windowrule = size 400 800, match:title ^(Friends List)$, match:class $steam
windowrule = size 1000 800, match:title ^(Steam Settings)$, match:class $steam
windowrule = size 1000 800, match:title ^(Add Non-Steam Game)$, match:class $steam
# allow tearing for games started with gamescope
windowrulev2 = immediate, class:^(gamescope)$
# Float and disable blur for Steam windows that aren't the main window
windowrule = float 1, match:class $steam, match:title negative:^(Steam)$
windowrule = no_blur 1, match:class $steam, match:title negative:^(Steam)$
# windowrule = center 1, match:class $steam, match:title negative:^(Steam)$
# Allow tearing for games started with Gamescope
windowrule = immediate 1, match:class $gamescope
# Layer rules
# waybar blur
layerrule = blur on, match:namespace bottom
layerrule = blur on, match:namespace top
layerrule = ignore_alpha 0.5, match:namespace bottom
layerrule = ignore_alpha 0.5, match:namespace top
# launcher blur
layerrule = blur on, match:namespace launcher
layerrule = ignore_alpha 0.5, match:namespace launcher
+11
View File
@@ -0,0 +1,11 @@
#!/bin/bash
url=$(playerctl metadata mpris:artUrl 2>/dev/null)
if [[ "$url" == file://* ]]; then
cp "${url#file://}" /tmp/hyprlock_art.png
echo "/tmp/hyprlock_art.png"
elif [[ "$url" == http* ]]; then
curl -s "$url" -o /tmp/hyprlock_art.png
echo "/tmp/hyprlock_art.png"
else
echo "$HOME/.config/hypr/catppuccin-hyprland/assets/mocha.webp"
fi
+1 -7
View File
@@ -15,13 +15,7 @@ start() {
notify-send -u low "$PROGRAM_NAME" "$PROGRAM_NAME is starting ..."
ANDROID_SERIAL=$ANDROID_SERIAL droidcam-cli -a -v -size=1920x1080 adb 4747 &> /dev/null &
PID=$!
sleep 1
if ! ps -p "$PID" > /dev/null; then
notify-send -u critical "$PROGRAM_NAME" "$PROGRAM_NAME did not start"
exit 1
fi
echo "$PID" > "$PID_FILE"
echo $! > "$PID_FILE"
}
+54
View File
@@ -0,0 +1,54 @@
#!/bin/bash
# ~/.config/hypr/scripts/lid_handler.sh
# The file that tells Hyprland to keep the lid off during reloads
LID_STATE_FILE="$HOME/.config/hypr/lid_state.conf"
restart_ui() {
# The Quickshell bar follows monitor hotplug on its own, so only the
# wallpaper daemon needs a kick.
systemctl restart --user hyprpaper
}
if [[ "$1" == "close" ]]; then
# Check if ANY external monitor is connected and active
if hyprctl monitors all | grep -qE "Monitor (DP|HDMI|Type-C)-"; then
# Prevent laptop screen from turning on during manual config reloads
echo "monitor=eDP-1, disable" > "$LID_STATE_FILE"
# Extract the CURRENT live settings of all external monitors using jq
# This grabs the active resolution, refresh rate, position, and scale.
LIVE_MONITORS=$(hyprctl -j monitors | jq -c '.[] | select(.name != "eDP-1")')
# 3. Disable the laptop screen
hyprctl keyword monitor "eDP-1, disable"
# 4. Re-apply the live settings to external monitors so they don't reset
echo "$LIVE_MONITORS" | while read -r mon_json; do
NAME=$(echo "$mon_json" | jq -r '.name')
WIDTH=$(echo "$mon_json" | jq -r '.width')
HEIGHT=$(echo "$mon_json" | jq -r '.height')
REFRESH=$(echo "$mon_json" | jq -r '.refreshRate')
X=$(echo "$mon_json" | jq -r '.x')
Y=$(echo "$mon_json" | jq -r '.y')
SCALE=$(echo "$mon_json" | jq -r '.scale')
# Formats it exactly as Hyprland expects: DP-1, 1920x1080@240, 0x0, 1
hyprctl keyword monitor "$NAME, ${WIDTH}x${HEIGHT}@${REFRESH}, ${X}x${Y}, $SCALE"
done
# restart ui
restart_ui
fi
elif [[ "$1" == "open" ]]; then
# Clear the override file so the laptop screen is allowed to turn on again
echo "" > "$LID_STATE_FILE"
# Let Hyprland reload itself.
# This automatically re-enables eDP-1 based on your hardcoded hyprland.conf!
hyprctl reload
restart_ui
fi
+2 -2
View File
@@ -18,14 +18,14 @@ start() {
gpu-screen-recorder \
-w screen \
-f 60 \
-a "default_input|default_output" \
-a default_output -a default_input \
-fm vfr \
-c mkv \
-encoder gpu \
-bm qp \
-cr full \
-tune quality \
-k av1 \
-k av1_10bit \
-q high \
-r 120 \
-replay-storage ram \
+49
View File
@@ -0,0 +1,49 @@
#!/bin/sh
# Get active window info in JSON format
WINDOW_INFO=$(hyprctl activewindow -j)
# Extract window class name (app name)
APP_NAME=$(echo "$WINDOW_INFO" | jq -r '.class')
# If app name is empty, null, or invalid, default to "unknown"
if [ -z "$APP_NAME" ] || [ "$APP_NAME" = "null" ]; then
APP_NAME="unknown"
fi
# Sanitize app name: convert to lowercase and replace characters that aren't letters, numbers, hyphens, or underscores with underscores
APP_NAME_SAFE=$(echo "$APP_NAME" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9_-]/_/g')
# Extract geometry: "x,y wxh"
GEOMETRY=$(echo "$WINDOW_INFO" | jq -r '"\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"')
# Check if geometry is valid
if [ -z "$GEOMETRY" ] || [ "$GEOMETRY" = "null,null nullxnull" ]; then
notify-send -u normal "Screenshot Error" "No active window found to screenshot."
exit 1
fi
ACTION=$1
case "$ACTION" in
copy)
grim -g "$GEOMETRY" - | wl-copy
notify-send -u low "Screenshot" "Active window ($APP_NAME) copied to clipboard"
;;
save)
SCREENSHOTS_DIR="$HOME/Pictures/Screenshots"
APP_DIR="$SCREENSHOTS_DIR/$APP_NAME_SAFE"
mkdir -p "$APP_DIR"
FILE_NAME="$(date +'%Y-%m-%d_%H-%M-%S').png"
FILE_PATH="$APP_DIR/$FILE_NAME"
grim -g "$GEOMETRY" "$FILE_PATH"
notify-send -u low "Screenshot" "Saved active window to $APP_NAME_SAFE/$FILE_NAME"
;;
*)
echo "Usage: $0 {copy|save}"
exit 1
;;
esac
exit 0
+13
View File
@@ -0,0 +1,13 @@
#!/bin/bash
status=$(playerctl status 2>/dev/null)
if [ "$status" = "Playing" ] || [ "$status" = "Paused" ]; then
title=$(playerctl metadata title | sed 's/&/\&amp;/g; s/</\&lt;/g; s/>/\&gt;/g')
artist=$(playerctl metadata artist | sed 's/&/\&amp;/g; s/</\&lt;/g; s/>/\&gt;/g')
if [ ${#title} -gt 25 ]; then title="${title:0:22}..."; fi
if [ ${#artist} -gt 25 ]; then artist="${artist:0:22}..."; fi
echo "<span weight='bold' foreground='#cba6f7'>$title</span>"
echo "<span foreground='#bac2de' size='small'>$artist</span>"
else
echo "<span weight='bold' foreground='#cdd6f4'>No Media</span>"
echo "<span size='small' foreground='#a6adc8'>Idling</span>"
fi
+14
View File
@@ -0,0 +1,14 @@
#!/bin/bash
# 1. Network
net=$(nmcli -t -f active,ssid dev wifi | grep '^yes' | cut -d: -f2 || echo 'Offline')
if [ ${#net} -gt 15 ]; then net="${net:0:12}..."; fi
# 2. Battery
bat_cap=$(cat /sys/class/power_supply/BAT0/capacity)
bat_stat=$(cat /sys/class/power_supply/BAT0/status)
if [ "$bat_stat" = "Charging" ]; then icon="󰂄"; else icon="󰁹"; fi
# 3. Load
cpu=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}' | cut -d. -f1)
# Output 3 lines for the vertical stack
echo "󰖩 $net"
echo "$icon $bat_cap% ($bat_stat)"
echo "󰍛 Load: $cpu%"
+166
View File
@@ -0,0 +1,166 @@
{
"log_level": "LOG_LEVEL_INFO",
"log_subprocesses_to_journal": false,
"dbus": {
"enabled": true,
"connect_timeout": "20s",
"connect_interval": "0.200s",
"notifications": {
"enabled": true
},
"systray": {
"enabled": true
},
"shortcuts": {
"enabled": true
},
"brightness": {
"enabled": true,
"adjust_step_percent": 5,
"min_brightness": 1,
"enable_logind": true,
"hud_notifications": true
},
"power": {
"enabled": true,
"low_percent": 10,
"critical_percent": 5,
"hud_notifications": true
}
},
"audio": {
"enabled": true,
"volume_step_percent": 5,
"volume_exceed_maximum": false,
"hud_notifications": true
},
"panels": [
{
"id": "panel0",
"edge": "EDGE_TOP",
"size": 34,
"monitor": "",
"modules": [
{
"pager": {
"icon_size": 14,
"active_monitor_only": false,
"scroll_wrap_workspaces": true,
"scroll_include_inactive": true,
"enable_workspace_names": false,
"pinned": [1, 2, 3, 4, 5, 6],
"preview_width": 256
}
},
{
"spacer": {
"size": 8,
"expand": false
}
},
{
"taskbar": {
"icon_size": 24,
"active_workspace_only": true,
"active_monitor_only": true,
"group_tasks": true,
"expand": false
}
},
{
"spacer": {
"expand": true
}
},
{
"clock": {
"time_format": "15:04",
"date_format": "%a %d %b",
"tooltip_time_format": "15:04",
"tooltip_date_format": "Monday, 02 January 2006"
}
},
{
"spacer": {
"expand": true
}
},
{
"systray": {
"icon_size": 18,
"menu_icon_size": 18,
"pinned": [
"nm-applet"
],
"modules": [
{
"power": {
"icon_size": 18,
"icon_symbolic": true
}
}
]
}
},
{
"spacer": {
"size": 8,
"expand": false
}
},
{
"notifications": {
"icon_size": 18,
"notification_icon_size": 48,
"default_timeout": "7s",
"position": "POSITION_TOP_RIGHT",
"margin": 24
}
},
{
"spacer": {
"size": 8,
"expand": false
}
},
{
"audio": {
"icon_size": 18,
"icon_symbolic": true,
"command_mixer": "pavucontrol",
"enable_source": true
}
},
{
"spacer": {
"size": 8,
"expand": false
}
},
{
"session": {
"icon_size": 18,
"icon_symbolic": true,
"overlay_icon_size": 64,
"overlay_icon_symbolic": true,
"command_logout": "uwsm stop",
"command_reboot": "systemctl reboot",
"command_suspend": "systemctl suspend",
"command_shutdown": "systemctl poweroff"
}
},
{
"spacer": {
"size": 8,
"expand": false
}
}
]
}
],
"launch_wrapper": [
"uwsm",
"app",
"--"
]
}
+127
View File
@@ -0,0 +1,127 @@
/* Catppuccin Mocha Palette */
@define-color base #1e1e2e;
@define-color mantle #181825;
@define-color crust #11111b;
@define-color surface0 #313244;
@define-color surface1 #45475a;
@define-color surface2 #585b70;
@define-color text #cdd6f4;
@define-color subtext0 #a6adc8;
@define-color subtext1 #bac2de;
@define-color overlay0 #6c7086;
@define-color overlay1 #7f849c;
@define-color overlay2 #9399b2;
@define-color blue #89b4fa;
@define-color lavender #b4befe;
@define-color sapphire #74c7ec;
@define-color sky #89dceb;
@define-color teal #94e2d5;
@define-color green #a6e3a1;
@define-color yellow #f9e2af;
@define-color peach #fab387;
@define-color maroon #eba0ac;
@define-color red #f38ba8;
@define-color mauve #cba6f7;
@define-color flamingo #f2cdcd;
@define-color rosewater #f5e0dc;
* {
font-family: "JetBrainsMono Nerd Font";
font-size: 13px;
border: none;
box-shadow: none;
}
window#panel0 {
background-color: alpha(@base, 0.7);
color: @text;
}
#pager {
margin: 4px;
}
#pager button {
background-color: @surface0;
color: @subtext0;
border-radius: 12px;
margin: 0 2px;
padding: 0 12px;
transition: all 0.2s ease-in-out;
}
#pager button.active {
background-color: @mauve;
color: @base;
}
#pager button:hover {
background-color: @surface1;
color: @text;
}
#taskbar button {
background-color: transparent;
color: @subtext1;
border-radius: 12px;
margin: 0 2px;
padding: 0 8px;
}
#taskbar button.active {
background-color: @surface0;
border-bottom: 2px solid @mauve;
}
#clock, #systray, #audio, #session, #notifications {
background-color: @surface0;
color: @text;
border-radius: 15px;
margin: 4px 3px;
padding: 0 12px;
}
#notifications {
color: @yellow;
}
#clock {
color: @mauve;
font-weight: bold;
}
#audio {
color: @sapphire;
}
#audio.muted {
color: @subtext0;
}
#session {
color: @red;
padding: 0 8px;
}
/* Notifications and HUD */
#notifications {
background-color: @base;
color: @text;
border: 1px solid @surface1;
border-radius: 12px;
}
#hud {
background-color: alpha(@base, 0.8);
color: @text;
border-radius: 20px;
padding: 10px;
}
#hud .progress-bar {
background-color: @surface1;
}
#hud .progress-bar-fill {
background-color: @mauve;
}
+21 -14
View File
@@ -1,35 +1,42 @@
[Default Applications]
text/html=zen.desktop
x-scheme-handler/http=zen.desktop
x-scheme-handler/https=zen.desktop
x-scheme-handler/about=brave-browser.desktop
x-scheme-handler/unknown=brave-browser.desktop
image/png=feh.desktop
x-scheme-handler/discord=vesktop.desktop
application/pdf=org.pwmt.zathura-pdf-poppler.desktop
image/jpeg=feh.desktop
audio/flac=mpv.desktop
x-scheme-handler/ror2mm=r2modman.desktop
image/webp=feh.desktop
image/png=feh.desktop
x-scheme-handler/http=brave-browser.desktop
x-scheme-handler/https=brave-browser.desktop
x-scheme-handler/chrome=zen.desktop
text/html=brave-browser.desktop
application/x-extension-htm=zen.desktop
application/x-extension-html=zen.desktop
application/x-extension-shtml=zen.desktop
application/xhtml+xml=zen.desktop
application/x-extension-xhtml=zen.desktop
application/x-extension-xht=zen.desktop
x-scheme-handler/about=brave-browser.desktop
x-scheme-handler/unknown=brave-browser.desktop
application/vnd.openxmlformats-officedocument.wordprocessingml.document=libreoffice-writer.desktop
x-scheme-handler/ror2mm=r2modman.desktop
image/webp=feh.desktop
x-scheme-handler/claude-cli=claude-code-url-handler.desktop
x-scheme-handler/msteams=teams-for-linux.desktop
x-scheme-handler/slack=slack.desktop
audio/flac=mpv.desktop
x-scheme-handler/codex=ChatGPT.desktop
[Added Associations]
image/png=feh.desktop;
application/pdf=org.pwmt.zathura-pdf-poppler.desktop;
image/jpeg=feh.desktop;
audio/flac=mpv.desktop;
image/webp=feh.desktop;
image/png=feh.desktop;
x-scheme-handler/http=zen.desktop;
x-scheme-handler/https=zen.desktop;
x-scheme-handler/chrome=zen.desktop;
text/html=zen.desktop;
x-scheme-handler/chrome=zen.desktop;
application/vnd.openxmlformats-officedocument.wordprocessingml.document=libreoffice-writer.desktop;
image/webp=feh.desktop;
application/x-extension-htm=zen.desktop;
application/x-extension-html=zen.desktop;
application/x-extension-shtml=zen.desktop;
application/xhtml+xml=zen.desktop;
application/x-extension-xhtml=zen.desktop;
application/x-extension-xht=zen.desktop;
audio/flac=mpv.desktop;
Submodule
+1
Submodule nvim added at 8d657d0f8d
-334
View File
@@ -1,334 +0,0 @@
vim.o.number = true
vim.o.wrap = false
vim.o.tabstop = 4
vim.o.shiftwidth = 4
vim.o.smartcase = true
vim.o.ignorecase = true
vim.o.hlsearch = false
vim.o.signcolumn = 'yes'
vim.o.clipboard = 'unnamedplus'
vim.o.undofile = true
vim.o.undodir = '/home/narl/.cache/nvim-undodir'
vim.g.mapleader = ','
-- Set up 'mini.deps' (customize to your liking)
require('mini.deps').setup()
local add = MiniDeps.add
add({
source = 'williamboman/mason.nvim'
})
add({
source = 'stevearc/conform.nvim'
})
add({
source = 'williamboman/mason-lspconfig.nvim'
})
add({
source = 'mfussenegger/nvim-lint'
})
add({
source = 'akinsho/toggleterm.nvim'
})
-- Add to current session (install if absent)
add({
source = 'neovim/nvim-lspconfig',
-- Supply dependencies near target plugin
depends = { 'williamboman/mason.nvim' },
})
add({
source = 'seblyng/roslyn.nvim',
})
add({
source = 'tris203/rzls.nvim',
})
add({
source = 'nvim-treesitter/nvim-treesitter',
-- Use 'master' while monitoring updates in 'main'
checkout = 'master',
monitor = 'main',
-- Perform action after every checkout
hooks = { post_checkout = function() vim.cmd('TSUpdate') end },
})
add({
-- Completion framework:
source = 'hrsh7th/nvim-cmp',
-- LSP completion source:
depends = {'hrsh7th/cmp-nvim-lsp',
'hrsh7th/cmp-nvim-lua',
'hrsh7th/cmp-nvim-lsp-signature-help',
'hrsh7th/cmp-vsnip',
'hrsh7th/cmp-path',
'hrsh7th/cmp-buffer',
'hrsh7th/vim-vsnip',
},
})
add({ source = "catppuccin/nvim", name = "catppuccin" })
require('mini.files').setup({
mappings = {
show_help = 'gh',
},
})
require('mini.icons').setup({style = 'ascii'})
require('mini.pick').setup({})
require('mini.snippets').setup({})
require('mini.notify').setup({})
require('mini.statusline').setup({})
require('mini.tabline').setup({})
require('mini.git').setup({})
local imap_expr = function(lhs, rhs)
vim.keymap.set('i', lhs, rhs, { expr = true })
end
imap_expr('<Tab>', [[pumvisible() ? "\<C-n>" : "\<Tab>"]])
imap_expr('<S-Tab>', [[pumvisible() ? "\<C-p>" : "\<S-Tab>"]])
_G.cr_action = function()
-- If there is selected item in popup, accept it with <C-y>
if vim.fn.complete_info()['selected'] ~= -1 then return '\25' end
-- Fall back to plain `<CR>`. You might want to customize this
-- according to other plugins. For example if 'mini.pairs' is set up, replace
-- next line with `return MiniPairs.cr()`
return '\r'
end
vim.keymap.set('i', '<CR>', 'v:lua.cr_action()', { expr = true })
require("toggleterm").setup{
size = function(term)
if term.direction == "horizontal" then
return 30
elseif term.direction == "vertical" then
return 69
end
end,
open_mapping = [[<c-\>]],
hide_numbers = true,
shade_terminals = true,
persist_size = true,
direction = 'float',
close_on_exit = true,
shell = vim.o.shell,
}
require('nvim-treesitter.configs').setup {
ensure_installed = { "lua", "rust", "toml", "c_sharp" },
auto_install = true,
highlight = {
enable = true,
additional_vim_regex_highlighting=false,
},
ident = { enable = true },
rainbow = {
enable = true,
extended_mode = true,
max_file_lines = nil,
}
}
require("mason").setup({
registries = {
"github:mason-org/mason-registry",
"github:Crashdummyy/mason-registry",
},
ui = {
icons = {
package_installed = "",
package_pending = "",
package_uninstalled = ""
}
}
})
require("mason-lspconfig").setup()
vim.lsp.config('rust_analyzer', {
-- Server-specific settings. See `:help lsp-quickstart`
settings = {
['rust-analyzer'] = {},
},
})
require('roslyn').setup({
config = {
-- the rest of your Roslyn configuration
handlers = require("rzls.roslyn_handlers"),
},
})
require("catppuccin").setup({
flavour = "auto", -- latte, frappe, macchiato, mocha
background = { -- :h background
light = "latte",
dark = "mocha",
},
transparent_background = false, -- disables setting the background color.
show_end_of_buffer = false, -- shows the '~' characters after the end of buffers
term_colors = false, -- sets terminal colors (e.g. `g:terminal_color_0`)
dim_inactive = {
enabled = false, -- dims the background color of inactive window
shade = "dark",
percentage = 0.15, -- percentage of the shade to apply to the inactive window
},
no_italic = false, -- Force no italic
no_bold = false, -- Force no bold
no_underline = false, -- Force no underline
styles = { -- Handles the styles of general hi groups (see `:h highlight-args`):
comments = { "italic" }, -- Change the style of comments
conditionals = { "italic" },
loops = {},
functions = {},
keywords = {},
strings = {},
variables = {},
numbers = {},
booleans = {},
properties = {},
types = {},
operators = {},
-- miscs = {}, -- Uncomment to turn off hard-coded styles
},
color_overrides = {},
custom_highlights = {},
default_integrations = true,
integrations = {
cmp = true,
gitsigns = true,
nvimtree = true,
treesitter = true,
notify = false,
mini = {
enabled = true,
indentscope_color = "",
},
-- For more plugins integrations please scroll down (https://github.com/catppuccin/nvim#integrations)
},
})
local sign = function(opts)
vim.fn.sign_define(opts.name, {
texthl = opts.name,
text = opts.text,
numhl = ''
})
end
sign({name = 'DiagnosticSignError', text = ''})
sign({name = 'DiagnosticSignWarn', text = ''})
sign({name = 'DiagnosticSignHint', text = ''})
sign({name = 'DiagnosticSignInfo', text = ''})
--Set completeopt to have a better completion experience
-- :help completeopt
-- menuone: popup even when there's only one match
-- noinsert: Do not insert text until a selection is made
-- noselect: Do not select, force to select one from the menu
-- shortness: avoid showing extra messages when using completion
-- updatetime: set updatetime for CursorHold
vim.opt.completeopt = {'menuone', 'noselect', 'noinsert'}
vim.opt.shortmess = vim.opt.shortmess + { c = true}
vim.api.nvim_set_option('updatetime', 300)
-- Fixed column for diagnostics to appear
-- Show autodiagnostic popup on cursor hover_range
-- Goto previous / next diagnostic warning / error
-- Show inlay_hints more frequently
vim.cmd([[
set signcolumn=yes
autocmd CursorHold * lua vim.diagnostic.open_float(nil, { focusable = false })
]])
vim.diagnostic.config({
virtual_text = false,
signs = true,
update_in_insert = true,
underline = true,
severity_sort = false,
float = {
border = 'rounded',
source = 'always',
header = '',
prefix = '',
},
})
-- setup must be called before loading
vim.cmd.colorscheme "catppuccin"
vim.keymap.set('n', '<leader>w', '<cmd>write<cr>', {desc = 'Save file'})
vim.keymap.set('n', '<leader>q', '<cmd>quitall<cr>', {desc = 'Exit vim'})
-- Simplified clipboard mappings
-- vim.keymap.set({'n', 'x', 'o'}, '<leader>y', '"+y', {desc = 'Copy to clipboard'})
-- vim.keymap.set({'n', 'x'}, '<leader>p', '"+p', {desc = 'Paste from clipboard'})
vim.keymap.set('n', '<leader>e', '<cmd>lua MiniFiles.open()<cr>', {desc = 'File explorer'})
vim.keymap.set('n', '<leader><space>', '<cmd>Pick buffers<cr>', {desc = 'Search open files'})
vim.keymap.set('n', '<leader>ff', '<cmd>Pick files<cr>', {desc = 'Search all files'})
vim.keymap.set('n', '<leader>fh', '<cmd>Pick help<cr>', {desc = 'Search help tags'})
vim.keymap.set('n', '<leader>h', '<cmd>wincmd h<cr>')
vim.keymap.set('n', '<leader>l', '<cmd>wincmd l<cr>')
vim.keymap.set('n', '<leader>j', '<cmd>wincmd j<cr>')
vim.keymap.set('n', '<leader>k', '<cmd>wincmd k<cr>')
-- Rust
local cmp = require'cmp'
cmp.setup({
-- Enable LSP snippets
snippet = {
expand = function(args)
vim.fn["vsnip#anonymous"](args.body)
end,
},
mapping = {
['<C-p>'] = cmp.mapping.select_prev_item(),
['<C-n>'] = cmp.mapping.select_next_item(),
-- Add tab support
['<S-Tab>'] = cmp.mapping.select_prev_item(),
['<Tab>'] = cmp.mapping.select_next_item(),
['<C-S-f>'] = cmp.mapping.scroll_docs(-4),
['<C-f>'] = cmp.mapping.scroll_docs(4),
['<C-Space>'] = cmp.mapping.complete(),
['<C-e>'] = cmp.mapping.close(),
['<CR>'] = cmp.mapping.confirm({
behavior = cmp.ConfirmBehavior.Insert,
select = true,
})
},
-- Installed sources:
sources = {
{ name = 'path' }, -- file paths
{ name = 'nvim_lsp', keyword_length = 3 }, -- from language server
{ name = 'nvim_lsp_signature_help'}, -- display function signatures with current parameter emphasized
{ name = 'nvim_lua', keyword_length = 2}, -- complete neovim's Lua runtime API such vim.lsp.*
{ name = 'buffer', keyword_length = 2 }, -- source current buffer
{ name = 'vsnip', keyword_length = 2 }, -- nvim-cmp source for vim-vsnip
{ name = 'calc'}, -- source for math calculation
},
window = {
completion = cmp.config.window.bordered(),
documentation = cmp.config.window.bordered(),
},
formatting = {
fields = {'menu', 'abbr', 'kind'},
format = function(entry, item)
local menu_icon ={
nvim_lsp = 'λ',
vsnip = '',
buffer = 'Ω',
path = '🖫',
}
item.menu = menu_icon[entry.source.name]
return item
end,
},
})
-6
View File
@@ -1,6 +0,0 @@
#!/bin/bash
rm -rf ~/.config/nvim
cp -r nvim ~/.config/
git clone https://github.com/neovim/nvim-lspconfig ~/.config/nvim/pack/vendor/start/nvim-lspconfig
git clone https://github.com/echasnovski/mini.nvim ~/.config/nvim/pack/vendor/start/mini.nvim
+1799
View File
File diff suppressed because it is too large Load Diff
+225
View File
@@ -0,0 +1,225 @@
# Takemi
A Persona 5 flavoured Quickshell desktop for Hyprland. Crimson, black and white,
with no gradients anywhere. Everything leans by the same 14°, corners are
chopped rather than rounded, and every surface is one continuous slab divided by
hairlines rather than a cluster of floating cards.
Replaces Waybar, dunst and hyprlock.
## Running
```sh
qs # starts the shell (Hyprland does this via autostart.conf)
qs -p lockpreview.qml # the lock screen in an ordinary window, for styling
```
Hyprland starts it from `~/.config/hypr/modules/autostart.conf`.
## Layout
Two surfaces. Status moves off the bar and onto a vertical rail, because on a
1080p panel horizontal space is cheap and vertical space is not: a 48px rail
costs 2.5% of the width, where another 48px strip along the bottom would have
cost 4.4% of the height on top of what the bar already takes.
```
┌────────────────────────────────────────────┐
│ ◆ │ 1 2 3 │ window title ♪ TRACK │ 42% │ 00:09 │ bar — 48px exclusive
├────────────────────────────────────────────┤
│ ▐█▌│ rail — 48px exclusive
│ windows ▐ ▌│
│ ▐ ▌│
│ ▐ ▌│
└────────────────────────────────────────────┘
```
- **bar** — one slab: identity and workspaces on the left; the focused window,
the player, the CPU/MEM/GPU readout and the clock on the right.
- **rail** — one slab: network, bluetooth, audio, mic, backlight, battery, tray,
notifications, power. Popouts open leftward, into the screen.
Each surface is a single continuous `P5Panel` with modules divided by sheared
hairlines. `BarPill` is chromeless by default — a module is *content inside* a
surface, not a surface of its own — and marks hover with a crimson underline.
Pass `standalone: true` for the rare thing that really is its own panel.
```
shell.qml entrypoint — bar, rail, power menu, toasts, OSD per screen
config/ palette, type scale, geometry, motion curves
components/ the P5 primitives: panels, gauges, sliders, split-ink text
services/ data sources, all singletons
bar/ the two surfaces and their modules
popouts/ hover panels hanging off rail and bar modules
overlays/ power menu, notification toasts, volume/brightness OSD
lock/ session lock
assets/ halftone and stripe tiles, generated with ImageMagick
```
`P5Panel` is the base surface everything sits on. It does not auto-size —
callers set implicit sizes from their own layout (`row.implicitWidth +
contentPad * 2`), which keeps the shape maths out of binding loops.
## Modules
| Module | Where | Left click | Right click | Middle | Scroll | Hover |
|---|---|---|---|---|---|---|
| Sigil | bar | app menu | reload shell | | | |
| Workspaces | bar | switch | | | | |
| Clock | bar | pin calendar | | | | calendar |
| Network | rail | pin panel | toggle Wi-Fi | nm-connection-editor | | networks |
| Bluetooth | rail | pin panel | toggle adapter | | | devices |
| Volume | rail | mute | pin panel | pavucontrol | volume | audio mixer |
| Mic | rail | mute | pin panel | | mic volume | audio mixer |
| Brightness | rail | | | | brightness | |
| Battery | rail | pin panel | | | | power detail |
| Tray | rail | activate | app menu | secondary | | |
| Bell | rail | history + mark read | do not disturb | | | history |
| Power | rail | power menu | | | | |
| Media | bar | play/pause | next | raise player | next/prev | full player |
| CPU/MEM/GPU | bar | btop | | | | resource dashboard |
Popouts open on a short dwell and stay while the pointer is over the trigger or
the panel. Clicking pins one open.
## Keybinds
Set in `~/.config/hypr/modules/keybinds.conf`:
- `Super+Ctrl+L` — lock
- `Super+P` — power menu
- `Super+Shift+N` — toggle do not disturb
- `Super+Ctrl+Shift+N` — clear notifications
- `Super+Shift+R` — reload the shell
All of these go through Quickshell's IPC, so they work from any script:
```sh
qs ipc call shell lock
qs ipc call shell power
qs ipc call shell toggleDnd
qs ipc call shell clearNotifications
qs ipc call shell reloadConfig
```
## Data sources
Hardware telemetry comes from `fluxo`, whose hardware modules are configured to
emit raw pipe-delimited values rather than display strings — `services/Sys.qml`
parses them and does its own formatting. The previous human-readable Waybar
formats are preserved in `~/.config/fluxo/config.toml.waybar-bak`.
Everything else is native: PipeWire for audio, BlueZ for bluetooth,
NetworkManager for Wi-Fi, UPower for battery, MPRIS for media, and Quickshell's
own notification server. These are event-driven, so the bar and OSD react the
instant a volume key is pressed instead of on the next poll.
## Lock screen
Authenticates through `/etc/pam.d/hyprlock`, which on this box is just
`auth include login`. The visuals live in `lock/LockFace.qml` so they can be
styled in an ordinary window (`qs -p lockpreview.qml`) without locking the
session.
If the shell ever dies while the session is locked, the compositor keeps the
session secured by protocol and there is no unlocker left to talk to — recovery
means restarting Hyprland from a TTY.
## What was retired
- `waybar.service` — disabled. Its config is still in `~/.config/waybar`.
- `dunst.service` — masked, so it cannot be D-Bus activated and steal
`org.freedesktop.Notifications`. Undo with
`systemctl --user unmask dunst.service`.
- `hyprlock` — no longer bound. `hyprlock.conf` is untouched.
## Optional
`power-profiles-daemon` is not installed (TLP is), so the power-profile
switching in `services/Battery.qml` stays dormant. Nothing else depends on it.
The display face is Archivo Black, set italic almost everywhere. Change
`Theme.fontDisplay` and everything follows.
## Palette discipline
Crimson, black, white. That is the whole palette.
**Changing the accent.** The colour is written in exactly three places, one per
program:
| File | Line | Covers |
|---|---|---|
| `quickshell/config/Theme.qml` | `readonly property color accent: "#ff2d40"` | the shell |
| `hypr/modules/takemi.conf` | `$accent = rgb(ff2d40)` | window borders, groups |
| `alacritty/takemi.toml` | `red`, cursor, selection | the terminal |
Everything else derives. `accentDim` and `accentSoft` come off `accent` via
`Qt.darker`/`Qt.lighter`, `glow` (the hover highlight) *is* `accent`, and every
Hyprland border, group indicator and focus state references `$accent`. Change
those lines and the whole setup recolours — swap in Persona 4's yellow or
Persona 3's blue and nothing else needs touching.
## The rest of the desktop
- **Alacritty** — `alacritty/takemi.toml`, selected by the `import` in
`alacritty.toml`. The Catppuccin files are left in place, just unreferenced.
Near-black ground, white text, crimson cursor and selection. The sixteen ANSI
slots keep their hues because syntax highlighters need to tell them apart, but
every one is desaturated so nothing competes with the accent.
- **Neovim** — `nvim/lua/takemi.lua`, loaded through `nvim/colors/takemi.lua`
so `:colorscheme takemi` and `require("takemi").lualine()` both work. Same
palette, same rule: crimson is spent only on keywords, types and errors,
functions are plain white-bold, and `terminal_color_0..15` mirror
`takemi.toml` slot for slot so `:terminal` matches the shell around it.
- **Fish** — `fish/conf.d/takemi_theme.fish`, with a preview copy in
`fish/themes/Takemi.theme` for `fish_config`. Replaced the Catppuccin
`fish_frozen_theme.fish` that fish 4.3 generated on upgrade. The prompt arrow
is white and turns crimson on a non-zero exit — the shell's one "wrong"
signal, and so the one place that earns the accent.
- **Fuzzel** — `fuzzel/takemi.ini`, selected by the `include` in `fuzzel.ini`.
Square corners rather than the stock radius, and a fully opaque ground.
- **No glass anywhere.** Alacritty is `opacity = 1.0, blur = false`, and
Hyprland's `decoration:blur` is disabled with both opacities at `1.0`. Blur is
the signature of the frosted-glass look, which is the opposite of flat ink on
flat ground — and with nothing translucent left it was costing three render
passes for no visible result.
White is the resting voice — text, icons, idle indicators. Crimson is the only
accent and always means one thing: active, or wrong. Black is structure, used as
a hard keyline rather than as a soft shadow. **There are no gradients in this
shell**; every fill is flat. `Theme.sheen` still exists as a no-op property
because a teal-to-transparent wash on every panel was the single biggest source
of the murky blue cast the design used to have.
`primary`, `glow`, `blue`, `ok` and `warn` survive in `Theme.qml` only as
aliases onto white, crimson and grey, so the existing call sites keep working —
don't introduce new uses. `warn` used to alias `accentSoft`, which put a
washed-out pink-red wherever something was merely notable; there is no
half-crimson in this palette, so it aliases the real `accent` now and anything
merely informational (brightness, most readouts) is white instead. `Theme.heat()` is a continuous white→crimson ramp, so
a CPU figure that has gone red means the same thing as a battery that has gone
red. Tray icons are force-flattened to a single colour for the same reason: app
brand colours wreck the palette faster than anything else in the shell.
The wallpaper is teal. The UI used to be teal too, and the two fought each other
into a blue-grey mush. Going monochrome-plus-red is what lets the wallpaper be
the colour in the composition.
## Geometry discipline
**One angle, one chamfer, everywhere.** `Theme.skew` is `tan(14°)` and every
edge in the shell leans by exactly that, in the same direction; every corner is
chopped by exactly `Theme.cut`. A vertical panel (the rail) leans its horizontal
edges by a fraction of its *width*, which works out to the same 14°.
This is deliberate and was learned the hard way. An earlier pass gave every
module a different lean, chamfer and height from per-index variance tables, on
the theory that Persona geometry is "chaotic". It isn't — Persona UI is
meticulously clean, and the chaos lives in composition and motion, not in each
element being a different shape. Randomised geometry just reads as noise. If you
find yourself adding a variance table, don't.
Each surface is **one continuous slab**, with modules divided by sheared
hairline rules rather than by gaps. A row of separate floating cards reads as
clutter; that is what the dividers exist to avoid.
Binary file not shown.

After

Width:  |  Height:  |  Size: 338 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 B

+75
View File
@@ -0,0 +1,75 @@
import QtQuick
import Quickshell
import Quickshell.Hyprland
import "root:/config"
import "root:/components"
// Focused window title, glitching on every change the way a Persona 5 caption
// snaps into place.
Item {
id: root
required property var screenRef
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(screenRef)
readonly property HyprlandToplevel toplevel: Hyprland.activeToplevel
// Only speak for the monitor this bar lives on.
readonly property bool mine: toplevel !== null
&& (root.monitor === null || toplevel.monitor === null
|| toplevel.monitor.id === root.monitor.id)
readonly property string title: mine && toplevel.title ? toplevel.title : "—"
// The bar shrinks this when the three clusters would otherwise collide.
property real maxWidth: 240
implicitWidth: Math.min(maxWidth, Math.max(70, label.implicitWidth + 4))
implicitHeight: 20
Behavior on implicitWidth {
NumberAnimation { duration: Theme.durSlow; easing.type: Easing.OutExpo }
}
Marquee {
id: label
anchors.fill: parent
text: root.title
color: root.mine ? Theme.subtext : Theme.muted
pixelSize: Theme.fsSmall
family: Theme.fontDisplay
italic: true
weight: Font.DemiBold
}
onTitleChanged: flash.restart()
// A quick crimson wipe under the title on focus change.
Rectangle {
id: wipe
anchors.bottom: parent.bottom
height: 2
width: 0
color: Theme.accent
opacity: 0
}
SequentialAnimation {
id: flash
ParallelAnimation {
NumberAnimation {
target: wipe; property: "width"
from: 0; to: root.width
duration: Theme.durBase; easing.type: Easing.OutExpo
}
NumberAnimation {
target: wipe; property: "opacity"
from: 0; to: 1; duration: Theme.durFast
}
}
NumberAnimation {
target: wipe; property: "opacity"
to: 0; duration: Theme.durSlow
}
}
}
+143
View File
@@ -0,0 +1,143 @@
import QtQuick
import Quickshell
import Quickshell.Wayland
import "root:/config"
import "root:/components"
import "root:/services"
// One bar per monitor, and one surface.
//
// Identity and workspaces on the left, the player, metrics and clock on the
// right, all inside a single continuous slab and separated by hairline rules
// rather than by gaps. Nothing floats and nothing has its own card. Status
// lives on the rail, which is likewise one slab — two surfaces, not a dozen
// islands.
PanelWindow {
id: root
required property var modelData
screen: modelData
WlrLayershell.layer: WlrLayer.Top
WlrLayershell.namespace: "takemi-bar"
anchors {
top: true
left: true
right: true
}
margins {
top: Theme.barMargin
left: Theme.barMargin
right: Theme.barMargin
}
implicitHeight: Theme.barHeight
exclusiveZone: Theme.barHeight + Theme.barMargin
color: "transparent"
// The slab. One panel, full width, flat fill, black keyline.
P5Panel {
id: slab
anchors.fill: parent
lean: Theme.skew
chop: Theme.cut
chopCorners: [1, 3]
padding: 0
fill: Theme.surface
fillOpacity: 1.0
border: Theme.alpha(Theme.outline, 0.9)
borderWidth: 1
slash: true
slashColor: Theme.accent
slashWidth: 5
// No offset copy on the big slabs. The 3px black silhouette behind the
// fill is a print-misregistration trick, and at this scale it stops
// reading as one: on a 1900px bar you only ever see it at the chopped
// corners, where it turns the single clean cut into a staggered double
// edge that looks like a rendering fault. The black keyline still
// carries the heavy outer contour, which is what the corner needs.
drop: false
}
readonly property real edgeInset: Theme.barHeight * Theme.skew + Theme.padM
// ------------------------------------------------------------------ left
Row {
id: leftGroup
anchors.left: parent.left
anchors.leftMargin: root.edgeInset
anchors.verticalCenter: parent.verticalCenter
spacing: 0
Sigil {
id: sigil
screenRef: root.modelData
}
Divider {}
Workspaces {
id: spaces
anchors.verticalCenter: parent.verticalCenter
screenRef: root.modelData
}
Divider {}
ActiveWindow {
anchors.verticalCenter: parent.verticalCenter
screenRef: root.modelData
maxWidth: Math.max(120, root.width
- leftGroup.x - rightGroup.width - sigil.implicitWidth
- spaces.implicitWidth - root.edgeInset * 2 - Theme.padXL)
}
}
// ----------------------------------------------------------------- right
Row {
id: rightGroup
anchors.right: parent.right
anchors.rightMargin: root.edgeInset
anchors.verticalCenter: parent.verticalCenter
spacing: 0
MediaPill {
screenRef: root.modelData
}
Divider {}
Resources {
screenRef: root.modelData
}
Divider {}
Clock {
screenRef: root.modelData
}
}
// A hairline rule between modules, sheared to the house angle. This is what
// divides the bar now — gaps between cards are what made it look scattered.
component Divider: Item {
anchors.verticalCenter: parent.verticalCenter
implicitWidth: Theme.padM * 2
implicitHeight: Theme.barHeight
Rectangle {
anchors.centerIn: parent
width: 1
height: 20
color: Theme.alpha(Theme.outline, 0.9)
transform: Matrix4x4 {
matrix: Qt.matrix4x4(1, -Theme.skew, 0, 20 * Theme.skew,
0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
}
}
}
}
+148
View File
@@ -0,0 +1,148 @@
import QtQuick
import "root:/config"
import "root:/components"
// Shared chrome for every bar module.
//
// The bar is one continuous slab, so by default a module draws no panel of its
// own — it is content inside the bar's surface, and marks hover with a crimson
// underline rather than by lighting up a card. That is what stops the bar from
// reading as a row of floating islands.
//
// `standalone: true` brings back the individual leaning slab, for the few
// places that genuinely are separate surfaces.
Item {
id: root
property color accent: Theme.accent
property bool active: false
property bool slash: false
property real lean: Theme.skew
property bool leanLeft: false
property real padding: Theme.padM
property bool interactive: true
property bool halftone: false
property bool standalone: false
property real chop: Theme.cut
property var chopCorners: [1, 3]
readonly property bool hovered: hover.hovered
readonly property real leanInset: standalone ? panelLoader.item?.leanInset ?? 0 : 0
// The hover rule's own strip, reserved at the bottom of the module.
//
// The rule used to be drawn into the same box as the content, so anything
// taller than about 32px — the media pill's art, the metric meters — had a
// crimson line struck through its bottom edge on hover. Reserving the band
// and centring content in what is left is what keeps the rule under the
// module instead of across it.
readonly property real ruleHeight: 2
readonly property real ruleInset: 5
readonly property real ruleBand: root.standalone ? 0 : root.ruleHeight + root.ruleInset
// Total horizontal inset a module must add on top of its content width.
readonly property real contentPad: standalone
? (panelLoader.item?.contentPad ?? root.padding)
: root.padding
default property alias content: holder.data
signal clicked()
signal rightClicked()
signal middleClicked()
signal scrolled(real delta)
implicitHeight: Theme.barHeight
Loader {
id: panelLoader
anchors.fill: parent
active: root.standalone
sourceComponent: P5Panel {
lean: root.lean
leanLeft: root.leanLeft
chop: root.chop
chopCorners: root.chopCorners
padding: root.padding
halftone: root.halftone
halftoneColor: root.accent
fill: root.active ? Theme.surfaceAlt : Theme.surface
fillOpacity: 1.0
border: root.hovered || root.active
? root.accent
: Theme.alpha(Theme.outline, 0.9)
borderWidth: root.hovered || root.active ? Theme.stroke : 1
slash: root.slash || root.active
slashColor: root.accent
}
}
Item {
id: holder
anchors.fill: parent
anchors.leftMargin: root.contentPad
anchors.rightMargin: root.contentPad
anchors.bottomMargin: root.ruleBand
}
// Hover mark for in-bar modules: a crimson rule under the content, wiping
// out from the leading edge. Sheared to match the one angle everything uses.
Item {
visible: !root.standalone && root.interactive
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.bottomMargin: root.ruleInset
height: root.ruleHeight
clip: true
Rectangle {
height: parent.height
width: root.hovered || root.active ? parent.width : 0
color: root.accent
transform: Matrix4x4 {
matrix: Qt.matrix4x4(1, -Theme.skew, 0, 2 * Theme.skew,
0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
}
Behavior on width {
NumberAnimation { duration: Theme.durBase; easing.type: Easing.OutExpo }
}
}
}
HoverHandler {
id: hover
enabled: root.interactive
cursorShape: Qt.PointingHandCursor
}
TapHandler {
enabled: root.interactive
acceptedButtons: Qt.LeftButton
onTapped: root.clicked()
}
TapHandler {
enabled: root.interactive
acceptedButtons: Qt.RightButton
onTapped: root.rightClicked()
}
TapHandler {
enabled: root.interactive
acceptedButtons: Qt.MiddleButton
onTapped: root.middleClicked()
}
WheelHandler {
enabled: root.interactive
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
onWheel: event => root.scrolled(event.angleDelta.y)
}
}
+101
View File
@@ -0,0 +1,101 @@
import QtQuick
import Quickshell
import "root:/config"
import "root:/components"
import "root:/popouts"
// Centre-stage clock. Hovering drops the calendar.
BarPill {
id: root
required property var screenRef
accent: Theme.accent
slash: true
padding: Theme.padS
implicitWidth: layout.implicitWidth + contentPad * 2
SystemClock {
id: clock
precision: SystemClock.Seconds
}
onClicked: calendar.pinned = !calendar.pinned
Row {
id: layout
anchors.centerIn: parent
spacing: Theme.padM
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: -1
Text {
text: Qt.formatDateTime(clock.date, "ddd").toUpperCase()
color: Theme.accent
font.family: Theme.fontMono
font.pixelSize: Theme.fsMicro
font.letterSpacing: 2.5
renderType: Text.NativeRendering
}
Text {
text: Qt.formatDateTime(clock.date, "dd MMM").toUpperCase()
color: Theme.subtext
font.family: Theme.fontMono
font.pixelSize: Theme.fsMicro
font.letterSpacing: 1
renderType: Text.NativeRendering
}
}
Rectangle {
anchors.verticalCenter: parent.verticalCenter
width: 2
height: 22
color: Theme.alpha(Theme.accent, 0.6)
transform: Matrix4x4 {
matrix: Qt.matrix4x4(1, -Theme.skew, 0, 22 * Theme.skew,
0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
}
}
SplitText {
id: timeText
anchors.verticalCenter: parent.verticalCenter
text: Qt.formatDateTime(clock.date, "HH:mm")
pixelSize: Theme.fsTitle
split: 1.4
}
// Seconds, kept quiet so they read as a ticking detail rather than noise.
Text {
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 4
text: Qt.formatDateTime(clock.date, "ss")
color: Theme.alpha(Theme.primary, 0.8)
font.family: Theme.fontMono
font.pixelSize: Theme.fsMicro
renderType: Text.NativeRendering
}
}
// Glitch the time on the hour, because it should feel like something happened.
property int lastHour: -1
Connections {
target: clock
function onDateChanged() {
const h = clock.date.getHours();
if (root.lastHour !== -1 && h !== root.lastHour) timeText.glitch();
root.lastHour = h;
}
}
CalendarPopout {
id: calendar
anchorItem: root
triggerHovered: root.hovered
clockDate: clock.date
}
}
+185
View File
@@ -0,0 +1,185 @@
import QtQuick
import QtQuick.Shapes
import Quickshell
import "root:/config"
import "root:/components"
import "root:/services"
import "root:/popouts"
// Now-playing module. Collapses to nothing when no player is around.
BarPill {
id: root
required property var screenRef
accent: Theme.primary
padding: Theme.padS
visible: Media.hasPlayer || width > 1
implicitWidth: Media.hasPlayer
? layout.implicitWidth + contentPad * 2
: 0
Behavior on implicitWidth {
NumberAnimation { duration: Theme.durSlow; easing.type: Easing.OutExpo }
}
clip: true
onClicked: Media.playPause()
onRightClicked: Media.next()
onMiddleClicked: Media.raise()
onScrolled: delta => delta > 0 ? Media.next() : Media.previous()
Row {
id: layout
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
spacing: Theme.padS
// Album art, chopped into the house shape.
Item {
id: artFrame
anchors.verticalCenter: parent.verticalCenter
width: 24
height: 24
Shape {
id: artMask
anchors.fill: parent
visible: false
layer.enabled: true
preferredRendererType: Shape.CurveRenderer
ShapePath {
fillColor: "white"
strokeColor: "transparent"
PathPolyline {
path: Geom.chamfer(Geom.parallelogram(24, 24, 0.18), 5, [1, 3])
}
}
}
Image {
id: art
anchors.fill: parent
source: Media.artUrl
fillMode: Image.PreserveAspectCrop
cache: true
asynchronous: true
visible: status === Image.Ready
layer.enabled: true
layer.effect: MaskedArt { maskItem: artMask }
}
// Fallback: the source app's glyph.
Icon {
anchors.centerIn: parent
visible: art.status !== Image.Ready
text: Media.sourceIcon
font.pixelSize: Theme.fsLarge
color: Theme.primary
pulsing: Media.playing
pulseScale: 1.12
}
}
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: 0
Marquee {
width: 130
height: 14
text: Media.title || Media.identity
color: Theme.text
pixelSize: Theme.fsSmall
family: Theme.fontDisplay
weight: Font.DemiBold
italic: true
}
Marquee {
width: 130
height: 12
text: Media.artist || Media.album || Media.identity
color: Theme.muted
pixelSize: Theme.fsMicro
family: Theme.fontMono
}
}
// Play state, as a two-bar equaliser that freezes when paused.
Row {
anchors.verticalCenter: parent.verticalCenter
spacing: 2
Repeater {
model: 3
Rectangle {
required property int index
width: 3
height: 6
anchors.verticalCenter: parent.verticalCenter
color: Media.playing ? Theme.primary : Theme.muted
SequentialAnimation on height {
running: Media.playing
loops: Animation.Infinite
NumberAnimation {
to: 4 + (index * 5) % 13
duration: 320 + index * 90
easing.type: Easing.InOutSine
}
NumberAnimation {
to: 14 - (index * 4) % 9
duration: 280 + index * 70
easing.type: Easing.InOutSine
}
}
Behavior on color {
ColorAnimation { duration: Theme.durBase }
}
}
}
}
}
// Track progress, hairline along the bottom of the pill.
Rectangle {
anchors.bottom: parent.bottom
anchors.bottomMargin: 3
anchors.left: parent.left
anchors.leftMargin: root.leanInset
width: Math.max(0, (root.width - root.leanInset * 2) * Media.progress)
height: 2
color: Theme.accent
visible: Media.canSeek
Behavior on width {
NumberAnimation { duration: 480; easing.type: Easing.OutQuad }
}
}
onVisibleChanged: if (visible) titleGlitch.restart()
Connections {
target: Media
function onTrackChanged() { titleGlitch.restart(); }
}
SequentialAnimation {
id: titleGlitch
NumberAnimation {
target: artFrame; property: "rotation"
from: -8; to: 0; duration: Theme.durSlow; easing.type: Easing.OutBack
}
}
MediaPopout {
id: popout
anchorItem: root
triggerHovered: root.hovered && Media.hasPlayer
}
}
+75
View File
@@ -0,0 +1,75 @@
import QtQuick
import Quickshell
import "root:/config"
import "root:/components"
import "root:/services"
import "root:/popouts"
// Notification bell with an unread badge. Click opens the history, right click
// toggles do-not-disturb.
BarPill {
id: root
required property var screenRef
accent: Notifs.dnd ? Theme.muted : Theme.primary
padding: Theme.padS
implicitWidth: Theme.barHeight - 4 + contentPad
onClicked: {
popout.pinned = !popout.pinned;
Notifs.markRead();
}
onRightClicked: Notifs.toggleDnd()
Icon {
id: bell
anchors.centerIn: parent
text: Notifs.icon
font.pixelSize: Theme.fsLarge
color: {
if (Notifs.dnd) return Theme.muted;
if (Notifs.hasUnread) return Theme.accent;
return root.hovered ? Theme.glow : Theme.primary;
}
}
// Unread badge, chopped like everything else.
Rectangle {
visible: Notifs.unread > 0 && !Notifs.dnd
anchors.right: parent.right
anchors.rightMargin: 2
anchors.top: parent.top
anchors.topMargin: 4
width: Math.max(12, badge.implicitWidth + 5)
height: 12
color: Theme.accent
Text {
id: badge
anchors.centerIn: parent
text: Notifs.unread > 9 ? "9+" : Notifs.unread
color: Theme.text
font.family: Theme.fontMono
font.pixelSize: 8
font.weight: Font.Bold
renderType: Text.NativeRendering
}
transform: Matrix4x4 {
matrix: Qt.matrix4x4(1, -Theme.skew, 0, 12 * Theme.skew,
0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
}
}
Connections {
target: Notifs
function onPopupRequested() { bell.bump(); }
}
NotifPopout {
id: popout
anchorItem: root
triggerHovered: root.hovered
}
}
+42
View File
@@ -0,0 +1,42 @@
import QtQuick
import Quickshell
import "root:/config"
import "root:/components"
import "root:/services"
// Far right. Opens the full-screen power menu.
BarPill {
id: root
required property var screenRef
accent: Theme.accent
slash: true
padding: Theme.padS
active: Actions.powerMenuOpen
implicitWidth: Theme.barHeight - 4 + contentPad
onClicked: Actions.togglePowerMenu()
Icon {
id: glyph
anchors.centerIn: parent
text: "󰐥"
font.pixelSize: Theme.fsLarge
color: root.hovered || Actions.powerMenuOpen ? Theme.accent : Theme.subtext
}
// A crimson halo that swells under the pointer.
Rectangle {
anchors.centerIn: glyph
z: -1
width: root.hovered ? 26 : 0
height: width
radius: width / 2
color: Theme.alpha(Theme.accent, 0.18)
Behavior on width {
NumberAnimation { duration: Theme.durBase; easing.type: Easing.OutBack }
}
}
}
+231
View File
@@ -0,0 +1,231 @@
import QtQuick
import Quickshell
import Quickshell.Wayland
import "root:/config"
import "root:/components"
import "root:/services"
import "root:/popouts"
// The right-hand status rail — one slab, not a stack of cards.
//
// Connectivity, audio, power, tray and notifications all sit inside a single
// continuous column, divided by hairline rules the same way the bar divides its
// modules. Same lean, same chamfer, same keyline as the bar and the dock, so
// the three surfaces read as one system.
//
// On a 1080p panel this is the cheap edge: 48px of width is 2.5% of the screen,
// where the same 48px of height would be 4.4% on top of what the bar takes.
PanelWindow {
id: root
required property var modelData
screen: modelData
WlrLayershell.layer: WlrLayer.Top
WlrLayershell.namespace: "takemi-rail"
anchors {
top: true
bottom: true
right: true
}
margins {
top: Theme.barHeight + Theme.barMargin * 2
bottom: Theme.barMargin
right: Theme.barMargin
}
implicitWidth: Theme.railWidth
exclusiveZone: Theme.railWidth + Theme.barMargin
color: "transparent"
// The slab.
P5Panel {
id: slab
anchors.fill: parent
vertical: true
lean: Theme.skew
chop: Theme.cut
chopCorners: [1, 3]
padding: 0
fill: Theme.surface
fillOpacity: 1.0
border: Theme.alpha(Theme.outline, 0.9)
borderWidth: 1
slash: true
slashColor: Theme.accent
slashWidth: 5
// Same as the bar — see the note there. The doubled corner is worse on
// the rail, because its chopped corners sit against the wallpaper's
// high-contrast stripes rather than against other chrome.
drop: false
}
readonly property real edgeInset: Theme.railWidth * Theme.skew + Theme.padM
// ------------------------------------------------------------------- top
Column {
id: upper
anchors.top: parent.top
anchors.topMargin: root.edgeInset
anchors.horizontalCenter: parent.horizontalCenter
spacing: 0
RailIcon {
id: netIcon
icon: Net.icon
dim: !Sys.netUp
onClicked: netPopout.pinned = !netPopout.pinned
onRightClicked: Net.toggleWifi()
onMiddleClicked: Actions.openNetworkSettings()
}
RailIcon {
id: btIcon
icon: Bt.icon
dim: !Bt.enabled
onClicked: btPopout.pinned = !btPopout.pinned
onRightClicked: Bt.toggle()
}
Divider {}
RailIcon {
id: volIcon
icon: Audio.icon
readout: Audio.muted ? "" : Audio.volumePercent + "%"
alert: Audio.muted
onClicked: Audio.toggleMute()
onRightClicked: audioPopout.pinned = !audioPopout.pinned
onMiddleClicked: Actions.openAudioSettings()
onScrolled: delta => Audio.changeVolume(delta > 0 ? 0.05 : -0.05)
}
RailIcon {
id: micIcon
icon: Audio.micIcon
alert: Audio.micMuted
onClicked: Audio.toggleMicMute()
onRightClicked: audioPopout.pinned = !audioPopout.pinned
onScrolled: delta => Audio.setMicVolume(Audio.micVolume + (delta > 0 ? 0.05 : -0.05))
}
RailIcon {
id: brightIcon
visible: Brightness.available
icon: Brightness.icon
readout: Math.round(Brightness.percent) + "%"
onScrolled: delta => Brightness.change(delta > 0 ? 5 : -5)
}
Divider { visible: Battery.available }
RailIcon {
id: battIcon
visible: Battery.available
icon: Battery.icon
readout: Math.round(Battery.percent) + "%"
alert: Battery.critical
pulsing: Battery.critical
onClicked: battPopout.pinned = !battPopout.pinned
}
}
// ---------------------------------------------------------------- bottom
Column {
id: lower
anchors.bottom: parent.bottom
anchors.bottomMargin: root.edgeInset
anchors.horizontalCenter: parent.horizontalCenter
spacing: 0
Tray {
id: tray
anchors.horizontalCenter: parent.horizontalCenter
}
Divider { visible: tray.visible }
RailIcon {
id: bellIcon
icon: Notifs.icon
readout: Notifs.unread > 0
? (Notifs.unread > 9 ? "9+" : String(Notifs.unread))
: ""
dim: Notifs.dnd
alert: Notifs.hasUnread && !Notifs.dnd
onClicked: {
notifPopout.pinned = !notifPopout.pinned;
Notifs.markRead();
}
onRightClicked: Notifs.toggleDnd()
}
RailIcon {
id: powerIcon
icon: "󰐥"
alert: Actions.powerMenuOpen
onClicked: Actions.togglePowerMenu()
}
}
// The rail's counterpart to the bar's divider: a horizontal hairline,
// sheared to the same angle the rail's own edges lean at.
component Divider: Item {
implicitWidth: Theme.railWidth
implicitHeight: Theme.padM + 4
Rectangle {
anchors.centerIn: parent
width: 22
height: 1
color: Theme.alpha(Theme.outline, 0.9)
transform: Matrix4x4 {
matrix: Qt.matrix4x4(1, 0, 0, 0,
-Theme.skew, 1, 0, 22 * Theme.skew / 2,
0, 0, 1, 0, 0, 0, 0, 1)
}
}
}
// ------------------------------------------------------------- popouts
// All of these hang off the left edge of the rail, opening into the screen.
NetPopout {
id: netPopout
anchorItem: netIcon
triggerHovered: netIcon.hovered
fromEdge: Edges.Left
}
BtPopout {
id: btPopout
anchorItem: btIcon
triggerHovered: btIcon.hovered
fromEdge: Edges.Left
}
AudioPopout {
id: audioPopout
anchorItem: volIcon
triggerHovered: volIcon.hovered || micIcon.hovered
fromEdge: Edges.Left
}
BatteryPopout {
id: battPopout
anchorItem: battIcon
triggerHovered: battIcon.hovered
fromEdge: Edges.Left
visible: Battery.available && shown
}
NotifPopout {
id: notifPopout
anchorItem: bellIcon
triggerHovered: bellIcon.hovered
fromEdge: Edges.Left
}
}
+125
View File
@@ -0,0 +1,125 @@
import QtQuick
import "root:/config"
import "root:/components"
// One slot on the right-hand rail: a glyph with an optional micro readout
// stacked beneath it, and a crimson bar that wipes down the leading edge on
// hover. The rail is only 48px wide, so unlike StatusIcon the readout sits
// under the glyph rather than beside it, and anything longer than a percentage
// belongs in the popout instead.
Item {
id: root
property string icon: ""
property string readout: ""
property color tint: Theme.primary
property bool alert: false
property bool dim: false
property bool pulsing: false
readonly property bool hovered: hover.hovered
// Clearance between the wipe and the rail's left edge, chosen so the bar
// stays inside the slab once `scale` has expanded the icon about its centre.
readonly property real wipeInset: 5
signal clicked()
signal rightClicked()
signal middleClicked()
signal scrolled(real delta)
implicitWidth: Theme.railWidth
implicitHeight: root.readout !== "" ? 42 : 32
Column {
id: layout
anchors.centerIn: parent
spacing: 1
Icon {
id: glyph
anchors.horizontalCenter: parent.horizontalCenter
text: root.icon
pulsing: root.pulsing
font.pixelSize: Theme.fsLarge
color: {
if (root.alert) return Theme.accent;
if (root.dim) return Theme.muted;
if (root.hovered) return Theme.glow;
return root.tint;
}
Behavior on color {
ColorAnimation { duration: Theme.durBase }
}
}
Text {
anchors.horizontalCenter: parent.horizontalCenter
visible: root.readout !== ""
text: root.readout
color: root.dim ? Theme.muted : Theme.subtext
font.family: Theme.fontMono
font.pixelSize: Theme.fsMicro
font.weight: Font.DemiBold
renderType: Text.NativeRendering
Behavior on color {
ColorAnimation { duration: Theme.durBase }
}
}
}
// Leading-edge wipe. On the rail this runs vertically down the left side,
// mirroring the slash P5Panel puts on horizontal modules.
//
// Held off the edge by `wipeInset`: the icon spans the rail's full width, so
// at x = 0 this landed exactly on the slab's own border, and the 1.08 hover
// scale then pushed it out past the silhouette onto the desktop. The inset
// has to survive that scale, which is why it is not simply 1 or 2.
//
// It is crimson rather than `tint` because it only ever appears on hover,
// and hover is crimson everywhere else in the shell (Theme.glow). Painting
// it white put a white bar on the rail's edge for no stated reason.
Rectangle {
anchors.left: parent.left
anchors.leftMargin: root.wipeInset
anchors.verticalCenter: parent.verticalCenter
width: 2
height: root.hovered ? layout.implicitHeight : 0
color: Theme.glow
Behavior on height {
NumberAnimation { duration: Theme.durBase; easing.type: Easing.OutExpo }
}
}
scale: root.hovered ? 1.08 : 1.0
Behavior on scale {
NumberAnimation { duration: Theme.durBase; easing.type: Easing.OutBack }
}
onAlertChanged: if (alert) glyph.bump()
HoverHandler {
id: hover
cursorShape: Qt.PointingHandCursor
}
TapHandler {
acceptedButtons: Qt.LeftButton
onTapped: root.clicked()
}
TapHandler {
acceptedButtons: Qt.RightButton
onTapped: root.rightClicked()
}
TapHandler {
acceptedButtons: Qt.MiddleButton
onTapped: root.middleClicked()
}
WheelHandler {
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
onWheel: event => root.scrolled(event.angleDelta.y)
}
}
+106
View File
@@ -0,0 +1,106 @@
import QtQuick
import Quickshell
import "root:/config"
import "root:/components"
import "root:/services"
import "root:/popouts"
// Compact CPU / MEM / GPU readout. Each metric is a number over a segmented
// meter; hovering opens the full gauge cluster.
BarPill {
id: root
required property var screenRef
accent: Theme.heat(Math.max(Sys.cpuUsage, Sys.memPercent))
padding: Theme.padM
implicitWidth: layout.implicitWidth + contentPad * 2
onClicked: Actions.openSystemMonitor()
Row {
id: layout
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
spacing: Theme.padM
Metric {
label: "CPU"
value: Sys.cpuUsage
readout: Math.round(Sys.cpuUsage) + "%"
}
Divider {}
Metric {
label: "MEM"
value: Sys.memPercent
readout: Sys.memUsed.toFixed(1) + "G"
}
Divider { visible: Sys.gpuAvailable }
Metric {
visible: Sys.gpuAvailable
label: "GPU"
value: Sys.gpuUsage
readout: Math.round(Sys.gpuUsage) + "%"
}
}
component Divider: Rectangle {
anchors.verticalCenter: parent.verticalCenter
width: 1
height: 18
color: Theme.alpha(Theme.outline, 0.8)
transform: Matrix4x4 {
matrix: Qt.matrix4x4(1, -Theme.skew, 0, 18 * Theme.skew,
0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
}
}
// The CPU/MEM/GPU labels are gone: three characters of chrome per metric,
// repeated three times, in the most cramped part of the shell. The number
// over its meter is legible on its own, and dropping them buys the room to
// set the figure in display italic instead of squeezing it into mono.
component Metric: Column {
id: metric
property string label: ""
property real value: 0
property string readout: ""
anchors.verticalCenter: parent.verticalCenter
spacing: 2
Text {
text: metric.readout
color: Theme.heat(metric.value)
font.family: Theme.fontDisplay
font.pixelSize: Theme.fsBody
font.weight: Theme.weightDisplay
font.italic: true
font.letterSpacing: 0.5
renderType: Text.NativeRendering
Behavior on color {
ColorAnimation { duration: Theme.durBase }
}
}
MeterBar {
value: metric.value
segments: 9
segmentWidth: 3
spacing: 2
height: 5
}
}
SysPopout {
id: popout
anchorItem: root
triggerHovered: root.hovered
}
}
+44
View File
@@ -0,0 +1,44 @@
import QtQuick
import Quickshell
import "root:/config"
import "root:/components"
import "root:/services"
// The house mark, far left. Click launches the app menu; right click reloads
// the shell, which is handy while tweaking the config.
BarPill {
id: root
required property var screenRef
accent: Theme.accent
slash: true
padding: Theme.padS
lean: Theme.skew
implicitWidth: Theme.barHeight + contentPad
onClicked: Actions.launch("fuzzel")
onRightClicked: Actions.reloadShell()
// The wordmark. Was the Death arcana skull (nf-md-skull, U+F068C) — a
// pictogram in a shell that otherwise says everything in heavy italic
// type. SplitText puts it in the display face with the crimson-and-black
// offset every other heading carries, so the house mark is built out of
// the same parts as the rest of the bar.
SplitText {
id: mark
anchors.centerIn: parent
text: "P5"
pixelSize: Theme.fsLarge
letterSpacing: 0
color: root.hovered ? Theme.accent : Theme.primary
}
// Kick the ghosts out and let them snap back. The skull could spin a full
// turn and still read as a skull; a wordmark upside down just reads as
// broken, so the click gets the glitch instead.
Connections {
target: root
function onClicked() { mark.glitch(); }
}
}
+117
View File
@@ -0,0 +1,117 @@
import QtQuick
import Quickshell
import "root:/config"
import "root:/components"
import "root:/services"
import "root:/popouts"
// Network, bluetooth, audio, mic, backlight and battery, in one slab. Each
// glyph carries its own popout.
BarPill {
id: root
required property var screenRef
accent: Theme.primary
padding: Theme.padS
interactive: false
implicitWidth: layout.implicitWidth + contentPad * 2
Row {
id: layout
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
spacing: Theme.padM
StatusIcon {
id: netIcon
icon: Net.icon
label: Sys.netUp ? Sys.rate(Sys.netRx + Sys.netTx) : ""
labelWidth: 62
tint: Theme.primary
dim: !Sys.netUp
onClicked: netPopout.pinned = !netPopout.pinned
onRightClicked: Net.toggleWifi()
onMiddleClicked: Actions.openNetworkSettings()
}
StatusIcon {
id: btIcon
icon: Bt.icon
tint: Bt.connected.length > 0 ? Theme.blue : Theme.primary
dim: !Bt.enabled
onClicked: btPopout.pinned = !btPopout.pinned
onRightClicked: Bt.toggle()
}
StatusIcon {
id: volIcon
icon: Audio.icon
label: Audio.muted ? "" : Audio.volumePercent + "%"
labelWidth: Audio.muted ? 0 : 34
alert: Audio.muted
onClicked: Audio.toggleMute()
onRightClicked: audioPopout.pinned = !audioPopout.pinned
onMiddleClicked: Actions.openAudioSettings()
onScrolled: delta => Audio.changeVolume(delta > 0 ? 0.05 : -0.05)
}
StatusIcon {
id: micIcon
icon: Audio.micIcon
alert: Audio.micMuted
onClicked: Audio.toggleMicMute()
onRightClicked: audioPopout.pinned = !audioPopout.pinned
onScrolled: delta => Audio.setMicVolume(Audio.micVolume + (delta > 0 ? 0.05 : -0.05))
}
StatusIcon {
id: brightIcon
visible: Brightness.available
icon: Brightness.icon
label: Math.round(Brightness.percent) + "%"
labelWidth: 34
// Brightness is never an alarm — it stays white and lets the
// battery be the only thing in the cluster that can go crimson.
tint: Theme.text
onScrolled: delta => Brightness.change(delta > 0 ? 5 : -5)
}
StatusIcon {
id: battIcon
visible: Battery.available
icon: Battery.icon
label: Math.round(Battery.percent) + "%"
labelWidth: 34
tint: Battery.tint
alert: Battery.critical
pulsing: Battery.critical
onClicked: battPopout.pinned = !battPopout.pinned
}
}
NetPopout {
id: netPopout
anchorItem: netIcon
triggerHovered: netIcon.hovered
}
BtPopout {
id: btPopout
anchorItem: btIcon
triggerHovered: btIcon.hovered
}
AudioPopout {
id: audioPopout
anchorItem: volIcon
triggerHovered: volIcon.hovered || micIcon.hovered
}
BatteryPopout {
id: battPopout
anchorItem: battIcon
triggerHovered: battIcon.hovered
visible: Battery.available && shown
}
}
+108
View File
@@ -0,0 +1,108 @@
import QtQuick
import "root:/config"
import "root:/components"
// One indicator inside the status cluster: a glyph, an optional readout, and a
// crimson underline that wipes in on hover.
Item {
id: root
property string icon: ""
property string label: ""
property color tint: Theme.primary
property bool alert: false
property bool dim: false
property bool pulsing: false
// Fixed label width. Readouts that change width constantly (throughput,
// percentages) would otherwise shove the whole cluster around.
property real labelWidth: 0
readonly property bool hovered: hover.hovered
signal clicked()
signal rightClicked()
signal middleClicked()
signal scrolled(real delta)
implicitWidth: layout.implicitWidth
implicitHeight: Theme.barHeight - Theme.padS * 2
Row {
id: layout
anchors.centerIn: parent
spacing: 5
Icon {
id: glyph
anchors.verticalCenter: parent.verticalCenter
text: root.icon
pulsing: root.pulsing
color: {
if (root.alert) return Theme.accent;
if (root.dim) return Theme.muted;
if (root.hovered) return Theme.glow;
return root.tint;
}
}
Text {
anchors.verticalCenter: parent.verticalCenter
visible: root.label !== ""
text: root.label
width: root.labelWidth > 0 ? root.labelWidth : implicitWidth
horizontalAlignment: Text.AlignRight
elide: Text.ElideRight
color: root.dim ? Theme.muted : Theme.subtext
font.family: Theme.fontMono
font.pixelSize: Theme.fsSmall
font.weight: Font.DemiBold
renderType: Text.NativeRendering
Behavior on color {
ColorAnimation { duration: Theme.durBase }
}
}
}
Rectangle {
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
height: 2
width: root.hovered ? layout.implicitWidth : 0
color: root.alert ? Theme.accent : root.tint
Behavior on width {
NumberAnimation { duration: Theme.durBase; easing.type: Easing.OutExpo }
}
}
scale: root.hovered ? 1.06 : 1.0
Behavior on scale {
NumberAnimation { duration: Theme.durBase; easing.type: Easing.OutBack }
}
onAlertChanged: if (alert) glyph.bump()
HoverHandler {
id: hover
cursorShape: Qt.PointingHandCursor
}
TapHandler {
acceptedButtons: Qt.LeftButton
onTapped: root.clicked()
}
TapHandler {
acceptedButtons: Qt.RightButton
onTapped: root.rightClicked()
}
TapHandler {
acceptedButtons: Qt.MiddleButton
onTapped: root.middleClicked()
}
WheelHandler {
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
onWheel: event => root.scrolled(event.angleDelta.y)
}
}
+103
View File
@@ -0,0 +1,103 @@
import QtQuick
import QtQuick.Effects
import Quickshell
import Quickshell.Services.SystemTray
import Quickshell.Widgets
import "root:/config"
import "root:/components"
// StatusNotifier tray, as a vertical column for the right-hand rail. Left click
// activates, right click opens the app's own menu, middle click is the
// secondary action. The surrounding slab is the caller's business — this is
// just the stack of icons.
Column {
id: root
spacing: Theme.padS + 2
visible: SystemTray.items.values.length > 0
Repeater {
model: SystemTray.items
Item {
id: entry
required property SystemTrayItem modelData
width: 18
height: 18
anchors.horizontalCenter: parent.horizontalCenter
// App icons arrive in their own brand colours, which wrecks the
// two-hue palette faster than anything else in the shell. Flatten
// every one of them to a single-colour silhouette: white at rest,
// crimson under the pointer. Detail inside the glyph is lost on
// purpose — that flattening *is* the screen-printed look.
IconImage {
id: img
anchors.fill: parent
source: entry.modelData.icon
asynchronous: true
layer.enabled: true
layer.effect: MultiEffect {
colorization: 1.0
colorizationColor: itemHover.hovered
? Theme.accent
: Theme.text
Behavior on colorizationColor {
ColorAnimation { duration: Theme.durFast }
}
}
opacity: itemHover.hovered ? 1.0 : 0.82
Behavior on opacity {
NumberAnimation { duration: Theme.durFast }
}
}
scale: itemHover.hovered ? 1.18 : 1.0
Behavior on scale {
NumberAnimation { duration: Theme.durBase; easing.type: Easing.OutBack }
}
HoverHandler {
id: itemHover
cursorShape: Qt.PointingHandCursor
}
TapHandler {
acceptedButtons: Qt.LeftButton
onTapped: {
if (entry.modelData.onlyMenu) {
menuAnchor.open();
} else {
entry.modelData.activate();
}
}
}
TapHandler {
acceptedButtons: Qt.RightButton
onTapped: menuAnchor.open()
}
TapHandler {
acceptedButtons: Qt.MiddleButton
onTapped: entry.modelData.secondaryActivate()
}
// Menus open to the left, into the screen rather than off its edge.
QsMenuAnchor {
id: menuAnchor
menu: entry.modelData.menu
anchor.item: entry
anchor.edges: Edges.Left
anchor.gravity: Edges.Left
anchor.margins.right: Theme.popoutGap
}
}
}
}
+149
View File
@@ -0,0 +1,149 @@
import QtQuick
import Quickshell
import Quickshell.Hyprland
import "root:/config"
import "root:/components"
// Workspace indicator: leaning ticks that stretch open when focused. Occupied
// workspaces glow teal, urgent ones snap to crimson.
Item {
id: root
required property var screenRef
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(screenRef)
readonly property int focusedId: monitor?.activeWorkspace?.id ?? -1
// Live workspaces on this monitor, keyed by id, ignoring special workspaces.
readonly property var occupancy: {
const map = {};
for (const w of (Hyprland.workspaces?.values ?? [])) {
if (w.id < 1) continue;
if (root.monitor && w.monitor && w.monitor.id !== root.monitor.id) continue;
map[w.id] = {
count: w.toplevels?.values?.length ?? 0,
urgent: w.urgent,
fullscreen: w.hasFullscreen
};
}
return map;
}
// Always show 1..5, plus anything beyond that which is actually in use.
readonly property var slots: {
const ids = [1, 2, 3, 4, 5];
for (const key in root.occupancy) {
const id = parseInt(key);
if (ids.indexOf(id) === -1) ids.push(id);
}
return ids.sort((a, b) => a - b);
}
implicitWidth: row.implicitWidth
implicitHeight: 24
Row {
id: row
anchors.verticalCenter: parent.verticalCenter
spacing: 6
Repeater {
model: root.slots
Item {
id: pip
required property var modelData
required property int index
readonly property int wsId: modelData
readonly property var info: root.occupancy[wsId]
readonly property bool occupied: info !== undefined && info.count > 0
readonly property bool urgent: info !== undefined && info.urgent
readonly property bool focused: root.focusedId === wsId
readonly property bool hovered: pipHover.hovered
// Every tick is the same height and the same shear. Only the
// width changes, and only to say which workspace is focused.
width: focused ? 32 : (occupied ? 16 : 9)
height: 18
Behavior on width {
NumberAnimation {
duration: Theme.durSlow
easing.type: Easing.OutBack
easing.overshoot: 1.6
}
}
Rectangle {
id: tick
anchors.fill: parent
// Focused is a solid crimson block. Occupied is a white
// block at half weight. Empty is an outline. Three states,
// two colours, no ambiguity.
color: {
if (pip.focused || pip.urgent) return Theme.accent;
if (pip.hovered) return Theme.text;
if (pip.occupied) return Theme.alpha(Theme.text, 0.5);
return "transparent";
}
border.color: pip.occupied || pip.focused
? "transparent"
: Theme.alpha(Theme.text, 0.35)
border.width: 1
transform: Matrix4x4 {
matrix: Qt.matrix4x4(
1, -Theme.skew, 0, pip.height * Theme.skew,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1)
}
Behavior on color {
ColorAnimation { duration: Theme.durBase }
}
}
// The focused workspace wears its number.
Text {
anchors.centerIn: parent
opacity: pip.focused ? 1 : 0
visible: opacity > 0.01
text: pip.wsId
color: Theme.ink
font.family: Theme.fontDisplay
font.pixelSize: Theme.fsBody
font.weight: Theme.weightDisplay
font.italic: true
renderType: Text.NativeRendering
Behavior on opacity {
NumberAnimation { duration: Theme.durBase }
}
}
// Fullscreen marker.
Rectangle {
visible: pip.info !== undefined && pip.info.fullscreen && !pip.focused
width: 4; height: 4
color: Theme.accent
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.bottom
anchors.topMargin: 1
}
HoverHandler {
id: pipHover
cursorShape: Qt.PointingHandCursor
}
TapHandler {
onTapped: Hyprland.dispatch("workspace " + pip.wsId)
}
}
}
}
}
+120
View File
@@ -0,0 +1,120 @@
import QtQuick
import QtQuick.Shapes
import "root:/config"
// Radial gauge used across the resource popout. Sweeps a 270° arc with a
// tick-marked rail behind it and the reading set in the middle.
Item {
id: root
property real value: 0 // 0..100
property string label: ""
property string readout: Math.round(value) + "%"
property string sub: ""
property color arcColor: Theme.heat(value)
property real thickness: 7
property real startAngle: 135
property real sweep: 270
property int ticks: 24
implicitWidth: 96
implicitHeight: 96
readonly property real _r: Math.min(width, height) / 2 - thickness / 2 - 4
readonly property real _cx: width / 2
readonly property real _cy: height / 2
// Rail
Shape {
anchors.fill: parent
preferredRendererType: Shape.CurveRenderer
ShapePath {
fillColor: "transparent"
strokeColor: Theme.alpha(Theme.outline, 0.5)
strokeWidth: root.thickness
capStyle: ShapePath.FlatCap
PathAngleArc {
centerX: root._cx; centerY: root._cy
radiusX: root._r; radiusY: root._r
startAngle: root.startAngle
sweepAngle: root.sweep
}
}
}
// Tick marks around the rail.
Repeater {
model: root.ticks
Rectangle {
required property int index
readonly property real a: (root.startAngle + root.sweep * (index / (root.ticks - 1))) * Math.PI / 180
readonly property real rr: root._r + root.thickness / 2 + 3
width: 2
height: index % 4 === 0 ? 6 : 3
color: Theme.alpha(Theme.primary, index % 4 === 0 ? 0.55 : 0.25)
x: root._cx + Math.cos(a) * rr - width / 2
y: root._cy + Math.sin(a) * rr - height / 2
rotation: (root.startAngle + root.sweep * (index / (root.ticks - 1))) + 90
}
}
// Value arc
Shape {
anchors.fill: parent
preferredRendererType: Shape.CurveRenderer
ShapePath {
fillColor: "transparent"
strokeColor: root.arcColor
strokeWidth: root.thickness
capStyle: ShapePath.FlatCap
PathAngleArc {
id: valueArc
centerX: root._cx; centerY: root._cy
radiusX: root._r; radiusY: root._r
startAngle: root.startAngle
sweepAngle: root.sweep * Math.max(0, Math.min(100, root.value)) / 100
Behavior on sweepAngle {
NumberAnimation {
duration: Theme.durSlow
easing.type: Easing.OutExpo
}
}
}
}
}
Column {
anchors.centerIn: parent
spacing: -2
SplitText {
anchors.horizontalCenter: parent.horizontalCenter
text: root.readout
pixelSize: Theme.fsLarge
color: Theme.text
split: 1.2
splitOpacity: 0.6
}
Text {
anchors.horizontalCenter: parent.horizontalCenter
text: root.label
color: Theme.muted
font.family: Theme.fontMono
font.pixelSize: Theme.fsMicro
font.letterSpacing: 2
renderType: Text.NativeRendering
}
Text {
anchors.horizontalCenter: parent.horizontalCenter
visible: root.sub !== ""
text: root.sub
color: Theme.subtext
font.family: Theme.fontMono
font.pixelSize: Theme.fsMicro
renderType: Text.NativeRendering
}
}
}
+123
View File
@@ -0,0 +1,123 @@
pragma Singleton
import QtQuick
import Quickshell
// Polygon maths for the Persona 5 panel language: everything leans, and corners
// get chopped rather than rounded.
Singleton {
id: root
// A right-leaning parallelogram filling w x h. `lean` is the horizontal
// offset applied to the top edge, as a fraction of height.
function parallelogram(w: real, h: real, lean: real): var {
const off = h * lean;
return [
Qt.point(off, 0),
Qt.point(w, 0),
Qt.point(w - off, h),
Qt.point(0, h)
];
}
// Same, leaning the other way.
function parallelogramL(w: real, h: real, lean: real): var {
const off = h * lean;
return [
Qt.point(0, 0),
Qt.point(w - off, 0),
Qt.point(w, h),
Qt.point(off, h)
];
}
// Vertical counterpart: the *horizontal* edges slant instead, by a fraction
// of width. A tall rail slab has to lean this way — leaning its vertical
// edges by a fraction of its height would shear it clean off the screen.
function parallelogramV(w: real, h: real, lean: real): var {
const off = w * lean;
return [
Qt.point(0, off),
Qt.point(w, 0),
Qt.point(w, h - off),
Qt.point(0, h)
];
}
function parallelogramVL(w: real, h: real, lean: real): var {
const off = w * lean;
return [
Qt.point(0, 0),
Qt.point(w, off),
Qt.point(w, h),
Qt.point(0, h - off)
];
}
function rect(w: real, h: real): var {
return [Qt.point(0, 0), Qt.point(w, 0), Qt.point(w, h), Qt.point(0, h)];
}
// Move `dist` px from `p` toward `q`.
function toward(p: point, q: point, dist: real): point {
const dx = q.x - p.x;
const dy = q.y - p.y;
const len = Math.hypot(dx, dy);
if (len < 0.0001) return p;
const t = Math.min(dist, len / 2) / len;
return Qt.point(p.x + dx * t, p.y + dy * t);
}
// Chop the listed corners of a polygon. `corners` is an array of indices;
// pass null to chop every corner.
function chamfer(pts: var, size: real, corners: var): var {
if (size <= 0) return root.closed(pts);
const n = pts.length;
const out = [];
for (let i = 0; i < n; i++) {
const p = pts[i];
if (corners !== null && corners.indexOf(i) === -1) {
out.push(p);
continue;
}
out.push(root.toward(p, pts[(i - 1 + n) % n], size));
out.push(root.toward(p, pts[(i + 1) % n], size));
}
return root.closed(out);
}
function closed(pts: var): var {
if (pts.length === 0) return pts;
const out = pts.slice();
out.push(pts[0]);
return out;
}
// Shrink a polygon toward its centroid — used for inner strokes.
function inset(pts: var, amount: real): var {
let cx = 0, cy = 0;
for (const p of pts) { cx += p.x; cy += p.y; }
cx /= pts.length; cy /= pts.length;
return pts.map(p => {
const dx = cx - p.x, dy = cy - p.y;
const len = Math.hypot(dx, dy);
if (len < 0.0001) return p;
const t = amount / len;
return Qt.point(p.x + dx * t, p.y + dy * t);
});
}
// A jagged "torn paper" edge, the Persona 5 speech-bubble signature.
// Returns a polygon `w` x `h` whose bottom edge is serrated.
function torn(w: real, h: real, teeth: int, depth: real): var {
const out = [Qt.point(0, 0), Qt.point(w, 0)];
const step = w / teeth;
for (let i = 0; i < teeth; i++) {
const x1 = w - i * step - step / 2;
const x2 = w - (i + 1) * step;
out.push(Qt.point(x1, h));
out.push(Qt.point(x2, h - depth));
}
return out;
}
}
+45
View File
@@ -0,0 +1,45 @@
import QtQuick
import "root:/config"
// Nerd Font glyph with an optional pulse, used for every status indicator.
Text {
id: root
property bool pulsing: false
property real pulseScale: 1.18
font.family: Theme.fontIcon
font.pixelSize: Theme.fsLarge
color: Theme.primary
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
renderType: Text.NativeRendering
Behavior on color {
ColorAnimation { duration: Theme.durBase }
}
SequentialAnimation on scale {
running: root.pulsing
loops: Animation.Infinite
alwaysRunToEnd: true
NumberAnimation { to: root.pulseScale; duration: 620; easing.type: Easing.OutExpo }
NumberAnimation { to: 1.0; duration: 620; easing.type: Easing.InOutQuad }
}
function bump() {
bumpAnim.restart();
}
SequentialAnimation {
id: bumpAnim
NumberAnimation {
target: root; property: "scale"
to: 1.35; duration: Theme.durFast; easing.type: Easing.OutExpo
}
NumberAnimation {
target: root; property: "scale"
to: 1.0; duration: Theme.durSlow; easing.type: Easing.OutBack
}
}
}
+62
View File
@@ -0,0 +1,62 @@
import QtQuick
import "root:/config"
// Horizontally scrolling text that only moves when it actually overflows, and
// pauses at each end so titles stay readable.
Item {
id: root
property string text: ""
property int pixelSize: Theme.fsSmall
property string family: Theme.fontDisplay
property int weight: Theme.weightBody
property bool italic: false
property color color: Theme.text
property real speed: 26 // px per second
property int pause: 1400 // ms held at each end
property bool running: true
readonly property bool overflowing: label.implicitWidth > width + 1
clip: true
implicitHeight: label.implicitHeight
implicitWidth: label.implicitWidth
Text {
id: label
y: 0
height: root.height
text: root.text
color: root.color
verticalAlignment: Text.AlignVCenter
font.family: root.family
font.pixelSize: root.pixelSize
font.weight: root.weight
font.italic: root.italic
renderType: Text.NativeRendering
}
SequentialAnimation {
id: scroll
running: root.running && root.overflowing && root.visible
loops: Animation.Infinite
PauseAnimation { duration: root.pause }
NumberAnimation {
target: label; property: "x"
from: 0; to: Math.min(0, root.width - label.implicitWidth)
duration: Math.max(1, Math.abs(root.width - label.implicitWidth) / root.speed * 1000)
easing.type: Easing.Linear
}
PauseAnimation { duration: root.pause }
NumberAnimation {
target: label; property: "x"
to: 0
duration: Theme.durSlow
easing.type: Easing.OutExpo
}
}
onOverflowingChanged: if (!overflowing) label.x = 0
onTextChanged: { label.x = 0; scroll.restart(); }
}
+14
View File
@@ -0,0 +1,14 @@
import QtQuick
import QtQuick.Effects
// Layer effect that clips whatever it is applied to into the silhouette of
// `maskItem` — used to chop album art into the shell's panel shape.
MultiEffect {
property Item maskItem
maskEnabled: maskItem !== null
maskSource: maskItem
// Hard edge — the chopped corners should read as cuts, not fades.
maskThresholdMin: 0.5
maskSpreadAtMin: 0.0
}
+59
View File
@@ -0,0 +1,59 @@
import QtQuick
import "root:/config"
// A segmented load meter — slanted ticks that light up left to right. Reads as
// a gauge at a glance and keeps the panel language consistent.
Item {
id: root
property real value: 0 // 0..100
property int segments: 14
property real segmentWidth: 4
property real spacing: 3
property color activeColor: Theme.heat(value)
property color idleColor: Theme.alpha(Theme.outline, 0.55)
property real lean: Theme.skew
readonly property int litCount: Math.round(Math.max(0, Math.min(100, value)) / 100 * segments)
implicitWidth: segments * segmentWidth + (segments - 1) * spacing
implicitHeight: 14
Row {
anchors.fill: parent
spacing: root.spacing
Repeater {
model: root.segments
Item {
required property int index
width: root.segmentWidth
height: root.height
Rectangle {
width: root.segmentWidth
height: root.height
color: parent.index < root.litCount ? root.activeColor : root.idleColor
// Peak segments glow, so a pegged CPU is visible peripherally.
opacity: parent.index < root.litCount
? (parent.index >= root.segments - 2 ? 1.0 : 0.9)
: 1.0
transform: Matrix4x4 {
matrix: Qt.matrix4x4(
1, -root.lean, 0, root.height * root.lean,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1)
}
Behavior on color {
ColorAnimation { duration: Theme.durBase }
}
}
}
}
}
}
+91
View File
@@ -0,0 +1,91 @@
import QtQuick
import "root:/config"
import "root:/components"
// One metric in a popout: a label and its reading on a line, with a wide
// sheared segmented meter underneath.
//
// This replaces the radial Gauge. A 270° dial was the only curved thing in a
// shell whose whole geometry is sheared slabs and hard chamfers, so it read as
// though it had been imported from another design. The meter says the same
// thing in the language the bar and the OSD already speak, and it gets far more
// resolution across a popout's width than a 88px dial did.
Item {
id: root
property string label: ""
property real value: 0 // 0..100
property string readout: Math.round(root.value) + "%"
property string sub: ""
property color tone: Theme.heat(root.value)
property int segments: 24
property real segmentSpacing: 3
implicitHeight: head.height + Theme.padS + meter.height
Item {
id: head
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
height: Math.max(name.implicitHeight, figure.implicitHeight)
Text {
id: name
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
text: root.label.toUpperCase()
color: Theme.subtext
font.family: Theme.fontMono
font.pixelSize: Theme.fsMicro
font.letterSpacing: 2
renderType: Text.NativeRendering
}
// The secondary figure — temperature, used-of-total. Sits next to the
// label rather than under the number so the right edge stays a single
// clean column of readings.
Text {
anchors.left: name.right
anchors.leftMargin: Theme.padM
anchors.right: figure.left
anchors.rightMargin: Theme.padM
anchors.verticalCenter: parent.verticalCenter
visible: root.sub !== ""
text: root.sub
color: Theme.muted
elide: Text.ElideRight
font.family: Theme.fontMono
font.pixelSize: Theme.fsMicro
renderType: Text.NativeRendering
}
SplitText {
// Not `value` — an id by that name shadows the `value` property, and
// the defaults above then round a Text item instead of a number.
id: figure
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
text: root.readout
pixelSize: Theme.fsBody
color: Theme.text
split: 1
splitOpacity: 0.5
}
}
MeterBar {
id: meter
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
height: 12
segments: root.segments
spacing: root.segmentSpacing
// Fill the row exactly rather than leaving a ragged tail on the right.
segmentWidth: (width - (root.segments - 1) * root.segmentSpacing) / root.segments
value: root.value
activeColor: root.tone
}
}
+191
View File
@@ -0,0 +1,191 @@
import QtQuick
import Quickshell
import Quickshell.Services.Notifications
import "root:/config"
import "root:/services"
// One notification, used both in the history list and as a floating toast.
Item {
id: root
required property var notif
property bool showActions: true
readonly property color tone: root.notif
? Notifs.urgencyColor(root.notif.urgency)
: Theme.primary
signal dismissed()
implicitHeight: panel.height
P5Panel {
id: panel
width: parent.width
height: layout.implicitHeight + Theme.padM * 2
lean: 0.05
chop: 12
fill: Theme.surface
fillOpacity: 0.97
border: Theme.alpha(root.tone, hover.hovered ? 0.95 : 0.5)
slash: true
slashColor: root.tone
slashWidth: 4
halftone: root.notif?.urgency === NotificationUrgency.Critical
halftoneColor: Theme.accent
halftoneOpacity: 0.12
padding: Theme.padM
Column {
id: layout
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: 3
// App line
Row {
spacing: Theme.padS
Icon {
anchors.verticalCenter: parent.verticalCenter
text: Notifs.appIconFor(root.notif)
color: root.tone
font.pixelSize: Theme.fsBody
}
Text {
anchors.verticalCenter: parent.verticalCenter
text: (root.notif?.appName || "System").toUpperCase()
color: root.tone
font.family: Theme.fontMono
font.pixelSize: 8
font.letterSpacing: 2
renderType: Text.NativeRendering
}
}
Text {
width: parent.width
text: root.notif?.summary || ""
color: Theme.text
elide: Text.ElideRight
maximumLineCount: 2
wrapMode: Text.WordWrap
font.family: Theme.fontDisplay
font.pixelSize: Theme.fsBody
font.weight: Font.Black
font.italic: true
renderType: Text.NativeRendering
}
Text {
width: parent.width
visible: text !== ""
text: root.notif?.body || ""
color: Theme.subtext
elide: Text.ElideRight
maximumLineCount: 4
wrapMode: Text.WordWrap
textFormat: Text.StyledText
font.family: Theme.fontDisplay
font.pixelSize: Theme.fsSmall
renderType: Text.NativeRendering
}
// Inline image, when the sender supplied one.
Image {
visible: source != "" && status === Image.Ready
source: root.notif?.image || ""
sourceSize.height: 90
fillMode: Image.PreserveAspectFit
asynchronous: true
}
Row {
visible: root.showActions && (root.notif?.actions?.length ?? 0) > 0
spacing: Theme.padS
topPadding: Theme.padS
Repeater {
model: root.notif?.actions ?? []
Item {
id: actionChip
required property var modelData
implicitWidth: actionLabel.implicitWidth + Theme.padM
implicitHeight: 22
Rectangle {
anchors.fill: parent
color: actionHover.hovered
? Theme.alpha(root.tone, 0.3)
: Theme.alpha(root.tone, 0.1)
border.width: 1
border.color: Theme.alpha(root.tone, 0.6)
transform: Matrix4x4 {
matrix: Qt.matrix4x4(1, -Theme.skew, 0, 22 * Theme.skew,
0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
}
}
Text {
id: actionLabel
anchors.centerIn: parent
text: actionChip.modelData.text
color: Theme.text
font.family: Theme.fontDisplay
font.pixelSize: Theme.fsMicro
font.italic: true
font.weight: Font.DemiBold
renderType: Text.NativeRendering
}
HoverHandler {
id: actionHover
cursorShape: Qt.PointingHandCursor
}
TapHandler {
onTapped: {
actionChip.modelData.invoke();
root.dismissed();
}
}
}
}
}
}
// Close affordance.
Icon {
anchors.right: parent.right
anchors.top: parent.top
visible: hover.hovered
text: "󰅖"
color: closeHover.hovered ? Theme.accent : Theme.muted
font.pixelSize: Theme.fsBody
HoverHandler {
id: closeHover
cursorShape: Qt.PointingHandCursor
}
TapHandler {
onTapped: root.dismissed()
}
}
}
HoverHandler {
id: hover
}
// Middle click dismisses, matching the old dunst muscle memory.
TapHandler {
acceptedButtons: Qt.MiddleButton
onTapped: root.dismissed()
}
}
+103
View File
@@ -0,0 +1,103 @@
import QtQuick
import QtQuick.Shapes
import "root:/config"
import "root:/components"
// The shared ground for the two full-screen surfaces: a crimson wedge leaning
// at the house angle, a tiled stripe field that sweeps in from the left, and a
// halftone dot wash over the top.
//
// The lock screen and the power menu each used to draw their own version of
// this. They disagreed — the power menu had a wedge and a full stripe field,
// the lock had a 42px stripe band and no wedge, and the wedge leaned at 0.32
// where every panel in the shell leans at Theme.skew. Building both on one
// component is what makes them read as the same object seen twice rather than
// as two guesses at the same brief.
Item {
id: root
// 0 = withdrawn, 1 = fully present. Drives the stripe slide, the stripe
// opacity and the wedge together, so a caller animates one number instead
// of keeping three in sync. The power menu runs it both ways on open and
// close; the lock runs it once on entry.
property real reveal: 1
property color tone: Theme.accent
property bool wedge: true
property real wedgeOpacity: 0.35
// Bottom-left corner of the wedge and its span, as fractions of width. The
// wedge leans right going up, like every other edge in the shell, so its
// top edge sits `leanOffset` further right than its bottom.
property real wedgeLeft: 0
property real wedgeSpan: 0.34
property bool stripes: true
property real stripeOpacity: 0.10
property bool halftone: true
property real halftoneOpacity: 0.05
property color halftoneColor: Theme.primary
// ONE angle, everywhere — the same rule the panels follow.
readonly property real leanOffset: root.height * Theme.skew
// Diagonal stripe field, sliding in from off-screen left.
Image {
anchors.fill: parent
visible: root.stripes && root.reveal > 0
source: Theme.texStripes
fillMode: Image.Tile
opacity: root.stripeOpacity * root.reveal
smooth: false
layer.enabled: true
layer.effect: TintEffect {
tintColor: root.tone
}
transform: Translate {
x: -root.width * (1 - root.reveal)
}
}
// The wedge. Drawn after the stripes so it reads as a slab laid over them.
Shape {
anchors.fill: parent
visible: root.wedge && root.reveal > 0
opacity: root.reveal
preferredRendererType: Shape.CurveRenderer
ShapePath {
fillColor: Theme.alpha(Theme.accentDim, root.wedgeOpacity)
strokeColor: "transparent"
joinStyle: ShapePath.MiterJoin
PathPolyline {
path: {
const x = root.wedgeLeft * root.width;
const span = root.wedgeSpan * root.width;
const off = root.leanOffset;
return Geom.closed([
Qt.point(x + off, 0),
Qt.point(x + off + span, 0),
Qt.point(x + span, root.height),
Qt.point(x, root.height)
]);
}
}
}
}
// Screen-printed dot wash over the whole thing.
Image {
anchors.fill: parent
visible: root.halftone
source: Theme.texHalftone
fillMode: Image.Tile
opacity: root.halftoneOpacity
smooth: false
layer.enabled: true
layer.effect: TintEffect { tintColor: root.halftoneColor }
}
}
+106
View File
@@ -0,0 +1,106 @@
import QtQuick
import "root:/config"
// Chopped, leaning button. On hover it lunges toward the pointer and flips to
// crimson-on-white; on press it snaps flat.
Item {
id: root
property string text: ""
property string icon: ""
property color accent: Theme.primary
property color hoverFill: Theme.accent
property bool destructive: false
property real lean: Theme.skew
property real lunge: 6
property bool wide: false
signal clicked()
readonly property bool hovered: hover.hovered
readonly property bool pressed: tap.pressed
implicitWidth: wide ? 260 : (row.implicitWidth + panel.contentPad * 2)
implicitHeight: 44
P5Panel {
id: panel
anchors.fill: parent
lean: root.lean
padding: Theme.padS
fill: root.hovered ? (root.destructive ? root.hoverFill : Theme.text) : Theme.surface
fillOpacity: root.hovered ? 1.0 : 0.9
border: root.hovered ? "transparent" : Theme.alpha(root.accent, 0.55)
slash: !root.hovered
slashColor: root.destructive ? Theme.accent : root.accent
halftone: root.hovered
halftoneColor: root.destructive ? Theme.text : Theme.base
halftoneOpacity: 0.14
Behavior on fillOpacity {
NumberAnimation { duration: Theme.durFast }
}
Row {
id: row
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
spacing: Theme.padM
Icon {
anchors.verticalCenter: parent.verticalCenter
visible: root.icon !== ""
text: root.icon
font.pixelSize: Theme.fsTitle
color: root.hovered
? (root.destructive ? Theme.text : Theme.base)
: root.accent
}
Text {
anchors.verticalCenter: parent.verticalCenter
text: root.text
color: root.hovered
? (root.destructive ? Theme.text : Theme.base)
: Theme.text
font.family: Theme.fontDisplay
font.pixelSize: Theme.fsBody
font.weight: Theme.weightDisplay
font.italic: true
font.letterSpacing: 1.5
font.capitalization: Font.AllUppercase
renderType: Text.NativeRendering
Behavior on color {
ColorAnimation { duration: Theme.durFast }
}
}
}
}
transform: Translate {
x: root.pressed ? 0 : (root.hovered ? root.lunge : 0)
Behavior on x {
NumberAnimation {
duration: Theme.durBase
easing.type: Easing.OutBack
}
}
}
scale: root.pressed ? 0.97 : 1.0
Behavior on scale {
NumberAnimation { duration: Theme.durFast; easing.type: Easing.OutExpo }
}
HoverHandler {
id: hover
cursorShape: Qt.PointingHandCursor
}
TapHandler {
id: tap
onTapped: root.clicked()
}
}

Some files were not shown because too many files have changed in this diff Show More