diff --git a/.gitignore b/.gitignore
index 2b72cbc..cab348d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -79,3 +79,4 @@ fabric.properties
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
+temp
\ No newline at end of file
diff --git a/conf/autostart.conf b/conf/autostart.conf
deleted file mode 100644
index 248d2c9..0000000
--- a/conf/autostart.conf
+++ /dev/null
@@ -1,12 +0,0 @@
-#################
-### AUTOSTART ###
-#################
-
-# Autostart necessary processes (like notifications daemons, status bars, etc.)
-# Or execute your favorite apps at launch like this:
-
-exec-once = systemctl --user start hyprpolkitagent
-exec-once = waybar &
-exec-once = hyprpaper &
-exec-once = qs &
-
diff --git a/conf/env.conf b/conf/env.conf
deleted file mode 100644
index d45d567..0000000
--- a/conf/env.conf
+++ /dev/null
@@ -1,8 +0,0 @@
-#############################
-### ENVIRONMENT VARIABLES ###
-#############################
-
-# See https://wiki.hypr.land/Configuring/Environment-variables/
-
-env = XCURSOR_SIZE,24
-env = HYPRCURSOR_SIZE,24
diff --git a/conf/monitors.conf b/conf/monitors.conf
deleted file mode 100644
index b16cedd..0000000
--- a/conf/monitors.conf
+++ /dev/null
@@ -1,10 +0,0 @@
-################
-### MONITORS ###
-################
-
-# See https://wiki.hypr.land/Configuring/Monitors/
-monitor=HDMI-A-1, 2560x1440@120.00, 0x0, 1
-monitor=DP-3, 2560x1440@239.97, 2560x0, 1
-monitor=DP-2, 2560x1440@239.97, 5120x0, 1
-monitor=DP-1, 2560x1440@239.97, 2560x-1440, 1
-monitor=,preferred,auto,auto
\ No newline at end of file
diff --git a/conf/pathvars.conf b/conf/pathvars.conf
deleted file mode 100644
index e69de29..0000000
diff --git a/conf/programs.conf b/conf/programs.conf
deleted file mode 100644
index cfa8cc3..0000000
--- a/conf/programs.conf
+++ /dev/null
@@ -1,9 +0,0 @@
-###################
-### MY PROGRAMS ###
-###################
-
-# See https://wiki.hypr.land/Configuring/Keywords/
-
-$terminal = foot
-$fileManager = dolphin
-$menu = hyprlauncher
\ No newline at end of file
diff --git a/conf/style/animations.conf b/conf/style/animations.conf
deleted file mode 100644
index a401baf..0000000
--- a/conf/style/animations.conf
+++ /dev/null
@@ -1,6 +0,0 @@
-animations {
- enabled = true
- bezier = serpent, 0.25, 0.9, 0.2, 1.0
- animation = windows, 1, 4, serpent
- animation = fade, 1, 6, serpent
-}
\ No newline at end of file
diff --git a/conf/style/colors.conf b/conf/style/colors.conf
deleted file mode 100644
index 163cc1d..0000000
--- a/conf/style/colors.conf
+++ /dev/null
@@ -1,4 +0,0 @@
-general {
- col.active_border = rgba(1b6f52ff)
- col.inactive_border = rgba(1f2a27ff)
-}
\ No newline at end of file
diff --git a/dotfiles/.config/Thunar/uca.xml b/dotfiles/.config/Thunar/uca.xml
new file mode 100644
index 0000000..164340a
--- /dev/null
+++ b/dotfiles/.config/Thunar/uca.xml
@@ -0,0 +1,15 @@
+
+
+
+ utilities-terminal
+ Open Terminal Here
+
+ 1771004124403776-1
+ kitty -d %f
+ Example for a custom action
+
+ *
+
+
+
+
diff --git a/dotfiles/.config/fish/config.fish b/dotfiles/.config/fish/config.fish
new file mode 100644
index 0000000..7afdfe4
--- /dev/null
+++ b/dotfiles/.config/fish/config.fish
@@ -0,0 +1,2 @@
+source /usr/share/cachyos-fish-config/cachyos-config.fish
+starship init fish | source
\ No newline at end of file
diff --git a/dotfiles/.config/hypr/conf/autostart.conf b/dotfiles/.config/hypr/conf/autostart.conf
new file mode 100644
index 0000000..c2518ef
--- /dev/null
+++ b/dotfiles/.config/hypr/conf/autostart.conf
@@ -0,0 +1,19 @@
+#################
+### AUTOSTART ###
+#################
+
+exec-once = gsettings set org.gnome.desktop.interface gtk-theme "Serpensortia"
+exec-once = gsettings set org.gnome.desktop.interface icon-theme "Silvery-Dark-Icons"
+exec-once = gsettings set org.gnome.desktop.interface cursor-theme "Volantes Cursors"
+exec-once = gsettings set org.gnome.desktop.interface font-name "Fira Sans Semi-Bold 11"
+exec-once = gsettings set org.gnome.desktop.interface color-scheme "prefer_dark"
+
+# Autostart necessary processes (like notifications daemons, status bars, etc.)
+# Or execute your favorite apps at launch like this:
+
+exec-once = systemctl --user start hyprpolkitagent
+exec-once = hyprpaper &
+exec-once = waybar &
+exec-once = dunst &
+
+
diff --git a/dotfiles/.config/hypr/conf/env.conf b/dotfiles/.config/hypr/conf/env.conf
new file mode 100644
index 0000000..7e76d48
--- /dev/null
+++ b/dotfiles/.config/hypr/conf/env.conf
@@ -0,0 +1,54 @@
+#############################
+### ENVIRONMENT VARIABLES ###
+#############################
+
+# See https://wiki.hypr.land/Configuring/Environment-variables/
+
+# XDG Desktop Portal
+env = XDG_CURRENT_DESKTOP,Hyprland
+env = XDG_SESSION_TYPE,wayland
+env = XDG_SESSION_DESKTOP,Hyprland
+
+# QT
+env = QT_QPA_PLATFORM,wayland;xcb
+env = QT_QPA_PLATFORMTHEME,qt6ct
+env = QT_WAYLAND_DISABLE_WINDOWDECORATION,1
+env = QT_AUTO_SCREEN_SCALE_FACTOR,1
+
+# GTK
+env = GDK_SCALE,1
+
+env = XCURSOR_SIZE,20
+env = HYPRCURSOR_SIZE,20
+
+# Mozilla
+env = MOZ_ENABLE_WAYLAND,1
+env = EGL_PLATFORM,wayland
+
+# Disable appimage launcher by default
+env = APPIMAGELAUNCHER_DISABLE,1
+
+# OZONE
+env = OZONE_PLATFORM,wayland
+
+# NVIDIA https://wiki.hyprland.org/Nvidia/
+env = WLR_NO_HARDWARE_CURSORS,1 # On hyprland >v0.41, now configured on variable cursor section
+env = LIBVA_DRIVER_NAME,nvidia
+env = GBM_BACKEND,nvidia-drm
+env = SDL_VIDEODRIVER,wayland
+env = WLR_DRM_NO_ATOMIC,1
+env = __GLX_VENDOR_LIBRARY_NAME,nvidia
+env = __GL_VRR_ALLOWED,1
+env = __NV_PRIME_RENDER_OFFLOAD,1
+env = __VK_LAYER_NV_optimus,NVIDIA_only
+
+# Default Apps
+env = TERMINAL,$terminal
+env = VISUAL,vim
+env = EDITOR,vim
+env = SHELL,fish
+env = BROWSER,$browser
+
+cursor {
+ no_hardware_cursors = true
+}
\ No newline at end of file
diff --git a/conf/input.conf b/dotfiles/.config/hypr/conf/input.conf
similarity index 66%
rename from conf/input.conf
rename to dotfiles/.config/hypr/conf/input.conf
index c710d41..a9c4601 100644
--- a/conf/input.conf
+++ b/dotfiles/.config/hypr/conf/input.conf
@@ -10,7 +10,7 @@ input {
kb_options =
kb_rules =
- follow_mouse = 1
+ follow_mouse = 0
sensitivity = 0 # -1.0 - 1.0, 0 means no modification.
@@ -21,10 +21,3 @@ input {
# See https://wiki.hypr.land/Configuring/Gestures
gesture = 3, horizontal, workspace
-
-# Example per-device config
-# See https://wiki.hypr.land/Configuring/Keywords/#per-device-input-configs for more
-device {
- name = epic-mouse-v1
- sensitivity = -0.5
-}
\ No newline at end of file
diff --git a/conf/keybinds.conf b/dotfiles/.config/hypr/conf/keybinds.conf
similarity index 77%
rename from conf/keybinds.conf
rename to dotfiles/.config/hypr/conf/keybinds.conf
index 51e1121..f296f21 100644
--- a/conf/keybinds.conf
+++ b/dotfiles/.config/hypr/conf/keybinds.conf
@@ -6,14 +6,16 @@
$mainMod = SUPER # Sets "Windows" key as main modifier
# Example binds, see https://wiki.hypr.land/Configuring/Binds/ for more
-bind = $mainMod, Q, exec, $terminal
+bind = $mainMod, T, exec, $terminal
bind = $mainMod, C, killactive,
-bind = $mainMod, M, exec, command -v hyprshutdown >/dev/null 2>&1 && hyprshutdown || hyprctl dispatch exit
bind = $mainMod, E, exec, $fileManager
+bind = $mainMod, Q, exec, $browser
bind = $mainMod, V, togglefloating,
-bind = $mainMod, R, exec, $menu
+bind = $mainMod, space, exec, $menu
bind = $mainMod, P, pseudo, # dwindle
+bind = $mainMod, F11, fullscreen, #
bind = $mainMod, J, togglesplit, # dwindle
+bind = $mainMod, L, exec, hyprlock
# Move focus with mainMod + arrow keys
bind = $mainMod, left, movefocus, l
@@ -21,6 +23,11 @@ bind = $mainMod, right, movefocus, r
bind = $mainMod, up, movefocus, u
bind = $mainMod, down, movefocus, d
+bind = $mainMod SHIFT, left, movetoworkspace, e+1
+bind = $mainMod SHIFT, right, movetoworkspace, e-1
+bind = $mainMod SHIFT, up, movetoworkspace, 2
+bind = $mainMod SHIFT, downu, movetoworkspace, 4
+
# Switch workspaces with mainMod + [0-9]
bind = $mainMod, 1, workspace, 1
bind = $mainMod, 2, workspace, 2
@@ -49,20 +56,16 @@ bind = $mainMod SHIFT, 0, movetoworkspace, 10
bind = $mainMod, S, togglespecialworkspace, magic
bind = $mainMod SHIFT, S, movetoworkspace, special:magic
-# Scroll through existing workspaces with mainMod + scroll
-bind = $mainMod, mouse_down, workspace, e+1
-bind = $mainMod, mouse_up, workspace, e-1
-
# Move/resize windows with mainMod + LMB/RMB and dragging
-bindm = $mainMod, mouse:272, movewindow
-bindm = $mainMod, mouse:273, resizewindow
+bindm = alt, mouse:272, movewindow
+bindm = alt, 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 = ,XF86AudioRaiseVolume, exec, $SCRIPT_DIR/volume up
+bindel = ,XF86AudioLowerVolume, exec, $SCRIPT_DIR/volume down
+bindel = ,XF86AudioMute, exec, $SCRIPT_DIR/volume mute
bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle
-bindel = ,XF86MonBrightnessUp, exec, brightnessctl -e4 -n2 set 5%+
+bindel = ,XF86MonBrightnessUp, exec, brightnessctl -e4 -n2 set 5%+#
bindel = ,XF86MonBrightnessDown, exec, brightnessctl -e4 -n2 set 5%-
# Requires playerctl
diff --git a/dotfiles/.config/hypr/conf/monitors.conf b/dotfiles/.config/hypr/conf/monitors.conf
new file mode 100644
index 0000000..9044ffe
--- /dev/null
+++ b/dotfiles/.config/hypr/conf/monitors.conf
@@ -0,0 +1,10 @@
+################
+### MONITORS ###
+################
+
+# See https://wiki.hypr.land/Configuring/Monitors/
+monitor=$left-monitor, 2560x1440@120.00, 0x0, 1
+monitor=$bottom-monitor, 2560x1440@239.97, 2560x0, 1
+monitor=$right-monitor, 2560x1440@239.97, 5120x0, 1
+monitor=$top-monitor, 2560x1440@239.97, 2560x-1440, 1
+monitor=,preferred,auto,auto
\ No newline at end of file
diff --git a/conf/permissions.conf b/dotfiles/.config/hypr/conf/permissions.conf
similarity index 100%
rename from conf/permissions.conf
rename to dotfiles/.config/hypr/conf/permissions.conf
diff --git a/conf/style.conf b/dotfiles/.config/hypr/conf/style.conf
similarity index 100%
rename from conf/style.conf
rename to dotfiles/.config/hypr/conf/style.conf
diff --git a/dotfiles/.config/hypr/conf/style/animations.conf b/dotfiles/.config/hypr/conf/style/animations.conf
new file mode 100644
index 0000000..9ceeb8e
--- /dev/null
+++ b/dotfiles/.config/hypr/conf/style/animations.conf
@@ -0,0 +1,35 @@
+animations {
+ enabled = true
+ # Animation curves
+
+ bezier = linear, 0, 0, 1, 1
+ bezier = md3_standard, 0.2, 0, 0, 1
+ bezier = md3_decel, 0.05, 0.7, 0.1, 1
+ bezier = md3_accel, 0.3, 0, 0.8, 0.15
+ bezier = overshot, 0.05, 0.9, 0.1, 1.1
+ bezier = crazyshot, 0.1, 1.5, 0.76, 0.92
+ bezier = hyprnostretch, 0.05, 0.9, 0.1, 1.0
+ bezier = menu_decel, 0.1, 1, 0, 1
+ bezier = menu_accel, 0.38, 0.04, 1, 0.07
+ bezier = easeInOutCirc, 0.85, 0, 0.15, 1
+ bezier = easeOutCirc, 0, 0.55, 0.45, 1
+ bezier = easeOutExpo, 0.16, 1, 0.3, 1
+ bezier = softAcDecel, 0.26, 0.26, 0.15, 1
+ bezier = md2, 0.4, 0, 0.2, 1 # use with .2s duration
+ # Animation configs
+ animation = windows, 1, 3, md3_decel, popin 60%
+ animation = windowsIn, 1, 3, md3_decel, popin 60%
+ animation = windowsOut, 1, 3, md3_accel, popin 60%
+ animation = border, 1, 10, default
+ animation = fade, 1, 3, md3_decel
+ # animation = layers, 1, 2, md3_decel, slide
+ animation = layersIn, 1, 3, menu_decel, slide
+ animation = layersOut, 1, 1.6, menu_accel
+ animation = fadeLayersIn, 1, 2, menu_decel
+ animation = fadeLayersOut, 1, 4.5, menu_accel
+ animation = workspaces, 1, 7, menu_decel, slide
+ # animation = workspaces, 1, 2.5, softAcDecel, slide
+ # animation = workspaces, 1, 7, menu_decel, slidefade 15%
+ # animation = specialWorkspace, 1, 3, md3_decel, slidefadevert 15%
+ animation = specialWorkspace, 1, 3, md3_decel, slidevert
+}
\ No newline at end of file
diff --git a/dotfiles/.config/hypr/conf/style/colors.conf b/dotfiles/.config/hypr/conf/style/colors.conf
new file mode 100644
index 0000000..c878354
--- /dev/null
+++ b/dotfiles/.config/hypr/conf/style/colors.conf
@@ -0,0 +1,4 @@
+general {
+ col.active_border = rgba(124326ff)
+ col.inactive_border = rgba(080c08ff)
+}
\ No newline at end of file
diff --git a/conf/style/decoration.conf b/dotfiles/.config/hypr/conf/style/decoration.conf
similarity index 84%
rename from conf/style/decoration.conf
rename to dotfiles/.config/hypr/conf/style/decoration.conf
index d646bf0..3ce7f19 100644
--- a/conf/style/decoration.conf
+++ b/dotfiles/.config/hypr/conf/style/decoration.conf
@@ -1,5 +1,5 @@
decoration {
- rounding = 6
+ rounding = 8
blur {
enabled = true
size = 5
diff --git a/conf/style/general.conf b/dotfiles/.config/hypr/conf/style/general.conf
similarity index 82%
rename from conf/style/general.conf
rename to dotfiles/.config/hypr/conf/style/general.conf
index 2928549..5be8ab8 100644
--- a/conf/style/general.conf
+++ b/dotfiles/.config/hypr/conf/style/general.conf
@@ -1,8 +1,8 @@
general {
- gaps_in = 8
- gaps_out = 18
+ gaps_in = 5
+ gaps_out = 10
- border_size = 2
+ border_size = 5
# Set to true enable resizing windows by clicking and dragging on borders and gaps
resize_on_border = false
diff --git a/conf/windows.conf b/dotfiles/.config/hypr/conf/windows.conf
similarity index 100%
rename from conf/windows.conf
rename to dotfiles/.config/hypr/conf/windows.conf
diff --git a/hyprland.conf b/dotfiles/.config/hypr/hyprland.conf
similarity index 94%
rename from hyprland.conf
rename to dotfiles/.config/hypr/hyprland.conf
index caf1b1d..aad93fd 100644
--- a/hyprland.conf
+++ b/dotfiles/.config/hypr/hyprland.conf
@@ -4,9 +4,8 @@
# Refer to the wiki for more information.
# https://wiki.hypr.land/Configuring/
-
+source=./shared.conf
source=./conf/monitors.conf
-source=./conf/programs.conf
source=./conf/autostart.conf
source=./conf/env.conf
source=./conf/permissions.conf
diff --git a/dotfiles/.config/hypr/hyprlock.conf b/dotfiles/.config/hypr/hyprlock.conf
new file mode 100644
index 0000000..6bd7672
--- /dev/null
+++ b/dotfiles/.config/hypr/hyprlock.conf
@@ -0,0 +1,71 @@
+# _ _ _
+# | |__ _ _ _ __ _ __| | ___ ___| | __
+# | '_ \| | | | '_ \| '__| |/ _ \ / __| |/ /
+# | | | | |_| | |_) | | | | (_) | (__| <
+# |_| |_|\__, | .__/|_| |_|\___/ \___|_|\_\
+# |___/|_|
+#
+
+background {
+ monitor =
+ path = screenshot
+ color = rgba(17, 17, 17, 0.5)
+ blur_passes = 1
+}
+
+input-field {
+ monitor =
+ size = 200, 50
+ outline_thickness = 3
+ dots_size = 0.33 # Scale of input-field height, 0.2 - 0.8
+ dots_spacing = 0.15 # Scale of dots' absolute size, 0.0 - 1.0
+ dots_center = true
+ dots_rounding = -1 # -1 default circle, -2 follow input-field rounding
+ outer_color = rgb(1c7a44)
+ inner_color = rgb(080c08)
+ font_color = rgb(c0c0c0)
+ fade_on_empty = true
+ fade_timeout = 1000 # Milliseconds before fade_on_empty is triggered.
+ placeholder_text = Input Password... # Text rendered in the input box when it's empty.
+ hide_input = false
+ rounding = -1 # -1 means complete rounding (circle/oval)
+ check_color = rgb(424a42)
+ fail_color = rgb(dc143c) # if authentication failed, changes outer_color and fail message color
+ fail_text = Nice Try ($ATTEMPTS) # can be set to empty
+ fail_transition = 300 # transition time in ms between normal outer_color and fail_color
+ capslock_color = -1
+ numlock_color = -1
+ bothlock_color = -1 # when both locks are active. -1 means don't change outer color (same for above)
+ invert_numlock = false # change color if numlock is off
+ swap_font_color = false # see below
+ position = 0, -20
+ halign = center
+ valign = center
+}
+
+label {
+ monitor =
+ #clock
+ text = cmd[update:1000] echo "$TIME"
+ color = rgba(200, 200, 200, 1.0)
+ font_size = 55
+ font_family = Fira Semibold
+ position = -100, 40
+ halign = right
+ valign = bottom
+ shadow_passes = 5
+ shadow_size = 10
+}
+
+label {
+ monitor =
+ text = $USER
+ color = rgba(200, 200, 200, 1.0)
+ font_size = 20
+ font_family = Fira Semibold
+ position = -100, 160
+ halign = right
+ valign = bottom
+ shadow_passes = 5
+ shadow_size = 10
+}
diff --git a/dotfiles/.config/hypr/hyprpaper.conf b/dotfiles/.config/hypr/hyprpaper.conf
new file mode 100644
index 0000000..7c4bfed
--- /dev/null
+++ b/dotfiles/.config/hypr/hyprpaper.conf
@@ -0,0 +1,31 @@
+source=./shared.conf
+preload = ~/.themes/Serpensortia/wallpaper/top.jxl
+preload = ~/.themes/Serpensortia/wallpaper/bottom.jxl
+preload = ~/.themes/Serpensortia/wallpaper/left.jxl
+preload = ~/.themes/Serpensortia/wallpaper/right.jxl
+
+wallpaper {
+ monitor = $top-monitor
+ path = ~/.themes/Serpensortia/wallpaper/top.jxl
+ fit_mode = cover
+ timeout = 1
+}
+wallpaper {
+ monitor = $bottom-monitor
+ path = ~/.themes/Serpensortia/wallpaper/bottom.jxl
+ fit_mode = cover
+ timeout = 1
+}
+wallpaper {
+ monitor = $left-monitor
+ path = ~/.themes/Serpensortia/wallpaper/left.jxl
+ fit_mode = cover
+ timeout = 1
+}
+wallpaper {
+ monitor = $right-monitor
+ path = ~/.themes/Serpensortia/wallpaper/right.jxl
+ fit_mode = cover
+ timeout = 1
+}
+splash = false
diff --git a/dotfiles/.config/hypr/shared.conf b/dotfiles/.config/hypr/shared.conf
new file mode 100644
index 0000000..a9d5768
--- /dev/null
+++ b/dotfiles/.config/hypr/shared.conf
@@ -0,0 +1,13 @@
+# Monitors
+$left-monitor=HDMI-A-1
+$bottom-monitor=DP-3
+$right-monitor=DP-2
+$top-monitor=DP-1
+
+# Apps
+$terminal = kitty
+$fileManager = thunar
+$browser = vivaldi
+$menu = rofi -show
+
+$SCRIPT_DIR = ~/.config/hypr/conf/scripts
\ No newline at end of file
diff --git a/dotfiles/.config/qt6ct/qt6ct.conf b/dotfiles/.config/qt6ct/qt6ct.conf
new file mode 100644
index 0000000..86a8640
--- /dev/null
+++ b/dotfiles/.config/qt6ct/qt6ct.conf
@@ -0,0 +1,31 @@
+[Appearance]
+color_scheme_path=$HOME/.config/qt6ct/colors/Serpensortia.conf
+custom_palette=true
+icon_theme=Silvery-Dark-Icons
+standard_dialogs=xdgdesktopportal
+style=Fusion
+
+[Fonts]
+fixed="Fira Sans SemiBold,11,-1,5,600,0,0,0,0,0,0,0,0,0,0,1,Regular"
+general="Fira Sans SemiBold,11,-1,5,600,0,0,0,0,0,0,0,0,0,0,1,Regular"
+
+[Interface]
+activate_item_on_single_click=1
+buttonbox_layout=0
+cursor_flash_time=1000
+dialog_buttons_have_icons=1
+double_click_interval=400
+gui_effects=@Invalid()
+keyboard_scheme=2
+menus_have_icons=true
+show_shortcuts_in_context_menus=true
+stylesheets=$HOME/.config/qt6ct/qss/Serpensortia.qss
+toolbutton_style=4
+underline_shortcut=1
+wheel_scroll_lines=3
+
+[SettingsWindow]
+geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\0\0\0\0\0\0\0\0\x4\xe6\0\0\x2\x9e\0\0\0\0\0\0\0\0\0\0\x4\xe6\0\0\x2\x9e\0\0\0\0\x2\0\0\0\n\0\0\0\0\0\0\0\0\0\0\0\x4\xe6\0\0\x2\x9e)
+
+[Troubleshooting]
+force_raster_widgets=1
diff --git a/dotfiles/.local/bin/volume b/dotfiles/.local/bin/volume
new file mode 100755
index 0000000..0ea7457
--- /dev/null
+++ b/dotfiles/.local/bin/volume
@@ -0,0 +1,44 @@
+#!/bin/bash
+
+msgTag="volume"
+TIME=1000
+
+case "$1" in
+ up)
+ wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+
+ ;;
+ down)
+ wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%-
+ ;;
+ mute)
+ wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
+ mute=$(wpctl get-volume @DEFAULT_AUDIO_SINK@ | grep -q MUTED && echo "yes" || echo "no")
+ if [[ "$mute" == "yes" ]]; then
+ dunstify -t $TIME \
+ -a "Volume" \
+ -h string:x-dunst-stack-tag:$msgTag \
+ "Muted"
+ else
+ dunstify -t $TIME \
+ -a "Volume" \
+ -h string:x-dunst-stack-tag:$msgTag \
+ "Unmuted"
+ fi
+ exit 0
+ ;;
+ *)
+ echo "Usage: $0 [up/down/mute/mic]"
+ exit 1
+ ;;
+esac
+
+volume=$(wpctl get-volume @DEFAULT_AUDIO_SINK@ | awk '{print int($2*100)}')
+mute=$(wpctl get-volume @DEFAULT_AUDIO_SINK@ | grep -q MUTED && echo "yes" || echo "no")
+
+if [[ "$mute" != "yes" ]]; then
+ dunstify -t $TIME \
+ -a "Volume" \
+ -h string:x-dunst-stack-tag:$msgTag \
+ -h int:value:"$volume" \
+ "Volume: $volume%"
+fi
diff --git a/dotfiles/.themes/Serpensortia/index.theme b/dotfiles/.themes/Serpensortia/index.theme
new file mode 100644
index 0000000..5ddd67c
--- /dev/null
+++ b/dotfiles/.themes/Serpensortia/index.theme
@@ -0,0 +1,11 @@
+[Desktop Entry]
+Type=X-GNOME-Metatheme
+Name=Serpensortia
+Comment=Generated Serpent Theme
+Encoding=UTF-8
+
+[X-GNOME-Metatheme]
+GtkTheme=Serpensortia
+IconTheme=Silvery-Dark-Icons
+CursorTheme=Volanes Cursors
+ButtonLayout=close,maximize:menu
diff --git a/dotfiles/.themes/Serpensortia/wallpaper/bottom.jxl b/dotfiles/.themes/Serpensortia/wallpaper/bottom.jxl
new file mode 100644
index 0000000..6f7e965
Binary files /dev/null and b/dotfiles/.themes/Serpensortia/wallpaper/bottom.jxl differ
diff --git a/dotfiles/.themes/Serpensortia/wallpaper/left.jxl b/dotfiles/.themes/Serpensortia/wallpaper/left.jxl
new file mode 100644
index 0000000..394fc34
Binary files /dev/null and b/dotfiles/.themes/Serpensortia/wallpaper/left.jxl differ
diff --git a/dotfiles/.themes/Serpensortia/wallpaper/right.jxl b/dotfiles/.themes/Serpensortia/wallpaper/right.jxl
new file mode 100644
index 0000000..0ce6a2e
Binary files /dev/null and b/dotfiles/.themes/Serpensortia/wallpaper/right.jxl differ
diff --git a/dotfiles/.themes/Serpensortia/wallpaper/top.jxl b/dotfiles/.themes/Serpensortia/wallpaper/top.jxl
new file mode 100644
index 0000000..24d55c2
Binary files /dev/null and b/dotfiles/.themes/Serpensortia/wallpaper/top.jxl differ
diff --git a/setup.sh b/setup.sh
new file mode 100755
index 0000000..9adc87d
--- /dev/null
+++ b/setup.sh
@@ -0,0 +1,176 @@
+#!/usr/bin/env bash
+
+packages=(
+ "wget"
+ "unzip"
+ "git"
+ "gum"
+ "gvfs"
+ "hyprland"
+ "waybar"
+ "rofi"
+ "kitty"
+ "dunst"
+ "flatpak"
+ "thunar"
+ "thunar-archive-plugin"
+ "thunar-media-tags-plugin"
+ "thunar-shares-plugin"
+ "thunar-vcs-plugin"
+ "thunar-volman"
+ "qt5-wayland"
+ "qt6-wayland"
+ "qt5ct"
+ "qt6ct"
+ "go"
+ "hyprpaper"
+ "hyprlock"
+ "hyprpolkitagent"
+ "hicolor-icon-theme"
+ "woff2-font-awesome"
+ "vim"
+ "vivaldi"
+ "fastfetch"
+ "ttf-fira-sans"
+ "ttf-fira-code"
+ "ttf-firacode-nerd"
+ "jq"
+ "brightnessctl"
+ "networkmanager"
+ "wireplumber"
+ "wlogout"
+ "jetbrains-toolbox"
+ "xdg-desktop-portal-hyprland"
+)
+
+packagesToRemove=(
+ "cachyos-micro-settings"
+ "micro"
+ "dolphin"
+)
+
+_checkCommandExists() {
+ cmd="$1"
+ if ! command -v "$cmd" >/dev/null; then
+ echo 1
+ return
+ fi
+ echo 0
+ return
+}
+
+_isInstalled() {
+ package="$1"
+ check="$(sudo pacman -Qs --color always "${package}" | grep "local" | grep "${package} ")"
+ if [ -n "${check}" ]; then
+ echo 0
+ return #true
+ fi
+ echo 1
+ return #false
+}
+
+_installPackages() {
+ for pkg; do
+ if [[ $(_isInstalled "${pkg}") == 0 ]]; then
+ echo " .. ${pkg} is already installed."
+ continue
+ fi
+ echo "Package not installed: ${pkg}"
+ paru --noconfirm -S "${pkg}"
+ done
+}
+
+_removePackages() {
+ for pkg; do
+ if [[ ! $(_isInstalled "${pkg}") == 0 ]]; then
+ echo " .. ${pkg} is not installed."
+ continue
+ fi
+ paru --noconfirm -R "${pkg}"
+ done
+}
+
+_generateThemes() {
+ cd sithego || exit
+ go mod download
+ go run .
+ cd ..
+}
+
+_copyThemes() {
+ for folder in dotfiles/.themes/*; do
+ destDir="$HOME/.themes/$(basename "$folder")"
+ if [ -d "$destDir" ]; then
+ echo " .. creating Backup for $HOME/.themes/$(basename "$folder")"
+ backupDir="$HOME/.backup/arindOS/$(date +%Y%m%d_%H%M%S)/.themes"
+ mkdir -p "$backupDir"
+ mv "$destDir" "$backupDir/$(basename "$folder")"
+ fi
+ cp -r "$folder" "$destDir"
+ done
+}
+
+_copyIcons() {
+ for folder in dotfiles/.icons/*; do
+ destDir="$HOME/.icons/$(basename "$folder")"
+ if [ -d "$destDir" ]; then
+ echo " .. creating Backup for $HOME/.icons/$(basename "$folder")"
+ backupDir="$HOME/.backup/arindOS/$(date +%Y%m%d_%H%M%S)/.icons"
+ mkdir -p "$backupDir"
+ mv "$destDir" "$backupDir/$(basename "$folder")"
+ fi
+ cp -r "$folder" "$destDir"
+ done
+}
+
+_copyConfig() {
+ for folder in dotfiles/.config/*; do
+ destDir="$HOME/.config/$(basename "$folder")"
+ if [ -d "$destDir" ]; then
+ echo " .. creating Backup for $HOME/.config/$(basename "$folder")"
+ backupDir="$HOME/.backup/arindOS/$(date +%Y%m%d_%H%M%S)/.config"
+ mkdir -p "$backupDir"
+ mv -v "$destDir" "$backupDir/$(basename "$folder")"
+ fi
+ cp -rvf "$folder" "$destDir"
+ done
+ # use envsubst for qt6ct.conf
+ envsubst < dotfiles/.config/qt6ct/qt6ct.conf > "$HOME/.config/qt6ct/qt6ct.conf"
+ # copy qt6 to qt5
+ mkdir -p "$HOME/.config/qt5ct"
+ cp -v "$HOME/.config/qt6ct/qt6ct.conf" "$HOME/.config/qt5ct/qt5ct.conf"
+}
+
+if [[ $(_checkCommandExists "paru") != 0 ]]; then
+ echo "..The installer requires paru. paru will be installed now"
+ sudo pacman -Sy paru
+fi
+
+clear
+
+echo ":::::::::::::::::::::::::::"
+echo ":: ::"
+echo ":: Installing arindOS ::"
+echo ":: ::"
+echo ":::::::::::::::::::::::::::"
+
+echo ":::::::::::::::::::::::::::"
+echo ":: Removing packages ::"
+echo ":::::::::::::::::::::::::::"
+#_removePackages "${packagesToRemove[@]}"
+echo ":::::::::::::::::::::::::::"
+echo ":: Installing packages ::"
+echo ":::::::::::::::::::::::::::"
+#_installPackages "${packages[@]}"
+echo ":::::::::::::::::::::::::::"
+echo ":: Generating themes ::"
+echo ":::::::::::::::::::::::::::"
+_generateThemes
+_copyThemes
+_copyIcons
+_copyConfig
+echo ":::::::::::::::::::::::::::"
+echo ":: Installation complete ::"
+echo ":::::::::::::::::::::::::::"
+
diff --git a/sithego/go.mod b/sithego/go.mod
new file mode 100644
index 0000000..1643f12
--- /dev/null
+++ b/sithego/go.mod
@@ -0,0 +1,5 @@
+module Sithego
+
+go 1.26
+
+require github.com/pelletier/go-toml/v2 v2.2.4
diff --git a/sithego/go.sum b/sithego/go.sum
new file mode 100644
index 0000000..3cf50e1
--- /dev/null
+++ b/sithego/go.sum
@@ -0,0 +1,2 @@
+github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
+github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
diff --git a/sithego/main.go b/sithego/main.go
new file mode 100644
index 0000000..27b4169
--- /dev/null
+++ b/sithego/main.go
@@ -0,0 +1,33 @@
+package main
+
+import (
+ "Sithego/themer"
+ "Sithego/themer/adapters/gtk"
+ "Sithego/themer/adapters/intellij"
+ "Sithego/themer/adapters/qt"
+ "Sithego/themer/adapters/starship"
+)
+
+func main() {
+ theme, err := themer.LoadTheme("theme.conf")
+ if err != nil {
+ panic(err)
+ }
+
+ if err := gtk.New(gtk.WithOutputDir("../dotfiles/.themes/")).Generate(theme); err != nil {
+ panic(err)
+ }
+
+ if err := qt.New(qt.WithOutputDir("../dotfiles/.config/")).Generate(theme); err != nil {
+ panic(err)
+ }
+
+ if err := intellij.New(intellij.WithOutputDir("../dotfiles/.themes/")).Generate(theme); err != nil {
+ panic(err)
+ }
+
+ if err := starship.New(starship.WithOutputDir("../dotfiles/.config/")).Generate(theme); err != nil {
+ panic(err)
+ }
+
+}
diff --git a/sithego/theme.conf b/sithego/theme.conf
new file mode 100644
index 0000000..67ed52d
--- /dev/null
+++ b/sithego/theme.conf
@@ -0,0 +1,30 @@
+[Meta]
+Name="Serpensortia"
+Type="dark"
+Version="0.1"
+
+[Primitive]
+black="#131d13"
+silver="#c0c0c0"
+emerald="#2ecc71"
+crimson="#dc143c"
+
+[Colors.Semantic]
+background="black|800"
+surface="black"
+surfaceAlt="black|400"
+disabled="black|400"
+border="black|700"
+text="silver"
+accent="emerald|700"
+warn="crimson"
+
+[Spacing]
+paddingSmall="1px 2px"
+padding="2px 4px"
+paddingLarge="4px 8px"
+MarginSmall="1px"
+Margin="2px"
+RadiusSmall="4px"
+Radius="8px"
+RadiusLarge="16px"
diff --git a/sithego/themer/adapter.go b/sithego/themer/adapter.go
new file mode 100644
index 0000000..e197071
--- /dev/null
+++ b/sithego/themer/adapter.go
@@ -0,0 +1,6 @@
+package themer
+
+type Adapter interface {
+ Name() string
+ Generate(theme Theme)
+}
diff --git a/sithego/themer/adapters/gtk/components/base.css b/sithego/themer/adapters/gtk/components/base.css
new file mode 100644
index 0000000..61c1ee7
--- /dev/null
+++ b/sithego/themer/adapters/gtk/components/base.css
@@ -0,0 +1,25 @@
+* {
+ -GtkHTML-cursor-color: {{ .Theme.Colors.Semantic.Text.Value }};
+ -GtkIMHtml-cursor-color: {{ .Theme.Colors.Semantic.Text.Value }};
+ -GtkTextView-error-underline-color: {{ .Theme.Colors.Semantic.Warn.Value }};
+ -W3C-focus-color: {{ .Theme.Colors.Semantic.Accent.Value }};
+ outline-color: {{ .Theme.Colors.Semantic.Accent.Alpha .Theme.Colors.Semantic.Background 0.5 }};
+ background-clip: padding-box;
+ -gtk-secondary-caret-color: {{ .Theme.Colors.Semantic.Accent.Value }};
+}
+
+.background {
+ background-color: {{ .Theme.Colors.Semantic.Background.Value }};
+ color: {{ .Theme.Colors.Semantic.Text.Value }};
+}
+
+:disabled {
+ color: {{ .Theme.Colors.Semantic.Disabled.Value }};
+}
+
+window,
+.window-frame {
+ background-color: {{ .Theme.Colors.Semantic.Background.Value }};
+ color: {{ .Theme.Colors.Semantic.Text.Value }};
+ border-radius: {{ .Theme.Spacing.RadiusLarge }};
+}
diff --git a/sithego/themer/adapters/gtk/components/buttons.css b/sithego/themer/adapters/gtk/components/buttons.css
new file mode 100644
index 0000000..5218723
--- /dev/null
+++ b/sithego/themer/adapters/gtk/components/buttons.css
@@ -0,0 +1,36 @@
+button {
+ background-color: {{ .Theme.Colors.Semantic.SurfaceAlt.Value }};
+ color: {{ .Theme.Colors.Semantic.Text.Value }};
+ border: 1px solid {{ .Theme.Colors.Semantic.Border.Value }};
+ border-radius: {{ .Theme.Spacing.Radius }};
+ padding: {{ .Theme.Spacing.Padding }};
+ transition: all 0.2s ease;
+}
+
+button:hover {
+ background-color: {{ .Theme.Colors.Semantic.Border.Value }};
+}
+
+button:active,
+button:checked {
+ background-color: {{ .Theme.Colors.Semantic.Accent.Value }};
+ color: {{ .Theme.Colors.Semantic.Background.Value }};
+}
+
+button:disabled {
+ background-color: {{ .Theme.Colors.Semantic.Background.Value }};
+ color: {{ .Theme.Colors.Semantic.Disabled.Value }};
+ border-color: {{ .Theme.Colors.Semantic.Disabled.Value }};
+}
+
+button.suggested-action {
+ background-color: {{ .Theme.Colors.Semantic.Accent.Value }};
+ color: {{ .Theme.Colors.Semantic.Background.Value }};
+ border-color: {{ .Theme.Colors.Semantic.Accent.Value }};
+}
+
+button.destructive-action {
+ background-color: {{ .Theme.Colors.Semantic.Warn.Value }};
+ color: {{ .Theme.Colors.Semantic.Background.Value }};
+ border-color: {{ .Theme.Colors.Semantic.Warn.Value }};
+}
diff --git a/sithego/themer/adapters/gtk/components/checks.css b/sithego/themer/adapters/gtk/components/checks.css
new file mode 100644
index 0000000..ed8bd51
--- /dev/null
+++ b/sithego/themer/adapters/gtk/components/checks.css
@@ -0,0 +1,49 @@
+check, radio {
+ margin: 0 {{ .Theme.Spacing.Margin }};
+ min-height: 18px;
+ min-width: 18px;
+ border: 1px solid {{ .Theme.Colors.Semantic.Border.Value }};
+ border-radius: {{ .Theme.Spacing.Radius }};
+ background-color: {{ .Theme.Colors.Semantic.SurfaceAlt.Value }};
+ color: transparent;
+ -gtk-icon-source: none;
+ transition: all 0.2s ease;
+}
+
+radio {
+ border-radius: 50%;
+}
+
+check:checked {
+ background-color: {{ .Theme.Colors.Semantic.SurfaceAlt.Value }};
+ border-color: {{ .Theme.Colors.Semantic.Accent.Value }};
+ background-image:
+ linear-gradient(45deg, transparent 45%, {{ .Theme.Colors.Semantic.Accent.Value }} 45%, {{ .Theme.Colors.Semantic.Accent.Value }} 55%, transparent 55%),
+ linear-gradient(-45deg, transparent 45%, {{ .Theme.Colors.Semantic.Accent.Value }} 45%, {{ .Theme.Colors.Semantic.Accent.Value }} 55%, transparent 55%);
+ background-size: 70% 70%;
+ background-repeat: no-repeat;
+ background-position: center;
+}
+
+radio:checked {
+ background-color: {{ .Theme.Colors.Semantic.SurfaceAlt.Value }};
+ border-color: {{ .Theme.Colors.Semantic.Accent.Value }};
+ background-image: radial-gradient(circle, {{ .Theme.Colors.Semantic.Accent.Value }} 35%, transparent 40%);
+}
+
+check:indeterminate {
+ background-color: {{ .Theme.Colors.Semantic.SurfaceAlt.Value }};
+ border-color: {{ .Theme.Colors.Semantic.Accent.Value }};
+ background-image: linear-gradient(to right, {{ .Theme.Colors.Semantic.Accent.Value }}, {{ .Theme.Colors.Semantic.Accent.Value }});
+ background-size: 60% 2px;
+ background-repeat: no-repeat;
+ background-position: center;
+}
+
+check:disabled,
+radio:disabled {
+ background-color: {{ .Theme.Colors.Semantic.Background.Value }};
+ border-color: {{ .Theme.Colors.Semantic.Disabled.Value }};
+ color: transparent;
+ background-image: none;
+}
diff --git a/sithego/themer/adapters/gtk/components/entries.css b/sithego/themer/adapters/gtk/components/entries.css
new file mode 100644
index 0000000..2ada332
--- /dev/null
+++ b/sithego/themer/adapters/gtk/components/entries.css
@@ -0,0 +1,19 @@
+entry {
+ background-color: {{ .Theme.Colors.Semantic.Surface.Value }};
+ color: {{ .Theme.Colors.Semantic.Text.Value }};
+ border: 1px solid {{ .Theme.Colors.Semantic.Border.Value }};
+ border-radius: {{ .Theme.Spacing.Radius }};
+ padding: {{ .Theme.Spacing.PaddingSmall }};
+ caret-color: {{ .Theme.Colors.Semantic.Accent.Value }};
+}
+
+entry:focus {
+ border-color: {{ .Theme.Colors.Semantic.Accent.Value }};
+ box-shadow: inset 0 0 0 1px {{ .Theme.Colors.Semantic.Accent.Value }};
+}
+
+entry:disabled {
+ background-color: {{ .Theme.Colors.Semantic.Background.Value }};
+ color: {{ .Theme.Colors.Semantic.Disabled.Value }};
+ border-color: {{ .Theme.Colors.Semantic.Disabled.Value }};
+}
diff --git a/sithego/themer/adapters/gtk/components/headerbar.css b/sithego/themer/adapters/gtk/components/headerbar.css
new file mode 100644
index 0000000..83fed5a
--- /dev/null
+++ b/sithego/themer/adapters/gtk/components/headerbar.css
@@ -0,0 +1,11 @@
+headerbar {
+ background-color: {{ .Theme.Colors.Semantic.Surface.Value }};
+ color: {{ .Theme.Colors.Semantic.Text.Value }};
+ border-bottom: 1px solid {{ .Theme.Colors.Semantic.Border.Value }};
+ box-shadow: none;
+ padding: {{ .Theme.Spacing.PaddingSmall }};
+}
+
+headerbar .title {
+ font-weight: bold;
+}
diff --git a/sithego/themer/adapters/gtk/components/menus.css b/sithego/themer/adapters/gtk/components/menus.css
new file mode 100644
index 0000000..1e44403
--- /dev/null
+++ b/sithego/themer/adapters/gtk/components/menus.css
@@ -0,0 +1,53 @@
+list,
+menu {
+ background-color: {{ .Theme.Colors.Semantic.Surface.Value }};
+ color: {{ .Theme.Colors.Semantic.Text.Value }};
+ border: 1px solid {{ .Theme.Colors.Semantic.Border.Value }};
+ border-radius: {{ .Theme.Spacing.Radius }};
+}
+
+menubar {
+ background-color: {{ .Theme.Colors.Semantic.Surface.Value }};
+ color: {{ .Theme.Colors.Semantic.Text.Value }};
+ border-bottom: 1px solid {{ .Theme.Colors.Semantic.Border.Value }};
+ padding: {{ .Theme.Spacing.PaddingSmall }};
+}
+
+menubar > menuitem {
+ padding: {{ .Theme.Spacing.Padding }};
+ min-height: 24px;
+ transition: all 0.2s ease;
+}
+
+menuitem {
+ min-height: 24px;
+ padding: {{ .Theme.Spacing.Padding }};
+}
+
+menubar > menuitem:hover {
+ background-color: {{ .Theme.Colors.Semantic.Accent.Value }};
+ border-radius: {{ .Theme.Spacing.RadiusSmall }};
+}
+
+list row:selected,
+treeview.view:selected,
+.view:selected,
+iconview.view:selected,
+cell:selected,
+*:selected {
+ background-color: {{ .Theme.Colors.Semantic.Accent.Alpha .Theme.Colors.Semantic.Background 0.3 }};
+ color: {{ .Theme.Colors.Semantic.Text.Value }};
+ border: 1px solid {{ .Theme.Colors.Semantic.Accent.Value }};
+ border-radius: {{ .Theme.Spacing.Radius }};
+}
+
+menuitem:hover {
+ background-color: {{ .Theme.Colors.Semantic.Accent.Value }};
+ color: {{ .Theme.Colors.Semantic.Background.Value }};
+ border-radius: {{ .Theme.Spacing.RadiusSmall }};
+}
+
+menuitem:disabled {
+ color: {{ .Theme.Colors.Semantic.Disabled.Value }};
+ background-color: transparent;
+}
diff --git a/sithego/themer/adapters/gtk/components/notebook.css b/sithego/themer/adapters/gtk/components/notebook.css
new file mode 100644
index 0000000..9e175a8
--- /dev/null
+++ b/sithego/themer/adapters/gtk/components/notebook.css
@@ -0,0 +1,32 @@
+notebook {
+ background-color: {{ .Theme.Colors.Semantic.Background.Value }};
+ border: 1px solid {{ .Theme.Colors.Semantic.Border.Value }};
+}
+
+notebook header {
+ background-color: {{ .Theme.Colors.Semantic.Surface.Value }};
+}
+
+notebook tab {
+ padding: {{ .Theme.Spacing.PaddingLarge }};
+ border: 1px solid transparent;
+ border-radius: {{ .Theme.Spacing.Radius }} {{ .Theme.Spacing.Radius }} 0 0;
+ transition: all 0.2s ease;
+}
+
+notebook tab:hover {
+ background-color: {{ .Theme.Colors.Semantic.SurfaceAlt.Value }};
+}
+
+notebook tab:checked {
+ background-color: {{ .Theme.Colors.Semantic.Background.Value }};
+ border-color: {{ .Theme.Colors.Semantic.Border.Value }};
+ border-bottom-color: transparent;
+ border-bottom: 2px solid {{ .Theme.Colors.Semantic.Accent.Value }};
+ box-shadow: inset 0 -2px 0 {{ .Theme.Colors.Semantic.Accent.Value }};
+}
+
+notebook tab label {
+ font-weight: bold;
+ color: {{ .Theme.Colors.Semantic.Text.Value }};
+}
diff --git a/sithego/themer/adapters/gtk/components/scrollbars.css b/sithego/themer/adapters/gtk/components/scrollbars.css
new file mode 100644
index 0000000..a0ccd77
--- /dev/null
+++ b/sithego/themer/adapters/gtk/components/scrollbars.css
@@ -0,0 +1,24 @@
+scrollbar {
+ background-color: transparent;
+}
+
+scrollbar trough {
+ background-color: {{ .Theme.Colors.Semantic.SurfaceAlt.Value }};
+ border: 1px solid {{ .Theme.Colors.Semantic.Border.Value }};
+}
+
+scrollbar slider {
+ background-color: {{ .Theme.Colors.Semantic.Border.Value }};
+ border: 2px solid transparent;
+ border-radius: {{ .Theme.Spacing.RadiusLarge }};
+ min-width: 8px;
+ min-height: 8px;
+}
+
+scrollbar slider:hover {
+ background-color: {{ .Theme.Colors.Semantic.Accent.Value }};
+}
+
+scrollbar button {
+ display: none;
+}
diff --git a/sithego/themer/adapters/gtk/components/widgets.css b/sithego/themer/adapters/gtk/components/widgets.css
new file mode 100644
index 0000000..00f17b1
--- /dev/null
+++ b/sithego/themer/adapters/gtk/components/widgets.css
@@ -0,0 +1,77 @@
+/* Selection */
+selection,
+row:selected,
+iconview:selected,
+treeview.view:selected,
+.view:selected,
+iconview.view:selected,
+cell:selected,
+*:selected {
+ background-color: {{ .Theme.Colors.Semantic.Accent.Alpha .Theme.Colors.Semantic.Background 0.3 }};
+ color: {{ .Theme.Colors.Semantic.Text.Value }};
+ border: 1px solid {{ .Theme.Colors.Semantic.Accent.Value }};
+ border-radius: {{ .Theme.Spacing.Radius }};
+}
+
+/* Sliders (Scales) */
+scale trough {
+ background-color: {{ .Theme.Colors.Semantic.SurfaceAlt.Value }};
+ border: 1px solid {{ .Theme.Colors.Semantic.Border.Value }};
+ border-radius: {{ .Theme.Spacing.Radius }};
+ min-height: 4px;
+}
+
+scale highlight {
+ background-color: {{ .Theme.Colors.Semantic.Accent.Value }};
+ border-radius: {{ .Theme.Spacing.Radius }};
+}
+
+scale slider {
+ background-color: {{ .Theme.Colors.Semantic.Surface.Value }};
+ border: 1px solid {{ .Theme.Colors.Semantic.Border.Value }};
+ border-radius: 50%;
+ min-height: 16px;
+ min-width: 16px;
+ margin: -6px 0;
+}
+
+scale slider:hover {
+ background-color: {{ .Theme.Colors.Semantic.Accent.Value }};
+ border-color: {{ .Theme.Colors.Semantic.Accent.Value }};
+}
+
+/* Switches */
+switch {
+ background-color: {{ .Theme.Colors.Semantic.SurfaceAlt.Value }};
+ border: 1px solid {{ .Theme.Colors.Semantic.Border.Value }};
+ border-radius: {{ .Theme.Spacing.Radius }};
+ color: transparent;
+}
+
+switch:checked {
+ background-color: {{ .Theme.Colors.Semantic.Accent.Value }};
+ border-color: {{ .Theme.Colors.Semantic.Accent.Value }};
+}
+
+switch slider {
+ background-color: {{ .Theme.Colors.Semantic.Text.Value }};
+ border: 1px solid {{ .Theme.Colors.Semantic.Border.Value }};
+ border-radius: 50%;
+ margin: {{ .Theme.Spacing.MarginSmall }};
+ min-width: 18px;
+ min-height: 18px;
+}
+
+scale:disabled trough,
+scale:disabled highlight,
+scale:disabled slider,
+switch:disabled {
+ background-color: {{ .Theme.Colors.Semantic.Background.Value }};
+ border-color: {{ .Theme.Colors.Semantic.Disabled.Value }};
+ color: {{ .Theme.Colors.Semantic.Disabled.Value }};
+}
+
+switch:disabled slider {
+ background-color: {{ .Theme.Colors.Semantic.Disabled.Value }};
+ border-color: {{ .Theme.Colors.Semantic.Disabled.Value }};
+}
diff --git a/sithego/themer/adapters/gtk/gtk.go b/sithego/themer/adapters/gtk/gtk.go
new file mode 100644
index 0000000..f52098c
--- /dev/null
+++ b/sithego/themer/adapters/gtk/gtk.go
@@ -0,0 +1,93 @@
+package gtk
+
+import (
+ "Sithego/themer"
+ "os"
+ "path/filepath"
+ "text/template"
+)
+
+type Adapter struct {
+ OutputDir string
+}
+
+type Option func(*Adapter)
+
+func WithOutputDir(dir string) Option {
+ return func(a *Adapter) {
+ a.OutputDir = dir
+ }
+}
+
+func New(opt ...Option) *Adapter {
+ home, _ := os.UserHomeDir()
+ a := &Adapter{
+ OutputDir: home + "/.themes/",
+ }
+ for _, o := range opt {
+ o(a)
+ }
+ return a
+}
+
+func (a *Adapter) Name() string {
+ return "GTK"
+}
+
+func (a *Adapter) Generate(t themer.Theme) error {
+ components := []string{
+ "template.css",
+ "components/base.css",
+ "components/headerbar.css",
+ "components/buttons.css",
+ "components/entries.css",
+ "components/menus.css",
+ "components/widgets.css",
+ "components/checks.css",
+ "components/scrollbars.css",
+ "components/notebook.css",
+ }
+
+ outputDir := a.OutputDir + t.Meta.Name + "/gtk-3.0"
+ _ = os.RemoveAll(outputDir)
+ outputGTK4 := a.OutputDir + t.Meta.Name + "/gtk-4.0"
+ _ = os.RemoveAll(outputGTK4)
+
+ if err := os.MkdirAll(outputDir, 0775); err != nil {
+ return err
+ }
+
+ for _, component := range components {
+ templatePath := filepath.Join("themer/adapters/gtk", component)
+ templ, err := template.ParseFiles(templatePath)
+ if err != nil {
+ return err
+ }
+
+ outputName := filepath.Base(component)
+ if outputName == "template.css" {
+ outputName = "gtk.css"
+ }
+ outputPath := filepath.Join(outputDir, outputName)
+
+ file, err := os.Create(outputPath)
+ if err != nil {
+ return err
+ }
+
+ err = templ.Execute(file, struct {
+ Theme themer.Theme
+ }{
+ Theme: t,
+ })
+ _ = file.Close()
+ if err != nil {
+ return err
+ }
+ }
+
+ if err := os.MkdirAll(outputGTK4, 0775); err != nil {
+ return err
+ }
+ return os.CopyFS(outputGTK4, os.DirFS(outputDir))
+}
diff --git a/sithego/themer/adapters/gtk/index.theme b/sithego/themer/adapters/gtk/index.theme
new file mode 100644
index 0000000..4732201
--- /dev/null
+++ b/sithego/themer/adapters/gtk/index.theme
@@ -0,0 +1,11 @@
+[Desktop Entry]
+Type=X-GNOME-Metatheme
+Name=Serpensortia
+Comment=Generated Serpent Theme
+Encoding=UTF-8
+
+[X-GNOME-Metatheme]
+GtkTheme=Serpensortia
+IconTheme=Tela-circle-dark
+CursorTheme=Vimix-dark
+ButtonLayout=close,maximize:menu
diff --git a/sithego/themer/adapters/gtk/template.css b/sithego/themer/adapters/gtk/template.css
new file mode 100644
index 0000000..aabd418
--- /dev/null
+++ b/sithego/themer/adapters/gtk/template.css
@@ -0,0 +1,9 @@
+@import url("base.css");
+@import url("headerbar.css");
+@import url("buttons.css");
+@import url("entries.css");
+@import url("menus.css");
+@import url("widgets.css");
+@import url("checks.css");
+@import url("scrollbars.css");
+@import url("notebook.css");
diff --git a/sithego/themer/adapters/intellij/intellij.go b/sithego/themer/adapters/intellij/intellij.go
new file mode 100644
index 0000000..ffbf6e4
--- /dev/null
+++ b/sithego/themer/adapters/intellij/intellij.go
@@ -0,0 +1,112 @@
+package intellij
+
+import (
+ "Sithego/themer"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "text/template"
+)
+
+type Adapter struct {
+ OutputDir string
+}
+
+type Option func(*Adapter)
+
+func WithOutputDir(dir string) Option {
+ abs, err := filepath.Abs(dir)
+ if err != nil {
+ panic(err)
+ }
+ return func(a *Adapter) {
+ a.OutputDir = abs
+ }
+}
+
+func New(opt ...Option) *Adapter {
+ home, _ := os.UserHomeDir()
+ a := &Adapter{
+ OutputDir: home + "/.themes/",
+ }
+ for _, o := range opt {
+ o(a)
+ }
+ return a
+}
+
+func (a *Adapter) Name() string {
+ return "IntelliJ"
+}
+
+func (a *Adapter) Generate(t themer.Theme) error {
+ // 1. Create temporary directory structure for JAR bundling
+ tmpDir, err := os.MkdirTemp("", "intellij-theme-*")
+ if err != nil {
+ return err
+ }
+ defer func(path string) {
+ err := os.RemoveAll(path)
+ if err != nil {
+
+ }
+ }(tmpDir)
+
+ metaInfDir := filepath.Join(tmpDir, "META-INF")
+ if err := os.MkdirAll(metaInfDir, 0775); err != nil {
+ return err
+ }
+
+ funcMap := template.FuncMap{
+ "lower": strings.ToLower,
+ }
+
+ // 2. Generate plugin.xml
+ pluginTempl := template.New("template.plugin.xml").Funcs(funcMap)
+ pluginTempl, err = pluginTempl.ParseFiles("themer/adapters/intellij/template.plugin.xml")
+ if err != nil {
+ return err
+ }
+ pluginFile, err := os.Create(filepath.Join(metaInfDir, "plugin.xml"))
+ if err != nil {
+ return err
+ }
+ if err := pluginTempl.Execute(pluginFile, struct{ Theme themer.Theme }{Theme: t}); err != nil {
+ _ = pluginFile.Close()
+ return err
+ }
+ _ = pluginFile.Close()
+
+ // 3. Generate .theme.json
+ themeTempl, err := template.ParseFiles("themer/adapters/intellij/template.theme.json")
+ if err != nil {
+ return err
+ }
+ themeName := t.Meta.Name + ".theme.json"
+ themeFile, err := os.Create(filepath.Join(tmpDir, themeName))
+ if err != nil {
+ return err
+ }
+ if err := themeTempl.Execute(themeFile, struct{ Theme themer.Theme }{Theme: t}); err != nil {
+ _ = themeFile.Close()
+ return err
+ }
+ _ = themeFile.Close()
+
+ // 4. Bundle everything into a JAR (using zip)
+ jarName := t.Meta.Name + ".jar"
+ outputDir := filepath.Join(a.OutputDir, t.Meta.Name, "intellij")
+ if err := os.MkdirAll(outputDir, 0775); err != nil {
+ return err
+ }
+ jarPath := filepath.Join(outputDir, jarName)
+ _ = os.Remove(jarPath) // Remove old JAR if exists
+ cmd := exec.Command("zip", "-r", jarPath, ".")
+ cmd.Dir = tmpDir
+ if err := cmd.Run(); err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/sithego/themer/adapters/intellij/template.plugin.xml b/sithego/themer/adapters/intellij/template.plugin.xml
new file mode 100644
index 0000000..250d7ef
--- /dev/null
+++ b/sithego/themer/adapters/intellij/template.plugin.xml
@@ -0,0 +1,16 @@
+
+ de.arindy.{{ .Theme.Meta.Name | lower }}
+ {{ .Theme.Meta.Name }} Theme
+ {{ .Theme.Meta.Version }}
+ Arindy
+
+
+
+ com.intellij.modules.platform
+
+
+
+
+
diff --git a/sithego/themer/adapters/intellij/template.theme.json b/sithego/themer/adapters/intellij/template.theme.json
new file mode 100644
index 0000000..7bf43c1
--- /dev/null
+++ b/sithego/themer/adapters/intellij/template.theme.json
@@ -0,0 +1,91 @@
+{
+ "name": "{{ .Theme.Meta.Name }}",
+ "dark": {{ if eq .Theme.Meta.Type "dark" }}true{{ else }}false{{ end }},
+ "parentTheme": "Islands Dark",
+ "author": "Arindy",
+ "colors": {
+ "ScrollBar.thumb": "{{ .Theme.Colors.Semantic.Border.Value }}",
+ "ScrollBar.track": "{{ .Theme.Colors.Semantic.Background.Value }}",
+ "ScrollBar.hoverThumb": "{{ .Theme.Colors.Semantic.Accent.Value }}",
+ "ScrollBar.hoverTrack": "{{ .Theme.Colors.Semantic.Surface.Value }}"
+ },
+ "ui": {
+ "*": {
+ "background": "{{ .Theme.Colors.Semantic.Background.Value }}",
+ "foreground": "{{ .Theme.Colors.Semantic.Text.Value }}",
+ "selectionBackground": "{{ .Theme.Colors.Semantic.Accent.Alpha .Theme.Colors.Semantic.Background 0.3 }}",
+ "selectionForeground": "{{ .Theme.Colors.Semantic.Text.Value }}",
+ "focusColor": "{{ .Theme.Colors.Semantic.Accent.Value }}",
+ "borderColor": "{{ .Theme.Colors.Semantic.Border.Value }}",
+ "disabledBackground": "{{ .Theme.Colors.Semantic.Background.Value }}",
+ "disabledForeground": "{{ .Theme.Colors.Semantic.Disabled.Value }}"
+ },
+ "Button": {
+ "startBackground": "{{ .Theme.Colors.Semantic.SurfaceAlt.Value }}",
+ "endBackground": "{{ .Theme.Colors.Semantic.SurfaceAlt.Value }}",
+ "foreground": "{{ .Theme.Colors.Semantic.Text.Value }}",
+ "focusedBorderColor": "{{ .Theme.Colors.Semantic.Accent.Value }}",
+ "default": {
+ "startBackground": "{{ .Theme.Colors.Semantic.Accent.Value }}",
+ "endBackground": "{{ .Theme.Colors.Semantic.Accent.Value }}",
+ "foreground": "{{ .Theme.Colors.Semantic.Background.Value }}",
+ "focusedBorderColor": "{{ .Theme.Colors.Semantic.Accent.Value }}"
+ }
+ },
+ "ComboBox": {
+ "modifiedItemForeground": "{{ .Theme.Colors.Semantic.Accent.Value }}"
+ },
+ "List": {
+ "background": "{{ .Theme.Colors.Semantic.Surface.Value }}",
+ "selectionBackground": "{{ .Theme.Colors.Semantic.Accent.Alpha .Theme.Colors.Semantic.Background 0.3 }}",
+ "selectionForeground": "{{ .Theme.Colors.Semantic.Text.Value }}"
+ },
+ "Menu": {
+ "background": "{{ .Theme.Colors.Semantic.Surface.Value }}",
+ "foreground": "{{ .Theme.Colors.Semantic.Text.Value }}",
+ "selectionBackground": "{{ .Theme.Colors.Semantic.Accent.Value }}",
+ "selectionForeground": "{{ .Theme.Colors.Semantic.Background.Value }}"
+ },
+ "MenuBar": {
+ "background": "{{ .Theme.Colors.Semantic.Surface.Value }}",
+ "foreground": "{{ .Theme.Colors.Semantic.Text.Value }}",
+ "selectionBackground": "{{ .Theme.Colors.Semantic.Accent.Value }}",
+ "selectionForeground": "{{ .Theme.Colors.Semantic.Background.Value }}"
+ },
+ "Panel": {
+ "background": "{{ .Theme.Colors.Semantic.Background.Value }}"
+ },
+ "SidePanel": {
+ "background": "{{ .Theme.Colors.Semantic.Surface.Value }}"
+ },
+ "TabbedPane": {
+ "background": "{{ .Theme.Colors.Semantic.Surface.Value }}",
+ "underlineColor": "{{ .Theme.Colors.Semantic.Accent.Value }}",
+ "hoverColor": "{{ .Theme.Colors.Semantic.SurfaceAlt.Value }}"
+ },
+ "Table": {
+ "background": "{{ .Theme.Colors.Semantic.Surface.Value }}",
+ "gridColor": "{{ .Theme.Colors.Semantic.Border.Value }}"
+ },
+ "TextField": {
+ "background": "{{ .Theme.Colors.Semantic.Surface.Value }}",
+ "foreground": "{{ .Theme.Colors.Semantic.Text.Value }}",
+ "caretColor": "{{ .Theme.Colors.Semantic.Accent.Value }}"
+ },
+ "ToolWindow": {
+ "Header": {
+ "background": "{{ .Theme.Colors.Semantic.Surface.Value }}",
+ "inactiveBackground": "{{ .Theme.Colors.Semantic.Background.Value }}"
+ },
+ "Button": {
+ "selectedBackground": "{{ .Theme.Colors.Semantic.Accent.Value }}",
+ "selectedForeground": "{{ .Theme.Colors.Semantic.Background.Value }}"
+ }
+ },
+ "Tree": {
+ "rowHeight": 24,
+ "selectionBackground": "{{ .Theme.Colors.Semantic.Accent.Alpha .Theme.Colors.Semantic.Background 0.3 }}",
+ "selectionForeground": "{{ .Theme.Colors.Semantic.Text.Value }}"
+ }
+ }
+}
diff --git a/sithego/themer/adapters/qt/colors.conf b/sithego/themer/adapters/qt/colors.conf
new file mode 100644
index 0000000..7165f4a
--- /dev/null
+++ b/sithego/themer/adapters/qt/colors.conf
@@ -0,0 +1,4 @@
+[ColorScheme]
+active_colors={{ .Theme.Colors.Semantic.Text.Value }}, {{ .Theme.Colors.Semantic.Background.Value }}, {{ .Theme.Colors.Semantic.SurfaceAlt.Value }}, {{ .Theme.Colors.Semantic.Surface.Value }}, {{ .Theme.Colors.Semantic.Disabled.Value }}, {{ .Theme.Colors.Semantic.Text.Value }}, {{ .Theme.Colors.Semantic.Text.Value }}, {{ .Theme.Colors.Semantic.Text.Value }}, {{ .Theme.Colors.Semantic.Text.Value }}, {{ .Theme.Colors.Semantic.Background.Value }}, {{ .Theme.Colors.Semantic.Background.Value }}, {{ .Theme.Colors.Semantic.Border.Value }}, {{ .Theme.Colors.Semantic.Accent.Value }}, {{ .Theme.Colors.Semantic.Background.Value }}, {{ .Theme.Colors.Semantic.Accent.Value }}, {{ .Theme.Colors.Semantic.Warn.Value }}, {{ .Theme.Colors.Semantic.Background.Value }}, {{ .Theme.Colors.Semantic.Text.Value }}, {{ .Theme.Colors.Semantic.Accent.Value }}, {{ .Theme.Colors.Semantic.Background.Value }}, {{ .Theme.Colors.Semantic.Accent.Alpha .Theme.Colors.Semantic.Background 0.3 }}
+disabled_colors={{ .Theme.Colors.Semantic.Disabled.Value }}, {{ .Theme.Colors.Semantic.Background.Value }}, {{ .Theme.Colors.Semantic.SurfaceAlt.Value }}, {{ .Theme.Colors.Semantic.Surface.Value }}, {{ .Theme.Colors.Semantic.Disabled.Value }}, {{ .Theme.Colors.Semantic.Disabled.Value }}, {{ .Theme.Colors.Semantic.Disabled.Value }}, {{ .Theme.Colors.Semantic.Disabled.Value }}, {{ .Theme.Colors.Semantic.Disabled.Value }}, {{ .Theme.Colors.Semantic.Background.Value }}, {{ .Theme.Colors.Semantic.Background.Value }}, {{ .Theme.Colors.Semantic.Border.Value }}, {{ .Theme.Colors.Semantic.Disabled.Value }}, {{ .Theme.Colors.Semantic.Background.Value }}, {{ .Theme.Colors.Semantic.Disabled.Value }}, {{ .Theme.Colors.Semantic.Warn.Value }}, {{ .Theme.Colors.Semantic.Background.Value }}, {{ .Theme.Colors.Semantic.Disabled.Value }}, {{ .Theme.Colors.Semantic.Disabled.Value }}, {{ .Theme.Colors.Semantic.Background.Value }}, {{ .Theme.Colors.Semantic.Disabled.Value }}
+inactive_colors={{ .Theme.Colors.Semantic.Text.Value }}, {{ .Theme.Colors.Semantic.Background.Value }}, {{ .Theme.Colors.Semantic.SurfaceAlt.Value }}, {{ .Theme.Colors.Semantic.Surface.Value }}, {{ .Theme.Colors.Semantic.Disabled.Value }}, {{ .Theme.Colors.Semantic.Text.Value }}, {{ .Theme.Colors.Semantic.Text.Value }}, {{ .Theme.Colors.Semantic.Text.Value }}, {{ .Theme.Colors.Semantic.Text.Value }}, {{ .Theme.Colors.Semantic.Background.Value }}, {{ .Theme.Colors.Semantic.Background.Value }}, {{ .Theme.Colors.Semantic.Border.Value }}, {{ .Theme.Colors.Semantic.Accent.Value }}, {{ .Theme.Colors.Semantic.Background.Value }}, {{ .Theme.Colors.Semantic.Accent.Value }}, {{ .Theme.Colors.Semantic.Warn.Value }}, {{ .Theme.Colors.Semantic.Background.Value }}, {{ .Theme.Colors.Semantic.Text.Value }}, {{ .Theme.Colors.Semantic.Accent.Value }}, {{ .Theme.Colors.Semantic.Background.Value }}, {{ .Theme.Colors.Semantic.Accent.Alpha .Theme.Colors.Semantic.Background 0.3 }}
diff --git a/sithego/themer/adapters/qt/qt.go b/sithego/themer/adapters/qt/qt.go
new file mode 100644
index 0000000..34bc254
--- /dev/null
+++ b/sithego/themer/adapters/qt/qt.go
@@ -0,0 +1,105 @@
+package qt
+
+import (
+ "Sithego/themer"
+ "os"
+ "path/filepath"
+ "text/template"
+)
+
+type Adapter struct {
+ OutputDir string
+}
+
+type Option func(*Adapter)
+
+func WithOutputDir(dir string) Option {
+ return func(a *Adapter) {
+ a.OutputDir = dir
+ }
+}
+
+func New(opt ...Option) *Adapter {
+ home, _ := os.UserHomeDir()
+ a := &Adapter{
+ OutputDir: home + "/.config/",
+ }
+ for _, o := range opt {
+ o(a)
+ }
+ return a
+}
+
+func (a *Adapter) Name() string {
+ return "Qt"
+}
+
+func (a *Adapter) Generate(t themer.Theme) error {
+ qssComponents := []string{
+ "template.qss",
+ }
+ outputDir := filepath.Join(a.OutputDir, "qt6ct")
+ if err := os.MkdirAll(outputDir, 0775); err != nil {
+ return err
+ }
+
+ for _, component := range qssComponents {
+ templatePath := filepath.Join("themer/adapters/qt", component)
+ templ, err := template.ParseFiles(templatePath)
+ if err != nil {
+ return err
+ }
+ qssOutputDir := filepath.Join(outputDir, "qss")
+ err = os.MkdirAll(qssOutputDir, 0775)
+ if err != nil {
+ return err
+ }
+ outputPath := filepath.Join(qssOutputDir, t.Meta.Name+".qss")
+
+ file, err := os.Create(outputPath)
+ if err != nil {
+ return err
+ }
+
+ err = templ.Execute(file, struct {
+ Theme themer.Theme
+ }{
+ Theme: t,
+ })
+ _ = file.Close()
+ if err != nil {
+ return err
+ }
+ }
+
+ // 2. Generate qt5ct/qt6ct color scheme (.conf)
+ confTemplatePath := "themer/adapters/qt/colors.conf"
+ if _, err := os.Stat(confTemplatePath); err == nil {
+ templ, err := template.ParseFiles(confTemplatePath)
+ if err != nil {
+ return err
+ }
+ confOutputDir := filepath.Join(outputDir, "colors")
+ err = os.MkdirAll(confOutputDir, 0775)
+ if err != nil {
+ return err
+ }
+ outputPath := filepath.Join(confOutputDir, t.Meta.Name+".conf")
+ file, err := os.Create(outputPath)
+ if err != nil {
+ return err
+ }
+
+ err = templ.Execute(file, struct {
+ Theme themer.Theme
+ }{
+ Theme: t,
+ })
+ _ = file.Close()
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
diff --git a/sithego/themer/adapters/qt/template.qss b/sithego/themer/adapters/qt/template.qss
new file mode 100644
index 0000000..303a518
--- /dev/null
+++ b/sithego/themer/adapters/qt/template.qss
@@ -0,0 +1,115 @@
+/* Global Styles */
+QWidget {
+ background-color: {{ .Theme.Colors.Semantic.Background.Value }};
+ color: {{ .Theme.Colors.Semantic.Text.Value }};
+ selection-background-color: {{ .Theme.Colors.Semantic.Accent.Value }};
+ selection-color: {{ .Theme.Colors.Semantic.Background.Value }};
+}
+
+/* Buttons */
+QPushButton {
+ background-color: {{ .Theme.Colors.Semantic.SurfaceAlt.Value }};
+ border: 1px solid {{ .Theme.Colors.Semantic.Border.Value }};
+ border-radius: {{ .Theme.Spacing.Radius }};
+ padding: {{ .Theme.Spacing.Padding }};
+}
+
+QPushButton:hover {
+ background-color: {{ .Theme.Colors.Semantic.Border.Value }};
+}
+
+QPushButton:pressed {
+ background-color: {{ .Theme.Colors.Semantic.Accent.Value }};
+ color: {{ .Theme.Colors.Semantic.Background.Value }};
+}
+
+QPushButton:disabled {
+ background-color: {{ .Theme.Colors.Semantic.Background.Value }};
+ color: {{ .Theme.Colors.Semantic.Disabled.Value }};
+ border-color: {{ .Theme.Colors.Semantic.Disabled.Value }};
+}
+
+/* Input Fields */
+QLineEdit, QTextEdit, QPlainTextEdit {
+ background-color: {{ .Theme.Colors.Semantic.Surface.Value }};
+ border: 1px solid {{ .Theme.Colors.Semantic.Border.Value }};
+ border-radius: {{ .Theme.Spacing.Radius }};
+ padding: {{ .Theme.Spacing.PaddingSmall }};
+}
+
+QLineEdit:focus {
+ border: 1px solid {{ .Theme.Colors.Semantic.Accent.Value }};
+}
+
+/* Menus and Lists */
+QListView, QTreeView, QTableView {
+ background-color: {{ .Theme.Colors.Semantic.Surface.Value }};
+ border: 1px solid {{ .Theme.Colors.Semantic.Border.Value }};
+ border-radius: {{ .Theme.Spacing.Radius }};
+ alternate-background-color: {{ .Theme.Colors.Semantic.SurfaceAlt.Value }};
+}
+
+QListView::item:selected, QTreeView::item:selected, QTableView::item:selected {
+ background-color: {{ .Theme.Colors.Semantic.Accent.Alpha .Theme.Colors.Semantic.Background 0.3 }};
+ border: 1px solid {{ .Theme.Colors.Semantic.Accent.Value }};
+ color: {{ .Theme.Colors.Semantic.Text.Value }};
+}
+
+/* Scrollbars */
+QScrollBar:vertical {
+ background: {{ .Theme.Colors.Semantic.SurfaceAlt.Value }};
+ width: 12px;
+ margin: 0px;
+}
+
+QScrollBar::handle:vertical {
+ background: {{ .Theme.Colors.Semantic.Border.Value }};
+ min-height: 20px;
+ border-radius: {{ .Theme.Spacing.RadiusSmall }};
+ margin: 2px;
+}
+
+QScrollBar::handle:vertical:hover {
+ background: {{ .Theme.Colors.Semantic.Accent.Value }};
+}
+
+QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {
+ height: 0px;
+}
+
+/* Tabs */
+QTabBar::tab {
+ background: {{ .Theme.Colors.Semantic.Surface.Value }};
+ border: 1px solid {{ .Theme.Colors.Semantic.Border.Value }};
+ padding: {{ .Theme.Spacing.Padding }};
+ border-top-left-radius: {{ .Theme.Spacing.Radius }};
+ border-top-right-radius: {{ .Theme.Spacing.Radius }};
+}
+
+QTabBar::tab:selected {
+ background: {{ .Theme.Colors.Semantic.Background.Value }};
+ border-bottom-color: {{ .Theme.Colors.Semantic.Accent.Value }};
+}
+
+/* Checkboxes and Radio Buttons */
+QCheckBox::indicator, QRadioButton::indicator {
+ width: 18px;
+ height: 18px;
+ border: 1px solid {{ .Theme.Colors.Semantic.Border.Value }};
+ background-color: {{ .Theme.Colors.Semantic.SurfaceAlt.Value }};
+ border-radius: {{ .Theme.Spacing.Radius }};
+}
+
+QRadioButton::indicator {
+ border-radius: 9px;
+}
+
+QCheckBox::indicator:checked {
+ border-color: {{ .Theme.Colors.Semantic.Accent.Value }};
+ background-color: {{ .Theme.Colors.Semantic.Accent.Value }};
+}
+
+QRadioButton::indicator:checked {
+ border-color: {{ .Theme.Colors.Semantic.Accent.Value }};
+ background-color: {{ .Theme.Colors.Semantic.Accent.Value }};
+}
diff --git a/sithego/themer/adapters/starship/starship.go b/sithego/themer/adapters/starship/starship.go
new file mode 100644
index 0000000..a4f8c14
--- /dev/null
+++ b/sithego/themer/adapters/starship/starship.go
@@ -0,0 +1,60 @@
+package starship
+
+import (
+ "Sithego/themer"
+ "os"
+ "path/filepath"
+ "text/template"
+)
+
+type Adapter struct {
+ OutputDir string
+}
+
+type Option func(*Adapter)
+
+func WithOutputDir(dir string) Option {
+ return func(a *Adapter) {
+ a.OutputDir = dir
+ }
+}
+
+func New(opt ...Option) *Adapter {
+ home, _ := os.UserHomeDir()
+ a := &Adapter{
+ OutputDir: home + "/.config/",
+ }
+ for _, o := range opt {
+ o(a)
+ }
+ return a
+}
+
+func (a *Adapter) Name() string {
+ return "Starship"
+}
+
+func (a *Adapter) Generate(t themer.Theme) error {
+ templatePath := filepath.Join("themer/adapters/starship", "starship.toml")
+ templ, err := template.ParseFiles(templatePath)
+ if err != nil {
+ return err
+ }
+ outputPath := filepath.Join(a.OutputDir, "starship.toml")
+
+ file, err := os.Create(outputPath)
+ if err != nil {
+ return err
+ }
+
+ err = templ.Execute(file, struct {
+ Theme themer.Theme
+ }{
+ Theme: t,
+ })
+ _ = file.Close()
+ if err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/sithego/themer/adapters/starship/starship.toml b/sithego/themer/adapters/starship/starship.toml
new file mode 100644
index 0000000..7b3b2dc
--- /dev/null
+++ b/sithego/themer/adapters/starship/starship.toml
@@ -0,0 +1,159 @@
+"$schema" = 'https://starship.rs/config-schema.json'
+
+format = """
+[](color_bg1)\
+[](bg:color_bg1 fg:color_fg0)\
+$username\
+[](fg:color_bg1)\
+$directory\
+[](bg:color_bg1 fg:color_black)\
+$git_branch\
+$git_status\
+[](fg:color_bg1 bg:color_blue)\
+$c\
+$cpp\
+$rust\
+$golang\
+$nodejs\
+$php\
+$java\
+$kotlin\
+$haskell\
+$python\
+[](fg:color_blue bg:color_bg3)\
+$docker_context\
+$conda\
+$pixi\
+[](fg:color_bg3 bg:color_bg1)\
+$time\
+[ ](fg:color_bg1)\
+$cmd_duration\
+$line_break$character"""
+
+palette = 'serpensortia'
+
+[palettes.serpensortia]
+color_black = "#000000"
+color_fg0 = "{{ .Theme.Colors.Semantic.Text.Value }}"
+color_bg1 = "{{ .Theme.Colors.Semantic.Surface.Value }}"
+color_bg3 = "{{ .Theme.Colors.Semantic.SurfaceAlt.Value }}"
+color_blue = "{{ .Theme.Colors.Semantic.Accent.Value }}"
+color_aqua = "{{ .Theme.Colors.Semantic.Accent.Value }}"
+color_accent = "{{ .Theme.Colors.Semantic.Accent.Value }}"
+color_orange = "{{ .Theme.Colors.Semantic.Accent.Value }}"
+color_purple = "{{ .Theme.Colors.Semantic.Accent.Value }}"
+color_warn = "{{ .Theme.Colors.Semantic.Accent.Value }}"
+color_yellow = "{{ .Theme.Colors.Semantic.Accent.Value }}"
+
+[username]
+show_always = true
+style_user = "bg:color_bg1 fg:color_accent"
+style_root = "bg:color_warn fg:color_bg1"
+format = '[ $user ]($style)'
+
+[directory]
+style = "fg:color_bg0 bg:color_text"
+format = "[ $path ]($style)[$read_only]($read_only_style) "
+read_only_style = "{{ .Theme.Colors.Semantic.Warn.Value }}"
+read_only = ""
+truncation_length = 0
+truncation_symbol = "…/"
+
+[directory.substitutions]
+"Documents" = " "
+"Downloads" = " "
+"Music" = " "
+"Pictures" = " "
+"workspace" = " "
+
+[git_branch]
+symbol = ""
+style = "bg:color_bg1"
+format = '[[ $symbol $branch ](fg:color_accent bg:color_bg1)]($style)'
+
+[git_status]
+style = "bg:color_bg1"
+format = '[[($all_status$ahead_behind )](fg:color_accent bg:color_bg1)]($style)'
+
+[nodejs]
+symbol = ""
+style = "bg:color_blue"
+format = '[[ $symbol( $version) ](fg:color_fg0 bg:color_blue)]($style)'
+
+[c]
+symbol = " "
+style = "bg:color_blue"
+format = '[[ $symbol( $version) ](fg:color_fg0 bg:color_blue)]($style)'
+
+[cpp]
+symbol = " "
+style = "bg:color_blue"
+format = '[[ $symbol( $version) ](fg:color_fg0 bg:color_blue)]($style)'
+
+[rust]
+symbol = ""
+style = "bg:color_blue"
+format = '[[ $symbol( $version) ](fg:color_fg0 bg:color_blue)]($style)'
+
+[golang]
+symbol = ""
+style = "bg:color_blue"
+format = '[[ $symbol( $version) ](fg:color_fg0 bg:color_blue)]($style)'
+
+[php]
+symbol = ""
+style = "bg:color_blue"
+format = '[[ $symbol( $version) ](fg:color_fg0 bg:color_blue)]($style)'
+
+[java]
+symbol = ""
+style = "bg:color_blue"
+format = '[[ $symbol( $version) ](fg:color_fg0 bg:color_blue)]($style)'
+
+[kotlin]
+symbol = ""
+style = "bg:color_blue"
+format = '[[ $symbol( $version) ](fg:color_fg0 bg:color_blue)]($style)'
+
+[haskell]
+symbol = ""
+style = "bg:color_blue"
+format = '[[ $symbol( $version) ](fg:color_fg0 bg:color_blue)]($style)'
+
+[python]
+symbol = ""
+style = "bg:color_blue"
+format = '[[ $symbol( $version) ](fg:color_fg0 bg:color_blue)]($style)'
+
+[docker_context]
+symbol = ""
+style = "bg:color_bg3"
+format = '[[ $symbol( $context) ](fg:#83a598 bg:color_bg3)]($style)'
+
+[conda]
+style = "bg:color_bg3"
+format = '[[ $symbol( $environment) ](fg:#83a598 bg:color_bg3)]($style)'
+
+[pixi]
+style = "bg:color_bg3"
+format = '[[ $symbol( $version)( $environment) ](fg:color_fg0 bg:color_bg3)]($style)'
+
+[time]
+disabled = false
+time_format = "%R"
+style = "bg:color_bg1"
+format = '[[ $time ](fg:color_fg0 bg:color_bg1)]($style)'
+
+[line_break]
+disabled = false
+
+[character]
+disabled = false
+success_symbol = '[❯](bold green)'
+error_symbol = '[✖](bold red)'
+
+[cmd_duration]
+disabled = false
+min_time = 50
+show_milliseconds = true
+format = '[$duration](bold)'
\ No newline at end of file
diff --git a/sithego/themer/theme.go b/sithego/themer/theme.go
new file mode 100644
index 0000000..b965f93
--- /dev/null
+++ b/sithego/themer/theme.go
@@ -0,0 +1,180 @@
+package themer
+
+import (
+ "os"
+ "strconv"
+ "strings"
+
+ "github.com/pelletier/go-toml/v2"
+)
+
+type Theme struct {
+ Meta struct {
+ Name string
+ Type string
+ Version string
+ }
+ Primitive map[string]string
+ Colors struct {
+ Semantic struct {
+ Background Color
+ Surface Color
+ SurfaceAlt Color
+ Disabled Color
+ Border Color
+ Text Color
+ Accent Color
+ Warn Color
+ }
+ } `toml:"Colors"`
+ Spacing struct {
+ Padding string
+ PaddingSmall string
+ PaddingLarge string
+ Margin string
+ MarginSmall string
+ Radius string
+ RadiusSmall string
+ RadiusLarge string
+ } `toml:"Spacing"`
+}
+
+type Color struct {
+ raw string
+ Value string
+}
+
+func (c Color) Alpha(bg Color, amount float64) string {
+ r1, g1, b1, ok1 := parseHexRGB(c.Value)
+ r2, g2, b2, ok2 := parseHexRGB(bg.Value)
+ if !ok1 || !ok2 {
+ return c.Value
+ }
+ r := blend8(r2, r1, amount)
+ g := blend8(g2, g1, amount)
+ b := blend8(b2, b1, amount)
+ return formatHexRGB(r, g, b)
+}
+
+func (c *Color) UnmarshalText(text []byte) error {
+ c.raw = strings.TrimSpace(string(text))
+ return nil
+}
+
+func LoadTheme(path string) (Theme, error) {
+ theme := Theme{}
+ if themeFile, err := os.ReadFile(path); err != nil {
+ return theme, err
+ } else {
+ if err := toml.Unmarshal(themeFile, &theme); err != nil {
+ return theme, err
+ }
+ }
+ theme.resolveColor(&theme.Colors.Semantic.Background)
+ theme.resolveColor(&theme.Colors.Semantic.Surface)
+ theme.resolveColor(&theme.Colors.Semantic.SurfaceAlt)
+ theme.resolveColor(&theme.Colors.Semantic.Disabled)
+ theme.resolveColor(&theme.Colors.Semantic.Border)
+ theme.resolveColor(&theme.Colors.Semantic.Text)
+ theme.resolveColor(&theme.Colors.Semantic.Accent)
+ theme.resolveColor(&theme.Colors.Semantic.Warn)
+
+ return theme, nil
+}
+
+func (t Theme) resolveColor(color *Color) {
+ raw, shadeRaw, hasShade := strings.Cut(color.raw, "|")
+ base := strings.TrimSpace(raw)
+ shade, err := strconv.Atoi(strings.TrimSpace(shadeRaw))
+ if primitive, ok := t.Primitive[base]; ok {
+ base = primitive
+ } else {
+ base = raw
+ }
+ base = normalizeHex(base)
+ if !hasShade || err != nil {
+ color.Value = base
+ return
+ }
+ if shade < 0 {
+ shade = 0
+ }
+ if shade > 1000 {
+ shade = 1000
+ }
+
+ r, g, b, ok := parseHexRGB(base)
+ if !ok {
+ color.Value = base
+ return
+ }
+
+ switch {
+ case shade == 500:
+ // unchanged
+ case shade < 500:
+ amount := float64(500-shade) / 500.0
+ r = blend8(r, 255, amount)
+ g = blend8(g, 255, amount)
+ b = blend8(b, 255, amount)
+ default:
+ amount := float64(shade-500) / 500.0
+ r = blend8(r, 0, amount)
+ g = blend8(g, 0, amount)
+ b = blend8(b, 0, amount)
+ }
+ color.Value = formatHexRGB(r, g, b)
+}
+
+func normalizeHex(s string) string {
+ s = strings.TrimSpace(s)
+ if s == "" {
+ return s
+ }
+ if strings.HasPrefix(s, "#") {
+ return s
+ }
+ return "#" + s
+}
+
+func parseHexRGB(s string) (uint8, uint8, uint8, bool) {
+ s = strings.TrimSpace(s)
+ if strings.HasPrefix(s, "#") {
+ s = s[1:]
+ }
+ if len(s) != 6 {
+ return 0, 0, 0, false
+ }
+ // Manual hex parsing to avoid extra deps; strconv handles base 16 fine.
+ rv, err1 := strconv.ParseUint(s[0:2], 16, 8)
+ gv, err2 := strconv.ParseUint(s[2:4], 16, 8)
+ bv, err3 := strconv.ParseUint(s[4:6], 16, 8)
+ if err1 != nil || err2 != nil || err3 != nil {
+ return 0, 0, 0, false
+ }
+ return uint8(rv), uint8(gv), uint8(bv), true
+}
+func formatHexRGB(r, g, b uint8) string {
+ const hex = "0123456789abcdef"
+ out := make([]byte, 7)
+ out[0] = '#'
+ out[1] = hex[r>>4]
+ out[2] = hex[r&0x0f]
+ out[3] = hex[g>>4]
+ out[4] = hex[g&0x0f]
+ out[5] = hex[b>>4]
+ out[6] = hex[b&0x0f]
+ return string(out)
+}
+
+func blend8(a, b uint8, t float64) uint8 {
+ // result = a*(1-t) + b*t, rounded
+ v := float64(a)*(1.0-t) + float64(b)*t
+ if v < 0 {
+ v = 0
+ }
+ if v > 255 {
+ v = 255
+ }
+ return uint8(v + 0.5)
+}