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) +}