diff --git a/apps.md b/apps.md index ebb58ed..636f652 100644 --- a/apps.md +++ b/apps.md @@ -15,26 +15,25 @@ ansible-playbook -K play.yml Deps: `pkgconfig patch flex bison which` 1. Audio - `pipewire wireplumber pipewire-pulse pipewire-alsa pipewire-jack qpwgraph` 2. Wayland compositor - `hyprland xdg-desktop-portal-hyprland polkit-kde-agent` -3. Status bar - `waybar` +3. Status bar - `aylurs-gtk-shell` 4. Terminal - `foot` 5. Screenshotting - `wl-clipboard slurp grim` 6. Application picker - `rofi-lbonn-wayland` -7. Notifications - `mako` -8. Background - `swww` -9. File manager - `thunar gvfs gvfs-smb` -10. File syncing - `syncthing` -11. Music - `spotify spicetify-cli` +7. Background - `swww` +8. File manager - `thunar gvfs gvfs-smb` +9. File syncing - `syncthing` +10. Music - `spotify spicetify-cli` ``` curl -fsSL https://raw.githubusercontent.com/spicetify/spicetify-marketplace/main/resources/install.sh | sh spicetify backup apply ``` -12. Fonts - `ttf-jebrains-mono-nerd` -13. Discord - `vencord-desktop-git` -14. Browser - `vivaldi` +11. Fonts - `ttf-jebrains-mono-nerd` +12. Discord - `vencord-desktop-git` +13. Browser - `vivaldi` ``` (credit: Archwiki) Go to chrome://flags page, then search wayland. You will see the Preferred Ozone platform setting. Set it to auto. The default one is "X11". "Auto" selects Wayland if possible, X11 otherwise. ``` -15. Documents - `wps-office ttf-wps-fonts` -16. Code editor - `visual-studio-code-bin` -17. Extras - `pipes.sh fastfetch lemurs nushell` \ No newline at end of file +14. Documents - `wps-office ttf-wps-fonts` +15. Code editor - `visual-studio-code-bin` +16. Extras - `pipes.sh fastfetch lemurs nushell catppuccin-gtk-theme-latte` \ No newline at end of file diff --git a/manual.md b/manual.md index 2d354cf..4ce0595 100644 --- a/manual.md +++ b/manual.md @@ -3,10 +3,10 @@ Make new user ``` pacman -S sudo -useradd -mU yf -echo "yf ALL=(ALL:ALL) ALL" >> /etc/sudoers -passwd yf -su yf +useradd -mU sophie +echo "sophie ALL=(ALL:ALL) ALL" >> /etc/sudoers +passwd sophie +su sophie ``` Install yay @@ -26,14 +26,14 @@ mkdir /etc/systemd/system/getty@tty1.service.d cat <<- "EOF" > /etc/systemd/system/getty@tty1.service.d/skip-username.conf [Service] ExecStart= -ExecStart=-/sbin/agetty -o '-p -- yf' --noclear --skip-login - $TERM +ExecStart=-/sbin/agetty -o '-p -- sophie' --noclear --skip-login - $TERM Environment=XDG_SESSION_TYPE=wayland EOF ``` Remove password ``` -sudo sed -i 's/yf:[^:]*/yf:/' /etc/shadow +sudo sed -i 's/sophie:[^:]*/sophie:/' /etc/shadow ``` Install stow @@ -50,7 +50,7 @@ stow src Automatically log into Hyprland ``` -cat <<- "EOF" > /home/yf/.bash_profile +cat <<- "EOF" > /home/sophie/.bash_profile if [[ "$(tty)" == "/dev/tty1" ]] then Hyprland diff --git a/old_wallpaper.png b/old_wallpaper.png new file mode 100644 index 0000000..3855aaa Binary files /dev/null and b/old_wallpaper.png differ diff --git a/play.yml b/play.yml index 096cb67..3f60040 100644 --- a/play.yml +++ b/play.yml @@ -25,15 +25,15 @@ - name: Create user group ansible.builtin.group: - name: yf + name: sophie state: present become: yes - name: Create user ansible.builtin.user: - name: yf + name: sophie create_home: yes - groups: yf + groups: sophie append: yes state: present become: yes @@ -45,11 +45,11 @@ state: present become: yes - - name: Give user yf max sudoers + - name: Give user sophie max sudoers community.general.sudoers: name: main-user state: present - user: yf + user: sophie runas: ALL commands: ALL become: yes @@ -69,7 +69,7 @@ use: makepkg state: present become: yes - become_user: yf + become_user: sophie - name: Install stow community.general.pacman: @@ -80,26 +80,25 @@ - name: Clone my dotfiles ansible.builtin.git: - repo: 'https://github.com/fucksophie/dots.git' - dest: /home/yf/.shell + repo: 'https://git.sad.ovh/sophie/dots.git' + dest: /home/sophie/.shell become: yes - become_user: yf + become_user: sophie - name: Upgrade the system using yay kewlfft.aur.aur: upgrade: yes use: yay become: yes - become_user: yf - + become_user: sophie - name: Run stow - ansible.builtin.shell: "stow . --target=/home/yf/ --verbose=2" + ansible.builtin.shell: "stow . --target=/home/sophie/ --verbose=2" args: - chdir: /home/yf/.shell/src + chdir: /home/sophie/.shell/src register: result changed_when: 'result.stderr is search("LINK: ")' become: yes - become_user: yf + become_user: sophie - name: Install everything kewlfft.aur.aur: use: yay @@ -123,14 +122,14 @@ - hyprland - xdg-desktop-portal-hyprland-git - polkit-kde-agent - - waybar + - aylurs-gtk-shell + - catppuccin-gtk-theme-latte - foot - nushell - wl-clipboard - slurp - grim - rofi-lbonn-wayland-git - - mako - swww - thunar - gvfs @@ -149,16 +148,16 @@ - lemurs - syncthing become: yes - become_user: yf + become_user: sophie - name: Create .bash_profile ansible.builtin.file: - path: /home/yf/.bash_profile + path: /home/sophie/.bash_profile state: touch modification_time: preserve access_time: preserve become: yes - become_user: yf + become_user: sophie - name: Enable lemurs ansible.builtin.systemd: @@ -188,4 +187,7 @@ #! /bin/sh exec Hyprland become: yes - + - name: Set GTK interface theme + ansible.builtin.shell: "gsettings set org.gnome.desktop.interface gtk-theme 'Catppuccin-Latte-Standard-Pink-Light'" + become: yes + become_user: sophie \ No newline at end of file diff --git a/src/.config/ags/config.js b/src/.config/ags/config.js new file mode 100644 index 0000000..4667201 --- /dev/null +++ b/src/.config/ags/config.js @@ -0,0 +1,198 @@ +import { NotificationPopups } from "./notificationPopups.js"; + +const hyprland = await Service.import("hyprland"); +const notifications = await Service.import("notifications"); +const mpris = await Service.import("mpris"); +const audio = await Service.import("audio"); +const battery = await Service.import("battery"); +const systemtray = await Service.import("systemtray"); + +const date = Variable("", { + poll: [1000, 'date "+%H:%M:%S %b %e."'], +}); + +// widgets can be only assigned as a child in one container +// so to make a reuseable widget, make it a function +// then you can simply instantiate one by calling it + +function Workspaces(monitor) { + const activeId = hyprland.active.workspace.bind("id"); + const workspaces = hyprland + .bind("workspaces") + + .as((ws) => + ws + .filter((z) => z.monitorID == monitor) + .map(({ id }) => + Widget.Button({ + on_clicked: () => hyprland.messageAsync(`dispatch workspace ${id}`), + child: Widget.Label(`${id}`), + class_name: activeId.as((i) => `${i === id ? "focused" : ""}`), + }) + ) + ); + + return Widget.Box({ + class_name: "workspaces", + children: workspaces, + }); +} + +function ClientTitle() { + return Widget.Label({ + class_name: "client-title", + label: hyprland.active.client.bind("title"), + }); +} + +function Clock() { + return Widget.Label({ + class_name: "clock", + label: date.bind(), + }); +} + +function Media() { + const label = Utils.watch("", mpris, "player-changed", () => { + const player = mpris.players.find(z => z.entry == "spotify"); + if (player) { + const ms = player.metadata["mpris:length"]/1000; + const minutes = Math.floor((ms/1000)/60) + const seconds = Math.floor((ms/1000)%60) + + return `${player.track_artists.join(", ")} - ${player.track_title} [${minutes}:${seconds}]`; + } else { + return "Nothing is playing"; + } + }); + + return Widget.Button({ + class_name: "media", + on_primary_click: () => mpris.getPlayer("")?.playPause(), + on_scroll_up: () => mpris.getPlayer("")?.next(), + on_scroll_down: () => mpris.getPlayer("")?.previous(), + child: Widget.Label({ label }), + }); +} + +function Volume() { + const icons = { + 101: "overamplified", + 67: "high", + 34: "medium", + 1: "low", + 0: "muted", + }; + + function getIcon() { + const icon = audio.speaker.is_muted + ? 0 + : [101, 67, 34, 1, 0].find( + (threshold) => threshold <= audio.speaker.volume * 100 + ); + + return `audio-volume-${icons[icon]}-symbolic`; + } + + const icon = Widget.Icon({ + icon: Utils.watch(getIcon(), audio.speaker, getIcon), + }); + + const slider = Widget.Slider({ + hexpand: true, + draw_value: false, + on_change: ({ value }) => (audio.speaker.volume = value), + setup: (self) => + self.hook(audio.speaker, () => { + self.value = audio.speaker.volume || 0; + }), + }); + + return Widget.Box({ + class_name: "volume", + css: "min-width: 180px", + children: [icon, slider], + }); +} + +function BatteryLabel() { + const value = battery.bind("percent").as((p) => (p > 0 ? p / 100 : 0)); + const icon = battery + .bind("percent") + .as((p) => `battery-level-${Math.floor(p / 10) * 10}-symbolic`); + + return Widget.Box({ + class_name: "battery", + visible: battery.bind("available"), + children: [ + Widget.Icon({ icon }), + Widget.LevelBar({ + widthRequest: 140, + vpack: "center", + value, + }), + ], + }); +} + +function SysTray() { + const items = systemtray.bind("items").as((items) => + items.map((item) => + Widget.Button({ + child: Widget.Icon({ icon: item.bind("icon") }), + on_primary_click: (_, event) => item.activate(event), + on_secondary_click: (_, event) => item.openMenu(event), + tooltip_markup: item.bind("tooltip_markup"), + }) + ) + ); + + return Widget.Box({ + children: items, + }); +} + +// layout of the bar +function Left(monitor) { + return Widget.Box({ + spacing: 8, + children: [Workspaces(monitor), ClientTitle()], + }); +} + +function Center() { + return Widget.Box({ + spacing: 8, + children: [Media()], + }); +} + +function Right() { + return Widget.Box({ + hpack: "end", + spacing: 8, + children: [Volume(), BatteryLabel(), Clock(), SysTray()], + }); +} + +function Bar(monitor = 0) { + return Widget.Window({ + name: `bar-${monitor}`, // name has to be unique + class_name: "bar", + monitor, + anchor: ["top", "left", "right"], + exclusivity: "exclusive", + child: Widget.CenterBox({ + start_widget: Left(monitor), + center_widget: Center(), + end_widget: Right(), + }), + }); +} + +App.config({ + style: "./style.css", + windows: [Bar(0), Bar(1), NotificationPopups(0), NotificationPopups(1)], +}); + +export {}; diff --git a/src/.config/ags/notificationPopups.js b/src/.config/ags/notificationPopups.js new file mode 100644 index 0000000..4c63d74 --- /dev/null +++ b/src/.config/ags/notificationPopups.js @@ -0,0 +1,130 @@ +const notifications = await Service.import("notifications") + +/** @param {import('resource:///com/github/Aylur/ags/service/notifications.js').Notification} n */ +function NotificationIcon({ app_entry, app_icon, image }) { + if (image) { + return Widget.Box({ + css: `background-image: url("${image}");` + + "background-size: contain;" + + "background-repeat: no-repeat;" + + "background-position: center;", + }) + } + + let icon = "dialog-information-symbolic" + if (Utils.lookUpIcon(app_icon)) + icon = app_icon + + if (app_entry && Utils.lookUpIcon(app_entry)) + icon = app_entry + + return Widget.Box({ + child: Widget.Icon(icon), + }) +} + +/** @param {import('resource:///com/github/Aylur/ags/service/notifications.js').Notification} n */ +function Notification(n) { + const icon = Widget.Box({ + vpack: "start", + class_name: "icon", + child: NotificationIcon(n), + }) + + const title = Widget.Label({ + class_name: "title", + xalign: 0, + justification: "left", + hexpand: true, + max_width_chars: 24, + truncate: "end", + wrap: true, + label: n.summary, + use_markup: true, + }) + + const body = Widget.Label({ + class_name: "body", + hexpand: true, + use_markup: true, + xalign: 0, + justification: "left", + label: n.body, + wrap: true, + }) + + const actions = Widget.Box({ + class_name: "actions", + children: n.actions.map(({ id, label }) => Widget.Button({ + class_name: "action-button", + on_clicked: () => { + n.invoke(id) + n.dismiss() + }, + hexpand: true, + child: Widget.Label(label), + })), + }) + + return Widget.EventBox( + { + attribute: { id: n.id }, + on_primary_click: n.dismiss, + }, + Widget.Box( + { + class_name: `notification ${n.urgency}`, + vertical: true, + }, + Widget.Box([ + icon, + Widget.Box( + { vertical: true }, + title, + body, + ), + ]), + actions, + ), + ) +} + +export function NotificationPopups(monitor = 0) { + const list = Widget.Box({ + vertical: true, + children: notifications.popups.map(Notification), + }) + + function onNotified(_, /** @type {number} */ id) { + const n = notifications.getNotification(id) + if (n) + list.children = [Notification(n), ...list.children] + } + + function onDismissed(_, /** @type {number} */ id) { + list.children.find(n => n.attribute.id === id)?.destroy() + } + + list.hook(notifications, onNotified, "notified") + .hook(notifications, onDismissed, "dismissed") + + return Widget.Window({ + monitor, + name: `notifications${monitor}`, + class_name: "notification-popups", + anchor: ["top", "right"], + child: Widget.Box({ + css: "min-width: 2px; min-height: 2px;", + class_name: "notifications", + vertical: true, + child: list, + + /** this is a simple one liner that could be used instead of + hooking into the 'notified' and 'dismissed' signals. + but its not very optimized becuase it will recreate + the whole list everytime a notification is added or dismissed */ + // children: notifications.bind('popups') + // .as(popups => popups.map(Notification)) + }), + }) +} \ No newline at end of file diff --git a/src/.config/ags/style.css b/src/.config/ags/style.css new file mode 100644 index 0000000..8171592 --- /dev/null +++ b/src/.config/ags/style.css @@ -0,0 +1,85 @@ +window.bar { + background-color: @theme_bg_color; + color: @theme_fg_color; +} + +button { + min-width: 0; + padding-top: 0; + padding-bottom: 0; + background-color: transparent; +} + +button:active { + background-color: @theme_selected_bg_color; +} + +button:hover { + border-bottom: 3px solid @theme_fg_color; +} + +label { + font-weight: bold; +} + +window.notification-popups box.notifications { + padding: .5em; +} + +.body { + color: @theme_unfocused_fg_color; +} + +.actions .action-button { + margin: 0 .4em; + margin-top: .8em; +} + +.actions .action-button:first-child { + margin-left: 0; +} + +.actions .action-button:last-child { + margin-right: 0; +} + +.icon { + min-width: 68px; + min-height: 68px; + margin-right: 1em; +} + +.icon image { + font-size: 58px; + /* to center the icon */ + margin: 5px; + color: @theme_fg_color; +} + +.icon box { + min-width: 68px; + min-height: 68px; + border-radius: 7px; +} + +.workspaces button.focused { + border-bottom: 3px solid @theme_selected_bg_color; +} + +.notification { + min-width: 350px; + border-radius: 11px; + padding: 1em; + margin: .5em; + border: 1px solid @wm_borders_edge; + background-color: @theme_bg_color; +} + +.client-title { + color: @theme_selected_bg_color; +} + +levelbar block, +highlight { + min-height: 10px; +} \ No newline at end of file diff --git a/src/.config/hypr/hyprland.conf b/src/.config/hypr/hyprland.conf index 3db1a0a..09039c2 100644 --- a/src/.config/hypr/hyprland.conf +++ b/src/.config/hypr/hyprland.conf @@ -16,8 +16,7 @@ exec-once=dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRE exec-once=~/.config/hypr/portal.sh exec-once=swww init && swww img ~/wallpaper.jpg exec-once=nm-applet -exec-once=waybar -exec-once=mako +exec-once=ags exec=~/.config/hypr/import-gsettings.sh env = XCURSOR_SIZE,24 @@ -95,7 +94,7 @@ $mainMod = ALT bind = $mainMod, Q, killactive, bind = $mainMod, M, exit, -bind = $mainMod, Z, exec, alacritty --class floating +bind = $mainMod, Z, exec, foot -a floating bind = $mainMod, E, exec, thunar bind = $mainMod, O, exec, swaylock -i ~/wallpaper.png bind = $mainMod, V, togglefloating, diff --git a/src/.config/mako/config b/src/.config/mako/config deleted file mode 100644 index fc4feb7..0000000 --- a/src/.config/mako/config +++ /dev/null @@ -1,9 +0,0 @@ -# Colors - -background-color=#eff1f5 -text-color=#4c4f69 -border-color=#1e66f5 -progress-color=over #ccd0da - -[urgency=high] -border-color=#fe640b \ No newline at end of file diff --git a/src/.config/waybar/config b/src/.config/waybar/config deleted file mode 100644 index 904c3d9..0000000 --- a/src/.config/waybar/config +++ /dev/null @@ -1,78 +0,0 @@ -{ - "layer": "top", - "position": "top", - "height": 24, - "spacing": 4, - "modules-left": [ - "hyprland/workspaces", - "wlr/taskbar", - ], - "modules-center": [ - "hyprland/window" - ], - "modules-right": [ - "mpris", - "pulseaudio", - "battery", - "tray", - "clock" - ], - "wlr/taskbar": { - "on-click": "activate", - "on-click-middle": "close", - "ignore-list": [ - "foot" - ] - }, - "hyprland/workspaces": { - "on-click": "activate", - "on-scroll-up": "hyprctl dispatch workspace e-1", - "on-scroll-down": "hyprctl dispatch workspace e+1" - }, - "hyprland/window": { - "max-length": 128 - }, - "clock": { - "format": "{:%H:%M}", - "tooltip-format": "{:%Y %B}\n{calendar}" - }, -"mpris": { - "format": "{player_icon} {dynamic}", - "format-paused": "{status_icon} {dynamic}", - "player-icons": { - "default": "🎵" - }, - "status-icons": { - "paused": "⏸" - }, -}, -"pulseaudio": { - "format": "{volume}% {icon}", - "format-bluetooth": "{volume}% {icon} ", - "format-muted": "", - "format-icons": { - "headphone": "", - "hands-free": "", - "headset": "", - "phone": "", - "portable": "", - "car": "", - "default": ["", ""] - }, - "scroll-step": 1, - "on-click": "qpwgraph", -}, -"battery": { - "interval": 60, - "states": { - "warning": 30, - "critical": 15 - }, - "format": "{capacity}% {icon}", - "format-icons": ["", "", "", "", ""], - "max-length": 25 -}, - "tray": { - "spacing": 4 - } - } diff --git a/src/.config/waybar/style.css b/src/.config/waybar/style.css deleted file mode 100644 index 241e649..0000000 --- a/src/.config/waybar/style.css +++ /dev/null @@ -1,98 +0,0 @@ -@import "theme.css"; - -* { - font-family: FantasqueSansMono Nerd Font; - font-size: 17px; - min-height: 0; -} - -#waybar { - background: @surface1; - color: @text; - margin: 1px 1px; -} - -#workspaces { - border-radius: 1rem; - margin: 5px; - background-color: @surface0; - margin-left: 1rem; -} - -#workspaces button { - color: @lavender; - border-radius: 1rem; - padding: 0.4rem; -} - -#workspaces button.active { - color: @sky; - border-radius: 1rem; -} - -#workspaces button:hover { - color: @sapphire; - border-radius: 1rem; -} - -#custom-music, -#backlight, -#tray, -#clock, -#battery, -#pulseaudio, -#custom-lock, -#custom-power { - background-color: @surface0; - padding: 0.5rem 1rem; - margin: 5px 0; -} - -#clock { - color: @blue; - border-radius: 0px 1rem 1rem 0px; - margin-right: 1rem; -} - -#battery { - color: @green; -} - -#battery.charging { - color: @green; -} - -#battery.warning:not(.charging) { - color: @red; -} - -#backlight { - color: @yellow; -} - -#backlight, -#battery { - border-radius: 0; -} - -#pulseaudio { - color: @maroon; - border-radius: 1rem 0px 0px 1rem; - margin-left: 1rem; -} - -#custom-music { - color: @mauve; - border-radius: 1rem; -} - -#custom-lock { - border-radius: 1rem 0px 0px 1rem; - color: @lavender; -} - -#custom-power { - margin-right: 1rem; - border-radius: 0px 1rem 1rem 0px; - color: @red; -} diff --git a/src/.config/waybar/theme.css b/src/.config/waybar/theme.css deleted file mode 100644 index 8473843..0000000 --- a/src/.config/waybar/theme.css +++ /dev/null @@ -1,26 +0,0 @@ -@define-color rosewater #dc8a78; -@define-color flamingo #dd7878; -@define-color pink #ea76cb; -@define-color mauve #8839ef; -@define-color red #d20f39; -@define-color maroon #e64553; -@define-color peach #fe640b; -@define-color yellow #df8e1d; -@define-color green #40a02b; -@define-color teal #179299; -@define-color sky #04a5e5; -@define-color sapphire #209fb5; -@define-color blue #1e66f5; -@define-color lavender #7287fd; -@define-color text #4c4f69; -@define-color subtext1 #5c5f77; -@define-color subtext0 #6c6f85; -@define-color overlay2 #7c7f93; -@define-color overlay1 #8c8fa1; -@define-color overlay0 #9ca0b0; -@define-color surface2 #acb0be; -@define-color surface1 #bcc0cc; -@define-color surface0 #ccd0da; -@define-color base #eff1f5; -@define-color mantle #e6e9ef; -@define-color crust #dce0e8; \ No newline at end of file diff --git a/src/wallpaper.png b/src/wallpaper.png index 3855aaa..cf51012 100644 Binary files a/src/wallpaper.png and b/src/wallpaper.png differ