├── .github └── FUNDING.yml ├── .gitignore ├── .settings ├── apps.json ├── icon-theme └── settings.json ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SUPPORT.md ├── ags ├── .gitignore ├── .prettierrc ├── LICENSE ├── apps │ ├── emoji │ │ └── main.ts │ ├── settings │ │ ├── appearance.ts │ │ ├── apps.ts │ │ ├── bluetooth.ts │ │ ├── info.ts │ │ ├── main.ts │ │ ├── network.ts │ │ ├── themes.ts │ │ ├── variables.ts │ │ ├── wallpapers.ts │ │ └── weather.ts │ └── window.ts ├── assets │ ├── emoji.json │ └── icons │ │ └── google-gemini-symbolic.svg ├── config.js ├── icons.ts ├── main.ts ├── modules │ ├── audio.ts │ ├── bar.ts │ ├── calendar.ts │ ├── cheatsheet.ts │ ├── cliphist.ts │ ├── misc │ │ ├── cairo_roundedcorner.js │ │ ├── calendar_layout.ts │ │ ├── chat_message.ts │ │ ├── clickthrough.js │ │ ├── md2pango.ts │ │ ├── popupwindow.ts │ │ └── textview.ts │ ├── notificationPopups.ts │ ├── popups.ts │ ├── sideleft │ │ ├── applauncher.ts │ │ ├── chats.ts │ │ ├── gemini.ts │ │ ├── main.ts │ │ ├── players.ts │ │ └── weather.ts │ └── sideright │ │ ├── buttons.ts │ │ ├── main.ts │ │ ├── management.ts │ │ ├── navigation.ts │ │ ├── notifications.ts │ │ ├── sidebar.ts │ │ └── system.ts ├── scripts │ ├── apps.py │ ├── brightness.sh │ ├── cliphist.sh │ ├── dark-theme.sh │ ├── keybindings.py │ ├── network.sh │ ├── night-light.sh │ ├── requests.py │ ├── system.sh │ ├── themes.py │ ├── wayland-idle-inhibitor.py │ └── weather.sh ├── services │ ├── backlight.ts │ ├── battery_warning.ts │ ├── chatroom.d.ts │ ├── chatrooms.ts │ ├── configuration.ts │ └── gemini.ts ├── style-apps.css ├── style.css ├── themes │ ├── example.css │ └── old_workspaces.css ├── types └── variables.ts ├── alacritty └── alacritty.toml ├── electron-flags.conf ├── hypr ├── conf │ ├── animation.conf │ ├── apps.conf │ ├── autostart.conf │ ├── custom │ │ ├── cursor.conf │ │ ├── environment.conf │ │ ├── general.conf │ │ ├── input.conf │ │ └── monitor.conf │ ├── decoration.conf │ ├── environment.conf │ ├── keybinding.conf │ ├── layout.conf │ ├── misc.conf │ ├── window.conf │ └── windowrule.conf ├── hypridle.conf ├── hyprland.conf ├── hyprlock.conf └── scripts │ ├── active-monitor.py │ ├── apps.sh │ ├── disabledm.sh │ ├── exit.sh │ ├── init-wallpaper-engine.sh │ ├── lock.sh │ ├── monitors.sh │ ├── reboot.sh │ ├── restart-hypridle.sh │ ├── screenshot.sh │ ├── shutdown.sh │ ├── suspend.sh │ ├── toggle-animations.sh │ ├── toggleallfloat.sh │ ├── wallpaper.py │ └── xdg.sh ├── install.sh ├── material-colors ├── .vscode │ └── settings.json ├── LICENSE ├── custom.py ├── generate.py ├── gtk-material.sh ├── hooks │ ├── discord.sh │ ├── sddm.sh │ └── telegram.sh └── templates │ ├── alacritty-dark.toml │ ├── alacritty-light.toml │ ├── alacritty.toml │ ├── bg-color │ ├── colors-hyprland.conf │ ├── colors-sddm-style.conf │ ├── colors.tdesktop-theme │ ├── hyprlock.conf │ ├── material-discord.scss │ └── svg │ ├── brightness-onPrimary.svg │ └── dark-onPrimary.svg ├── screenshots ├── apps-menu.png ├── cheatsheet.png ├── emoji.png ├── gtk-theme.png ├── hyprlock.png ├── light-theme.png ├── player.png ├── screenshot1.png ├── settings.png ├── sidebar-system.png ├── sidebar.png └── sideleft.png ├── scripts ├── battery.sh ├── check_updates.sh ├── checkplatform.sh ├── cleanup.sh ├── diagnosis.sh ├── filemanager.sh ├── fontsearch.sh ├── nm-applet.sh ├── restart_ags.sh ├── thunarterminal.sh ├── unlock-pacman.sh └── update_timer.sh ├── sddm ├── Main.qml ├── scripts │ ├── disable.sh │ ├── enable.sh │ └── wallpaper.sh └── sddm.conf ├── setup ├── MicroTex │ ├── .gitignore │ └── PKGBUILD ├── after_update.sh ├── agsv1 │ ├── .gitignore │ └── PKGBUILD ├── copy.sh ├── google-sans │ ├── ProductSans-Black.ttf │ ├── ProductSans-BlackItalic.ttf │ ├── ProductSans-Bold.ttf │ ├── ProductSans-BoldItalic.ttf │ ├── ProductSans-Italic.ttf │ ├── ProductSans-Light.ttf │ ├── ProductSans-LightItalic.ttf │ ├── ProductSans-Medium.ttf │ ├── ProductSans-MediumItalic.ttf │ ├── ProductSans-Regular.ttf │ ├── ProductSans-Thin.ttf │ └── ProductSans-ThinItalic.ttf ├── gtk-3.0 │ ├── gtk.css │ └── settings.ini ├── gtk-4.0 │ └── gtk.css ├── import_settings.py └── wl-gammarelay.service ├── swappy └── config ├── update.sh └── wallpapers ├── birdandcat.jpg ├── default.jpg ├── kath.png ├── lofi-late-night-cats-iz.jpg ├── luminism-morning-landscape-ks.jpg └── minimalist-moon-night-mountains.jpg /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: koeqaife 2 | custom: [ 3 | 'https://www.donationalerts.com/r/koeqaife', 4 | 'https://etherscan.io/address/0xC6eaFAB219EaF1F050eF93Abe48Bfdd84D325Ccc', 5 | 'https://tronscan.org/#/address/TB4jWa9GT6gXWueNEMzWfpoLaytnuWon2W' 6 | ] 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ -------------------------------------------------------------------------------- /.settings/apps.json: -------------------------------------------------------------------------------- 1 | { 2 | "browser": "brave", 3 | "editor": "code", 4 | "filemanager": "thunar", 5 | "terminal": "alacritty" 6 | } 7 | -------------------------------------------------------------------------------- /.settings/icon-theme: -------------------------------------------------------------------------------- 1 | Tela-nord-dark 2 | Tela-nord-light 3 | -------------------------------------------------------------------------------- /.settings/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "custom-color": "none", 3 | "swww-anim": "wipe", 4 | "color-scheme": "dark", 5 | "generation-scheme": "tonalSpot", 6 | "wallpaper-engine": "swww", 7 | "hyprpaper-tpl": "preload = WALLPAPER\n wallpaper = ,WALLPAPER\n splash = false" 8 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | - Please keep in mind that dotfiles are personal. 3 | - Fixes are welcome. 4 | - If you add new features, I might be particular about details as I aim for high quality. 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hyprland dotfiles 2 | 3 | ![GitHub commit activity](https://img.shields.io/github/commit-activity/m/koeqaife/hyprland-material-you?style=for-the-badge&labelColor=%23424242&color=%23B2FF59) 4 | ![GitHub repo size](https://img.shields.io/github/repo-size/koeqaife/hyprland-material-you?style=for-the-badge&labelColor=%23424242&color=%2384FFFF) 5 | ![GitHub Repo stars](https://img.shields.io/github/stars/koeqaife/hyprland-material-you?style=for-the-badge&labelColor=%23424242&color=%23B9F6CA) 6 | ![GitHub contributors](https://img.shields.io/github/contributors/koeqaife/hyprland-material-you?style=for-the-badge&labelColor=%23424242&color=%23FFAB40) 7 | ![GitHub License](https://img.shields.io/github/license/koeqaife/hyprland-material-you?style=for-the-badge&labelColor=%23424242&color=%23FF9E80) 8 | 9 | [![Screenshot](screenshots/screenshot1.png "Screenshot")](screenshots/screenshot1.png) 10 | 11 | Hyprland Material You. It aims to provide a modern, feature-rich, and visually appealing desktop configuration. 12 | Here are some key features: 13 | 14 | - **Autogenerated Colors**: The project generates colors based on your wallpaper using Material colors. 15 | - **Fluid Animations**: Expect natural and fluid animations throughout the desktop experience. 16 | - **Design**: The design wherever possible is made by [Material 3 design](https://m3.material.io/) (or Material You). 17 | - **Ripple effect**: There is a ripple effect on almost all of the buttons on the interface 18 | 19 | > Discord: 20 | 21 | I'm creating v2 version for this dotfiles, so for any spoilers go to discord server. 22 | I'm doing everything **for free**, and you know, for me it's kinda difficult to find time and do this config, so please, if you can donate or if you want donate you can check my ko-fi. 23 | https://ko-fi.com/koeqaife 24 | 25 | ## To install 26 | 27 | ### Installation 28 | 29 | **⚠️ Known Issues:** 30 | - Ags crashes -> can be fixed with downgrading gjs to 1.82.1 31 | - Not always installs -> Wait for v2, v1 isn't maintaned anymore 32 | 33 | ```sh 34 | sudo pacman -Syu 35 | sudo pacman -S git 36 | cd ~ 37 | git clone --depth=1 https://github.com/koeqaife/hyprland-material-you.git 38 | mv hyprland-material-you dotfiles 39 | cd dotfiles 40 | ./install.sh 41 | ``` 42 | 43 | ## Screenshots 44 | 45 | - Sidebar 46 | 47 | [![Screenshot](screenshots/sidebar.png "Sidebar")](screenshots/sidebar.png)[![Screenshot](screenshots/sidebar-system.png "Sidebar system info")](screenshots/sidebar-system.png) 48 | 49 | - Settings 50 | 51 | [![Screenshot](screenshots/settings.png "Settings")](screenshots/settings.png) 52 | 53 | - Player 54 | 55 | [![Screenshot](screenshots/player.png "Player")](screenshots/player.png) 56 | 57 | - Apps 58 | 59 | [![Screenshot](screenshots/apps-menu.png "Apps")](screenshots/apps-menu.png) 60 | 61 | - Lock Screen (hyprlock) 62 | 63 | [![Screenshot](screenshots/hyprlock.png "Hyprlock")](screenshots/hyprlock.png) 64 | 65 | - Gtk theme: 66 | 67 | [![Screenshot](screenshots/gtk-theme.png "Dark gtk theme")](screenshots/gtk-theme.png) 68 | [![Screenshot](screenshots/light-theme.png "Light gtk theme")](screenshots/light-theme.png) 69 | 70 | - List of keybindings 71 | 72 | [![Screenshot](screenshots/cheatsheet.png "CheatSheet")](screenshots/cheatsheet.png) 73 | 74 | - Emoji picker 75 | 76 | [![Screenshot](screenshots/emoji.png "emoji picker")](screenshots/emoji.png) 77 | 78 | - Left sidebar 79 | 80 | [![Screenshot](screenshots/sideleft.png "sideleft")](screenshots/sideleft.png) 81 | 82 | > I got some code for AGS from [end-4](https://github.com/end-4/dots-hyprland/) and [kotontrion](https://github.com/kotontrion/dotfiles) configs, thanks to them. 83 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Help with Updates and Common Issues 2 | 3 | If you encounter the error **"Branches have diverged. Manual intervention may be required."** while trying to update, please use the following command to reset your branch in case of a complete history rewrite: 4 | 5 | ```sh 6 | git fetch origin 7 | git reset --hard origin/ 8 | ``` 9 | 10 | Make sure to replace `` with the name of your current branch. 11 | 12 | Before executing this command, ensure you have backed up any important changes, as this will discard local commits that are not in the remote branch. 13 | 14 | If you continue to experience issues after following these steps, please create a new issue with details of the problem you are facing. 15 | -------------------------------------------------------------------------------- /ags/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/* 2 | README.md 3 | tsconfig.json 4 | -------------------------------------------------------------------------------- /ags/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "trailingComma": "none", 4 | "arrowParents": "avoid", 5 | "bracketSpacing": true, 6 | "jsxBracketSameLine": false, 7 | "tabWidth": 4, 8 | "useTabs": false, 9 | "endOfLine": "auto", 10 | "printWidth": 120 11 | } 12 | -------------------------------------------------------------------------------- /ags/apps/settings/apps.ts: -------------------------------------------------------------------------------- 1 | // by koeqaife ;) 2 | 3 | const apps_script = `python -OOO ${App.configDir}/scripts/apps.py`; 4 | import { MaterialIcon } from "icons"; 5 | 6 | const Row = (app: string, title: string, icon: string) => 7 | Widget.EventBox({ 8 | class_name: "row", 9 | on_primary_click_release: (self) => { 10 | self.child.children[1]!.activate(); 11 | }, 12 | child: Widget.Box({ 13 | class_name: "row", 14 | vpack: "start", 15 | children: [ 16 | MaterialIcon(icon), 17 | Widget.Box({ 18 | vertical: true, 19 | hexpand: true, 20 | vpack: "center", 21 | children: [ 22 | Widget.Label({ 23 | hpack: "start", 24 | class_name: "title", 25 | label: title 26 | }) 27 | ] 28 | }), 29 | Widget.Entry({ 30 | hpack: "end", 31 | css: "border: 2px solid; border-color: transparent;", 32 | attribute: { 33 | get: (self) => { 34 | Utils.execAsync(`${apps_script} --get ${app}`) 35 | .then((out) => { 36 | self.text = out; 37 | }) 38 | .catch(print); 39 | } 40 | }, 41 | on_accept: (self) => { 42 | Utils.execAsync(`${apps_script} --${app} ${self.text}`) 43 | .then(() => { 44 | self.css = "border: 2px solid; border-color: #66BB6A;"; 45 | Utils.timeout(1000, () => { 46 | self.css = "border: 2px solid; border-color: transparent"; 47 | }); 48 | }) 49 | .catch(() => { 50 | self.css = "border: 2px solid; border-color: @error;"; 51 | Utils.timeout(1000, () => { 52 | self.css = "border: 2px solid; border-color: transparent"; 53 | }); 54 | self.attribute.get(self); 55 | }); 56 | }, 57 | setup: (self) => { 58 | self.attribute.get(self); 59 | } 60 | }) 61 | ] 62 | }) 63 | }); 64 | 65 | export function Apps() { 66 | const box = Widget.Box({ 67 | vertical: true, 68 | children: [ 69 | Row("browser", "Browser", "web"), 70 | Row("editor", "Editor", "edit"), 71 | Row("filemanager", "File manager", "folder"), 72 | Row("terminal", "Terminal", "terminal") 73 | ] 74 | }); 75 | return Widget.Scrollable({ 76 | hscroll: "never", 77 | child: box, 78 | vexpand: true 79 | }); 80 | } 81 | -------------------------------------------------------------------------------- /ags/apps/settings/info.ts: -------------------------------------------------------------------------------- 1 | // by koeqaife ;) 2 | 3 | import { Binding } from "types/service"; 4 | const GLib = imports.gi.GLib; 5 | import { cpu_cores, cpu_name, kernel_name, amount_of_ram, gpu_name, hostname, current_os, cur_uptime } from "variables"; 6 | 7 | type StringOrBinding = string | Binding | null; 8 | 9 | const empty_func = () => {}; 10 | 11 | const repo_link = "https://github.com/koeqaife/hyprland-material-you"; 12 | const current_de = GLib.getenv("DESKTOP_SESSION"); 13 | const author = "koeqaife"; 14 | 15 | const Row = ( 16 | title: StringOrBinding, 17 | description: StringOrBinding, 18 | on_primary_click: any = empty_func, 19 | on_secondary_click: any = empty_func 20 | ) => 21 | Widget.EventBox({ 22 | class_name: "row", 23 | on_primary_click_release: on_primary_click, 24 | on_secondary_click_release: on_secondary_click, 25 | child: Widget.Box({ 26 | class_name: "row", 27 | vpack: "start", 28 | children: [ 29 | Widget.Box({ 30 | vertical: true, 31 | hexpand: true, 32 | vpack: "center", 33 | hpack: "start", 34 | children: [ 35 | Widget.Label({ 36 | hpack: "start", 37 | class_name: "title", 38 | label: title 39 | }), 40 | Widget.Label({ 41 | hpack: "start", 42 | class_name: "description", 43 | label: description 44 | }) 45 | ] 46 | }) 47 | ] 48 | }) 49 | }); 50 | 51 | export function Info() { 52 | const box = Widget.Box({ 53 | vertical: true, 54 | children: [ 55 | Row("Dotfiles", "Material You"), 56 | Row("Author", author), 57 | Row("Repo", repo_link, () => { 58 | Utils.execAsync(`xdg-open "${repo_link}"`).catch(print); 59 | }), 60 | Widget.Separator(), 61 | Row("DE", current_de!), 62 | Row("OS", current_os), 63 | Row("Kernel", kernel_name), 64 | Row("Uptime", cur_uptime.bind()), 65 | Row("CPU", `${cpu_name} (${cpu_cores} Cores)`), 66 | Row("GPU", `${gpu_name}`), 67 | Row("Ram", amount_of_ram), 68 | Row("Hostname", hostname) 69 | ] 70 | }); 71 | return Widget.Scrollable({ 72 | hscroll: "never", 73 | child: box, 74 | vexpand: true 75 | }); 76 | } 77 | -------------------------------------------------------------------------------- /ags/apps/settings/main.ts: -------------------------------------------------------------------------------- 1 | // by koeqaife ;) 2 | 3 | import { RegularWindow } from "apps/window"; 4 | import { Network } from "./network"; 5 | import { Bluetooth } from "./bluetooth"; 6 | import { Appearance } from "./appearance"; 7 | import { Wallpapers } from "./wallpapers"; 8 | import { Info } from "./info"; 9 | import { Apps } from "./apps"; 10 | import { MaterialIcon } from "icons"; 11 | import { Weather } from "./weather"; 12 | import { Themes } from "./themes"; 13 | import { current_tab, current_window, set_current_window } from "./variables"; 14 | import Gtk from "gi://Gtk?version=3.0"; 15 | 16 | const hyprland = await Service.import("hyprland"); 17 | globalThis.OpenSettings = OpenSettings; 18 | 19 | export async function OpenSettings(cur_tab: string = "network") { 20 | current_tab.setValue(cur_tab); 21 | if (current_window) { 22 | const _current_workspace = hyprland.active.workspace.id; 23 | const _client = hyprland.clients.find((client) => { 24 | return client.class == "com.github.Aylur.ags" && client.title == "Settings"; 25 | }); 26 | if (_client && _current_workspace != _client.workspace.id) { 27 | current_window.hide(); 28 | current_window.show(); 29 | } else { 30 | current_window.show(); 31 | } 32 | } else SettingsWindow(cur_tab); 33 | } 34 | 35 | function Settings(cur_tab: string) { 36 | const stack = Widget.Stack({ 37 | children: { 38 | none: Widget.Box({ visible: true }), 39 | network: Page(Network(), "Network"), 40 | bluetooth: Page(Bluetooth(), "Bluetooth"), 41 | appearance: Page(Appearance(), "Appearance"), 42 | wallpaper: Page(Wallpapers(), "Wallpapers"), 43 | info: Page(Info(), "Info"), 44 | apps: Page(Apps(), "Apps"), 45 | weather: Page(Weather(), "Weather"), 46 | themes: Page(Themes(), "Themes") 47 | }, 48 | // @ts-ignore 49 | shown: cur_tab, 50 | vexpand: true, 51 | hexpand: true, 52 | transition: "crossfade", 53 | homogeneous: true, 54 | transition_duration: 200, 55 | setup: (self) => { 56 | self.hook(current_tab, () => { 57 | self.set_visible_child_name(current_tab.value); 58 | }); 59 | } 60 | }); 61 | const Row = (name: string, label: string, icon: string = "image-missing") => 62 | Widget.Button({ 63 | on_clicked: () => { 64 | current_tab.setValue(name); 65 | }, 66 | child: Widget.Box({ 67 | children: [MaterialIcon(icon), Widget.Label(label)] 68 | }), 69 | class_name: "sidebar_row", 70 | attribute: { name: name }, 71 | setup: (self) => { 72 | self.hook(current_tab, () => { 73 | self.toggleClassName("active", name == current_tab.value); 74 | }); 75 | } 76 | }); 77 | const sidebar = Widget.Box({ 78 | vertical: true, 79 | vexpand: true, 80 | class_name: "sidebar", 81 | spacing: 2, 82 | children: [ 83 | Row("network", "Network", "signal_wifi_4_bar"), 84 | Row("bluetooth", "Bluetooth", "bluetooth"), 85 | Widget.Separator(), 86 | Row("appearance", "Appearance", "palette"), 87 | Row("wallpaper", "Wallpapers", "image"), 88 | Row("themes", "Themes", "tune"), 89 | Widget.Separator(), 90 | Row("apps", "Apps", "grid_view"), 91 | Row("weather", "Weather", "cloud"), 92 | Widget.Separator(), 93 | Row("info", "Info", "info") 94 | ] 95 | }); 96 | return Widget.Box({ 97 | hexpand: true, 98 | vexpand: true, 99 | vertical: false, 100 | css: "background-color: @surface", 101 | children: [ 102 | Widget.Box({ 103 | class_name: "full_sidebar", 104 | vertical: true, 105 | children: [ 106 | Widget.Label({ 107 | class_name: "settings_title", 108 | label: "Settings" 109 | }), 110 | Widget.Scrollable({ 111 | hscroll: "never", 112 | child: sidebar 113 | }) 114 | ] 115 | }), 116 | stack 117 | ], 118 | setup: (self) => { 119 | current_tab.setValue(cur_tab); 120 | } 121 | }); 122 | } 123 | 124 | export const Page = (widget: Gtk.Widget, name: string) => 125 | Widget.Box({ 126 | vertical: true, 127 | children: [PageTitle(name), widget] 128 | }); 129 | 130 | export const PageTitle = (label: string) => 131 | Widget.Box({ 132 | class_name: "page_title", 133 | child: Widget.Label({ 134 | label: label, 135 | hpack: "start" 136 | }) 137 | }); 138 | 139 | export const SettingsWindow = (cur_tab: string) => { 140 | let window = RegularWindow({ 141 | title: "Settings", 142 | default_height: 600, 143 | default_width: 850, 144 | class_name: "settings", 145 | child: Settings(cur_tab), 146 | setup(win: any) { 147 | set_current_window(win); 148 | win.keybind("Escape", () => { 149 | win.close(); 150 | }); 151 | }, 152 | visible: true 153 | }); 154 | // @ts-ignore 155 | window.on("delete-event", () => { 156 | // @ts-ignore 157 | window.destroy(); 158 | set_current_window(undefined); 159 | return true; 160 | }); 161 | return window; 162 | }; 163 | -------------------------------------------------------------------------------- /ags/apps/settings/themes.ts: -------------------------------------------------------------------------------- 1 | // by koeqaife ;) 2 | 3 | import { Variable as VariableType } from "types/variable"; 4 | import { MaterialIcon } from "icons"; 5 | import config from "services/configuration"; 6 | import { type ThemeJson } from "variables"; 7 | import { custom_theme } from "variables"; 8 | 9 | const config_version = "2"; 10 | const themes_folder = `${App.configDir}/themes`; 11 | const get_themes_cmd = `python -OOO ${App.configDir}/scripts/themes.py -a ${themes_folder}`; 12 | let _themes = Utils.exec(get_themes_cmd); 13 | const themes: VariableType = Variable(JSON.parse(_themes)); 14 | const focused: VariableType = Variable(null); 15 | 16 | const DEFAULT: ThemeJson = { 17 | name: "Default", 18 | author: "koeqaife", 19 | config_version: "universal", 20 | description: "Hyprland-material-you theme", 21 | hide: false, 22 | load_default_css: true, 23 | path: undefined, 24 | version: "unknown" 25 | }; 26 | const MESSAGES = { 27 | may_not_be_compatible: "This theme may not be compatible with the current version of hyprland-material-you.", 28 | unknown_version: "This theme does not specify ConfigVersion, the theme may not be compatible." 29 | }; 30 | 31 | const theme = (theme: ThemeJson) => 32 | Widget.Button({ 33 | class_name: "row theme", 34 | hexpand: true, 35 | vpack: "start", 36 | setup: (self) => { 37 | if (config.config.current_theme == theme.path) focused.setValue(theme); 38 | self.hook(focused, () => { 39 | self.toggleClassName("focused", focused.value == theme); 40 | }); 41 | }, 42 | on_clicked: () => { 43 | focused.setValue(theme); 44 | }, 45 | child: Widget.Box({ 46 | vertical: true, 47 | hexpand: true, 48 | vpack: "center", 49 | children: [ 50 | Widget.Label({ 51 | hpack: "start", 52 | class_name: "title", 53 | label: theme.name, 54 | truncate: "end" 55 | }), 56 | // @ts-expect-error 57 | Widget.Box({ 58 | children: [ 59 | theme.config_version == "universal" || 60 | (theme.config_version != "0" && theme.config_version == config_version) 61 | ? null 62 | : MaterialIcon("error", "18px", { 63 | tooltip_text: 64 | theme.config_version == "0" 65 | ? MESSAGES.unknown_version 66 | : MESSAGES.may_not_be_compatible 67 | }), 68 | Widget.Label({ 69 | hpack: "start", 70 | class_name: "description", 71 | label: `${theme.description} (by ${theme.author})`, 72 | truncate: "end" 73 | }) 74 | ] 75 | }) 76 | ] 77 | }) 78 | }); 79 | 80 | const theme_list = () => { 81 | const reload = () => { 82 | Utils.execAsync(get_themes_cmd).then((out) => { 83 | themes.setValue(JSON.parse(out)); 84 | }); 85 | }; 86 | const _default = theme(DEFAULT); 87 | const box = Widget.Box({ 88 | vertical: true, 89 | children: [_default, ...themes.value.filter((value) => !value.hide).map((value) => theme(value))], 90 | vexpand: true, 91 | attribute: { 92 | reload: reload 93 | }, 94 | setup: (self) => { 95 | self.hook(themes, () => { 96 | try { 97 | box.children = [ 98 | _default, 99 | ...themes.value.filter((value) => !value.hide).map((value) => theme(value)) 100 | ]; 101 | } catch (e) { 102 | print("Error while reloading themes:", e); 103 | } 104 | }); 105 | } 106 | }); 107 | return box; 108 | }; 109 | 110 | export const Themes = () => { 111 | const _box = theme_list(); 112 | const _actions = Widget.Box({ 113 | class_name: "actions", 114 | hpack: "end", 115 | spacing: 5, 116 | children: [ 117 | Widget.Button({ 118 | hpack: "end", 119 | class_name: "standard_button", 120 | label: "Reload", 121 | on_clicked: () => { 122 | _box.attribute.reload(); 123 | } 124 | }), 125 | Widget.Button({ 126 | hpack: "end", 127 | class_name: "filled_button", 128 | label: "Select", 129 | on_clicked: () => { 130 | custom_theme.setValue(null); 131 | config.config = { 132 | ...config.config, 133 | current_theme: focused.value?.path || null 134 | }; 135 | } 136 | }) 137 | ] 138 | }); 139 | const _bottom = Widget.Box({ 140 | hexpand: true, 141 | vertical: true, 142 | class_name: "bottom_bar", 143 | children: [_actions] 144 | }); 145 | return Widget.Box({ 146 | vertical: true, 147 | class_name: "themes", 148 | children: [_box, _bottom] 149 | }); 150 | }; 151 | -------------------------------------------------------------------------------- /ags/apps/settings/variables.ts: -------------------------------------------------------------------------------- 1 | // by koeqaife ;) 2 | 3 | export let current_window; 4 | export function set_current_window(value: any) { 5 | current_window = value; 6 | } 7 | 8 | export const current_tab = Variable(""); 9 | export const saved_networks = Variable([]); 10 | 11 | const _saved_networks = async () => { 12 | const _saved = await Utils.execAsync(`${App.configDir}/scripts/network.sh --saved`); 13 | saved_networks.setValue(_saved.split("\n")); 14 | }; 15 | 16 | Utils.interval(10000, () => { 17 | if (current_tab.value == "network" && current_window?.visible) { 18 | _saved_networks().catch(print); 19 | } 20 | }); 21 | 22 | current_tab.connect("changed", () => { 23 | if (current_tab.value == "network") { 24 | _saved_networks().catch(print); 25 | } 26 | }); 27 | -------------------------------------------------------------------------------- /ags/apps/settings/weather.ts: -------------------------------------------------------------------------------- 1 | // by koeqaife ;) 2 | 3 | import conf from "services/configuration.ts"; 4 | 5 | const WeatherKey = () => 6 | Widget.EventBox({ 7 | class_name: "row", 8 | on_secondary_click_release: (self) => { 9 | Utils.execAsync(`xdg-open "https://openweathermap.org/api"`).catch(print); 10 | }, 11 | child: Widget.Box({ 12 | class_name: "row", 13 | vpack: "start", 14 | children: [ 15 | Widget.Box({ 16 | vertical: true, 17 | hexpand: true, 18 | vpack: "center", 19 | hpack: "start", 20 | children: [ 21 | Widget.Label({ 22 | hpack: "start", 23 | class_name: "title", 24 | label: "Api key" 25 | }), 26 | Widget.Label({ 27 | hpack: "start", 28 | class_name: "description", 29 | label: "openweathermap.org api key" 30 | }) 31 | ] 32 | }), 33 | Widget.Entry({ 34 | max_length: 32, 35 | hpack: "end", 36 | css: "border: 2px solid; border-color: transparent;", 37 | visibility: false, 38 | text: conf.config.weather, 39 | on_accept: (self) => { 40 | if (self.text!.length == 32) { 41 | self.css = "border: 2px solid; border-color: #66BB6A"; 42 | Utils.timeout(1000, () => { 43 | self.css = "border: 2px solid; border-color: transparent"; 44 | }); 45 | conf.set_value("weather", self.text!); 46 | } 47 | } 48 | }) 49 | ] 50 | }) 51 | }); 52 | 53 | const WeatherLocationKey = () => 54 | Widget.EventBox({ 55 | class_name: "row", 56 | on_secondary_click_release: (self) => { 57 | Utils.execAsync(`xdg-open "https://openweathermap.org"`).catch(print); 58 | }, 59 | child: Widget.Box({ 60 | class_name: "row", 61 | vpack: "start", 62 | children: [ 63 | Widget.Box({ 64 | vertical: true, 65 | hexpand: true, 66 | vpack: "center", 67 | hpack: "start", 68 | children: [ 69 | Widget.Label({ 70 | hpack: "start", 71 | class_name: "title", 72 | label: "Location key" 73 | }), 74 | Widget.Label({ 75 | hpack: "start", 76 | class_name: "description", 77 | label: "Search for your city at openweathermap.org" 78 | }) 79 | ] 80 | }), 81 | Widget.Entry({ 82 | hpack: "end", 83 | css: "border: 2px solid; border-color: transparent;", 84 | text: conf.config.weather_location_id, 85 | on_accept: (self) => { 86 | self.css = "border: 2px solid; border-color: #66BB6A"; 87 | Utils.timeout(1000, () => { 88 | self.css = "border: 2px solid; border-color: transparent"; 89 | }); 90 | conf.set_value("weather_location_id", self.text!); 91 | } 92 | }) 93 | ] 94 | }) 95 | }); 96 | 97 | export function Weather() { 98 | const box = Widget.Box({ 99 | vertical: true, 100 | children: [WeatherKey(), WeatherLocationKey()] 101 | }); 102 | return Widget.Scrollable({ 103 | hscroll: "never", 104 | child: box, 105 | vexpand: true 106 | }); 107 | } 108 | -------------------------------------------------------------------------------- /ags/apps/window.ts: -------------------------------------------------------------------------------- 1 | // by koeqaife ;) 2 | 3 | import Gtk from "gi://Gtk?version=3.0"; 4 | 5 | export const RegularWindow = Widget.subclass(Gtk.Window); 6 | -------------------------------------------------------------------------------- /ags/assets/icons/google-gemini-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 40 | ionicons-v5_logos 42 | 47 | 49 | 50 | 52 | ionicons-v5_logos 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /ags/config.js: -------------------------------------------------------------------------------- 1 | const entry = App.configDir + "/main.ts"; 2 | const outdir = "/tmp/ags/js"; 3 | 4 | App.addIcons(`${App.configDir}/assets/icons`); 5 | 6 | try { 7 | // prettier-ignore 8 | await Utils.execAsync([ 9 | "bun", "build", entry, 10 | "--outdir", outdir, 11 | "--external", "resource://*", 12 | "--external", "gi://*" 13 | ]); 14 | await import(`file://${outdir}/main.js`); 15 | } catch (error) { 16 | console.error(error); 17 | } 18 | 19 | export {}; 20 | -------------------------------------------------------------------------------- /ags/icons.ts: -------------------------------------------------------------------------------- 1 | import { Binding } from "types/service"; 2 | import { LabelProps } from "types/widgets/label"; 3 | 4 | export const MaterialIcon = (icon: string | Binding, size: string = "24px", props?: LabelProps) => 5 | Widget.Label({ 6 | label: icon, 7 | class_name: "icon material_icon", 8 | css: `font-size: ${size};`, 9 | hpack: "center", 10 | vpack: "center", 11 | ...props 12 | }); 13 | -------------------------------------------------------------------------------- /ags/main.ts: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // by koeqaife ;) 3 | 4 | // Import 5 | import Gdk from "gi://Gdk"; 6 | // widgets 7 | import { Bar, BarCornerTopLeft, BarCornerTopRight } from "./modules/bar.ts"; 8 | import { Notifications } from "./modules/notificationPopups.ts"; 9 | import { cliphist } from "./modules/cliphist.ts"; 10 | import { sideright } from "./modules/sideright/main.ts"; 11 | import { sideleft } from "./modules/sideleft/main.ts"; 12 | import {} from "apps/settings/main.ts"; 13 | import {} from "apps/emoji/main.ts"; 14 | import { cheatsheet } from "modules/cheatsheet.ts"; 15 | import Window from "types/widgets/window"; 16 | import { popups } from "modules/popups.ts"; 17 | import { start_battery_warning_service } from "services/battery_warning.ts"; 18 | import { audio_popup } from "./modules/audio.ts"; 19 | import { calendar } from "modules/calendar.ts"; 20 | import Gtk from "gi://Gtk?version=3.0"; 21 | import configuration from "services/configuration"; 22 | import { custom_theme, ThemeJson } from "variables"; 23 | const GLib = imports.gi.GLib; 24 | 25 | const range = (length: number, start = 1) => Array.from({ length }, (_, i) => i + start); 26 | function forMonitors(widget: (index: number) => Window): Window[] { 27 | const n = Gdk.Display.get_default()?.get_n_monitors() || 1; 28 | return range(n, 0).map(widget).flat(1); 29 | } 30 | function forMonitorsAsync(widget: (index: number) => Promise>) { 31 | const n = Gdk.Display.get_default()?.get_n_monitors() || 1; 32 | return range(n, 0).forEach((n) => widget(n).catch(print)); 33 | } 34 | 35 | const Windows = () => [ 36 | forMonitors(Notifications), 37 | forMonitors(BarCornerTopLeft), 38 | forMonitors(BarCornerTopRight), 39 | cliphist, 40 | sideright, 41 | cheatsheet, 42 | sideleft, 43 | forMonitors(popups), 44 | audio_popup, 45 | calendar 46 | ]; 47 | 48 | App.config({ 49 | windows: Windows().flat(1), 50 | // @ts-ignore 51 | onConfigParsed: function () {} 52 | }); 53 | 54 | configuration.connect("config-changed", (_, config) => { 55 | load_custom_css(); 56 | }); 57 | 58 | function load_custom_css() { 59 | if (configuration.config.current_theme == null) reload_css() 60 | else if ( 61 | configuration.config.current_theme && 62 | custom_theme && 63 | custom_theme.value?.path != configuration.config.current_theme 64 | ) { 65 | const theme_info: ThemeJson = JSON.parse( 66 | Utils.exec(`python -OOO ${App.configDir}/scripts/themes.py -f ${configuration.config.current_theme}`) 67 | ); 68 | custom_theme.setValue(theme_info); 69 | if (theme_info.load_default_css) reload_css(); 70 | else { 71 | App.resetCss(); 72 | App.applyCss(`${GLib.get_home_dir()}/.config/gtk-3.0/gtk.css`); 73 | } 74 | App.applyCss(theme_info.path!); 75 | } else if (custom_theme.value?.path != configuration.config.current_theme) reload_css(); 76 | } 77 | 78 | function reload_css() { 79 | App.resetCss(); 80 | App.applyCss(`${GLib.get_home_dir()}/.config/gtk-3.0/gtk.css`); 81 | App.applyCss(`${App.configDir}/style.css`); 82 | App.applyCss(`${App.configDir}/style-apps.css`); 83 | } 84 | 85 | function reload_colors() { 86 | App.applyCss(`${GLib.get_home_dir()}/.cache/material/colors.css`); 87 | } 88 | 89 | Utils.monitorFile(`${GLib.get_home_dir()}/.cache/material/colors.css`, reload_css); 90 | 91 | forMonitorsAsync(Bar); 92 | load_custom_css(); 93 | 94 | function enable_animations(bool: boolean) { 95 | const settings = Gtk.Settings.get_default()!; 96 | 97 | settings.gtk_enable_animations = bool; 98 | } 99 | 100 | globalThis.ReloadCSS = reload_css; 101 | globalThis.ReloadColors = reload_colors; 102 | globalThis.enableAnimations = enable_animations; 103 | globalThis.ReloadCustomCSS = load_custom_css; 104 | 105 | globalThis.reload_css = reload_css; 106 | globalThis.reload_colors = reload_colors; 107 | globalThis.enable_animations = enable_animations; 108 | globalThis.reload_custom_css = load_custom_css; 109 | 110 | start_battery_warning_service(); 111 | -------------------------------------------------------------------------------- /ags/modules/calendar.ts: -------------------------------------------------------------------------------- 1 | // by koeqaife ;) 2 | 3 | const { Box, Button, Label } = Widget; 4 | import { MaterialIcon } from "icons.ts"; 5 | 6 | import { get_calendar_layout } from "./misc/calendar_layout.js"; 7 | import popupwindow from "./misc/popupwindow.ts"; 8 | 9 | const WINDOW_NAME: string = "calendar"; 10 | 11 | type CalendarDay = { 12 | day: string; 13 | today: number; 14 | }; 15 | 16 | let calendar_json: CalendarDay[][] = get_calendar_layout(undefined, true); 17 | let month_shift: number = 0; 18 | 19 | function get_date_in_x_months_time(x: number): Date { 20 | const currentDate: Date = new Date(); 21 | let targetMonth: number = currentDate.getMonth() + x; 22 | let targetYear: number = currentDate.getFullYear(); 23 | 24 | targetYear += Math.floor(targetMonth / 12); 25 | targetMonth = ((targetMonth % 12) + 12) % 12; 26 | 27 | const targetDate: Date = new Date(targetYear, targetMonth, 1); 28 | 29 | return targetDate; 30 | } 31 | 32 | const week_days: CalendarDay[] = [ 33 | { day: "Mo", today: 0 }, 34 | { day: "Tu", today: 0 }, 35 | { day: "We", today: 0 }, 36 | { day: "Th", today: 0 }, 37 | { day: "Fr", today: 0 }, 38 | { day: "Sa", today: 0 }, 39 | { day: "Su", today: 0 } 40 | ]; 41 | 42 | const calendar_day = (day: string, today: number) => 43 | Widget.Button({ 44 | class_name: `calendar_button ${today == 1 ? "today" : today == -1 ? "othermonth" : ""}`, 45 | child: Widget.Overlay({ 46 | child: Box({ 47 | class_name: "overlay_box" 48 | }), 49 | overlays: [ 50 | Label({ 51 | hpack: "center", 52 | label: String(day) 53 | }) 54 | ] 55 | }) 56 | }); 57 | 58 | const calendar_widget = () => { 59 | const month_year = Widget.Button({ 60 | class_name: "calendar_monthyear", 61 | on_clicked: (): void => shift_x_months(0), 62 | setup: (button: any): void => { 63 | button.label = `${new Date().toLocaleString("default", { month: "long" })} ${new Date().getFullYear()}`; 64 | } 65 | }); 66 | 67 | const add_children = (box: ReturnType, calendar_json: CalendarDay[][]): void => { 68 | const children = box.get_children(); 69 | for (let i = 0; i < children.length; i++) { 70 | const child: any = children[i]; 71 | child.destroy(); 72 | } 73 | box.children = calendar_json.map((row, i) => 74 | Widget.Box({ 75 | spacing: 5, 76 | children: row.map((day, i) => calendar_day(day.day, day.today)) 77 | }) 78 | ); 79 | }; 80 | 81 | function shift_x_months(x: number): void { 82 | if (x == 0) month_shift = 0; 83 | else month_shift += x; 84 | 85 | const new_date: Date = month_shift == 0 ? new Date() : get_date_in_x_months_time(month_shift); 86 | 87 | calendar_json = get_calendar_layout(new_date, month_shift == 0); 88 | month_year.label = `${month_shift == 0 ? "" : "• "}${new_date.toLocaleString("default", { 89 | month: "long" 90 | })} ${new_date.getFullYear()}`; 91 | add_children(calendar_days, calendar_json); 92 | } 93 | 94 | const calendar_header = Widget.Box({ 95 | class_name: "calendar_header", 96 | spacing: 5, 97 | setup: (box: any): void => { 98 | box.pack_start(month_year, false, false, 0); 99 | box.pack_end( 100 | Widget.Box({ 101 | spacing: 5, 102 | children: [ 103 | Button({ 104 | class_name: "calendar_month_shift standard_icon_button", 105 | on_clicked: () => shift_x_months(-1), 106 | child: MaterialIcon("chevron_left", "20px") 107 | }), 108 | Button({ 109 | class_name: "calendar_month_shift standard_icon_button", 110 | on_clicked: () => shift_x_months(1), 111 | child: MaterialIcon("chevron_right", "20px") 112 | }) 113 | ] 114 | }), 115 | false, 116 | false, 117 | 0 118 | ); 119 | } 120 | }); 121 | 122 | const calendar_days = Widget.Box({ 123 | hexpand: true, 124 | vertical: true, 125 | spacing: 5, 126 | setup: (box: any): void => { 127 | add_children(box, calendar_json); 128 | } 129 | }); 130 | 131 | return Widget.EventBox({ 132 | on_scroll_up: (): void => shift_x_months(-1), 133 | on_scroll_down: (): void => shift_x_months(1), 134 | child: Widget.Box({ 135 | hpack: "center", 136 | class_name: "calendar_widget", 137 | children: [ 138 | Widget.Box({ 139 | hexpand: true, 140 | vertical: true, 141 | spacing: 5, 142 | children: [ 143 | calendar_header, 144 | Widget.Box({ 145 | homogeneous: true, 146 | spacing: 5, 147 | children: week_days.map((day, i) => calendar_day(day.day, day.today)) 148 | }), 149 | calendar_days 150 | ] 151 | }) 152 | ] 153 | }) 154 | }); 155 | }; 156 | 157 | export const calendar = popupwindow({ 158 | name: WINDOW_NAME, 159 | class_name: "calendar", 160 | visible: false, 161 | keymode: "exclusive", 162 | child: calendar_widget(), 163 | anchor: ["top", "right"] 164 | }); 165 | -------------------------------------------------------------------------------- /ags/modules/cheatsheet.ts: -------------------------------------------------------------------------------- 1 | // by koeqaife ;) 2 | 3 | import Gtk from "gi://Gtk?version=3.0"; 4 | import popupwindow from "modules/misc/popupwindow"; 5 | import { MaterialIcon } from "icons"; 6 | const hyprland = await Service.import("hyprland"); 7 | 8 | const WINDOW_NAME = "cheatsheet"; 9 | 10 | const load_keybindings_cmd = `python -OOO ${App.configDir}/scripts/keybindings.py`; 11 | let _keybindings = Utils.exec(load_keybindings_cmd); 12 | const keybindings = Variable(JSON.parse(_keybindings)); 13 | 14 | // hyprland.connect("event", (hyprland, name) => { 15 | // if (name == "configreloaded") { 16 | // print(name) 17 | // Utils.execAsync(load_keybindings_cmd).then((out) => { 18 | // keybindings.setValue(JSON.parse(out)); 19 | // }); 20 | // } 21 | // }) 22 | 23 | const icons = { 24 | super: "" 25 | }; 26 | 27 | const replace = { 28 | slash: "/", 29 | period: ".", 30 | escape: "Esc" 31 | }; 32 | 33 | const category_icons = { 34 | actions: "accessibility_new", 35 | applications: "apps", 36 | windows: "select_window", 37 | workspaces: "overview_key", 38 | misc: "construction", 39 | tools: "build" 40 | }; 41 | 42 | const CheatSheet = () => 43 | Widget.FlowBox({ 44 | attribute: { 45 | set: (self) => { 46 | for (let category in keybindings.value) { 47 | const box = Widget.Box({ 48 | class_name: "category", 49 | vertical: true, 50 | vpack: "fill", 51 | children: [ 52 | Widget.Box({ 53 | children: [ 54 | MaterialIcon(category_icons[category.toLowerCase()] || "category"), 55 | Widget.Label({ 56 | label: category, 57 | class_name: "title", 58 | hpack: "start" 59 | }) 60 | ] 61 | }), 62 | Widget.Separator() 63 | ] 64 | }); 65 | let commands = keybindings.value[category]; 66 | for (const command in commands) { 67 | const _command = command.replaceAll(" ", " + "); 68 | const key_list = _command.split(" "); 69 | const key_box = Widget.Box({ 70 | class_name: "row" 71 | }); 72 | for (const key of key_list) { 73 | if (key == "+") 74 | key_box.pack_start( 75 | Widget.Label({ 76 | label: "+", 77 | class_name: "plus", 78 | hpack: "start", 79 | vpack: "center" 80 | }), 81 | false, 82 | false, 83 | 0 84 | ); 85 | else if (icons[key]) 86 | key_box.pack_start( 87 | Widget.Label({ 88 | label: icons[key], 89 | class_name: "awesome_icon key", 90 | hpack: "start", 91 | vpack: "center" 92 | }), 93 | false, 94 | false, 95 | 0 96 | ); 97 | else 98 | key_box.pack_start( 99 | Widget.Label({ 100 | label: replace[key.toLowerCase()] || key.charAt(0).toUpperCase() + key.slice(1), 101 | class_name: "key", 102 | hpack: "start", 103 | vpack: "center" 104 | }), 105 | false, 106 | false, 107 | 0 108 | ); 109 | } 110 | key_box.pack_start( 111 | Widget.Label({ 112 | label: `: `, 113 | class_name: "separator", 114 | hpack: "start", 115 | vpack: "center" 116 | }), 117 | false, 118 | false, 119 | 0 120 | ); 121 | key_box.pack_start( 122 | Widget.Label({ 123 | label: `${commands[command]}`, 124 | class_name: "description", 125 | hpack: "start", 126 | vpack: "center" 127 | }), 128 | false, 129 | false, 130 | 0 131 | ); 132 | box.pack_start(key_box, false, false, 0); 133 | } 134 | self.add(box); 135 | } 136 | } 137 | }, 138 | setup: (self) => { 139 | self.set_max_children_per_line(3); 140 | self.set_min_children_per_line(3); 141 | self.set_selection_mode(Gtk.SelectionMode.NONE); 142 | self.attribute.set(self); 143 | } 144 | }); 145 | 146 | export const cheatsheet = popupwindow({ 147 | name: WINDOW_NAME, 148 | 149 | class_name: "cheatsheet", 150 | visible: false, 151 | keymode: "exclusive", 152 | child: CheatSheet(), 153 | anchor: [] 154 | }); 155 | -------------------------------------------------------------------------------- /ags/modules/misc/cairo_roundedcorner.js: -------------------------------------------------------------------------------- 1 | import Widget from "resource:///com/github/Aylur/ags/widget.js"; 2 | const Lang = imports.lang; 3 | import Gtk from "gi://Gtk?version=3.0"; 4 | 5 | export const RoundedCorner = (place, props) => 6 | Widget.DrawingArea({ 7 | ...props, 8 | hpack: place.includes("left") ? "start" : "end", 9 | vpack: place.includes("top") ? "start" : "end", 10 | setup: (widget) => 11 | Utils.timeout(1, () => { 12 | const c = widget.get_style_context().get_property("background-color", Gtk.StateFlags.NORMAL); 13 | const r = widget.get_style_context().get_property("border-radius", Gtk.StateFlags.NORMAL); 14 | widget.set_size_request(r, r); 15 | widget.connect( 16 | "draw", 17 | // @ts-ignore 18 | Lang.bind(widget, (widget, cr) => { 19 | const c = widget.get_style_context().get_property("background-color", Gtk.StateFlags.NORMAL); 20 | const r = widget.get_style_context().get_property("border-radius", Gtk.StateFlags.NORMAL); 21 | // const borderColor = widget.get_style_context().get_property('color', Gtk.StateFlags.NORMAL); 22 | // const borderWidth = widget.get_style_context().get_border(Gtk.StateFlags.NORMAL).left; // ur going to write border-width: something anyway 23 | widget.set_size_request(r, r); 24 | 25 | switch (place) { 26 | case "top_left": 27 | cr.arc(r, r, r, Math.PI, (3 * Math.PI) / 2); 28 | cr.lineTo(0, 0); 29 | break; 30 | 31 | case "top_right": 32 | cr.arc(0, r, r, (3 * Math.PI) / 2, 2 * Math.PI); 33 | cr.lineTo(r, 0); 34 | break; 35 | 36 | case "bottom_left": 37 | cr.arc(r, 0, r, Math.PI / 2, Math.PI); 38 | cr.lineTo(0, r); 39 | break; 40 | 41 | case "bottom_right": 42 | cr.arc(0, 0, r, 0, Math.PI / 2); 43 | cr.lineTo(r, r); 44 | break; 45 | } 46 | 47 | cr.closePath(); 48 | cr.setSourceRGBA(c.red, c.green, c.blue, c.alpha); 49 | cr.fill(); 50 | // cr.setLineWidth(borderWidth); 51 | // cr.setSourceRGBA(borderColor.red, borderColor.green, borderColor.blue, borderColor.alpha); 52 | // cr.stroke(); 53 | }) 54 | ); 55 | }) 56 | }); 57 | -------------------------------------------------------------------------------- /ags/modules/misc/calendar_layout.ts: -------------------------------------------------------------------------------- 1 | function check_leap_year(year) { 2 | return ( 3 | year % 400 == 0 || 4 | (year % 4 == 0 && year % 100 != 0)); 5 | } 6 | 7 | function month_day(month, year) { 8 | const leap_year = check_leap_year(year); 9 | if ((month <= 7 && month % 2 == 1) || (month >= 8 && month % 2 == 0)) return 31; 10 | if (month == 2 && leap_year) return 29; 11 | if (month == 2 && !leap_year) return 28; 12 | return 30; 13 | } 14 | 15 | function next_month_days(month, year) { 16 | const leap_year = check_leap_year(year); 17 | if (month == 1 && leap_year) return 29; 18 | if (month == 1 && !leap_year) return 28; 19 | if (month == 12) return 31; 20 | if ((month <= 7 && month % 2 == 1) || (month >= 8 && month % 2 == 0)) return 30; 21 | return 31; 22 | } 23 | 24 | function prev_month_days(month, year) { 25 | const leap_year = check_leap_year(year); 26 | if (month == 3 && leap_year) return 29; 27 | if (month == 3 && !leap_year) return 28; 28 | if (month == 1) return 31; 29 | if ((month <= 7 && month % 2 == 1) || (month >= 8 && month % 2 == 0)) return 30; 30 | return 31; 31 | } 32 | 33 | export function get_calendar_layout(date_object, highlight) { 34 | if (!date_object) date_object = new Date(); 35 | const weekday = (date_object.getDay() + 6) % 7; 36 | const day = date_object.getDate(); 37 | const month = date_object.getMonth() + 1; 38 | const year = date_object.getFullYear(); 39 | const weekday_of_month_first = (weekday + 35 - (day - 1)) % 7; 40 | const days_in_month = month_day(month, year); 41 | const days_in_next_month = next_month_days(month, year); 42 | const days_in_prev_month = prev_month_days(month, year); 43 | 44 | // Fill 45 | var month_diff = (weekday_of_month_first == 0 ? 0 : -1); 46 | var to_fill, dim; 47 | if(weekday_of_month_first == 0) { 48 | to_fill = 1; 49 | dim = days_in_month; 50 | } 51 | else { 52 | to_fill = (days_in_prev_month - (weekday_of_month_first - 1)); 53 | dim = days_in_prev_month; 54 | } 55 | var calendar = [...Array(6)].map(() => Array(7)); 56 | var i = 0, j = 0; 57 | while (i < 6 && j < 7) { 58 | calendar[i][j] = { 59 | "day": to_fill, 60 | "today": ((to_fill == day && month_diff == 0 && highlight) ? 1 : ( 61 | month_diff == 0 ? 0 : 62 | -1 63 | )) 64 | }; 65 | // Increment 66 | to_fill++; 67 | if (to_fill > dim) { // Next month? 68 | month_diff++; 69 | if (month_diff == 0) 70 | dim = days_in_month; 71 | else if (month_diff == 1) 72 | dim = days_in_next_month; 73 | to_fill = 1; 74 | } 75 | // Next tile 76 | j++; 77 | if (j == 7) { 78 | j = 0; 79 | i++; 80 | } 81 | 82 | } 83 | return calendar; 84 | } 85 | -------------------------------------------------------------------------------- /ags/modules/misc/clickthrough.js: -------------------------------------------------------------------------------- 1 | import Cairo from "gi://cairo?version=1.0"; 2 | 3 | export const dummyRegion = new Cairo.Region(); 4 | export const enable_click_through = (self) => self.input_shape_combine_region(dummyRegion); 5 | -------------------------------------------------------------------------------- /ags/modules/misc/md2pango.ts: -------------------------------------------------------------------------------- 1 | // Converts from Markdown to Pango. This does not support code blocks. 2 | // Partly inherited from https://github.com/ubunatic/md2pango 3 | 4 | const monospaceFonts = 'JetBrains Mono NF, JetBrains Mono Nerd Font, JetBrains Mono NL, SpaceMono NF, SpaceMono Nerd Font, monospace'; 5 | 6 | const replacements = { 7 | 'indents': [ 8 | { name: 'BULLET', re: /^(\s*)([\*\-]\s)(.*)(\s*)$/, sub: ' $1- $3' }, 9 | { name: 'NUMBERING', re: /^(\s*[0-9]+\.\s)(.*)(\s*)$/, sub: ' $1 $2' }, 10 | ], 11 | 'escapes': [ 12 | { name: 'COMMENT', re: //, sub: '' }, 13 | { name: 'AMPERSTAND', re: /&/g, sub: '&' }, 14 | { name: 'LESSTHAN', re: //g, sub: '>' }, 16 | ], 17 | 'sections': [ 18 | { name: 'H1', re: /^(#\s+)(.*)(\s*)$/, sub: '$2' }, 19 | { name: 'H2', re: /^(##\s+)(.*)(\s*)$/, sub: '$2' }, 20 | { name: 'H3', re: /^(###\s+)(.*)(\s*)$/, sub: '$2' }, 21 | { name: 'H4', re: /^(####\s+)(.*)(\s*)$/, sub: '$2' }, 22 | { name: 'H5', re: /^(#####\s+)(.*)(\s*)$/, sub: '$2' }, 23 | ], 24 | 'styles': [ 25 | { name: 'BOLD', re: /(\*\*)(\S[\s\S]*?\S)(\*\*)/g, sub: "$2" }, 26 | { name: 'UND', re: /(__)(\S[\s\S]*?\S)(__)/g, sub: "$2" }, 27 | { name: 'EMPH', re: /\*(\S.*?\S)\*/g, sub: "$1" }, 28 | // { name: 'EMPH', re: /_(\S.*?\S)_/g, sub: "$1" }, 29 | { name: 'HEXCOLOR', re: /#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/g, sub: '#$1' }, 30 | { name: 'INLCODE', re: /(`)([^`]*)(`)/g, sub: '$2' }, 31 | // { name: 'UND', re: /(__|\*\*)(\S[\s\S]*?\S)(__|\*\*)/g, sub: "$2" }, 32 | ], 33 | } 34 | 35 | const replaceCategory = (text, replaces) => { 36 | for (const type of replaces) { 37 | text = text.replace(type.re, type.sub); 38 | } 39 | return text; 40 | } 41 | 42 | export default (text: string) => { 43 | let lines = text.split('\n') 44 | let output: any[] = []; 45 | // Replace 46 | for (const line of lines) { 47 | let result = line; 48 | result = replaceCategory(result, replacements.indents); 49 | result = replaceCategory(result, replacements.escapes); 50 | result = replaceCategory(result, replacements.sections); 51 | result = replaceCategory(result, replacements.styles); 52 | output.push(result) 53 | } 54 | output = output.map(line => line.replace(/ +$/, '')) 55 | return output.join('\n'); 56 | } 57 | 58 | export const markdownTest = `## Inline formatting 59 | - **Bold** *Italics* __Underline__ 60 | - \`Monospace text\` 🤓 61 | - Colors 62 | - Nvidia green #7ABB08 63 | - Soundcloud orange #FF5500 64 | ## Code block 65 | \`\`\`cpp 66 | #include 67 | const std::string GREETING="UwU"; 68 | int main() { std::cout << GREETING; } 69 | \`\`\` 70 | \`\`\`py 71 | print("Hello world!") 72 | \`\`\` 73 | ## LaTeX 74 | \`\`\`latex 75 | \\frac{d}{dx} \\left( \\frac{x-438}{x^2+23x-7} \\right) = \\frac{-x^2 + 869}{(x^2+23x-7)^2} \\\\ → \\\\ cos(2x) = 2cos^2(x) - 1 = 1 - 2sin^2(x) = cos^2(x) - sin^2(x) 76 | \`\`\` 77 | `; -------------------------------------------------------------------------------- /ags/modules/misc/popupwindow.ts: -------------------------------------------------------------------------------- 1 | import App from "resource:///com/github/Aylur/ags/app.js"; 2 | import Widget from "resource:///com/github/Aylur/ags/widget.js"; 3 | import { WindowProps, Window } from "types/widgets/window"; 4 | import Gtk from "gi://Gtk?version=3.0"; 5 | 6 | type _WindowProps = WindowProps> | undefined[]; 7 | 8 | type Type = { 9 | name: string; 10 | child: any; 11 | showClassName?: string; 12 | hideClassName?: string; 13 | }; 14 | 15 | export default ({ 16 | name, 17 | child, 18 | showClassName = "", 19 | hideClassName = "", 20 | ...props 21 | }: T & Omit<_WindowProps, keyof Type>) => { 22 | return Widget.Window({ 23 | name, 24 | visible: false, 25 | type: Gtk.WindowType.POPUP, 26 | layer: "overlay", 27 | resizable: true, 28 | ...props, 29 | setup: (self) => { 30 | self.keybind("Escape", () => App.closeWindow(name)); 31 | if (showClassName != "" && hideClassName !== "") { 32 | self.hook(App, (self, currentName, visible) => { 33 | if (currentName === name) { 34 | self.toggleClassName(hideClassName, !visible); 35 | } 36 | }); 37 | 38 | if (showClassName !== "" && hideClassName !== "") self.class_name = `${showClassName} ${hideClassName}`; 39 | } 40 | }, 41 | child: child 42 | }); 43 | }; 44 | -------------------------------------------------------------------------------- /ags/modules/misc/textview.ts: -------------------------------------------------------------------------------- 1 | import Gtk from "gi://Gtk?version=3.0"; 2 | 3 | export const TextView = Widget.subclass(Gtk.TextView, "AgsTextView"); 4 | -------------------------------------------------------------------------------- /ags/modules/popups.ts: -------------------------------------------------------------------------------- 1 | // by koeqaife ;) 2 | 3 | const audio = await Service.import("audio"); 4 | import backlight_service from "services/backlight.ts"; 5 | import { MaterialIcon } from "icons.ts"; 6 | import Gtk from "types/@girs/gtk-3.0/gtk-3.0"; 7 | import Revealer from "types/widgets/revealer"; 8 | import Box from "types/widgets/box"; 9 | import Slider from "types/widgets/slider"; 10 | import { Binding } from "types/service"; 11 | import { audio_popup } from "./audio"; 12 | 13 | const brightness_icons = [ 14 | "brightness_1", 15 | "brightness_2", 16 | "brightness_3", 17 | "brightness_4", 18 | "brightness_5", 19 | "brightness_6", 20 | "brightness_7" 21 | ]; 22 | 23 | function get_brightness_icon(brightness: number): string { 24 | const totalIcons = brightness_icons.length; 25 | const maxBrightness = 1; 26 | const ratio = 1.6; 27 | 28 | let thresholds: number[] = []; 29 | for (let i = 0; i < totalIcons; i++) { 30 | const threshold = maxBrightness / Math.pow(ratio, totalIcons - i - 1); 31 | thresholds.push(threshold); 32 | } 33 | 34 | for (let i = 0; i < totalIcons; i++) { 35 | if (brightness < thresholds[i]) { 36 | return brightness_icons[i]; 37 | } 38 | } 39 | 40 | return brightness_icons[totalIcons - 1]; 41 | } 42 | 43 | type popup_on_change = ((self: Slider) => void) | undefined; 44 | type popup_setup = 45 | | (( 46 | self: Revealer< 47 | Box, unknown>, 48 | { 49 | count: number; 50 | } 51 | > 52 | ) => void) 53 | | undefined; 54 | 55 | const default_popup = ( 56 | icon: Gtk.Widget, 57 | value: number | Binding, 58 | on_change?: popup_on_change, 59 | setup?: popup_setup 60 | ) => 61 | Widget.Revealer({ 62 | transition_duration: 200, 63 | transition: "slide_up", 64 | child: Widget.Revealer({ 65 | reveal_child: false, 66 | transition_duration: 190, 67 | transition: "crossfade", 68 | child: Widget.Box({ 69 | class_name: "popup", 70 | children: [ 71 | icon, 72 | Widget.Slider({ 73 | min: 0, 74 | max: 100, 75 | draw_value: false, 76 | class_name: "popup_slider", 77 | value: value, 78 | on_change: on_change 79 | }) 80 | ] 81 | }), 82 | attribute: { count: 0 }, 83 | setup: setup 84 | }), 85 | setup: (self) => { 86 | self.child.connect("notify::child-revealed", () => { 87 | self.reveal_child = self.child.child_revealed; 88 | }); 89 | self.child.connect("notify::reveal-child", () => { 90 | if (self.child.reveal_child) self.reveal_child = true; 91 | }); 92 | } 93 | }); 94 | 95 | const backlight_popup = () => 96 | default_popup( 97 | MaterialIcon("brightness_1").hook(backlight_service, (self) => { 98 | self.label = get_brightness_icon(backlight_service.screen_value); 99 | }), 100 | backlight_service.bind("screen_value").as((n) => n * 100), 101 | (self) => { 102 | backlight_service.screen_value = self.value / 100; 103 | }, 104 | (self) => { 105 | backlight_service.connect("screen-changed", (_) => { 106 | self.attribute.count++; 107 | if (self.attribute.count > 0) self.reveal_child = true; 108 | Utils.timeout(1500, () => { 109 | self.attribute.count--; 110 | if (self.attribute.count <= 0) self.reveal_child = false; 111 | }); 112 | }); 113 | } 114 | ); 115 | 116 | const volume_popup = () => 117 | default_popup( 118 | MaterialIcon("volume_off", "20px").hook(audio.speaker, (self) => { 119 | try { 120 | const vol = audio.speaker.volume * 100; 121 | const icon = [ 122 | [101, "sound_detection_loud_sound"], 123 | [67, "volume_up"], 124 | [34, "volume_down"], 125 | [1, "volume_mute"], 126 | [0, "volume_off"] 127 | ].find(([threshold]) => Number(threshold) <= vol)?.[1]; 128 | if (!icon) self.label = "volume_off"; 129 | else if (audio.speaker.is_muted) self.label = "volume_off"; 130 | else self.label = String(icon!); 131 | } catch (e) { 132 | self.label = "volume_off"; 133 | print("Error while setting volume icon:", e); 134 | } 135 | }), 136 | audio.speaker.bind("volume").as((volume) => Math.floor(volume * 100)), 137 | (self) => { 138 | audio.speaker.volume = self.value / 100; 139 | }, 140 | (self) => { 141 | audio.speaker.connect("notify::volume", (_) => { 142 | if (audio_popup.visible) return; 143 | self.attribute.count++; 144 | if (self.attribute.count > 0) self.reveal_child = true; 145 | Utils.timeout(1500, () => { 146 | self.attribute.count--; 147 | if (self.attribute.count <= 0) self.reveal_child = false; 148 | }); 149 | }); 150 | } 151 | ); 152 | 153 | export const popups = (monitor = 0) => { 154 | const _volume_popup = volume_popup(); 155 | const _backlight_popup = backlight_popup(); 156 | return Widget.Window({ 157 | monitor, 158 | name: `popups${monitor}`, 159 | child: Widget.Box({ 160 | css: "min-height: 1px; min-width: 1px;", 161 | vertical: true, 162 | children: [_backlight_popup, _volume_popup] 163 | }), 164 | class_name: "popups", 165 | anchor: ["top"], 166 | visible: true 167 | }); 168 | }; 169 | -------------------------------------------------------------------------------- /ags/modules/sideleft/applauncher.ts: -------------------------------------------------------------------------------- 1 | // by koeqaife ;) 2 | 3 | const applications_service = await Service.import("applications"); 4 | import Box from "types/widgets/box"; 5 | import Gtk from "gi://Gtk?version=3.0"; 6 | import { Application } from "types/service/applications"; 7 | import { WINDOW_NAME, shown } from "modules/sideleft/main"; 8 | 9 | const AppItem = (repopulate: () => void) => (app: Application) => { 10 | let clickCount = 0; 11 | const button = Widget.Button({ 12 | class_name: "application_container", 13 | child: Widget.Box({ 14 | children: [ 15 | Widget.Icon({ 16 | class_name: "application_icon", 17 | // @ts-ignore 18 | icon: Utils.lookUpIcon(app.icon_name) ? app.icon_name : "image-missing", 19 | size: 42 20 | }), 21 | Widget.Label({ 22 | class_name: "application_label", 23 | label: app.name, 24 | xalign: 0, 25 | vpack: "center", 26 | truncate: "end" 27 | }) 28 | ] 29 | }), 30 | on_clicked: (self) => { 31 | clickCount++; 32 | if (clickCount === 2) { 33 | App.closeWindow(WINDOW_NAME); 34 | app.launch(); 35 | repopulate(); 36 | clickCount = 0; 37 | } 38 | } 39 | }); 40 | 41 | button.connect("focus-out-event", () => { 42 | clickCount = 0; 43 | }); 44 | 45 | return Widget.Box({ 46 | attribute: { app }, 47 | orientation: Gtk.Orientation.VERTICAL, 48 | children: [ 49 | button, 50 | Widget.Separator({ 51 | class_name: "application_divider", 52 | orientation: Gtk.Orientation.HORIZONTAL 53 | }) 54 | ] 55 | }); 56 | }; 57 | 58 | export const Applauncher = () => { 59 | let applications: Box[]; 60 | 61 | const list = Widget.Box({ 62 | vertical: true 63 | }); 64 | 65 | const entry = Widget.Entry({ 66 | hexpand: true, 67 | class_name: "applauncher_entry", 68 | placeholder_text: "Search", 69 | 70 | on_accept: () => { 71 | const results = applications.filter((item) => item.visible); 72 | if (results[0]) { 73 | App.closeWindow(WINDOW_NAME); 74 | results[0].attribute.app.launch(); 75 | } 76 | }, 77 | 78 | on_change: ({ text }) => 79 | applications.forEach((item) => { 80 | item.visible = item.attribute.app.match(text ?? ""); 81 | }) 82 | }); 83 | 84 | function reload() { 85 | applications_service.reload(); 86 | repopulate(); 87 | } 88 | 89 | function repopulate() { 90 | applications = applications_service.query("").map(AppItem(repopulate)); 91 | list.children = applications; 92 | } 93 | 94 | const menu = Widget.Menu({ 95 | children: [ 96 | Widget.MenuItem({ 97 | label: "Reload apps", 98 | on_activate: (self) => { 99 | reload(); 100 | } 101 | }) 102 | ] 103 | }); 104 | 105 | repopulate(); 106 | 107 | return Widget.EventBox({ 108 | on_secondary_click_release: (self, event) => { 109 | menu.popup_at_pointer(event); 110 | }, 111 | child: Widget.Box({ 112 | vertical: true, 113 | class_name: "applauncher_box", 114 | vexpand: true, 115 | children: [ 116 | entry, 117 | Widget.Separator(), 118 | Widget.Scrollable({ 119 | hscroll: "never", 120 | child: list, 121 | vexpand: true 122 | }) 123 | ], 124 | setup: (self) => { 125 | self.hook(shown, () => { 126 | try { 127 | if (shown.value == "apps") entry.grab_focus(); 128 | } catch (e) { 129 | print("Error while reloading applications:", e); 130 | } 131 | }); 132 | self.hook(App, (_, windowName, visible) => { 133 | if (windowName !== WINDOW_NAME) return; 134 | 135 | try { 136 | if (visible) { 137 | entry.text = ""; 138 | entry.grab_focus(); 139 | } 140 | } catch (e) { 141 | print("Error while setting application popup:", e); 142 | } 143 | }); 144 | } 145 | }) 146 | }); 147 | }; 148 | -------------------------------------------------------------------------------- /ags/modules/sideleft/main.ts: -------------------------------------------------------------------------------- 1 | // by koeqaife ;) 2 | 3 | import popupwindow from "../misc/popupwindow.ts"; 4 | import Gtk from "gi://Gtk?version=3.0"; 5 | import { MaterialIcon } from "icons.ts"; 6 | import { WeatherBox } from "./weather.ts"; 7 | import { Media } from "./players.ts"; 8 | import { Applauncher } from "./applauncher.ts"; 9 | import { geminiPage } from "./gemini.ts"; 10 | import { chatsPage } from "./chats.ts"; 11 | import config from "services/configuration"; 12 | 13 | export const WINDOW_NAME = "sideleft"; 14 | export const shown = Variable("weather"); 15 | 16 | export function toggleAppsWindow() { 17 | if (shown.value == "apps" && sideleft.visible) App.closeWindow(WINDOW_NAME); 18 | else { 19 | shown.setValue("apps"); 20 | App.openWindow(WINDOW_NAME); 21 | } 22 | } 23 | export function toggleMediaWindow() { 24 | if (shown.value == "media" && sideleft.visible) App.closeWindow(WINDOW_NAME); 25 | else { 26 | shown.setValue("media"); 27 | App.openWindow(WINDOW_NAME); 28 | } 29 | } 30 | 31 | globalThis.toggleMediaWindow = toggleMediaWindow; 32 | globalThis.toggleAppsWindow = toggleAppsWindow; 33 | 34 | type ButtonType = { 35 | page: string; 36 | label: string; 37 | icon?: string; 38 | icon_widget?: Gtk.Widget; 39 | }; 40 | 41 | function Button({ page, label, icon, icon_widget }: ButtonType) { 42 | return Widget.Button({ 43 | class_name: `navigation_button _${page}`, 44 | hexpand: true, 45 | vpack: "start", 46 | child: Widget.Box({ 47 | orientation: Gtk.Orientation.VERTICAL, 48 | class_name: "container_outer", 49 | children: [ 50 | Widget.Overlay({ 51 | child: Widget.Box({ 52 | orientation: Gtk.Orientation.VERTICAL, 53 | hpack: "center", 54 | class_name: "container" 55 | }), 56 | overlay: icon ? MaterialIcon(icon!, "20px") : icon_widget!, 57 | pass_through: true 58 | }), 59 | Widget.Label({ 60 | label: label, 61 | class_name: "label" 62 | }) 63 | ] 64 | }), 65 | on_clicked: () => { 66 | shown.setValue(page); 67 | }, 68 | setup: (self) => { 69 | self.hook(shown, () => { 70 | self.toggleClassName("active", shown.value == page); 71 | }); 72 | } 73 | }); 74 | } 75 | 76 | function Navigation() { 77 | let stack = Widget.Stack({ 78 | children: { 79 | weather: WeatherBox(), 80 | media: Media(), 81 | apps: Applauncher(), 82 | gemini: geminiPage, 83 | chats: config.config.show_beta ? chatsPage : Widget.Label("Beta functions disabled") 84 | }, 85 | hexpand: true, 86 | transition: "crossfade", 87 | transitionDuration: 200, 88 | // @ts-expect-error 89 | shown: shown.bind() 90 | }); 91 | const buttons = Widget.Box({ 92 | class_name: "rail", 93 | vertical: true, 94 | vexpand: true, 95 | hpack: "start", 96 | children: [ 97 | Button({ 98 | page: "weather", 99 | label: "Weather", 100 | icon: "cloud" 101 | }), 102 | Button({ 103 | page: "media", 104 | label: "Players", 105 | icon: "music_note" 106 | }), 107 | Button({ 108 | page: "apps", 109 | label: "Apps", 110 | icon: "search" 111 | }), 112 | Button({ 113 | page: "gemini", 114 | label: "Gemini", 115 | icon_widget: Widget.Icon({ 116 | icon: "google-gemini-symbolic", 117 | size: 20, 118 | class_name: "icon" 119 | }) 120 | }) 121 | ] 122 | }); 123 | if (config.config.show_beta) { 124 | buttons.add( 125 | Button({ 126 | page: "chats", 127 | label: "Chat", 128 | icon: "chat" 129 | }) 130 | ); 131 | } 132 | return Widget.Box({ 133 | vexpand: true, 134 | class_name: "sideleft", 135 | children: [buttons, stack], 136 | hexpand: true, 137 | setup: (self) => { 138 | const keys = Object.keys(stack.children); 139 | for (let i = 0; i < keys.length; i++) { 140 | const key = keys[i]; 141 | // @ts-expect-error 142 | self.keybind(`${i + 1}`, () => { 143 | shown.setValue(key); 144 | }); 145 | } 146 | } 147 | }); 148 | } 149 | 150 | function SideLeft() { 151 | return Widget.Box({ 152 | class_name: "sideleft_main_box", 153 | hexpand: true, 154 | children: [Navigation()] 155 | }); 156 | } 157 | 158 | export const sideleft = popupwindow({ 159 | name: WINDOW_NAME, 160 | 161 | class_name: "sideleft", 162 | visible: false, 163 | keymode: "exclusive", 164 | child: SideLeft(), 165 | anchor: ["top", "left", "bottom"], 166 | css: "min-width: 443px;" 167 | }); 168 | -------------------------------------------------------------------------------- /ags/modules/sideleft/players.ts: -------------------------------------------------------------------------------- 1 | // by koeqaife ;) 2 | 3 | import { MprisPlayer } from "types/service/mpris.ts"; 4 | import Label from "types/widgets/label.ts"; 5 | import { MaterialIcon } from "icons.ts"; 6 | import Pango10 from "gi://Pango?version=1.0"; 7 | const mpris = await Service.import("mpris"); 8 | const players = mpris.bind("players"); 9 | 10 | const FALLBACK_ICON = "audio-x-generic-symbolic"; 11 | const PLAY_ICON = "play_arrow"; 12 | const PAUSE_ICON = "pause"; 13 | const PREV_ICON = "skip_previous"; 14 | const NEXT_ICON = "skip_next"; 15 | 16 | function length_str(length: number): string { 17 | const min = Math.floor(length / 60); 18 | const sec = Math.floor(length % 60); 19 | const sec0 = sec < 10 ? "0" : ""; 20 | return `${min}:${sec0}${sec}`; 21 | } 22 | 23 | function Player(player: MprisPlayer) { 24 | const img = Widget.Box({ 25 | class_name: "img", 26 | vpack: "start", 27 | css: player.bind("cover_path").transform( 28 | (p) => ` 29 | background-image: url('${p}'); 30 | ` 31 | ) 32 | }); 33 | 34 | const title = Widget.Label({ 35 | class_name: "title", 36 | wrap: true, 37 | wrap_mode: Pango10.WrapMode.WORD_CHAR, 38 | xalign: 0, 39 | label: player.bind("track_title"), 40 | use_markup: false 41 | }); 42 | 43 | const artist = Widget.Label({ 44 | class_name: "artist", 45 | wrap: true, 46 | wrap_mode: Pango10.WrapMode.WORD_CHAR, 47 | xalign: 0, 48 | use_markup: false, 49 | label: player.bind("track_artists").transform((a) => a.join(", ")) 50 | }); 51 | 52 | const positionSlider = Widget.Slider({ 53 | class_name: "position", 54 | draw_value: false, 55 | on_change: ({ value }) => (player.position = value * player.length), 56 | visible: player.bind("length").as((l) => l > 0), 57 | setup: (self) => { 58 | function update() { 59 | try { 60 | const value = player.position / player.length; 61 | self.value = value > 0 ? value : 0; 62 | } catch (e) { 63 | self.value = 0; 64 | print("Error while setting position slider:", e); 65 | } 66 | } 67 | self.hook(player, update); 68 | self.hook(player, update, "position"); 69 | self.poll(1000, update); 70 | } 71 | }); 72 | 73 | const positionLabel = Widget.Label({ 74 | class_name: "position", 75 | hpack: "start", 76 | setup: (self) => { 77 | const update = (self: Label) => { 78 | self.label = length_str(player.position); 79 | self.visible = player.length > 0; 80 | }; 81 | 82 | self.hook(player, update, "position"); 83 | self.poll(1000, update); 84 | } 85 | }); 86 | 87 | const lengthLabel = Widget.Label({ 88 | class_name: "length", 89 | hpack: "end", 90 | visible: player.bind("length").transform((l) => l > 0), 91 | label: player.bind("length").transform(length_str) 92 | }); 93 | 94 | const icon = Widget.Icon({ 95 | class_name: "icon", 96 | hexpand: true, 97 | hpack: "end", 98 | vpack: "start", 99 | tooltip_text: player.identity || "", 100 | icon: player.bind("entry").transform((entry) => { 101 | const name = `${entry}-symbolic`; 102 | return Utils.lookUpIcon(name) ? name : FALLBACK_ICON; 103 | }) 104 | }); 105 | 106 | const playPause = Widget.Button({ 107 | class_name: "play-pause", 108 | on_clicked: () => player.playPause(), 109 | visible: player.bind("can_play"), 110 | child: MaterialIcon( 111 | player.bind("play_back_status").transform((s) => { 112 | switch (s) { 113 | case "Playing": 114 | return PAUSE_ICON; 115 | case "Paused": 116 | case "Stopped": 117 | return PLAY_ICON; 118 | } 119 | }), 120 | "18px" 121 | ) 122 | }); 123 | 124 | const prev = Widget.Button({ 125 | on_clicked: () => player.previous(), 126 | visible: player.bind("can_go_prev"), 127 | child: MaterialIcon(PREV_ICON, "18px") 128 | }); 129 | 130 | const next = Widget.Button({ 131 | on_clicked: () => player.next(), 132 | visible: player.bind("can_go_next"), 133 | child: MaterialIcon(NEXT_ICON, "18px") 134 | }); 135 | 136 | return Widget.Box( 137 | { 138 | class_name: "card player", 139 | vpack: "start" 140 | }, 141 | img, 142 | Widget.Box( 143 | { 144 | vertical: true, 145 | hexpand: true 146 | }, 147 | Widget.Box([title, icon]), 148 | artist, 149 | Widget.Box({ vexpand: true }), 150 | positionSlider, 151 | Widget.CenterBox({ 152 | start_widget: positionLabel, 153 | center_widget: Widget.Box({ 154 | class_name: "player_buttons", 155 | children: [prev, playPause, next] 156 | }), 157 | end_widget: lengthLabel 158 | }) 159 | ) 160 | ); 161 | } 162 | 163 | export function Media() { 164 | return Widget.Box({ 165 | vertical: true, 166 | css: "min-height: 2px; min-width: 2px;", 167 | vpack: "start", 168 | visible: players.as((p) => p.length > 0), 169 | children: players.as((p) => p.map(Player)) 170 | }); 171 | } 172 | -------------------------------------------------------------------------------- /ags/modules/sideright/buttons.ts: -------------------------------------------------------------------------------- 1 | // by koeqaife ;) 2 | 3 | import { MaterialIcon } from "icons"; 4 | 5 | const { GLib } = imports.gi; 6 | 7 | const scripts_dir = `${GLib.get_home_dir()}/dotfiles/hypr/scripts`; 8 | const lock_command = `${scripts_dir}/lock.sh`; 9 | const logout_command = `${scripts_dir}/exit.sh`; 10 | const shutdown_command = `${scripts_dir}/shutdown.sh`; 11 | const reboot_command = `${scripts_dir}/reboot.sh`; 12 | const suspend_command = `${scripts_dir}/suspend.sh`; 13 | 14 | function Button({ icon, command, tooltip, ...props }) { 15 | let clickCount = 0; 16 | const button = Widget.Button({ 17 | tooltip_text: tooltip, 18 | child: MaterialIcon(icon, "20px"), 19 | class_name: "outline_button", 20 | on_clicked: (self) => { 21 | clickCount++; 22 | if (clickCount === 2) { 23 | Utils.execAsync(command).catch(print); 24 | clickCount = 0; 25 | } 26 | }, 27 | ...props 28 | }); 29 | 30 | button.connect("focus-out-event", () => { 31 | clickCount = 0; 32 | }); 33 | 34 | return button; 35 | } 36 | 37 | export function Buttons() { 38 | return Widget.Box({ 39 | class_name: "sidebar_buttons", 40 | hexpand: true, 41 | spacing: 5, 42 | children: [ 43 | Button({ 44 | icon: "lock", 45 | command: lock_command, 46 | tooltip: "Lock", 47 | hexpand: true 48 | }), 49 | Button({ 50 | icon: "clear_night", 51 | command: suspend_command, 52 | tooltip: "Suspend", 53 | hexpand: true 54 | }), 55 | Button({ 56 | icon: "logout", 57 | command: logout_command, 58 | tooltip: "Logout", 59 | hexpand: true 60 | }), 61 | Button({ 62 | icon: "restart_alt", 63 | command: reboot_command, 64 | tooltip: "Reboot", 65 | hexpand: true 66 | }), 67 | Button({ 68 | icon: "power_settings_new", 69 | command: shutdown_command, 70 | tooltip: "Shutdown", 71 | hexpand: true 72 | }) 73 | ] 74 | }); 75 | } 76 | -------------------------------------------------------------------------------- /ags/modules/sideright/main.ts: -------------------------------------------------------------------------------- 1 | // by koeqaife ;) 2 | 3 | import popupwindow from "../misc/popupwindow.js"; 4 | import { SideBar } from "./sidebar.ts"; 5 | 6 | export const WINDOW_NAME = "sidebar"; 7 | 8 | export const sideright = popupwindow({ 9 | name: WINDOW_NAME, 10 | 11 | class_name: "sidebar", 12 | visible: false, 13 | keymode: "exclusive", 14 | child: SideBar(), 15 | anchor: ["top", "right", "bottom"], 16 | css: "min-width: 443px;" 17 | }); 18 | -------------------------------------------------------------------------------- /ags/modules/sideright/navigation.ts: -------------------------------------------------------------------------------- 1 | // by koeqaife ;) 2 | 3 | import { NotificationsBox } from "./notifications.ts"; 4 | import { SystemBox } from "./system.ts"; 5 | let shown = Variable("Messages"); 6 | import Gtk from "gi://Gtk?version=3.0"; 7 | import { MaterialIcon } from "icons.ts"; 8 | import config from "services/configuration.ts"; 9 | 10 | type ButtonType = { 11 | page: string; 12 | label: string; 13 | icon: string; 14 | }; 15 | 16 | function Button({ page, label, icon }: ButtonType) { 17 | return Widget.Button({ 18 | class_name: "navigation_button", 19 | hexpand: true, 20 | attribute: { page: page }, 21 | child: Widget.Box({ 22 | orientation: Gtk.Orientation.VERTICAL, 23 | class_name: "container_outer", 24 | children: [ 25 | Widget.Overlay({ 26 | child: Widget.Box({ 27 | orientation: Gtk.Orientation.VERTICAL, 28 | hpack: "center", 29 | class_name: "container" 30 | }), 31 | overlay: MaterialIcon(icon, "20px"), 32 | pass_through: true 33 | }), 34 | Widget.Label({ 35 | label: label, 36 | class_name: "label" 37 | }) 38 | ] 39 | }), 40 | on_clicked: () => { 41 | shown.setValue(page); 42 | } 43 | }); 44 | } 45 | 46 | export function Navigation() { 47 | const messages_apps = [ 48 | "discord", 49 | "materialgram", 50 | "telegram", 51 | "ayugram", 52 | "whatsapp", 53 | ...config.config.messages_notifications_filter 54 | ]; 55 | let stack = Widget.Stack({ 56 | children: { 57 | Messages: NotificationsBox({ include: messages_apps }), 58 | Notifications: NotificationsBox({ exclude: messages_apps }), 59 | System: SystemBox() 60 | }, 61 | transition: "crossfade", 62 | transitionDuration: 200, 63 | // @ts-expect-error 64 | shown: shown.bind() 65 | }); 66 | const buttons = Widget.Box({ 67 | class_name: "navigation", 68 | hexpand: true, 69 | children: [ 70 | Button({ 71 | page: "Messages", 72 | label: "Messages", 73 | icon: "chat" 74 | }), 75 | Button({ 76 | page: "Notifications", 77 | label: "Notifs", 78 | icon: "notifications" 79 | }), 80 | Button({ 81 | page: "System", 82 | label: "System", 83 | icon: "info" 84 | }) 85 | ], 86 | setup: (self) => { 87 | self.hook(shown, () => { 88 | try { 89 | for (const button of self.children) { 90 | if (!button.attribute || !button.attribute.page) continue; 91 | button.toggleClassName("active", button.attribute.page == shown.value); 92 | } 93 | } catch (e) { 94 | print("Error while reloading buttons:", e); 95 | } 96 | }); 97 | } 98 | }); 99 | return Widget.Box({ 100 | vexpand: true, 101 | orientation: Gtk.Orientation.VERTICAL, 102 | class_name: "sidebar_bottom", 103 | children: [stack, buttons], 104 | setup: (self) => { 105 | const keys = Object.keys(stack.children); 106 | for (let i = 0; i < keys.length; i++) { 107 | const key = keys[i]; 108 | // @ts-expect-error 109 | self.keybind(`${i + 1}`, () => { 110 | shown.setValue(key); 111 | }); 112 | } 113 | } 114 | }); 115 | } 116 | -------------------------------------------------------------------------------- /ags/modules/sideright/notifications.ts: -------------------------------------------------------------------------------- 1 | // by koeqaife ;) 2 | 3 | import { Notification as NotificationType } from "types/service/notifications"; 4 | import { NotificationPopups, Notification } from "modules/notificationPopups"; 5 | import Box from "types/widgets/box"; 6 | 7 | const notifications = await Service.import("notifications"); 8 | 9 | type NotificationsBoxType = { 10 | exclude?: string[]; 11 | include?: string[]; 12 | }; 13 | 14 | const NotificationReveal = (notification: NotificationType, visible = false, dismiss = true) => { 15 | const transition_duration = 200; 16 | const secondRevealer = Widget.Revealer({ 17 | vpack: "center", 18 | child: Notification(notification, dismiss), 19 | reveal_child: visible, 20 | transition: "crossfade", 21 | transition_duration: transition_duration, 22 | hexpand: true, 23 | class_name: "second_revealer", 24 | setup: (revealer) => { 25 | Utils.timeout(1, () => { 26 | revealer.reveal_child = true; 27 | }); 28 | } 29 | }); 30 | 31 | const firstRevealer = Widget.Revealer({ 32 | child: secondRevealer, 33 | reveal_child: true, 34 | transition: "slide_down", 35 | transition_duration: transition_duration, 36 | class_name: "first_revealer" 37 | }); 38 | 39 | type BoxAttrs = { 40 | destroyWithAnims: any; 41 | count: number; 42 | id: number; 43 | app: string; 44 | destroying: boolean; 45 | }; 46 | 47 | let box: Box; 48 | 49 | const destroyWithAnims = () => { 50 | if (box.attribute.destroying) return; 51 | box.attribute.destroying = true; 52 | secondRevealer.reveal_child = false; 53 | Utils.timeout(transition_duration, () => { 54 | firstRevealer.reveal_child = false; 55 | Utils.timeout(transition_duration, () => { 56 | box.destroy(); 57 | }); 58 | }); 59 | }; 60 | box = Widget.Box({ 61 | hexpand: true, 62 | attribute: { 63 | destroyWithAnims: destroyWithAnims, 64 | count: 0, 65 | id: notification.id, 66 | app: notification.app_name, 67 | destroying: false 68 | }, 69 | children: [firstRevealer] 70 | }); 71 | return box; 72 | }; 73 | 74 | export function NotificationsBox({ exclude = [], include = [] }: NotificationsBoxType) { 75 | const popups = NotificationPopups(false, { exclude: exclude, include: include }, false, NotificationReveal); 76 | 77 | const menu = Widget.Menu({ 78 | class_name: "notifications_menu", 79 | children: [ 80 | Widget.MenuItem({ 81 | child: Widget.Label({ 82 | label: "Close all", 83 | hpack: "start" 84 | }), 85 | class_name: "notifications_menu_item", 86 | on_activate: () => { 87 | for (let n of notifications.notifications) { 88 | if (n) { 89 | n.dismiss(); 90 | n.close(); 91 | } 92 | } 93 | } 94 | }) 95 | ] 96 | }); 97 | 98 | return Widget.EventBox({ 99 | vexpand: true, 100 | hexpand: true, 101 | on_secondary_click_release: (_, event) => { 102 | menu.popup_at_pointer(event); 103 | }, 104 | child: Widget.Scrollable({ 105 | class_name: "notifications_sidebar_scrollable", 106 | hscroll: "never", 107 | child: Widget.Box({ 108 | vertical: true, 109 | children: [ 110 | popups, 111 | Widget.Revealer({ 112 | child: Widget.Label({ 113 | label: "No notifications", 114 | class_name: "no_notifications" 115 | }), 116 | reveal_child: true, 117 | transition: "slide_down" 118 | }) 119 | ], 120 | setup: (self) => { 121 | popups.connect("notify::children", () => { 122 | type RevealerType = ReturnType; 123 | (self.children[1] as RevealerType).reveal_child = popups.children.length == 0; 124 | }); 125 | } 126 | }), 127 | hexpand: true 128 | }) 129 | }); 130 | } 131 | -------------------------------------------------------------------------------- /ags/modules/sideright/sidebar.ts: -------------------------------------------------------------------------------- 1 | // by koeqaife ;) 2 | 3 | import { Management } from "./management.ts"; 4 | import { Buttons } from "./buttons.ts"; 5 | import { Navigation } from "./navigation.ts"; 6 | import Gtk from "gi://Gtk?version=3.0"; 7 | 8 | export function SideBar() { 9 | return Widget.Box({ 10 | orientation: Gtk.Orientation.VERTICAL, 11 | class_name: "sidebar_main_box", 12 | hexpand: true, 13 | children: [ 14 | Management(), 15 | Buttons(), 16 | Navigation() 17 | // NotificationsBox() 18 | ] 19 | }); 20 | } 21 | -------------------------------------------------------------------------------- /ags/scripts/apps.py: -------------------------------------------------------------------------------- 1 | # by koeqaife ;) 2 | 3 | import argparse 4 | import os 5 | import re 6 | import json 7 | 8 | parser = argparse.ArgumentParser() 9 | group = parser.add_mutually_exclusive_group(required=True) 10 | group.add_argument('--browser', type=str, help="Change default browser") 11 | group.add_argument('--filemanager', type=str, help="Change file manager") 12 | group.add_argument('--editor', type=str, help="Change default editor") 13 | group.add_argument('--terminal', type=str, help="Change default terminal") 14 | group.add_argument('--get', type=str, help="Get default app", 15 | choices=["browser", "editor", "terminal", "filemanager"]) 16 | 17 | args = parser.parse_args() 18 | 19 | browser = args.browser 20 | filemanager = args.filemanager 21 | editor = args.editor 22 | terminal = args.terminal 23 | get = args.get 24 | 25 | value = (args.browser or args.filemanager or 26 | args.editor or args.terminal or args.get) 27 | 28 | u = os.path.expanduser 29 | 30 | CONFIG_FILE = u("~/dotfiles/hypr/conf/apps.conf") 31 | JSON_CONFIG_FILE = u("~/dotfiles/.settings/apps.json") 32 | 33 | with open(CONFIG_FILE) as f: 34 | original_env_str = f.read().strip() 35 | env_str = original_env_str 36 | 37 | 38 | def which(program: str): 39 | def is_executable(fpath): 40 | return os.path.isfile(fpath) and os.access(fpath, os.X_OK) 41 | 42 | fpath, fname = os.path.split(program) 43 | if fpath: 44 | if is_executable(program): 45 | return program 46 | else: 47 | for path in os.environ["PATH"].split(os.pathsep): 48 | path = path.strip('"') 49 | exe_file = os.path.join(path, program) 50 | if is_executable(exe_file): 51 | return exe_file 52 | raise ProgramNotFound(value) 53 | 54 | 55 | def extract_associations(env_str): 56 | pattern = re.compile( 57 | r'^\s*env\s*=\s*(\w+)\s*,\s*(.*?)\s*#\s*!\s*-\s*@(\w+)\s*$', 58 | re.MULTILINE 59 | ) 60 | associations = {} 61 | matches = pattern.findall(env_str) 62 | for key, _, association in matches: 63 | if association not in associations: 64 | associations[association] = [] 65 | if key not in associations[association]: 66 | associations[association].append(key) 67 | return associations 68 | 69 | 70 | associations = extract_associations(env_str) 71 | 72 | 73 | def replace_value(env_str, key, new_value): 74 | pattern = re.compile( 75 | r'^(\s*env\s*=\s*' + 76 | re.escape(key) + 77 | r'\s*,\s*)(.*?)\s*(#.*)?$', 78 | re.MULTILINE 79 | ) 80 | return re.sub(pattern, r'\1' + new_value + r' \3', env_str) 81 | 82 | 83 | class AssociationNotFound(Exception): 84 | def __init__(self, name: str, *args: object) -> None: 85 | error = f"{name} association not found, \n{associations}" 86 | super().__init__(error, *args) 87 | 88 | 89 | class ProgramNotFound(Exception): 90 | def __init__(self, name: str, *args: object) -> None: 91 | error = f"{name} not found" 92 | super().__init__(error, *args) 93 | 94 | 95 | def change_association(key: str, value: str): 96 | global env_str 97 | which(value) 98 | if key not in associations: 99 | raise AssociationNotFound(key) 100 | 101 | for assoc_key in associations[key]: 102 | env_str = replace_value(env_str, assoc_key, value) 103 | 104 | 105 | def read_json_config(): 106 | try: 107 | with open(JSON_CONFIG_FILE) as json_file: 108 | return json.load(json_file) 109 | except IOError as e: 110 | print(f"Error reading {JSON_CONFIG_FILE}: {e}") 111 | raise 112 | 113 | 114 | def write_json_config(config): 115 | try: 116 | with open(JSON_CONFIG_FILE, 'w') as json_file: 117 | json.dump(config, json_file, indent=4) 118 | except IOError as e: 119 | print(f"Error writing to {JSON_CONFIG_FILE}: {e}") 120 | raise 121 | 122 | 123 | def update_json_config(key: str, value: str): 124 | config = read_json_config() 125 | config[key] = value 126 | write_json_config(config) 127 | 128 | 129 | if get: 130 | json_config = read_json_config() 131 | print(json_config[get]) 132 | elif browser: 133 | change_association("browser", value) 134 | update_json_config("browser", value) 135 | elif filemanager: 136 | change_association("filemanager", value) 137 | update_json_config("filemanager", value) 138 | elif editor: 139 | change_association("editor", value) 140 | update_json_config("editor", value) 141 | elif terminal: 142 | change_association("terminal", value) 143 | update_json_config("terminal", value) 144 | 145 | if env_str != original_env_str: 146 | with open(CONFIG_FILE, 'w') as f: 147 | f.write(env_str + '\n') 148 | -------------------------------------------------------------------------------- /ags/scripts/brightness.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # by koeqaife ;) 3 | 4 | wl_gammarelay() { 5 | if ! busctl --user list | grep rs.wl.gammarelay; then 6 | systemctl --user restart wl-gammarelay.service 7 | fi 8 | } 9 | wl_gammarelay >/dev/null 10 | 11 | LOCKFILE=/tmp/brightness.lock 12 | 13 | get_brightness() { 14 | busctl --user get-property rs.wl-gammarelay / rs.wl.gammarelay Brightness | awk '{print $2}' 15 | } 16 | 17 | set_brightness() { 18 | if (($(echo "$1 < 0.05" | bc -l))); then 19 | BRIGHTNESS=0.05 20 | else 21 | BRIGHTNESS=$1 22 | fi 23 | busctl --user -- set-property rs.wl-gammarelay / rs.wl.gammarelay Brightness d $BRIGHTNESS 24 | } 25 | 26 | set() { 27 | if [ -n "$1" ]; then 28 | set_brightness $1 29 | else 30 | echo "Not enough arguments" 31 | exit 1 32 | fi 33 | } 34 | 35 | get() { 36 | if [ -e "$LOCKFILE" ] && kill -0 "$(cat $LOCKFILE)"; then 37 | local target_brightness=$(cat $BRIGHTNESS) 38 | echo $target_brightness 39 | exit 0 40 | fi 41 | percentage=$(get_brightness) 42 | 43 | echo "$percentage" 44 | } 45 | 46 | if [[ "$1" == "--set" ]]; then 47 | set $2 48 | elif [[ "$1" == "--get" ]]; then 49 | get 50 | fi 51 | -------------------------------------------------------------------------------- /ags/scripts/cliphist.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # by koeqaife ;) 3 | 4 | get() { 5 | cliphist list | iconv -f $(locale charmap) -t UTF-8 -c 6 | } 7 | 8 | copy_by_id() { 9 | id=$1 10 | cliphist decode $id | wl-copy 11 | } 12 | 13 | clear() { 14 | cliphist wipe 15 | } 16 | 17 | save_cache_file() { 18 | id=$1 19 | 20 | output_file="/tmp/ags/cliphist/$id.png" 21 | 22 | if [[ ! -f "$output_file" ]]; then 23 | mkdir -p "/tmp/ags/cliphist/" 24 | cliphist decode "$id" >"$output_file" 25 | fi 26 | 27 | echo $output_file 28 | } 29 | 30 | clear_tmp() { 31 | rm "/tmp/ags/cliphist/*" 32 | } 33 | 34 | if [[ "$1" == "--get" ]]; then 35 | get 36 | elif [[ "$1" == "--copy-by-id" ]]; then 37 | { copy_by_id "$2"; } 38 | elif [[ "$1" == "--save-by-id" ]]; then 39 | { save_cache_file "$2"; } 40 | elif [[ "$1" == "--clear-cache" ]]; then 41 | clear_tmp 42 | elif [[ "$1" == "--clear" ]]; then 43 | clear 44 | fi 45 | -------------------------------------------------------------------------------- /ags/scripts/dark-theme.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # by koeqaife ;) 3 | 4 | GENERATOR="$HOME/dotfiles/material-colors/generate.py" 5 | SETTINGS_FILE="$HOME/dotfiles/.settings/settings.json" 6 | 7 | # Function to read a value from the JSON file 8 | get_json_value() { 9 | local key=$1 10 | jq -r --arg key "$key" '.[$key]' $SETTINGS_FILE 11 | } 12 | 13 | # Function to update a value in the JSON file 14 | update_json_value() { 15 | local key=$1 16 | local value=$2 17 | jq --arg key "$key" --arg value "$value" \ 18 | '.[$key] = $value' $SETTINGS_FILE > "$SETTINGS_FILE.tmp" && mv "$SETTINGS_FILE.tmp" $SETTINGS_FILE 19 | } 20 | 21 | toggle() { 22 | local color_scheme=$(get_json_value "color-scheme") 23 | 24 | if [ "$color_scheme" == "dark" ]; then 25 | python -O $GENERATOR -R --color-scheme light 26 | update_json_value "color-scheme" "light" 27 | elif [ "$color_scheme" == "light" ]; then 28 | python -O $GENERATOR -R --color-scheme dark 29 | update_json_value "color-scheme" "dark" 30 | else 31 | echo "Unknown color scheme: $color_scheme" 32 | fi 33 | } 34 | 35 | set() { 36 | local new_scheme=$1 37 | python -O $GENERATOR -R --color-scheme $new_scheme 38 | update_json_value "color-scheme" $new_scheme 39 | } 40 | 41 | # Process arguments 42 | if [[ "$1" == "--toggle" ]]; then 43 | toggle 44 | elif [[ "$1" == "--set" ]]; then 45 | set $2 46 | else 47 | echo "Usage: $0 --toggle | --set " 48 | fi 49 | -------------------------------------------------------------------------------- /ags/scripts/keybindings.py: -------------------------------------------------------------------------------- 1 | # by koeqaife ;) 2 | 3 | import os 4 | import re 5 | import json 6 | 7 | HOME = os.path.expanduser("~") 8 | CONFIG = f"{HOME}/dotfiles/hypr" 9 | 10 | files = [f"{CONFIG}/hyprland.conf"] 11 | 12 | categories_dict: dict[str, str] = {} 13 | variables_dict: dict[str, str] = {} 14 | 15 | category_pattern = r"\n#! @(\w+): (.+)" 16 | variable_pattern = r"\n\$(\w+)\s*=\s*(.*)" 17 | text = "" 18 | bindings: dict[str, dict[str, str]] = {} 19 | 20 | 21 | def extract_category_and_description( 22 | line: str 23 | ) -> tuple[str | None, str | None, tuple | None]: 24 | pattern2 = r'bind\s*=\s*.*! @description:\s*"((?:[^"]|\\")*)"\s*;\s*@(\w+);\s*@replace\s*"([^"]*)"\s*>\s*"([^"]*)";.*' # noqa 25 | pattern = r'bind\s*=\s*.*! @description:\s*"((?:[^"]|\\")*)"\s*;\s*@(\w+);.*' # noqa 26 | 27 | match = re.search(pattern, line) 28 | match2 = re.search(pattern2, line) 29 | if match2: 30 | description = match2.group(1).strip().replace('\\"', '"') 31 | replace_from = match2.group(3).strip().lower() 32 | replace_to = match2.group(4).strip().lower() 33 | category = match2.group(2).strip() 34 | 35 | if category not in categories_dict: 36 | return None, None, None 37 | 38 | return description, category, (replace_from, replace_to) 39 | elif match: 40 | description = match.group(1).strip().replace('\\"', '"') 41 | category = match.group(2).strip() 42 | 43 | if category not in categories_dict: 44 | return None, None, None 45 | 46 | return description, category, None 47 | else: 48 | return None, None, None 49 | 50 | 51 | def extract_binding(line: str): 52 | line = line.replace(" =", "=") 53 | if not line.startswith("bind="): 54 | return 55 | line = line.lstrip("bind=").strip().lower().replace("super_l", "") 56 | _bindings = line.split(",") 57 | bindings = ' '.join([_bindings[0].strip(), _bindings[1].strip()]) 58 | return bindings 59 | 60 | 61 | def replace_variable(match: re.Match[str]): 62 | var_name = match.group(1) 63 | return variables_dict.get(var_name, match.group(0)) 64 | 65 | 66 | def load_categories(content: str): 67 | matches = re.findall(category_pattern, content) 68 | 69 | for key, value in matches: 70 | categories_dict[key] = value 71 | bindings[value] = {} 72 | return content 73 | 74 | 75 | def load_sources(file: str): 76 | with open(file) as f: 77 | content = f.read() 78 | for line in content.split("\n"): 79 | line = line.replace(" = ", "=") 80 | if not line.startswith("source="): 81 | continue 82 | file = os.path.expanduser(line.replace("source=", "")) 83 | if file not in files: 84 | files.append(file) 85 | 86 | 87 | def load_variables(content: str): 88 | matches = re.findall(variable_pattern, content) 89 | 90 | for var_name, var_value in matches: 91 | variables_dict[var_name] = var_value 92 | 93 | content_lines = content.split("\n") 94 | content_lines = [ 95 | line for line in content_lines if not line.startswith("$") 96 | ] 97 | content = "\n".join(content_lines) 98 | return content 99 | 100 | 101 | def load_file(file: str): 102 | global text 103 | with open(file) as f: 104 | content = f.read() 105 | 106 | content = load_categories(content) 107 | content = load_variables(content) 108 | 109 | # remove comments 110 | content = re.sub(r'^#.*$\n', '', content, flags=re.MULTILINE) 111 | text += f"\n{content}" 112 | 113 | 114 | def load(): 115 | global text, bindings 116 | text = re.sub(r"\$(\w+)", replace_variable, text) 117 | for line in text.split('\n'): 118 | if not line.replace(" ", "").startswith("bind="): 119 | continue 120 | 121 | description, category, replace = extract_category_and_description(line) 122 | if category is None or description is None: 123 | continue 124 | 125 | binding = extract_binding(line) 126 | if binding is None: 127 | continue 128 | 129 | category_name = categories_dict[category] 130 | if category_name not in bindings: 131 | bindings[category_name] = {} 132 | 133 | if replace is not None: 134 | binding = binding.replace(*replace) 135 | 136 | bindings[category_name][binding.strip()] = description.strip() 137 | 138 | 139 | while True: 140 | old_list = files 141 | for file in files: 142 | load_sources(file) 143 | if old_list == files: 144 | break 145 | 146 | for file in files: 147 | load_file(file) 148 | load() 149 | print(json.dumps(bindings, indent=4)) 150 | -------------------------------------------------------------------------------- /ags/scripts/network.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # by koeqaife ;) 3 | 4 | get_uuid() { 5 | local SSID="$1" 6 | local UUID=$(nmcli connection show | grep "$SSID" | grep wifi | awk '{print $2}') 7 | if [ -z "$UUID" ]; then 8 | echo undefined 9 | exit 1 10 | else 11 | echo $UUID 12 | fi 13 | } 14 | 15 | edit_by_ssid() { 16 | local SSID="$1" 17 | local UUID=$(get_uuid $SSID) 18 | nm-connection-editor -e $UUID 19 | } 20 | 21 | saved_networks() { 22 | nmcli connection show | grep "$SSID" | grep wifi | awk '{print $1}' 23 | } 24 | 25 | if [[ "$1" == "--get" ]]; then 26 | get_uuid $2 27 | elif [[ "$1" == "--edit" ]]; then 28 | edit_by_ssid $2 29 | elif [[ "$1" == "--saved" ]]; then 30 | saved_networks 31 | fi 32 | -------------------------------------------------------------------------------- /ags/scripts/night-light.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # by koeqaife ;) 3 | 4 | wl_gammarelay() { 5 | if ! busctl --user list | grep rs.wl.gammarelay; then 6 | systemctl --user restart wl-gammarelay.service 7 | fi 8 | } 9 | wl_gammarelay >/dev/null 10 | 11 | get_current_temperature() { 12 | busctl --user get-property rs.wl-gammarelay / rs.wl.gammarelay Temperature | awk '{print $2}' 13 | } 14 | 15 | set_temperature() { 16 | busctl --user set-property rs.wl-gammarelay / rs.wl.gammarelay Temperature q $1 17 | } 18 | 19 | toggle() { 20 | LOCKFILE=/tmp/smooth_toggle_night_light.lock 21 | ENABLE=/tmp/enable 22 | 23 | if [ -e "$LOCKFILE" ] && kill -0 "$(cat $LOCKFILE)"; then 24 | if [ -e "$ENABLE" ]; then 25 | if [[ $(cat $ENABLE) == "1" ]]; then 26 | echo 0 >$ENABLE 27 | echo "disabled" 28 | else 29 | echo 1 >$ENABLE 30 | echo "enabled" 31 | fi 32 | fi 33 | exit 0 34 | fi 35 | 36 | trap "rm -f $LOCKFILE; exit" INT TERM EXIT 37 | echo $$ >"$LOCKFILE" 38 | 39 | current_temp=$(get_current_temperature) 40 | 41 | day_temp=6500 42 | night_temp=3500 43 | step=50 44 | delay=0.005 45 | 46 | smooth_change() { 47 | local start_temp=$1 48 | local end_temp=$2 49 | local increment 50 | 51 | if [ "$start_temp" -lt "$end_temp" ]; then 52 | increment=$step 53 | else 54 | increment=-$step 55 | fi 56 | 57 | temp=$start_temp 58 | while [ "$temp" -ne "$end_temp" ]; do 59 | local mode=$(cat $ENABLE) 60 | 61 | if [ "$mode" -eq 0 ]; then 62 | end_temp=$day_temp 63 | else 64 | end_temp=$night_temp 65 | fi 66 | 67 | if [ "$temp" -eq "$end_temp" ]; then 68 | sleep 1 69 | continue 70 | fi 71 | 72 | set_temperature $temp 73 | 74 | if [ "$increment" -gt 0 ] && [ "$temp" -gt "$end_temp" ]; then 75 | temp=$end_temp 76 | elif [ "$increment" -lt 0 ] && [ "$temp" -lt "$end_temp" ]; then 77 | temp=$end_temp 78 | else 79 | temp=$((temp + increment)) 80 | fi 81 | 82 | sleep $delay 83 | 84 | local new_mode=$(cat $ENABLE) 85 | 86 | if [ "$new_mode" -ne "$mode" ]; then 87 | if [ "$new_mode" -eq 0 ]; then 88 | end_temp=$day_temp 89 | else 90 | end_temp=$night_temp 91 | fi 92 | 93 | if [ "$temp" -lt "$end_temp" ]; then 94 | increment=$step 95 | else 96 | increment=-$step 97 | fi 98 | 99 | temp=$(get_current_temperature) 100 | fi 101 | done 102 | if [ -e "$ENABLE" ]; then 103 | if [[ $(cat $ENABLE) == "1" ]]; then 104 | echo "enabled" 105 | else 106 | echo "disabled" 107 | fi 108 | fi 109 | set_temperature $end_temp 110 | } 111 | 112 | if [ "$current_temp" -lt "$(((day_temp + night_temp) / 2))" ]; then 113 | echo 0 >$ENABLE 114 | smooth_change $current_temp $day_temp 115 | else 116 | echo 1 >$ENABLE 117 | smooth_change $current_temp $night_temp 118 | fi 119 | 120 | rm -f "$LOCKFILE" 121 | trap - INT TERM EXIT 122 | } 123 | 124 | get() { 125 | day_temp=6500 126 | night_temp=5000 127 | 128 | current_temp=$(get_current_temperature) 129 | 130 | if [ "$current_temp" -lt "$(((day_temp + night_temp) / 2))" ]; then 131 | echo "enabled" 132 | else 133 | echo "disabled" 134 | fi 135 | } 136 | 137 | if [[ "$1" == "--toggle" ]]; then 138 | toggle 139 | elif [[ "$1" == "--get" ]]; then 140 | get 141 | fi 142 | -------------------------------------------------------------------------------- /ags/scripts/requests.py: -------------------------------------------------------------------------------- 1 | # by koeqaife ;) 2 | 3 | import argparse 4 | import json 5 | import os 6 | import sys 7 | 8 | current_path = os.path.dirname(os.path.abspath(__file__)) 9 | sys.path.pop(0) 10 | 11 | import requests # noqa 12 | 13 | parser = argparse.ArgumentParser() 14 | group = parser.add_mutually_exclusive_group(required=True) 15 | group.add_argument("--post", type=str) 16 | group.add_argument("--get", type=str) 17 | group.add_argument("--put", type=str) 18 | group.add_argument("--delete", type=str) 19 | parser.add_argument("--json", type=str) 20 | parser.add_argument("--headers", type=str) 21 | parser.add_argument("--verify", type=bool, default=True) 22 | 23 | args = parser.parse_args() 24 | 25 | _verify = args.verify 26 | _url: str = args.post or args.get or args.put or args.delete 27 | _post = args.post is not None 28 | _get = args.get is not None 29 | _put = args.put is not None 30 | _delete = args.delete is not None 31 | _json: dict | None = ( 32 | None if args.json is None 33 | else json.loads(args.json) 34 | ) 35 | _headers: dict | None = ( 36 | None if args.headers is None 37 | else json.loads(args.headers) 38 | ) 39 | 40 | 41 | def main(): 42 | _args = [_url] 43 | _kwargs = { 44 | "json": _json, 45 | "headers": _headers, 46 | "verify": _verify, 47 | } 48 | if _post: 49 | response = requests.post(*_args, **_kwargs) 50 | elif _get: 51 | response = requests.get(*_args, **_kwargs) 52 | elif _put: 53 | response = requests.put(*_args, **_kwargs) 54 | elif _delete: 55 | response = requests.delete(*_args, **_kwargs) 56 | return response 57 | 58 | 59 | if __name__ == "__main__": 60 | r = main() 61 | _type = "text" 62 | _json = None 63 | text = r.text 64 | try: 65 | _json = json.loads(text) 66 | _type = "json" 67 | except Exception: 68 | ... 69 | 70 | print(json.dumps({ 71 | "type": _type, 72 | "data": _json or text, 73 | "code": r.status_code 74 | })) 75 | -------------------------------------------------------------------------------- /ags/scripts/system.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # by koeqaife ;) 3 | 4 | get_cpu_usage() { 5 | top -bn1 | grep "Cpu(s)" | 6 | awk '{printf "%.0f\n", $2 + $4 + $6}' 7 | } 8 | 9 | get_ram_usage() { 10 | free -m | awk 'NR==2{printf "%.0f\n", $3*100/$2 }' 11 | } 12 | 13 | get_swap_usage() { 14 | free -m | awk 'NR==3 { if ($2 == 0) { print 0 } else { printf "%.0f\n", $3*100/$2 } }' 15 | } 16 | 17 | get_cpu_temp() { 18 | sensors | grep -i 'Tctl' | awk '{sum+=$2; count+=1} END {if (count > 0) print sum/count; else print "Undefined" return 1}' || sensors | grep -i 'core ' | awk '{sum+=$3; count+=1} END {if (count > 0) print sum/count; else print "Undefined"}' 19 | } 20 | 21 | get_cpu_name() { 22 | lscpu | awk -F ': +' '/Model name/ {sub(" @ .*", "", $2); print $2}' 23 | } 24 | 25 | get_ram() { 26 | echo "$(free -m | grep Mem | awk '{print $2}') MiB" 27 | } 28 | 29 | get_kernel() { 30 | uname -r 31 | } 32 | 33 | get_gpu() { 34 | lshw -C display | grep "product" | awk -F ': ' '{print $2}' | awk '{printf "%s%s", separator, $0; separator=", "} END{print ""}' 35 | } 36 | 37 | get_hostname() { 38 | cat /etc/hostname 39 | } 40 | 41 | get_os() { 42 | hostnamectl | grep "Operating System" | awk '{for (i=3; i<=NF; i++) printf $i " "; print ""}' 43 | } 44 | 45 | get_uptime() { 46 | uptime -p | sed -e 's/up //' \ 47 | -e 's/ hours\{0,1\}/h/g' \ 48 | -e 's/ minutes\{0,1\}/min/g' \ 49 | -e 's/ days\{0,1\}/d/g' \ 50 | -e 's/ seconds\{0,1\}/sec/g' \ 51 | -e 's/,/, /g' \ 52 | -e 's/ */ /g' \ 53 | -e 's/^ //g' \ 54 | -e 's/ $//g' 55 | } 56 | 57 | get_usage() { 58 | cat < str: 40 | string = re.sub(r'(? dict: 46 | _dict = { 47 | to_snake_case(key): value 48 | for key, value in dict.items() 49 | } 50 | 51 | if "name" not in _dict and "path" in _dict: 52 | _dict["name"] = os.path.basename(_dict["path"]) 53 | 54 | if "path" in _dict: 55 | _dict["path"] = os.path.abspath(_dict["path"]) 56 | 57 | for key, value in default_dict.items(): 58 | _dict.setdefault(key, value) 59 | 60 | for key in is_bool: 61 | _dict[key] = str(_dict.get(key)).lower() == "true" 62 | 63 | return _dict 64 | 65 | 66 | def extract_comment_values(file_path: str) -> Dict[str, str]: 67 | with open(file_path, 'r', encoding='utf-8') as file: 68 | lines = list(islice(file, 25)) 69 | content = ''.join(lines) 70 | 71 | comment_match = re.search(r'/\*\*(.*?)\*/', content, re.DOTALL) 72 | if not comment_match: 73 | return {"path": file_path} 74 | 75 | comment = comment_match.group(1).strip() 76 | 77 | pattern = re.compile(r'^\s*\*\s*(\w+):\s*(.+)$', re.MULTILINE) 78 | _dict = dict(pattern.findall(comment)) 79 | _dict["path"] = file_path 80 | return _dict 81 | 82 | 83 | def check_all_files(dir: str): 84 | files = [os.path.join(dir, f) for f in os.listdir(dir) 85 | if os.path.isfile(os.path.join(dir, f)) 86 | and f.endswith(".css")] 87 | info = [] 88 | for x in files: 89 | info.append(process_dict(extract_comment_values(x))) 90 | 91 | return info 92 | 93 | 94 | if __name__ == "__main__": 95 | result = None 96 | if folder: 97 | result = check_all_files(folder) 98 | elif file: 99 | result = process_dict(extract_comment_values(file)) 100 | elif current: 101 | print(CONFIG_VERSION) 102 | exit(0) 103 | 104 | print(json.dumps(result)) 105 | -------------------------------------------------------------------------------- /ags/scripts/wayland-idle-inhibitor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | from dataclasses import dataclass 5 | from signal import SIGINT, SIGTERM, signal 6 | from threading import Event 7 | import setproctitle 8 | 9 | from pywayland.client.display import Display # type: ignore 10 | from pywayland.protocol.idle_inhibit_unstable_v1.zwp_idle_inhibit_manager_v1 import ( # type: ignore 11 | ZwpIdleInhibitManagerV1, 12 | ) 13 | from pywayland.protocol.wayland.wl_compositor import WlCompositor # type: ignore 14 | from pywayland.protocol.wayland.wl_registry import WlRegistryProxy # type: ignore 15 | from pywayland.protocol.wayland.wl_surface import WlSurface # type: ignore 16 | 17 | 18 | @dataclass 19 | class GlobalRegistry: 20 | surface: WlSurface | None = None 21 | inhibit_manager: ZwpIdleInhibitManagerV1 | None = None 22 | 23 | 24 | def handle_registry_global( 25 | wl_registry: WlRegistryProxy, id_num: int, iface_name: str, version: int 26 | ) -> None: 27 | global_registry: GlobalRegistry = wl_registry.user_data or GlobalRegistry() 28 | 29 | if iface_name == "wl_compositor": 30 | compositor = wl_registry.bind(id_num, WlCompositor, version) 31 | global_registry.surface = compositor.create_surface() # type: ignore 32 | elif iface_name == "zwp_idle_inhibit_manager_v1": 33 | global_registry.inhibit_manager = wl_registry.bind( 34 | id_num, ZwpIdleInhibitManagerV1, version 35 | ) 36 | 37 | 38 | def main() -> None: 39 | done = Event() 40 | signal(SIGINT, lambda _, __: done.set()) 41 | signal(SIGTERM, lambda _, __: done.set()) 42 | 43 | global_registry = GlobalRegistry() 44 | 45 | display = Display() 46 | display.connect() 47 | 48 | registry = display.get_registry() # type: ignore 49 | registry.user_data = global_registry 50 | registry.dispatcher["global"] = handle_registry_global 51 | 52 | def shutdown() -> None: 53 | display.dispatch() 54 | display.roundtrip() 55 | display.disconnect() 56 | 57 | display.dispatch() 58 | display.roundtrip() 59 | 60 | if global_registry.surface is None or global_registry.inhibit_manager is None: 61 | print("Wayland seems not to support idle_inhibit_unstable_v1 protocol.") 62 | shutdown() 63 | sys.exit(1) 64 | 65 | inhibitor = global_registry.inhibit_manager.create_inhibitor( # type: ignore 66 | global_registry.surface 67 | ) 68 | 69 | display.dispatch() 70 | display.roundtrip() 71 | 72 | print("Inhibiting idle...") 73 | done.wait() 74 | print("Shutting down...") 75 | 76 | inhibitor.destroy() 77 | 78 | shutdown() 79 | 80 | 81 | if __name__ == "__main__": 82 | setproctitle.setproctitle("wayland-idle-inhibitor.py") 83 | main() 84 | -------------------------------------------------------------------------------- /ags/scripts/weather.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # by koeqaife ;) 3 | 4 | KEY=$2 5 | ID=$3 6 | UNIT="metric" 7 | 8 | cache_dir=$HOME/.cache/ags/weather 9 | cache_file="$cache_dir/weather_cache.json" 10 | cache_max_age=900 11 | mkdir -p $cache_dir 12 | 13 | get_weather_data() { 14 | current_time=$(date +%s) 15 | cache_key=$(echo "$KEY $ID $UNIT" | md5sum | awk '{ print $1 }') 16 | 17 | if [[ -f "$cache_file" ]]; then 18 | cached_key=$(cat "$cache_file" | jq -r '.cache_key') 19 | last_modified=$(stat -c %Y "$cache_file") 20 | 21 | if [[ "$cached_key" == "$cache_key" && $((current_time - last_modified)) < $cache_max_age ]]; then 22 | cat "$cache_file" | jq -r '.data' 23 | return 24 | fi 25 | fi 26 | 27 | weather=$(curl -sf "http://api.openweathermap.org/data/2.5/weather?APPID=$KEY&id=$ID&units=$UNIT") 28 | echo "{ \"cache_key\": \"$cache_key\", \"data\": $weather }" >"$cache_file" 29 | cat "$cache_file" | jq -r '.data' 30 | } 31 | 32 | if [[ "$1" == "weather" ]]; then 33 | get_weather_data 34 | fi 35 | -------------------------------------------------------------------------------- /ags/services/backlight.ts: -------------------------------------------------------------------------------- 1 | class BrightnessService extends Service { 2 | static { 3 | Service.register( 4 | this, 5 | { 6 | "screen-changed": ["float"] 7 | }, 8 | { 9 | "screen-value": ["float", "rw"] 10 | } 11 | ); 12 | } 13 | 14 | #interface = Utils.exec("sh -c 'ls -w1 /sys/class/backlight | head -1'"); 15 | 16 | #screenValue = 0; 17 | #max = Number(Utils.exec("brightnessctl max")); 18 | #brightness_file = `/sys/class/backlight/${this.#interface}/brightness`; 19 | 20 | get screen_value() { 21 | return this.#screenValue; 22 | } 23 | 24 | set screen_value(percent) { 25 | if (percent < 0) percent = 0; 26 | 27 | if (percent > 1) percent = 1; 28 | 29 | Utils.execAsync(`brightnessctl set ${percent * 100}% -q`); 30 | } 31 | 32 | constructor() { 33 | super(); 34 | 35 | Utils.monitorFile(this.#brightness_file, () => this.#onChange()); 36 | 37 | this.#onChange(); 38 | } 39 | 40 | async #onChange() { 41 | try { 42 | this.#screenValue = Number(await Utils.readFileAsync(this.#brightness_file)) / this.#max; 43 | 44 | } catch (e) { 45 | this.#screenValue = 0; 46 | print("Backlight service error:", e); 47 | } 48 | 49 | this.emit("changed"); 50 | this.notify("screen-value"); 51 | 52 | this.emit("screen-changed", this.#screenValue); 53 | } 54 | } 55 | 56 | const service = new BrightnessService(); 57 | 58 | export default service; 59 | -------------------------------------------------------------------------------- /ags/services/battery_warning.ts: -------------------------------------------------------------------------------- 1 | // by koeqaife ;) 2 | 3 | const battery = await Service.import("battery"); 4 | 5 | const battery_messages = { 6 | warnLevels: [15, 5, 1], 7 | warnTitles: ["Low battery", "Very low battery", "Critical Battery"], 8 | warnMessages: ["Plug in the charger", "Please plug in the charger", "Your PC is about to shut down"] 9 | }; 10 | 11 | let last_warning = 101; 12 | 13 | async function notifyUser(index) { 14 | Utils.execAsync([ 15 | "bash", 16 | "-c", 17 | `notify-send "${battery_messages.warnTitles[index]}" "${battery_messages.warnMessages[index]}" -u critical &` 18 | ]).catch(print); 19 | } 20 | 21 | async function battery_notification() { 22 | const percent = battery.percent; 23 | const charging = battery.charging; 24 | if (percent == 0) return; 25 | if (charging) { 26 | last_warning = 101; 27 | return; 28 | } 29 | 30 | const warningLevel = battery_messages.warnLevels 31 | .slice() 32 | .reverse() 33 | .find((level) => percent <= level && last_warning > level); 34 | 35 | if (warningLevel !== undefined) { 36 | const index = battery_messages.warnLevels.indexOf(warningLevel); 37 | last_warning = percent; 38 | await notifyUser(index); 39 | } 40 | } 41 | 42 | export async function start_battery_warning_service() { 43 | Utils.timeout(1, () => { 44 | if (!battery.available) return; 45 | battery_notification().catch(print); 46 | battery.connect("changed", () => battery_notification().catch(print)); 47 | }); 48 | } 49 | -------------------------------------------------------------------------------- /ags/services/chatroom.d.ts: -------------------------------------------------------------------------------- 1 | // by koeqaife ;) 2 | 3 | export type Message = { 4 | success: boolean; 5 | message?: string; 6 | rate_limit?: true; 7 | }; 8 | 9 | export type ChatMessage = { 10 | created_at: string; 11 | id: number; 12 | message: string; 13 | nickname: string; 14 | type: number; 15 | }; 16 | 17 | export type LastMessages = Message & { 18 | messages?: ChatMessage[]; 19 | }; 20 | 21 | export type CreateRoom = Message & { 22 | key: string; 23 | id: string; 24 | }; 25 | 26 | export type GetRoom = Message & { 27 | key: string | null; 28 | id: string | null; 29 | }; 30 | 31 | export type CreateUser = Message & { 32 | wait_for_accept: boolean 33 | }; 34 | export type CheckUser = Message; 35 | export type SendMessage = Message & ChatMessage; 36 | export type Online = Message; 37 | export type OnlineMember = { 38 | nickname: string; 39 | timestamp: number; 40 | }; 41 | export type OnlineList = Message & { 42 | hidden?: boolean; 43 | online?: OnlineMember[]; 44 | online_count?: number; 45 | }; 46 | 47 | export type GetInfo = Message & { 48 | max_rate_limit: number; 49 | version: number; 50 | } & { 51 | [key: string]: any; 52 | }; 53 | 54 | export type RequestParams = { 55 | url: string; 56 | method?: "get" | "post" | "put" | "delete"; 57 | json?: string; 58 | headers?: string; 59 | }; 60 | 61 | export type RequestReturn = { 62 | code: number; 63 | data: T; 64 | type: "text" | "json"; 65 | }; 66 | -------------------------------------------------------------------------------- /ags/services/configuration.ts: -------------------------------------------------------------------------------- 1 | // by koeqaife ;) 2 | 3 | const { GLib } = imports.gi; 4 | 5 | type ConfigType = { 6 | always_show_battery: boolean; 7 | show_taskbar: boolean; 8 | show_battery_percent: boolean; 9 | hide_empty_workspaces: boolean; 10 | weather: string; 11 | weather_location_id: string; 12 | current_theme: string | null; 13 | hide_applauncher_button: boolean; 14 | hide_media_button: boolean; 15 | workspaces_to_the_left: boolean; 16 | show_beta: boolean; 17 | hide_cliphist_button: boolean; 18 | messages_notifications_filter: string[]; 19 | }; 20 | 21 | export const default_config: ConfigType = { 22 | always_show_battery: false, 23 | show_taskbar: true, 24 | show_battery_percent: true, 25 | hide_empty_workspaces: false, 26 | weather: "", 27 | weather_location_id: "", 28 | current_theme: null, 29 | hide_applauncher_button: false, 30 | hide_media_button: false, 31 | workspaces_to_the_left: false, 32 | show_beta: false, 33 | hide_cliphist_button: false, 34 | messages_notifications_filter: [] 35 | }; 36 | 37 | Utils.exec(["mkdir", "-p", `${GLib.get_home_dir()}/.config/ags_config/`]); 38 | const config_file = `${GLib.get_home_dir()}/.config/ags_config/conf.json`; 39 | if (Utils.readFile(config_file).length < 2) { 40 | Utils.writeFileSync(JSON.stringify(default_config), config_file); 41 | } 42 | 43 | class ConfigService extends Service { 44 | static { 45 | Service.register( 46 | this, 47 | { 48 | "config-changed": ["jsobject"] 49 | }, 50 | { 51 | config: ["jsobject", "rw"] 52 | } 53 | ); 54 | } 55 | 56 | #config = default_config; 57 | #config_file = config_file; 58 | 59 | get config() { 60 | return this.#config; 61 | } 62 | 63 | set config(conf) { 64 | Utils.writeFile(JSON.stringify(conf), this.#config_file).catch(print); 65 | } 66 | 67 | set_value(key: keyof typeof default_config, value: string) { 68 | this.config = { ...this.config, [key]: value }; 69 | } 70 | 71 | constructor() { 72 | super(); 73 | 74 | const config_file = this.#config_file; 75 | Utils.monitorFile(config_file, () => this.#onChange()); 76 | 77 | this.#onChange(); 78 | } 79 | 80 | #onChange() { 81 | Utils.readFileAsync(this.#config_file).then((out) => { 82 | this.#config = { ...default_config, ...JSON.parse(out) }; 83 | this.emit("changed"); 84 | this.notify("config"); 85 | 86 | this.emit("config-changed", this.#config); 87 | }); 88 | } 89 | } 90 | 91 | const service = new ConfigService(); 92 | 93 | export default service; 94 | -------------------------------------------------------------------------------- /ags/themes/example.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Name: Example 3 | * Author: koeqaife 4 | * Version: 1.0.0 5 | * ConfigVersion: 2 6 | * LoadDefaultCss: true 7 | * Hide: false 8 | * Description: Theme Example File 9 | */ 10 | 11 | /* ConfigVersion is needed so that if after changes, could warn that the theme may not be compatible. */ 12 | /* To check the current ConfigVersion run the command “python ~/dotfiles/ags/scripts/themes.py -c” */ 13 | /* You can specify universal in ConfigVersion, but it is not recommended to do so */ 14 | -------------------------------------------------------------------------------- /ags/themes/old_workspaces.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Name: Old Workspaces 3 | * Author: koeqaife 4 | * Version: 1.0.0 5 | * ConfigVersion: universal 6 | * LoadDefaultCss: true 7 | * Hide: false 8 | * Description: Includes old workspaces style (Enable "Hide empty workspaces") 9 | */ 10 | 11 | .workspaces button { 12 | padding: 0px 5px; 13 | margin: 4px 3px 4px 3px; 14 | border-radius: 16px; 15 | border: 0px; 16 | } 17 | 18 | .workspaces button:last-child { 19 | margin: 4px 0px 4px 3px; 20 | } 21 | 22 | .workspaces button:first-child { 23 | margin: 4px 3px 4px 0px; 24 | } 25 | 26 | .workspaces button.active { 27 | background: @secondaryContainer; 28 | min-width: 40px; 29 | } 30 | -------------------------------------------------------------------------------- /ags/types: -------------------------------------------------------------------------------- 1 | /usr/share/com.github.Aylur.ags/types -------------------------------------------------------------------------------- /ags/variables.ts: -------------------------------------------------------------------------------- 1 | // by koeqaife ;) 2 | 3 | const GLib = imports.gi.GLib; 4 | 5 | export type WeatherJson = { 6 | coord: { 7 | lon: number; 8 | lat: number; 9 | }; 10 | weather: [ 11 | { 12 | id: number; 13 | main: string; 14 | description: string; 15 | icon: string; 16 | } 17 | ]; 18 | base: string; 19 | main: { 20 | temp: number; 21 | feels_like: number; 22 | temp_min: number; 23 | temp_max: number; 24 | pressure: number; 25 | humidity: number; 26 | sea_level: number; 27 | grnd_level: number; 28 | }; 29 | visibility: number; 30 | wind: { 31 | speed: number; 32 | deg: number; 33 | gust: number; 34 | }; 35 | clouds: { 36 | all: number; 37 | }; 38 | rain?: { 39 | "1h"?: string; 40 | "3h"?: string; 41 | }; 42 | snow?: { 43 | "1h"?: string; 44 | "3h"?: string; 45 | }; 46 | dt: number; 47 | sys: { 48 | type: number; 49 | id: number; 50 | country: string; 51 | sunrise: number; 52 | sunset: number; 53 | }; 54 | timezone: number; 55 | id: number; 56 | name: string; 57 | cod: number; 58 | no_data?: boolean; 59 | }; 60 | 61 | export type ThemeJson = { 62 | name: string; 63 | author: string; 64 | version: string; 65 | config_version: string; 66 | load_default_css: boolean; 67 | hide: boolean; 68 | description: string; 69 | path?: string; 70 | }; 71 | 72 | export const theme = Variable("dark"); 73 | export const main_color = Variable("#000000"); 74 | export const current_wallpaper = Variable(`${GLib.get_home_dir()}/dotfiles/wallpapers/default.png`); 75 | 76 | export const custom_theme = Variable(null); 77 | 78 | export const idle_inhibitor = Variable(false); 79 | export const cur_uptime = Variable("error"); 80 | Utils.interval(60000, () => { 81 | Utils.execAsync(`${App.configDir}/scripts/system.sh --uptime`) 82 | .then((out) => cur_uptime.setValue(out)) 83 | .catch(print); 84 | }); 85 | export const night_light = Variable(false); 86 | Utils.execAsync(`${App.configDir}/scripts/night-light.sh --get`) 87 | .then((out) => { 88 | if (out.trim() == "enabled") night_light.setValue(true); 89 | else if (out.trim() == "disabled") night_light.setValue(false); 90 | }) 91 | .catch(print); 92 | export const theme_settings = { 93 | color: Variable("none"), 94 | scheme: Variable("tonalSpot") 95 | }; 96 | 97 | const system_info = JSON.parse(await Utils.execAsync(`${App.configDir}/scripts/system.sh --json`)); 98 | export const cpu_name = system_info["cpu_name"] 99 | export const gpu_name = system_info["gpu_name"] 100 | export const cpu_cores = system_info["cpu_cores"]; 101 | export const amount_of_ram = system_info["ram"]; 102 | export const kernel_name = system_info["kernel"]; 103 | export const hostname = system_info["hostname"]; 104 | export const current_os = system_info["os"]; 105 | 106 | export const settings_file = `${GLib.get_home_dir()}/dotfiles/.settings/settings.json`; 107 | export const wallpaper_cache_file = `${GLib.get_home_dir()}/.cache/current_wallpaper`; 108 | 109 | function read_settings() { 110 | Utils.readFileAsync(settings_file) 111 | .then((out) => { 112 | const settings = JSON.parse(out); 113 | theme_settings.color.setValue(settings["custom-color"].trim()); 114 | theme_settings.scheme.setValue(settings["generation-scheme"].trim()); 115 | theme.setValue(settings["color-scheme"].trim()); 116 | }) 117 | .catch(print); 118 | 119 | Utils.readFileAsync(wallpaper_cache_file) 120 | .then((out) => { 121 | current_wallpaper.setValue(out.trim()); 122 | }) 123 | .catch((err) => { 124 | Utils.writeFileSync(current_wallpaper.value, wallpaper_cache_file); 125 | }); 126 | } 127 | read_settings(); 128 | 129 | Utils.monitorFile(settings_file, read_settings); 130 | 131 | Utils.monitorFile(wallpaper_cache_file, () => { 132 | Utils.readFileAsync(wallpaper_cache_file) 133 | .then((out) => { 134 | current_wallpaper.setValue(out); 135 | }) 136 | .catch(print); 137 | }); 138 | -------------------------------------------------------------------------------- /alacritty/alacritty.toml: -------------------------------------------------------------------------------- 1 | [general] 2 | import = [ 3 | "~/.cache/material/alacritty.toml" 4 | ] 5 | 6 | -------------------------------------------------------------------------------- /electron-flags.conf: -------------------------------------------------------------------------------- 1 | --enable-features=UseOzonePlatform --ozone-platform=wayland -------------------------------------------------------------------------------- /hypr/conf/animation.conf: -------------------------------------------------------------------------------- 1 | 2 | animations { 3 | enabled = true 4 | # Animation curves 5 | 6 | bezier = linear, 0, 0, 1, 1 7 | bezier = md3_standard, 0.2, 0, 0, 1 8 | bezier = md3_decel, 0.05, 0.7, 0.1, 1 9 | bezier = md3_accel, 0.3, 0, 0.8, 0.15 10 | bezier = overshot, 0.05, 0.9, 0.1, 1.1 11 | bezier = crazyshot, 0.1, 1.5, 0.76, 0.92 12 | bezier = hyprnostretch, 0.05, 0.9, 0.1, 1.0 13 | bezier = menu_decel, 0.1, 1, 0, 1 14 | bezier = menu_accel, 0.38, 0.04, 1, 0.07 15 | bezier = easeInOutCirc, 0.85, 0, 0.15, 1 16 | bezier = easeOutCirc, 0, 0.55, 0.45, 1 17 | bezier = easeOutExpo, 0.16, 1, 0.3, 1 18 | bezier = softAcDecel, 0.26, 0.26, 0.15, 1 19 | bezier = md2, 0.4, 0, 0.2, 1 # use with .2s duration 20 | # Animation configs 21 | animation = windows, 1, 3, md3_decel, popin 60% 22 | animation = windowsIn, 1, 3, md3_decel, popin 60% 23 | animation = windowsOut, 1, 3, md3_accel, popin 60% 24 | animation = border, 1, 10, default 25 | animation = fade, 1, 3, md3_decel 26 | animation = layers, 1, 2, md3_decel, slide 27 | animation = layersIn, 1, 3, menu_decel, slide 28 | animation = layersOut, 1, 1.6, menu_accel, slide 29 | animation = fadeLayersIn, 1, 2, menu_decel 30 | animation = fadeLayersOut, 1, 4.5, menu_accel 31 | animation = workspaces, 1, 7, menu_decel, slide 32 | # animation = workspaces, 1, 2.5, softAcDecel, slide 33 | # animation = workspaces, 1, 7, menu_decel, slidefade 15% 34 | # animation = specialWorkspace, 1, 3, md3_decel, slidefadevert 15% 35 | animation = specialWorkspace, 1, 3, md3_decel, slidevert 36 | 37 | } -------------------------------------------------------------------------------- /hypr/conf/apps.conf: -------------------------------------------------------------------------------- 1 | env = BROWSER, brave #! -@browser 2 | env = TERMINAL, alacritty #! -@terminal 3 | env = EDITOR, code #! -@editor 4 | env = FILEMANAGER, nautilus #! -@filemanager 5 | env = XDG_UTILS_TERMINAL, alacritty #! -@terminal 6 | env = XDG_UTILS_BROWSER, brave #! -@browser 7 | env = XDG_UTILS_FILEMANAGER, nautilus #! -@filemanager 8 | -------------------------------------------------------------------------------- /hypr/conf/autostart.conf: -------------------------------------------------------------------------------- 1 | # Setup XDG 2 | exec-once = ~/dotfiles/hypr/scripts/xdg.sh 3 | 4 | # Start Polkit 5 | exec-once = /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 6 | 7 | # Using hypridle to start hyprlock 8 | exec-once = hypridle 9 | 10 | # START APPLETS 11 | exec-once = nm-applet --indicator 12 | exec-once = blueman-applet 13 | 14 | # Load cliphist history 15 | exec-once = wl-paste --watch cliphist store 16 | 17 | # Initialize Wallpaper Engine 18 | exec-once = ~/dotfiles/hypr/scripts/init-wallpaper-engine.sh 19 | 20 | # exec-once = easyeffects --gapplication-service 21 | 22 | # start AGS 23 | exec-once = agsv1 24 | 25 | # Udiskie 26 | exec-once = udiskie & 27 | 28 | # Update checker 29 | exec-once = ~/dotfiles/scripts/update_timer.sh 30 | -------------------------------------------------------------------------------- /hypr/conf/custom/cursor.conf: -------------------------------------------------------------------------------- 1 | exec-once = hyprctl setcursor Bibata-Modern-Ice 24 2 | -------------------------------------------------------------------------------- /hypr/conf/custom/environment.conf: -------------------------------------------------------------------------------- 1 | # https://wiki.hyprland.org/Configuring/Environment-variables/ -------------------------------------------------------------------------------- /hypr/conf/custom/general.conf: -------------------------------------------------------------------------------- 1 | # Write custom hyprland settings here, such as keyboard layouts, monitor settings, etc. -------------------------------------------------------------------------------- /hypr/conf/custom/input.conf: -------------------------------------------------------------------------------- 1 | input { 2 | kb_layout = us 3 | kb_variant = 4 | kb_model = 5 | kb_options = grp:alt_shift_toggle 6 | numlock_by_default = true 7 | follow_mouse = 1 8 | touchpad { 9 | natural_scroll = false 10 | } 11 | sensitivity = 0 12 | } 13 | -------------------------------------------------------------------------------- /hypr/conf/custom/monitor.conf: -------------------------------------------------------------------------------- 1 | monitor=,preferred,auto,1 2 | -------------------------------------------------------------------------------- /hypr/conf/decoration.conf: -------------------------------------------------------------------------------- 1 | 2 | decoration { 3 | rounding = 20 4 | blur { 5 | enabled = false 6 | } 7 | active_opacity = 1 8 | inactive_opacity = 1 9 | fullscreen_opacity = 1 10 | shadow { 11 | enabled = true 12 | range = 10 13 | render_power = 3 14 | color = 0x66000000 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /hypr/conf/environment.conf: -------------------------------------------------------------------------------- 1 | env = XCURSOR_SIZE,24 2 | env = XDG_CURRENT_DESKTOP,Hyprland 3 | env = XDG_SESSION_TYPE,wayland 4 | env = XDG_SESSION_DESKTOP,Hyprland 5 | 6 | env = QT_QPA_PLATFORM,wayland;xcb 7 | env = QT_WAYLAND_DISABLE_WINDOWDECORATION,1 8 | env = QT_AUTO_SCREEN_SCALE_FACTOR,1 9 | env = QT_QPA_PLATFORMTHEME,qt5ct 10 | 11 | env = MOZ_ENABLE_WAYLAND,1 12 | env = GDK_SCALE,1 13 | env = SDL_VIDEODRIVER,wayland 14 | 15 | env = ELECTRON_ENABLE_WAYLAND, 1 16 | env = ELECTRON_OZONE_PLATFORM_HINT, wayland 17 | 18 | 19 | -------------------------------------------------------------------------------- /hypr/conf/keybinding.conf: -------------------------------------------------------------------------------- 1 | # SUPER KEY 2 | $mainMod = SUPER 3 | $scriptsDir = $HOME/dotfiles/hypr/scripts 4 | 5 | # Categories (for script) 6 | #! @actions: Actions 7 | #! @tools: Tools 8 | #! @apps: Applications 9 | #! @windows: Windows 10 | #! @workspaces: Workspaces 11 | #! @misc: Misc 12 | 13 | # Applications 14 | bind = $mainMod, RETURN, exec, $scriptsDir/apps.sh terminal #! @description: "Terminal"; @apps; 15 | bind = $mainMod, B, exec, $scriptsDir/apps.sh browser #! @description: "Browser"; @apps; 16 | bind = $mainMod, H, exec, pamac-manager #! @description: "Pamac-manager (if installed)"; @apps; 17 | bind = $mainMod SHIFT, M, exec, gnome-system-monitor #! @description: "Gnome system monitor"; @apps; 18 | bind = $mainMod, E, exec, $scriptsDir/apps.sh filemanager #! @description: "File Manager"; @apps; 19 | 20 | # Windows 21 | bind = $mainMod, Q, killactive #! @description: "Close window"; @windows; 22 | bind = $mainMod, F, fullscreen #! @description: "Open window in full screen mode"; @windows; 23 | bind = $mainMod, T, togglefloating #! @description: "Toggle floating"; @windows; 24 | bind = $mainMod SHIFT, T, exec, ~/dotfiles/hypr/scripts/toggleallfloat.sh #! @description: "Toggle all float windows"; @windows; 25 | bind = $mainMod, J, togglesplit #! @description: "Toggle split"; @windows; 26 | bind = $mainMod, left, movefocus, l 27 | bind = $mainMod, right, movefocus, r 28 | bind = $mainMod, up, movefocus, u 29 | bind = $mainMod, down, movefocus, d 30 | bindm = $mainMod, mouse:272, movewindow 31 | bindm = $mainMod, mouse:273, resizewindow 32 | bind = $mainMod SHIFT, right, resizeactive, 100 0 33 | bind = $mainMod SHIFT, left, resizeactive, -100 0 34 | bind = $mainMod SHIFT, up, resizeactive, 0 -100 35 | bind = $mainMod SHIFT, down, resizeactive, 0 100 36 | bind = $mainMod, G, togglegroup #! @description: "Toggle group"; @windows; 37 | 38 | # Actions 39 | bind = $mainMod SHIFT, A, exec, ~/dotfiles/hypr/scripts/toggle-animations.sh #! @description: "Toggle animations"; @actions; 40 | bind = $mainMod SHIFT, S, exec, ~/dotfiles/hypr/scripts/screenshot.sh #! @description: "Screenshot"; @actions; 41 | bind = $mainMod CTRL, S, exec, ~/dotfiles/hypr/scripts/screenshot.sh --window #! @description: "Window screenshot"; @actions; 42 | bind = $mainMod ALT, S, exec, ~/dotfiles/hypr/scripts/screenshot.sh --active #! @description: "Active screen screenshot"; @actions; 43 | bind = $mainMod SHIFT, W, exec, python -O ~/dotfiles/hypr/scripts/wallpaper.py -R -n #! @description: "Random wallpaper"; @actions; 44 | bind = $mainMod, L, exec, hyprlock --immediate #! @description: "Lock screen"; @actions; 45 | 46 | # Tools 47 | bind = $mainMod, Z, exec, agsv1 -r "toggleMediaWindow()" #! @description: "Players"; @tools; 48 | bind = $mainMod, period, exec, agsv1 -r 'OpenEmojiPicker()' #! @description: "Emoji Picker"; @tools; 49 | bind = $mainMod CTRL, C, exec, agsv1 -t cliphist 50 | bind = $mainMod, V, exec, agsv1 -t cliphist #! @description: "Clipboard history"; @tools; 51 | bind = $mainMod, SLASH, exec, agsv1 -t cheatsheet #! @description: "List of keybindings"; @tools; 52 | bind = $mainMod CTRL, W, exec, agsv1 -r "OpenSettings('wallpaper')" #! @description: "Change wallpaper"; @tools; 53 | bind = $mainMod, X, exec, agsv1 -r "toggleAppsWindow()" #! @description: "App Launcher"; @tools; 54 | bind = SUPER, SUPER_L, exec, agsv1 -t sidebar #! @description: "Sidebar"; @tools; 55 | 56 | # Workspaces 57 | bind = $mainMod, 1, workspace, 1 #! @description: "Switch workspace"; @workspaces; @replace "1" > "0-9"; 58 | bind = $mainMod, 2, workspace, 2 59 | bind = $mainMod, 3, workspace, 3 60 | bind = $mainMod, 4, workspace, 4 61 | bind = $mainMod, 5, workspace, 5 62 | bind = $mainMod, 6, workspace, 6 63 | bind = $mainMod, 7, workspace, 7 64 | bind = $mainMod, 8, workspace, 8 65 | bind = $mainMod, 9, workspace, 9 66 | bind = $mainMod, 0, workspace, 10 67 | bind = $mainMod SHIFT, 1, movetoworkspace, 1 #! @description: "Move window to workspace"; @workspaces; @replace "1" > "0-9"; 68 | bind = $mainMod SHIFT, 2, movetoworkspace, 2 69 | bind = $mainMod SHIFT, 3, movetoworkspace, 3 70 | bind = $mainMod SHIFT, 4, movetoworkspace, 4 71 | bind = $mainMod SHIFT, 5, movetoworkspace, 5 72 | bind = $mainMod SHIFT, 6, movetoworkspace, 6 73 | bind = $mainMod SHIFT, 7, movetoworkspace, 7 74 | bind = $mainMod SHIFT, 8, movetoworkspace, 8 75 | bind = $mainMod SHIFT, 9, movetoworkspace, 9 76 | bind = $mainMod SHIFT, 0, movetoworkspace, 10 77 | bind = $mainMod, mouse_down, workspace, e+1 78 | bind = $mainMod, mouse_up, workspace, e-1 79 | bind = $mainMod CTRL, down, workspace, empty #! @description: "Switch to empty workspace"; @workspaces; 80 | 81 | # Fn keys 82 | bind = , XF86MonBrightnessUp, exec, brightnessctl -q s +10% 83 | bind = , XF86MonBrightnessDown, exec, brightnessctl -q s 10%- 84 | bind = , XF86AudioRaiseVolume, exec, pactl set-sink-volume @DEFAULT_SINK@ +5% 85 | bind = , XF86AudioLowerVolume, exec, pactl set-sink-volume @DEFAULT_SINK@ -5% 86 | bind = , XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle 87 | bind = , XF86AudioPlay, exec, playerctl play-pause 88 | bind = , XF86AudioPause, exec, playerctl pause 89 | bind = , XF86AudioNext, exec, playerctl next 90 | bind = , XF86AudioPrev, exec, playerctl previous 91 | bind = , XF86AudioMicMute, exec, pactl set-source-mute @DEFAULT_SOURCE@ toggle 92 | bind = , XF86Calculator, exec, qalculate-gtk 93 | bind = , XF86Lock, exec, hyprlock 94 | bind = , XF86Tools, exec, agsv1 -r 'OpenSettings()' 95 | 96 | # misc 97 | bind = $mainMod, P, submap, passthru #! @description: "Passthrough $mainMod key to Virtual Machine"; @misc; 98 | submap = passthru 99 | bind = SUPER, Escape, submap, reset #! @description: "Cancel passthrough"; @misc; 100 | submap = reset 101 | -------------------------------------------------------------------------------- /hypr/conf/layout.conf: -------------------------------------------------------------------------------- 1 | dwindle { 2 | pseudotile = true 3 | preserve_split = true 4 | } 5 | 6 | master { 7 | smart_resizing = true 8 | new_on_active = true 9 | drop_at_cursor = true 10 | } 11 | 12 | gestures { 13 | workspace_swipe = false 14 | } 15 | -------------------------------------------------------------------------------- /hypr/conf/misc.conf: -------------------------------------------------------------------------------- 1 | misc { 2 | vfr = 1 3 | vrr = 1 4 | # layers_hog_mouse_focus = true 5 | animate_manual_resizes = false 6 | animate_mouse_windowdragging = false 7 | enable_swallow = false 8 | swallow_regex = (foot|kitty|allacritty|Alacritty) 9 | disable_splash_rendering = true 10 | 11 | disable_hyprland_logo = true 12 | force_default_wallpaper = 0 13 | new_window_takes_over_fullscreen = 2 14 | allow_session_lock_restore = true 15 | 16 | initial_workspace_tracking = false 17 | } 18 | 19 | gestures { 20 | workspace_swipe = true 21 | workspace_swipe_distance = 700 22 | workspace_swipe_fingers = 4 23 | workspace_swipe_cancel_ratio = 0.2 24 | workspace_swipe_min_speed_to_force = 5 25 | workspace_swipe_direction_lock = true 26 | workspace_swipe_direction_lock_threshold = 10 27 | workspace_swipe_create_new = true 28 | } 29 | -------------------------------------------------------------------------------- /hypr/conf/window.conf: -------------------------------------------------------------------------------- 1 | general { 2 | gaps_in = 5 3 | gaps_out = 14 4 | border_size = 0 5 | col.active_border = $border_color_active 6 | col.inactive_border = $border_color_inactive 7 | layout = dwindle 8 | } 9 | -------------------------------------------------------------------------------- /hypr/conf/windowrule.conf: -------------------------------------------------------------------------------- 1 | # ######## Window rules ######## 2 | windowrule = tile, class:^(Microsoft-edge)$ 3 | windowrule = tile, class:^(Brave-browser)$ 4 | windowrule = tile, class:^(Chromium)$ 5 | windowrule = float, class:^(blueman-manager)$ 6 | windowrule = float, class:^(blueberry.py)$ 7 | windowrule = float, class:^(nm-connection-editor)$ 8 | windowrule = float, class:^(qalculate-gtk)$ 9 | windowrule = float, class:^(steam)$ 10 | windowrule = float, class:^(com.github.Aylur.ags)$ 11 | windowrule = stayfocused, title:^()$, class:^(steam)$ 12 | windowrule = minsize 1 1, title:^()$, class:^(steam)$ 13 | windowrule = float, title:^(Volume Control)(.*)$ 14 | 15 | # Xwaylandvideobridge (if installed) 16 | windowrule = opacity 0.0 override, class:^(xwaylandvideobridge)$ 17 | windowrule = noanim, class:^(xwaylandvideobridge)$ 18 | windowrule = noinitialfocus, class:^(xwaylandvideobridge)$ 19 | windowrule = maxsize 1 1, class:^(xwaylandvideobridge)$ 20 | windowrule = noblur, class:^(xwaylandvideobridge)$ 21 | 22 | # Dialogs 23 | windowrule = float, title:^(Open File)(.*)$ 24 | windowrule = float, title:^(Select a File)(.*)$ 25 | windowrule = float, title:^(Choose wallpaper)(.*)$ 26 | windowrule = float, title:^(Open Folder)(.*)$ 27 | windowrule = float, title:^(Save As)(.*)$ 28 | windowrule = float, title:^(Library)(.*)$ 29 | windowrule = float, title:^(File Upload)(.*)$ 30 | 31 | # Tearing 32 | windowrule = immediate, class:.*\.exe 33 | windowrule = immediate, class:(steam_app)455 34 | 35 | # ######## Layer rules ######## 36 | # layerrule = xray 1, .* 37 | # layerrule = noanim, .* 38 | layerrule = noanim, walker 39 | layerrule = noanim, selection 40 | layerrule = noanim, overview 41 | layerrule = noanim, anyrun 42 | layerrule = noanim, popup.* 43 | layerrule = noanim, hyprpicker 44 | 45 | layerrule = noanim, noanim 46 | layerrule = blur, gtk-layer-shell 47 | layerrule = ignorezero, gtk-layer-shell 48 | layerrule = blur, launcher 49 | layerrule = ignorealpha 0.5, launcher 50 | layerrule = blur, notifications 51 | layerrule = ignorealpha 0.69, notifications 52 | 53 | layerrule = noanim, notifications 54 | -------------------------------------------------------------------------------- /hypr/hypridle.conf: -------------------------------------------------------------------------------- 1 | general { 2 | ignore_dbus_inhibit = false 3 | } 4 | 5 | general { 6 | lock_cmd = pidof hyprlock || hyprlock # avoid starting multiple hyprlock instances. 7 | before_sleep_cmd = loginctl lock-session # lock before suspend. 8 | after_sleep_cmd = hyprctl dispatch dpms on # to avoid having to press a key twice to turn on the display. 9 | } 10 | 11 | # Screenlock 12 | listener { 13 | # HYPRLOCK TIMEOUT 14 | timeout = 600 15 | # HYPRLOCK ONTIMEOUT 16 | on-timeout = loginctl lock-session 17 | } 18 | 19 | # dpms 20 | listener { 21 | # DPMS TIMEOUT 22 | timeout = 660 23 | # DPMS ONTIMEOUT 24 | on-timeout = hyprctl dispatch dpms off 25 | # DPMS ONRESUME 26 | on-resume = hyprctl dispatch dpms on 27 | } 28 | 29 | # Suspend 30 | listener { 31 | # SUSPEND TIMEOUT 32 | timeout = 0 33 | #SUSPEND ONTIMEOUT 34 | # on-timeout = systemctl suspend 35 | } 36 | -------------------------------------------------------------------------------- /hypr/hyprland.conf: -------------------------------------------------------------------------------- 1 | # Monitor (custom) 2 | source = ~/dotfiles/hypr/conf/custom/monitor.conf 3 | 4 | # Autostart 5 | source = ~/dotfiles/hypr/conf/autostart.conf 6 | 7 | # Environment 8 | source = ~/dotfiles/hypr/conf/environment.conf 9 | source = ~/dotfiles/hypr/conf/custom/environment.conf 10 | 11 | # Input (custom) 12 | source = ~/dotfiles/hypr/conf/custom/input.conf 13 | 14 | # Material colors 15 | source = ~/.cache/material/colors-hyprland.conf 16 | 17 | # Some files 18 | source = ~/dotfiles/hypr/conf/window.conf 19 | source = ~/dotfiles/hypr/conf/decoration.conf 20 | source = ~/dotfiles/hypr/conf/layout.conf 21 | source = ~/dotfiles/hypr/conf/misc.conf 22 | source = ~/dotfiles/hypr/conf/keybinding.conf 23 | source = ~/dotfiles/hypr/conf/windowrule.conf 24 | 25 | # Animations 26 | source = ~/dotfiles/hypr/conf/animation.conf 27 | 28 | # Apps 29 | source = ~/dotfiles/hypr/conf/apps.conf 30 | 31 | # Custom 32 | source = ~/dotfiles/hypr/conf/custom/general.conf 33 | source = ~/dotfiles/hypr/conf/custom/cursor.conf 34 | 35 | # xdg 36 | exec-once=dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP -------------------------------------------------------------------------------- /hypr/hyprlock.conf: -------------------------------------------------------------------------------- 1 | source = ~/.cache/material/hyprlock.conf 2 | -------------------------------------------------------------------------------- /hypr/scripts/active-monitor.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import subprocess 3 | import os 4 | import json 5 | import pathlib 6 | import shutil 7 | 8 | pathname = os.path.dirname(sys.argv[0]) 9 | homeFolder = os.path.expanduser('~') 10 | dotfiles = homeFolder + "/dotfiles/" 11 | 12 | result = subprocess.run(["bash", dotfiles + "hypr/scripts/monitors.sh"], capture_output=True, text=True) 13 | monitors_json = result.stdout.strip() 14 | monitors_arr = json.loads(monitors_json) 15 | for row in monitors_arr: 16 | if row["focused"]: 17 | print(row["id"]) 18 | -------------------------------------------------------------------------------- /hypr/scripts/apps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Path to your JSON file 4 | JSON_FILE="$HOME/dotfiles/.settings/apps.json" 5 | 6 | # Read the application type from the argument 7 | APP_TYPE=$1 8 | 9 | # Extract the corresponding application value from the JSON file using jq 10 | APP=$(jq -r ".$APP_TYPE" "$JSON_FILE") 11 | 12 | # Check if the application is defined in the JSON file 13 | if [ "$APP" != "null" ]; then 14 | # Open the specified application 15 | $APP 16 | else 17 | echo "No application defined for $APP_TYPE in $JSON_FILE" 18 | fi 19 | -------------------------------------------------------------------------------- /hypr/scripts/disabledm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | clear 3 | 4 | echo "Hyprland recommends the start with the tty login." 5 | echo "You can deactivate the current display manager (if exists)." 6 | echo "" 7 | echo "-> Do you really want to deactivate the display manager?" 8 | while true; do 9 | read -p "Do you want to enable the sddm display manager and setup theme? (Yy/Nn): " yn 10 | case $yn in 11 | [Yy]*) 12 | if [ -f /etc/systemd/system/display-manager.service ]; then 13 | sudo rm /etc/systemd/system/display-manager.service 14 | echo "Current display manager removed." 15 | else 16 | echo "No active display manager found." 17 | fi 18 | break 19 | ;; 20 | [Nn]*) 21 | exit 22 | break 23 | ;; 24 | *) echo "Please answer yes or no." ;; 25 | esac 26 | done 27 | -------------------------------------------------------------------------------- /hypr/scripts/exit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | killall -9 Hyprland 3 | sleep 2 4 | -------------------------------------------------------------------------------- /hypr/scripts/init-wallpaper-engine.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Path to your settings JSON file 4 | settings_file="$HOME/dotfiles/.settings/settings.json" 5 | 6 | # Read wallpaper engine from the JSON file 7 | wallpaper_engine=$(jq -r '.["wallpaper-engine"]' "$settings_file") 8 | 9 | if [ "$wallpaper_engine" == "swww" ]; then 10 | # swww 11 | echo ":: Using swww" 12 | swww-daemon 13 | swww-daemon --format xrgb 14 | sleep 0.5 15 | python -O ~/dotfiles/hypr/scripts/wallpaper.py -P 16 | elif [ "$wallpaper_engine" == "hyprpaper" ]; then 17 | # hyprpaper 18 | echo ":: Using hyprpaper" 19 | sleep 0.5 20 | python -O ~/dotfiles/hypr/scripts/wallpaper.py -P 21 | else 22 | echo ":: Wallpaper Engine disabled" 23 | python -O ~/dotfiles/hypr/scripts/wallpaper.py -P 24 | fi 25 | -------------------------------------------------------------------------------- /hypr/scripts/lock.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | hyprlock --immediate 3 | -------------------------------------------------------------------------------- /hypr/scripts/monitors.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | hyprctl -j monitors 3 | -------------------------------------------------------------------------------- /hypr/scripts/reboot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | systemctl reboot 3 | -------------------------------------------------------------------------------- /hypr/scripts/restart-hypridle.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | killall hypridle 3 | sleep 1 4 | hypridle & 5 | notify-send "hypridle has been restarted." 6 | -------------------------------------------------------------------------------- /hypr/scripts/screenshot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | DIR="$HOME/Pictures/screenshots/" 3 | NAME="screenshot_$(date +%d%m%Y_%H%M%S).png" 4 | 5 | # hyprshot -z -m region -o "/tmp" -f "$NAME" -s 6 | 7 | if [[ "$1" == "--window" ]]; then 8 | hyprshot -m window -o "/tmp" -f "$NAME" -s 9 | elif [[ "$1" == "--active" ]]; then 10 | hyprshot -m active -m output -o "/tmp" -f "$NAME" -s 11 | else 12 | hyprshot -m region -o "/tmp" -f "$NAME" -s -- 13 | fi 14 | 15 | swappy -f "/tmp/$NAME" -o "$DIR$NAME" 16 | -------------------------------------------------------------------------------- /hypr/scripts/shutdown.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | systemctl poweroff 3 | -------------------------------------------------------------------------------- /hypr/scripts/suspend.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | systemctl suspend 3 | -------------------------------------------------------------------------------- /hypr/scripts/toggle-animations.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cache_file="/tmp/toggle_animation" 3 | if [ -f $cache_file ]; then 4 | hyprctl keyword animations:enabled true 5 | agsv1 -r 'enableAnimations(true)' 6 | rm $cache_file 7 | else 8 | hyprctl keyword animations:enabled false 9 | agsv1 -r 'enableAnimations(false)' 10 | touch $cache_file 11 | fi 12 | -------------------------------------------------------------------------------- /hypr/scripts/toggleallfloat.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | hyprctl dispatch workspaceopt allfloat 3 | -------------------------------------------------------------------------------- /hypr/scripts/xdg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sleep 1 3 | 4 | # kill all possible running xdg-desktop-portals 5 | killall xdg-desktop-portal-hyprland 6 | killall xdg-desktop-portal-gnome 7 | killall xdg-desktop-portal-kde 8 | killall xdg-desktop-portal-lxqt 9 | killall xdg-desktop-portal-wlr 10 | killall xdg-desktop-portal-gtk 11 | killall xdg-desktop-portal 12 | sleep 1 13 | 14 | # start xdg-desktop-portal-hyprland 15 | /usr/lib/xdg-desktop-portal-hyprland & 16 | sleep 2 17 | 18 | # start xdg-desktop-portal 19 | /usr/lib/xdg-desktop-portal & 20 | sleep 1 21 | -------------------------------------------------------------------------------- /material-colors/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "Celebi", 4 | "getdata", 5 | "pywal" 6 | ] 7 | } -------------------------------------------------------------------------------- /material-colors/custom.py: -------------------------------------------------------------------------------- 1 | from materialyoucolor.scheme.dynamic_scheme import DynamicSchemeOptions, DynamicScheme # type: ignore # noqa 2 | from materialyoucolor.scheme.variant import Variant # type: ignore # noqa 3 | from materialyoucolor.palettes.tonal_palette import TonalPalette # type: ignore # noqa 4 | from materialyoucolor.utils.math_utils import sanitize_degrees_double # type: ignore # noqa 5 | 6 | """ 7 | This file is just an example, you can change anything you want here. 8 | !!! Do not rename the class SchemeCustom !!! 9 | """ 10 | 11 | 12 | class SchemeCustom(DynamicScheme): 13 | def __init__(self, source_color_hct, is_dark, contrast_level): 14 | super().__init__( 15 | DynamicSchemeOptions( 16 | source_color_argb=source_color_hct.to_int(), 17 | variant="custom", 18 | contrast_level=contrast_level, 19 | is_dark=is_dark, 20 | primary_palette=TonalPalette.from_hue_and_chroma( 21 | source_color_hct.hue, 48 22 | ), 23 | secondary_palette=TonalPalette.from_hue_and_chroma( 24 | sanitize_degrees_double(source_color_hct.hue + 10), 15 25 | ), 26 | tertiary_palette=TonalPalette.from_hue_and_chroma( 27 | sanitize_degrees_double(source_color_hct.hue + 30), 12 28 | ), 29 | neutral_palette=TonalPalette.from_hue_and_chroma( 30 | source_color_hct.hue, 3 31 | ), 32 | neutral_variant_palette=TonalPalette.from_hue_and_chroma( 33 | source_color_hct.hue, 3 34 | ), 35 | ) 36 | ) 37 | -------------------------------------------------------------------------------- /material-colors/gtk-material.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ICON_THEME_DARK=$(sed -n "1p" "$HOME"/dotfiles/.settings/icon-theme) 4 | ICON_THEME_LIGHT=$(sed -n "2p" "$HOME"/dotfiles/.settings/icon-theme) 5 | 6 | if [ "$1" == "--light" ]; then 7 | gsettings set org.gnome.desktop.interface gtk-theme adw-gtk3 8 | gsettings set org.gnome.desktop.interface color-scheme 'prefer-light' 9 | gsettings set org.gnome.desktop.interface icon-theme "$ICON_THEME_LIGHT" 10 | else 11 | gsettings set org.gnome.desktop.interface gtk-theme adw-gtk3-dark 12 | gsettings set org.gnome.desktop.interface color-scheme 'prefer-dark' 13 | gsettings set org.gnome.desktop.interface icon-theme "$ICON_THEME_DARK" 14 | fi 15 | -------------------------------------------------------------------------------- /material-colors/hooks/discord.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | material_cache="$HOME"/.cache/material/ 3 | 4 | sass $material_cache/material-discord.scss $material_cache/material-discord.css 5 | -------------------------------------------------------------------------------- /material-colors/hooks/sddm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | "$HOME"/dotfiles/sddm/scripts/wallpaper.sh 1>/dev/null 4 | -------------------------------------------------------------------------------- /material-colors/hooks/telegram.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cache_folder="$HOME"/.cache/material 3 | telegram_theme_cache="$HOME"/.cache/telegram-theme 4 | 5 | bg_color_file="$cache_folder/bg-color" 6 | bg_color=$(cat "$bg_color_file") 7 | magick -size 256x256 "xc:$bg_color" $telegram_theme_cache/tiled.png 8 | 9 | mkdir -p $telegram_theme_cache 10 | 11 | cp $cache_folder/colors.tdesktop-theme $telegram_theme_cache/colors.tdesktop-theme 12 | 13 | zip -q -j $telegram_theme_cache/pallete.tdesktop-theme $telegram_theme_cache/tiled.png $telegram_theme_cache/colors.tdesktop-theme 14 | -------------------------------------------------------------------------------- /material-colors/templates/alacritty-dark.toml: -------------------------------------------------------------------------------- 1 | [colors.primary] 2 | background = '' 3 | foreground = '' 4 | 5 | 6 | [colors.cursor] 7 | text = '#1E1E2E' 8 | cursor = '#F5E0DC' 9 | 10 | [colors.vi_mode_cursor] 11 | text = '#1E1E2E' 12 | cursor = '#B4BEFE' 13 | 14 | 15 | [colors.search.matches] 16 | foreground = '#1E1E2E' 17 | background = '#A6ADC8' 18 | 19 | [colors.search.focused_match] 20 | foreground = '#1E1E2E' 21 | background = '#A6E3A1' 22 | 23 | [colors.footer_bar] 24 | foreground = '#1E1E2E' 25 | background = '#A6ADC8' 26 | 27 | 28 | [colors.hints.start] 29 | foreground = '#1E1E2E' 30 | background = '#F9E2AF' 31 | 32 | [colors.hints.end] 33 | foreground = '#1E1E2E' 34 | background = '#A6ADC8' 35 | 36 | 37 | [colors.selection] 38 | text = '#1E1E2E' 39 | background = '#F5E0DC' 40 | 41 | 42 | [colors.normal] 43 | black = '#45475A' 44 | red = '#F38BA8' 45 | green = '#A6E3A1' 46 | yellow = '#F9E2AF' 47 | blue = '#89B4FA' 48 | magenta = '#F5C2E7' 49 | cyan = '#94E2D5' 50 | white = '#BAC2DE' 51 | 52 | 53 | [colors.bright] 54 | black = '#585B70' 55 | red = '#F38BA8' 56 | green = '#A6E3A1' 57 | yellow = '#F9E2AF' 58 | blue = '#89B4FA' 59 | magenta = '#F5C2E7' 60 | cyan = '#94E2D5' 61 | white = '#A6ADC8' 62 | 63 | 64 | [colors.dim] 65 | black = '#45475A' 66 | red = '#F38BA8' 67 | green = '#A6E3A1' 68 | yellow = '#F9E2AF' 69 | blue = '#89B4FA' 70 | magenta = '#F5C2E7' 71 | cyan = '#94E2D5' 72 | white = '#BAC2DE' -------------------------------------------------------------------------------- /material-colors/templates/alacritty-light.toml: -------------------------------------------------------------------------------- 1 | [colors.primary] 2 | background = '' 3 | foreground = '' 4 | 5 | 6 | [colors.cursor] 7 | text = '#EFF1F5' 8 | cursor = '#DC8A78' 9 | 10 | [colors.vi_mode_cursor] 11 | text = '#EFF1F5' 12 | cursor = '#7287FD' 13 | 14 | 15 | [colors.search.matches] 16 | foreground = '#EFF1F5' 17 | background = '#6C6F85' 18 | 19 | [colors.search.focused_match] 20 | foreground = '#EFF1F5' 21 | background = '#40A02B' 22 | 23 | [colors.footer_bar] 24 | foreground = '#EFF1F5' 25 | background = '#6C6F85' 26 | 27 | 28 | [colors.hints.start] 29 | foreground = '#EFF1F5' 30 | background = '#DF8E1D' 31 | 32 | [colors.hints.end] 33 | foreground = '#EFF1F5' 34 | background = '#6C6F85' 35 | 36 | 37 | [colors.selection] 38 | text = '#EFF1F5' 39 | background = '#DC8A78' 40 | 41 | 42 | [colors.normal] 43 | black = '#5C5F77' 44 | red = '#D20F39' 45 | green = '#40A02B' 46 | yellow = '#DF8E1D' 47 | blue = '#1E66F5' 48 | magenta = '#EA76CB' 49 | cyan = '#179299' 50 | white = '#ACB0BE' 51 | 52 | 53 | [colors.bright] 54 | black = '#6C6F85' 55 | red = '#D20F39' 56 | green = '#40A02B' 57 | yellow = '#DF8E1D' 58 | blue = '#1E66F5' 59 | magenta = '#EA76CB' 60 | cyan = '#179299' 61 | white = '#BCC0CC' 62 | 63 | 64 | [colors.dim] 65 | black = '#5C5F77' 66 | red = '#D20F39' 67 | green = '#40A02B' 68 | yellow = '#DF8E1D' 69 | blue = '#1E66F5' 70 | magenta = '#EA76CB' 71 | cyan = '#179299' 72 | white = '#ACB0BE' -------------------------------------------------------------------------------- /material-colors/templates/alacritty.toml: -------------------------------------------------------------------------------- 1 | [general] 2 | import = [ 3 | "/alacritty-.toml" 4 | ] 5 | [font] 6 | normal = { family = "MesloLGS NF", style = "Regular" } 7 | bold = { family = "MesloLGS NF", style = "Bold" } 8 | italic = { family = "MesloLGS NF", style = "Italic" } 9 | bold_italic = { family = "MesloLGS NF", style = "Bold Italic" } 10 | size = 12.0 11 | -------------------------------------------------------------------------------- /material-colors/templates/bg-color: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /material-colors/templates/colors-hyprland.conf: -------------------------------------------------------------------------------- 1 | $background = rgb() 2 | $foreground = rgb() 3 | $border_color_active = rgb() 4 | $border_color_inactive = rgb() 5 | # <\\outline> 6 | -------------------------------------------------------------------------------- /material-colors/templates/colors-sddm-style.conf: -------------------------------------------------------------------------------- 1 | ## Please see https://github.com/aczw/sddm-theme-corners/blob/main/CONFIG.md for 2 | ## more information about these options. Happy configuring! 3 | 4 | [General] 5 | 6 | # BgSource: string. Path to an image, used as the wallpaper. Can be placed 7 | # in the `backgrounds/` folder for convenience (see below!) 8 | # 9 | # FontFamily: string. Name of the font family. You can find this with 10 | # something like `fontconfig`, for example. 11 | # 12 | # FontSize: number. This value is used for everything *except* the date/time. 13 | # 14 | # Padding: number. How far away things should be from the edge of your screen. 15 | # 16 | # Radius: number. Corner radius for UI. Set to 0 to disable rounded corners. 17 | # 18 | # Scale: number. Adjusts the size of UI elements. Can be anything, but I 19 | # would stick between 1 and 2 (e.g. 1.5). 20 | 21 | BgSource="backgrounds/CURRENTWALLPAPER" 22 | FontFamily="Atkinson Hyperlegible" 23 | FontSize=9 24 | Padding=50 25 | Radius=10 26 | Scale=1 27 | 28 | # UserPictureEnabled: boolean. By default the user picture is shown. Set to false 29 | # if you don't have/want a user picture, or you don't use the 30 | # user selection functionality. 31 | # 32 | # UserBorderWidth: number. Width of the border around your picture. Set to 33 | # 0 to remove. 34 | # 35 | # UserBorderColor: color. Border color around your picture. Useless if border 36 | # width is 0. 37 | # 38 | # UserColor: color. Background color of the default, blank avatar. Only 39 | # visible if you don't have your own picture. 40 | 41 | UserPictureEnabled=false 42 | UserBorderWidth=5 43 | UserBorderColor="" 44 | UserColor="" 45 | 46 | # InputColor: color. Background color of the input fields. 47 | # 48 | # InputTextColor: color. Color of text you enter in the fields. 49 | # 50 | # InputBorderWidth: number. Width of the border around the active field. Set 51 | # to 0 to remove. 52 | # 53 | # InputBorderColor: color. Border color of active field. Useless if border 54 | # width is 0. 55 | # 56 | # UserPlaceholderText: string. Placeholder text shown when user field is empty. 57 | # 58 | # PassPlaceholderText: string. Placeholder text shown when user field is empty. 59 | # 60 | # HidePassword: boolean. Whether to replace your entered password with dots. 61 | 62 | InputColor="" 63 | InputTextColor="" 64 | InputBorderWidth=4 65 | InputBorderColor="" 66 | UserPlaceholderText="user" 67 | PassPlaceholderText="password" 68 | HidePassword=true 69 | 70 | # LoginButtonTextColor: color. Text color on the login button. 71 | # 72 | # LoginButtonText: string. Text displayed on the button. 73 | # 74 | # LoginButtonColor: color. Background color of the button. 75 | 76 | LoginButtonTextColor="" 77 | LoginButtonText="Login" 78 | LoginButtonColor="" 79 | 80 | # PopupColor: color. Background color of popup window. 81 | # 82 | # PopupActiveColor: color. Color around the currently selected entry. 83 | # 84 | # PopupActiveTextColor: color. Text color of the currently selected entry. 85 | # Mainly provided for potential contrast issues. 86 | 87 | PopupColor="" 88 | PopupActiveColor="" 89 | PopupActiveTextColor="" 90 | 91 | # SessionButtonColor: color. Session button background color. 92 | # 93 | # SessionIconColor: color. Color of the icon inside the session button. 94 | # 95 | # PowerButtonColor: color. Power button background color. 96 | # 97 | # PowerIconColor: color. Color of the icon inside the power button. 98 | 99 | SessionButtonColor="" 100 | SessionIconColor="" 101 | PowerButtonColor="" 102 | PowerIconColor="" 103 | 104 | # DateTimeSpacing: number. Spacing between the date and time. 105 | # 106 | # Date/TimeColor: color. Date/time text color. 107 | # 108 | # Date/TimeSize: number. Font size for the date/time. 109 | # 110 | # Date/TimeIsBold: boolean. Whether date/time text should be bolded. 111 | # 112 | # Date/TimeOpacity: number. Date/time text opacity. 113 | # 114 | # Date/TimeFormat: string. Change the format of how the date and time is displayed. 115 | # Note that they use different formats. 116 | 117 | DateTimeSpacing=-20 118 | 119 | DateColor="" 120 | DateSize=36 121 | DateIsBold=false 122 | DateOpacity=1.0 123 | DateFormat="dddd, MMMM d" 124 | 125 | TimeColor="" 126 | TimeSize=48 127 | TimeIsBold=true 128 | TimeOpacity=1.0 129 | TimeFormat="hh:mm AP" 130 | -------------------------------------------------------------------------------- /material-colors/templates/hyprlock.conf: -------------------------------------------------------------------------------- 1 | # Configuration 2 | # (general settings) 3 | general { 4 | grace = 2 5 | hide_cursor = true 6 | ignore_empty_input = true 7 | text_trim = true 8 | } 9 | # (background config) 10 | background { 11 | monitor = 12 | path = ~/.cache/current_wallpaper.png # only png supported for now 13 | color = rgba(, 1.0) 14 | blur_passes = 3 # 0 disables blurring 15 | blur_size = 1 16 | noise = 0.01 17 | contrast = 0.8916 18 | brightness = 0.7 19 | vibrancy = 0.1696 20 | vibrancy_darkness = 0.0 21 | } 22 | # (auth config) 23 | auth { 24 | fingerprint { 25 | enabled = true 26 | ready_message = 27 | present_message = 28 | } 29 | } 30 | # 31 | 32 | # Password input 33 | input-field { 34 | monitor = 35 | size = 225, 50 36 | outline_thickness = -1 37 | dots_size = 0.33 38 | dots_spacing = 0.45 39 | dots_center = true 40 | dots_rounding = -1 41 | outer_color = rgba(0,0,0,0) 42 | inner_color = rgba(0,0,0,0) 43 | font_color = rgba(, 1.0) 44 | fade_on_empty = true 45 | fade_timeout = 1000 46 | font_family = Product Sans 47 | placeholder_text = 48 | hide_input = false 49 | rounding = 4 50 | check_color = rgba(0,0,0,0) 51 | fail_color = rgba(0,0,0,0) 52 | fail_text = $FAIL ($ATTEMPTS) 53 | fail_transition = 200 54 | capslock_color = -1 55 | numlock_color = -1 56 | bothlock_color = -1 57 | invert_numlock = false 58 | swap_font_color = false 59 | position = 0, 150 60 | halign = center 61 | valign = bottom 62 | } 63 | # 64 | 65 | 66 | # Time 67 | # (hours) 68 | label { 69 | monitor = 70 | text = cmd[update:1000] echo -e "$(date +"%H")" 71 | color = rgba(, 1.0) 72 | shadow_pass = 2 73 | shadow_size = 3 74 | shadow_color = rgb(0,0,0) 75 | shadow_boost = 1.2 76 | font_size = 150 77 | font_family = Product Sans Light 78 | position = 0, 90 79 | halign = center 80 | valign = center 81 | } 82 | # (minutes) 83 | label { 84 | monitor = 85 | text = cmd[update:1000] echo -e "$(date +"%M")" 86 | color = rgba(, 1.0) 87 | font_size = 150 88 | font_family = Product Sans Light 89 | position = 0, -90 90 | halign = center 91 | valign = center 92 | } 93 | # 94 | 95 | # Date 96 | # (label) 97 | label { 98 | monitor = 99 | text = cmd[update:1000] echo -e "$(date +"%A, %B %d")" 100 | color = rgba(, 1.0) 101 | font_size = 15 102 | font_family = Product Sans Medium 103 | position = 100, -75 104 | shadow_passes = 5 105 | shadow_size = 10 106 | halign = left 107 | valign = top 108 | } 109 | # (icon) 110 | label { 111 | monitor = 112 | text = calendar_today 113 | color = rgba(, 1.0) 114 | font_size = 15 115 | font_family = Material Symbols Outlined 116 | position = 75, -75 117 | shadow_passes = 5 118 | shadow_size = 10 119 | halign = left 120 | valign = top 121 | } 122 | # 123 | 124 | # Input layout 125 | # (label) 126 | label { 127 | monitor = 128 | text = $LAYOUT 129 | color = rgba(, 1.0) 130 | font_size = 15 131 | font_family = Product Sans Medium 132 | position = 100, -110 133 | shadow_passes = 5 134 | shadow_size = 10 135 | halign = left 136 | valign = top 137 | } 138 | # (icon) 139 | label { 140 | monitor = 141 | text = keyboard 142 | color = rgba(, 1.0) 143 | font_size = 15 144 | font_family = Material Symbols Outlined 145 | position = 75, -112 146 | shadow_passes = 5 147 | shadow_size = 10 148 | halign = left 149 | valign = top 150 | } 151 | # 152 | 153 | # Battery 154 | # (label) 155 | label { 156 | monitor = 157 | text = cmd[update:1000] . ~/dotfiles/scripts/battery.sh status 158 | color = rgba(, 1.0) 159 | font_size = 15 160 | font_family = Product Sans Medium 161 | position = 100, -145 162 | shadow_passes = 5 163 | shadow_size = 10 164 | halign = left 165 | valign = top 166 | } 167 | # (icon) 168 | label { 169 | monitor = 170 | text = cmd[update:1000] . ~/dotfiles/scripts/battery.sh icon 171 | color = rgba(, 1.0) 172 | font_size = 15 173 | font_family = Material Symbols Outlined 174 | position = 78, -145 175 | shadow_passes = 5 176 | shadow_size = 10 177 | halign = left 178 | valign = top 179 | } 180 | # -------------------------------------------------------------------------------- /material-colors/templates/material-discord.scss: -------------------------------------------------------------------------------- 1 | @use "sass:color"; 2 | 3 | @import url(https://capnkitten.github.io/BetterDiscord/Themes/Material-Discord/css/source.css); 4 | @import "/colors.scss"; 5 | 6 | 7 | $color-scheme: ; 8 | 9 | $hue: round(color.channel($primary, "hue", $space: hsl)); 10 | $saturation: round(color.channel($primary, "saturation", $space: hsl)); 11 | $lightness: round(color.channel($primary, "lightness", $space: hsl)); 12 | 13 | * { 14 | transition: color 0.2s ease-in-out; 15 | transition-property: background-color, color; 16 | } 17 | 18 | .theme-#{$color-scheme} { 19 | --main-color: #{$background}; 20 | --main-alt: #{$surfaceContainerLow}; 21 | 22 | --message-color: #{$surfaceContainerLowest}; 23 | --message-color-hover: #{$surfaceContainer}; 24 | --message-color-alt: #{$surfaceContainer}; 25 | --attachment-color: #{$background}; 26 | 27 | --accent-hue: #{$hue}; 28 | --accent-saturation: #{$saturation}; 29 | --accent-lightness: #{$lightness}; 30 | --accent-text-color: #{$onPrimary}; 31 | 32 | --main-textarea-color: #{$surfaceContainerHigh}; 33 | --main-textarea-color-alt: #{$surfaceContainerHighest}; 34 | --status-picker-color: #{$surfaceContainerHigh}; 35 | 36 | --tooltip-color: #{$surfaceContainer}; 37 | --popout-color: #{$surfaceContainer}; 38 | --popout-color-alt: #{$surfaceContainerLowest}; 39 | --popout-header-border: #{$onSurface}; 40 | --separator-color: #{$outlineVariant}; 41 | --sidebar-panel-color: #{$surfaceContainerLowest}; 42 | --server-color: #{$surfaceContainerLow}; 43 | } 44 | 45 | [class*="botTag_"] svg path { 46 | fill: #{$onPrimary}; 47 | } 48 | 49 | [class*="repliedTextContent_"] { 50 | padding: 0px 5px 0px 5px !important; 51 | } 52 | 53 | [class*="userPopoutOuter_"] { 54 | border-radius: 16px !important; 55 | } 56 | -------------------------------------------------------------------------------- /material-colors/templates/svg/brightness-onPrimary.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | -------------------------------------------------------------------------------- /material-colors/templates/svg/dark-onPrimary.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | -------------------------------------------------------------------------------- /screenshots/apps-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/screenshots/apps-menu.png -------------------------------------------------------------------------------- /screenshots/cheatsheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/screenshots/cheatsheet.png -------------------------------------------------------------------------------- /screenshots/emoji.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/screenshots/emoji.png -------------------------------------------------------------------------------- /screenshots/gtk-theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/screenshots/gtk-theme.png -------------------------------------------------------------------------------- /screenshots/hyprlock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/screenshots/hyprlock.png -------------------------------------------------------------------------------- /screenshots/light-theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/screenshots/light-theme.png -------------------------------------------------------------------------------- /screenshots/player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/screenshots/player.png -------------------------------------------------------------------------------- /screenshots/screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/screenshots/screenshot1.png -------------------------------------------------------------------------------- /screenshots/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/screenshots/settings.png -------------------------------------------------------------------------------- /screenshots/sidebar-system.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/screenshots/sidebar-system.png -------------------------------------------------------------------------------- /screenshots/sidebar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/screenshots/sidebar.png -------------------------------------------------------------------------------- /screenshots/sideleft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/screenshots/sideleft.png -------------------------------------------------------------------------------- /scripts/battery.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script is used for the lockscreen battery indicator. 4 | 5 | for bat in /sys/class/power_supply/BAT*; do 6 | if [ -e "$bat/uevent" ]; then 7 | BAT_PATH="$bat" 8 | break 9 | fi 10 | done 11 | 12 | if [ -z "$BAT_PATH" ]; then 13 | echo "No battery found." 14 | exit 1 15 | fi 16 | 17 | source "$BAT_PATH/uevent" 18 | 19 | declare -A battery_icons_charging=( 20 | [100]="battery_charging_full" 21 | [90]="battery_charging_90" 22 | [80]="battery_charging_80" 23 | [70]="battery_charging_80" 24 | [60]="battery_charging_60" 25 | [50]="battery_charging_50" 26 | [40]="battery_charging_30" 27 | [30]="battery_charging_30" 28 | [20]="battery_charging_20" 29 | [10]="battery_charging_20" 30 | [0]="battery_charging_20" 31 | ) 32 | 33 | declare -A battery_icons=( 34 | [100]="battery_full" 35 | [90]="battery_6_bar" 36 | [80]="battery_5_bar" 37 | [70]="battery_5_bar" 38 | [60]="battery_4_bar" 39 | [50]="battery_3_bar" 40 | [40]="battery_2_bar" 41 | [30]="battery_2_bar" 42 | [20]="battery_1_bar" 43 | [10]="battery_1_bar" 44 | [0]="battery_alert" 45 | ) 46 | 47 | get_closest_battery_icon() { 48 | local level="$1" 49 | local charging="$2" 50 | local -n icons_array 51 | 52 | if [ "$charging" = "true" ]; then 53 | icons_array=battery_icons_charging 54 | else 55 | icons_array=battery_icons 56 | fi 57 | 58 | local levels=($(for key in "${!icons_array[@]}"; do echo "$key"; done | sort -nr)) 59 | 60 | for threshold in "${levels[@]}"; do 61 | if [ "$level" -ge "$threshold" ]; then 62 | echo "${icons_array[$threshold]}" 63 | return 64 | fi 65 | done 66 | 67 | echo "${icons_array[${levels[-1]}]}" 68 | } 69 | 70 | icon() { 71 | local capacity="$POWER_SUPPLY_CAPACITY" 72 | local charging="false" 73 | 74 | if [ "$POWER_SUPPLY_STATUS" = "Charging" ]; then 75 | charging="true" 76 | fi 77 | 78 | get_closest_battery_icon "$capacity" "$charging" 79 | } 80 | 81 | info() { 82 | cat "$BAT_PATH/uevent" 83 | } 84 | 85 | status() { 86 | echo "$POWER_SUPPLY_CAPACITY%" 87 | } 88 | 89 | case $1 in 90 | info) info ;; 91 | icon) icon ;; 92 | status) status ;; 93 | *) 94 | echo "Usage: $0 {info|icon|status}" 95 | exit 1 96 | ;; 97 | esac 98 | -------------------------------------------------------------------------------- /scripts/check_updates.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd $HOME/dotfiles 4 | 5 | OLD_SETTINGS=$HOME/dotfiles/.settings/old 6 | 7 | # Remove $OLD_SETTINGS folder if it is empty 8 | if [ -z "$(ls -A "$OLD_SETTINGS")" ]; then 9 | rmdir "$OLD_SETTINGS" 10 | fi 11 | 12 | git fetch 13 | UPSTREAM=${1:-'@{u}'} 14 | LOCAL=$(git rev-parse @) 15 | REMOTE=$(git rev-parse "$UPSTREAM") 16 | BASE=$(git merge-base @ "$UPSTREAM") 17 | 18 | if git diff-index --quiet HEAD --; then 19 | echo "The files have not been modified. You can update" 20 | else 21 | echo "The files have been modified. You can't update" 22 | echo "You can write \"$ git diff-index --name-only HEAD --\" to see which files have changed" 23 | exit 1 24 | fi 25 | 26 | if [ $LOCAL = $REMOTE ]; then 27 | echo "You have the latest version" 28 | exit 0 29 | elif [ $LOCAL = $BASE ]; then 30 | echo "You can run $ git pull" 31 | exit 2 32 | else 33 | echo "Your branch and the remote branch have diverged." 34 | exit 3 35 | fi 36 | -------------------------------------------------------------------------------- /scripts/checkplatform.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # ----------------------------------------------------- 3 | # 3 = Desktop 4 | # 10 = Laptop 5 | # ----------------------------------------------------- 6 | 7 | cat /sys/class/dmi/id/chassis_type 8 | -------------------------------------------------------------------------------- /scripts/cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo ":: Cleanup" 3 | 4 | sudo pacman -Rns $(pacman -Qtdq) 5 | 6 | yay -Scc 7 | -------------------------------------------------------------------------------- /scripts/diagnosis.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | clear 3 | sleep 0.5 4 | echo 5 | echo "This script will check that essential packages and " 6 | echo "execution commands are available on your system." 7 | echo 8 | 9 | _commandExists() { 10 | package="$1" 11 | if ! type $package >/dev/null 2>&1; then 12 | echo ":: ERROR: $package doesn't exists. Please install it with yay -S $2" 13 | else 14 | echo ":: OK: $package found." 15 | fi 16 | } 17 | 18 | _folderExists() { 19 | folder="$1" 20 | if [ ! -d $folder ]; then 21 | echo ":: ERROR: $folder doesn't exists." 22 | else 23 | echo ":: OK: $folder found." 24 | fi 25 | } 26 | 27 | _commandExists "ags" "aylurs-gtk-shell" 28 | _commandExists "hyprpaper" "hyprpaper" 29 | _commandExists "hyprlock" "hyprpaper" 30 | _commandExists "hypridle" "hyprpaper" 31 | _commandExists "wal" "pywal-16-colors" 32 | _commandExists "gum" "gum" 33 | _commandExists "swww" "swww" 34 | _commandExists "magick" "imagemagick" 35 | 36 | echo 37 | echo "Press return to exit" 38 | read 39 | -------------------------------------------------------------------------------- /scripts/filemanager.sh: -------------------------------------------------------------------------------- 1 | nautilus 2 | -------------------------------------------------------------------------------- /scripts/fontsearch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | fc-list | 4 | grep -ioE ": [^:]*$1[^:]+:" | 5 | sed -E 's/(^: |:)//g' | 6 | tr , \\n | 7 | sort | 8 | uniq 9 | -------------------------------------------------------------------------------- /scripts/nm-applet.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [[ "$1" == "stop" ]]; then 3 | killall nm-applet 4 | else 5 | nm-applet --indicator & 6 | fi 7 | -------------------------------------------------------------------------------- /scripts/restart_ags.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | killall agsv1 3 | sleep 1 4 | hyprctl dispatch exec agsv1 5 | -------------------------------------------------------------------------------- /scripts/thunarterminal.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | clear 3 | 4 | settings_file=~/dotfiles/.settings/apps.json 5 | 6 | echo "Checking for settings file: $settings_file" 7 | if [ -f "$settings_file" ]; then 8 | echo "Settings file found." 9 | terminal=$(jq -r '.terminal' "$settings_file") 10 | if [ $? -ne 0 ]; then 11 | echo "ERROR: Failed to parse JSON file with jq." 12 | exit 1 13 | fi 14 | echo ":: Installing $terminal" 15 | if [ -d ~/.config/xfce4 ]; then 16 | if [ ! -f ~/.config/xfce4/helpers.rc ]; then 17 | touch ~/.config/xfce4/helpers.rc 18 | fi 19 | echo "TerminalEmulator=$terminal" > ~/.config/xfce4/helpers.rc 20 | echo ":: $terminal defined as Thunar Terminal Emulator." 21 | else 22 | echo "ERROR: ~/.config/xfce4 not found. Please open Thunar once to create it." 23 | echo "Then start this script again." 24 | fi 25 | else 26 | echo "ERROR: $settings_file not found" 27 | fi 28 | sleep 3 29 | -------------------------------------------------------------------------------- /scripts/unlock-pacman.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sleep 1 3 | if [ -f /var/lib/pacman/db.lck ]; then 4 | sudo rm /var/lib/pacman/db.lck 5 | echo ":: Unlock complete" 6 | else 7 | echo ":: Pacman database is not locked" 8 | fi 9 | sleep 3 10 | -------------------------------------------------------------------------------- /scripts/update_timer.sh: -------------------------------------------------------------------------------- 1 | NOTIFICATION_SENT_FILE="/tmp/git_update_notification_sent" 2 | 3 | dotfiles_update() { 4 | notify-send -u critical --icon "software-update-available-symbolic" \ 5 | "Dotfiles update available" \ 6 | "If you haven't changed the dotfiles folder, you can write \n\$ ~/dotfiles/update.sh" 7 | } 8 | 9 | check_and_notify_update() { 10 | cd "$DOTFILES_DIR" || exit 1 11 | $HOME/dotfiles/scripts/check_updates.sh >/dev/null 12 | status=$? 13 | 14 | if [ $status -eq 2 ]; then 15 | if ! [ -f "$NOTIFICATION_SENT_FILE" ]; then 16 | dotfiles_update 17 | touch "$NOTIFICATION_SENT_FILE" 18 | fi 19 | elif [ $status -eq 1 ]; then 20 | exit 1 21 | fi 22 | } 23 | 24 | while true; do 25 | check_and_notify_update 26 | sleep 60 27 | done 28 | -------------------------------------------------------------------------------- /sddm/Main.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.15 2 | import QtQuick.Controls 2.15 3 | import QtQuick.Window 2.15 4 | 5 | import "./components" 6 | 7 | Rectangle { 8 | id: root 9 | 10 | height: Screen.height 11 | width: Screen.width 12 | 13 | Image { 14 | anchors { fill: parent } 15 | 16 | source: config.BgSource 17 | fillMode: Image.PreserveAspectCrop 18 | clip: true 19 | } 20 | 21 | Item { 22 | anchors { 23 | fill: parent 24 | margins: config.Padding 25 | } 26 | 27 | DateTimePanel { 28 | anchors { 29 | top: parent.top 30 | right: parent.right 31 | } 32 | } 33 | 34 | LoginPanel { 35 | anchors { fill: parent } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /sddm/scripts/disable.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | figlet "Disable SDDM" 3 | if [ -f /etc/systemd/system/display-manager.service ]; then 4 | if gum confirm "Do you want to disable the current display manager?"; then 5 | sudo rm /etc/systemd/system/display-manager.service 6 | echo ":: Current display manager removed." 7 | echo ":: Please reboot your system." 8 | fi 9 | else 10 | echo ":: No Display Manager enabled." 11 | fi 12 | sleep 3 13 | -------------------------------------------------------------------------------- /sddm/scripts/enable.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | figlet "Enable SDDM" 3 | if [ -f /etc/systemd/system/display-manager.service ]; then 4 | echo ":: Display Manager is already enabled." 5 | else 6 | if gum confirm "Do you want to enable SDDM as your display manager?"; then 7 | sudo systemctl enable sddm.service 8 | echo ":: Display manager SDDM has been enabled." 9 | echo ":: Please reboot your system!" 10 | fi 11 | fi 12 | sleep 3 13 | -------------------------------------------------------------------------------- /sddm/scripts/wallpaper.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cache_file="$HOME/.cache/current_wallpaper" 3 | if [ ! -d /etc/sddm.conf.d/ ]; then 4 | sudo mkdir /etc/sddm.conf.d 5 | echo "Folder /etc/sddm.conf.d created." 6 | fi 7 | 8 | cp $HOME/dotfiles/sddm/sddm.conf /etc/sddm.conf.d/ 9 | cp $HOME/dotfiles/sddm/sddm.conf /etc/ 10 | if [ "$1" != "init" ]; then 11 | echo "File /etc/sddm.conf.d/sddm.conf updated." 12 | fi 13 | 14 | current_wallpaper=$(cat "$cache_file") 15 | extension="${current_wallpaper##*.}" 16 | 17 | cp $current_wallpaper /usr/share/sddm/themes/corners/backgrounds/current_wallpaper.$extension 18 | 19 | if [ "$1" != "init" ]; then 20 | echo "Current wallpaper copied into /usr/share/sddm/themes/corners/backgrounds/" 21 | fi 22 | 23 | new_wall=$(echo $current_wallpaper | sed "s|$HOME/wallpaper/||g") 24 | cp $HOME/.cache/material/colors-sddm-style.conf /usr/share/sddm/themes/corners/theme.conf 25 | sed -i 's/CURRENTWALLPAPER/'"current_wallpaper.$extension"'/' /usr/share/sddm/themes/corners/theme.conf 26 | 27 | if [ "$1" != "init" ]; then 28 | echo "File theme.conf updated in /usr/share/sddm/themes/corners/" 29 | 30 | echo "DONE! Please logout to test sddm." 31 | fi 32 | -------------------------------------------------------------------------------- /sddm/sddm.conf: -------------------------------------------------------------------------------- 1 | [Autologin] 2 | # Whether sddm should automatically log back into sessions when they exit 3 | Relogin=false 4 | 5 | # Name of session file for autologin session (if empty try last logged in) 6 | Session= 7 | 8 | # Username for autologin session 9 | User= 10 | 11 | [General] 12 | # Which display server should be used. 13 | # Valid values are: x11, x11-user, wayland. Wayland support is experimental 14 | DisplayServer=x11 15 | 16 | # Comma-separated list of environment variables to be set 17 | GreeterEnvironment= 18 | 19 | # Halt command 20 | HaltCommand=/usr/bin/systemctl poweroff 21 | 22 | # Input method module 23 | InputMethod= 24 | 25 | # Comma-separated list of Linux namespaces for user session to enter 26 | Namespaces= 27 | 28 | # Initial NumLock state. Can be on, off or none. 29 | # If property is set to none, numlock won't be changed 30 | # NOTE: Currently ignored if autologin is enabled. 31 | Numlock=none 32 | 33 | # Reboot command 34 | RebootCommand=/usr/bin/systemctl reboot 35 | 36 | 37 | [Theme] 38 | # Current theme name 39 | Current=corners 40 | 41 | # Cursor size used in the greeter 42 | CursorSize=24 43 | 44 | # Cursor theme used in the greeter 45 | CursorTheme=Bibata-Modern-Ice 46 | 47 | # Number of users to use as threshold 48 | # above which avatars are disabled 49 | # unless explicitly enabled with EnableAvatars 50 | DisableAvatarsThreshold=7 51 | 52 | # Enable display of custom user avatars 53 | EnableAvatars=false 54 | 55 | # Global directory for user avatars 56 | # The files should be named .face.icon 57 | FacesDir=/usr/share/sddm/faces 58 | 59 | # Font used in the greeter 60 | Font= 61 | 62 | # Theme directory path 63 | # ThemeDir=/usr/share/sddm/themes 64 | ThemeDir=/usr/share/sddm/themes 65 | 66 | [Users] 67 | # Default $PATH for logged in users 68 | DefaultPath=/usr/local/sbin:/usr/local/bin:/usr/bin 69 | 70 | # Comma-separated list of shells. 71 | # Users with these shells as their default won't be listed 72 | HideShells= 73 | 74 | # Comma-separated list of users that should not be listed 75 | HideUsers= 76 | 77 | # Maximum user id for displayed users 78 | MaximumUid=60513 79 | 80 | # Minimum user id for displayed users 81 | MinimumUid=1000 82 | 83 | # Remember the session of the last successfully logged in user 84 | RememberLastSession=true 85 | 86 | # Remember the last successfully logged in user 87 | RememberLastUser=true 88 | 89 | # When logging in as the same user twice, restore the original session, rather than create a new one 90 | ReuseSession=true 91 | 92 | 93 | [Wayland] 94 | # Path of the Wayland compositor to execute when starting the greeter 95 | CompositorCommand=weston --shell=fullscreen-shell.so 96 | 97 | # Enable Qt's automatic high-DPI scaling 98 | EnableHiDPI=true 99 | 100 | # Path to a script to execute when starting the desktop session 101 | SessionCommand=/usr/share/sddm/scripts/wayland-session 102 | 103 | # Comma-separated list of directories containing available Wayland sessions 104 | SessionDir=/usr/local/share/wayland-sessions,/usr/share/wayland-sessions 105 | 106 | # Path to the user session log file 107 | SessionLogFile=.local/share/sddm/wayland-session.log 108 | 109 | 110 | [X11] 111 | # Path to a script to execute when starting the display server 112 | DisplayCommand=/usr/share/sddm/scripts/Xsetup 113 | 114 | # Path to a script to execute when stopping the display server 115 | DisplayStopCommand=/usr/share/sddm/scripts/Xstop 116 | 117 | # Enable Qt's automatic high-DPI scaling 118 | EnableHiDPI=true 119 | 120 | # Arguments passed to the X server invocation 121 | ServerArguments=-nolisten tcp 122 | 123 | # Path to X server binary 124 | ServerPath=/usr/bin/X 125 | 126 | # Path to a script to execute when starting the desktop session 127 | SessionCommand=/usr/share/sddm/scripts/Xsession 128 | 129 | # Comma-separated list of directories containing available X sessions 130 | SessionDir=/usr/local/share/xsessions,/usr/share/xsessions 131 | 132 | # Path to the user session log file 133 | SessionLogFile=.local/share/sddm/xorg-session.log 134 | 135 | # Path to Xephyr binary 136 | XephyrPath=/usr/bin/Xephyr 137 | 138 | 139 | -------------------------------------------------------------------------------- /setup/MicroTex/.gitignore: -------------------------------------------------------------------------------- 1 | /MicroTeX/ 2 | /pkg/ 3 | /src/ 4 | /microtex-git* -------------------------------------------------------------------------------- /setup/MicroTex/PKGBUILD: -------------------------------------------------------------------------------- 1 | pkgname=m-microtex-git 2 | _pkgname=MicroTeX 3 | pkgver=r492.d87ebec 4 | pkgrel=1 5 | pkgdesc="A dynamic, cross-platform, and embeddable LaTeX rendering library" 6 | arch=("x86_64") 7 | url="https://github.com/NanoMichael/${_pkgname}" 8 | license=('MIT') 9 | depends=( 10 | tinyxml2 11 | gtkmm3 12 | gtksourceviewmm 13 | cairomm 14 | ) 15 | makedepends=("git" "cmake") 16 | source=("git+${url}.git") 17 | sha256sums=("SKIP") 18 | 19 | pkgver() { 20 | cd $_pkgname 21 | printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)" 22 | } 23 | 24 | build() { 25 | cd $_pkgname 26 | cmake -B build -S . -DCMAKE_BUILD_TYPE=None 27 | cmake --build build 28 | } 29 | 30 | package() { 31 | cd $_pkgname 32 | install -Dm0755 -t "$pkgdir/opt/$_pkgname/" build/LaTeX 33 | cp -r build/res "$pkgdir/opt/$_pkgname/" 34 | install -Dm0644 -t "$pkgdir/usr/share/licenses/$pkgname/" LICENSE 35 | } -------------------------------------------------------------------------------- /setup/after_update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BACKUP_DIR="$HOME/dotfiles/.backup" 4 | 5 | FILES_TO_RESTORE=( 6 | "./hypr/conf/custom/*" 7 | "./.settings/*" 8 | "./hypr/conf/apps.conf" 9 | "./wallpapers/*" 10 | "./hypr/hypridle.conf" 11 | "./electron-flags.conf" 12 | "./ags/README.md" 13 | "./ags/tsconfig.json", 14 | "./material-colors/custom.py" 15 | ) 16 | 17 | ask_continue() { 18 | local message=$1 19 | local exit_on_no=${2:-false} 20 | if gum confirm "$message"; then 21 | return 0 22 | else 23 | echo ":: Skipping $message." 24 | if $exit_on_no; then 25 | echo ":: Exiting script." 26 | exit 0 27 | else 28 | return 1 29 | fi 30 | fi 31 | } 32 | 33 | install_microtex() { 34 | cd $HOME/dotfiles/setup/MicroTex/ 35 | makepkg -si 36 | } 37 | 38 | restore_files() { 39 | for file_pattern in "${FILES_TO_RESTORE[@]}"; do 40 | for file in $BACKUP_DIR/$file_pattern; do 41 | if [ -e "$file" ]; then 42 | original_path="${file/$BACKUP_DIR\//}" 43 | cp "$file" "$original_path" 44 | echo "Restored: $original_path" 45 | fi 46 | done 47 | done 48 | } 49 | 50 | skip_worktree() { 51 | for file_pattern in "${FILES_TO_RESTORE[@]}"; do 52 | git update-index --skip-worktree $file_pattern 2>/dev/null || echo "Unable to mark: $file_pattern" 53 | done 54 | } 55 | 56 | copy_files() { 57 | "$HOME/dotfiles/setup/copy.sh" 58 | } 59 | 60 | cd $HOME/dotfiles 61 | git ls-files -v | grep '^S' | awk '{print $2}' | xargs git update-index --no-skip-worktree 62 | restore_files 63 | skip_worktree 64 | 65 | cp -f "$HOME/dotfiles/setup/wl-gammarelay.service" "$HOME/.config/systemd/user/" 66 | ask_continue "Import the old settings into the new settings?" && python "$HOME/dotfiles/setup/import_settings.py" 67 | ask_continue "Proceed with installing/updating packages?" && "$HOME/dotfiles/install.sh packages" 68 | ask_continue "Proceed with installing MicroTex?" && install_microtex 69 | ask_continue "Proceed to copy files?" && copy_files 70 | 71 | exit 0 72 | -------------------------------------------------------------------------------- /setup/agsv1/.gitignore: -------------------------------------------------------------------------------- 1 | /pkg/ 2 | /src/ 3 | /agsv1-* 4 | /libgnome-volume-control -------------------------------------------------------------------------------- /setup/agsv1/PKGBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: kotontrion 2 | 3 | # This package is only intended to be used while migrating from ags v1.8.2 to ags v2.0.0. 4 | # Many ags configs are quite big and it takes a while to migrate, therefore I made this package 5 | # to install ags v1.8.2 as "agsv1", so both versions can be installed at the same time, making it 6 | # possible to migrate bit by bit while still having a working v1 config around. 7 | # 8 | # First update the aylurs-gtk-shell package to v2, then install this one. 9 | # 10 | # This package won't receive any updates anymore, so as soon as you migrated, uninstall this one. 11 | 12 | pkgname=agsv1 13 | _pkgname=ags 14 | pkgver=1.9.0 15 | pkgrel=1 16 | pkgdesc="Aylurs's Gtk Shell (AGS), An eww inspired gtk widget system." 17 | arch=('x86_64') 18 | url="https://github.com/Aylur/ags" 19 | license=('GPL-3.0-only') 20 | makedepends=('git' 'gobject-introspection' 'meson' 'glib2-devel' 'npm' 'typescript') 21 | depends=('gjs' 'glib2' 'glibc' 'gtk3' 'gtk-layer-shell' 'libpulse' 'pam') 22 | optdepends=('gnome-bluetooth-3.0: required for bluetooth service' 23 | 'greetd: required for greetd service' 24 | 'libdbusmenu-gtk3: required for systemtray service' 25 | 'libsoup3: required for the Utils.fetch feature' 26 | 'libnotify: required for sending notifications' 27 | 'networkmanager: required for network service' 28 | 'power-profiles-daemon: required for powerprofiles service' 29 | 'upower: required for battery service') 30 | backup=('etc/pam.d/ags') 31 | source=("$pkgname-$pkgver.tar.gz::https://github.com/Aylur/ags/archive/refs/tags/v${pkgver}.tar.gz" 32 | "git+https://gitlab.gnome.org/GNOME/libgnome-volume-control") 33 | sha256sums=('962f99dcf202eef30e978d1daedc7cdf213e07a3b52413c1fb7b54abc7bd08e6' 34 | SKIP) 35 | 36 | prepare() { 37 | cd "$srcdir/$_pkgname-$pkgver" 38 | rm -rf subprojects/gvc 39 | mv -T "$srcdir"/libgnome-volume-control subprojects/gvc 40 | } 41 | 42 | build() { 43 | cd "$srcdir/$_pkgname-$pkgver" 44 | npm install 45 | arch-meson build --libdir "lib/$_pkgname" -Dbuild_types=true 46 | meson compile -C build 47 | } 48 | 49 | package() { 50 | cd "$srcdir/$_pkgname-$pkgver" 51 | meson install -C build --destdir "$pkgdir" 52 | rm ${pkgdir}/usr/bin/ags 53 | ln -sf /usr/share/com.github.Aylur.ags/com.github.Aylur.ags ${pkgdir}/usr/bin/agsv1 54 | } 55 | -------------------------------------------------------------------------------- /setup/copy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo ":: gtk..." 3 | mv $HOME/.config/gtk-3.0 --backup $HOME/.config/gtk-3.0-bk 4 | mv $HOME/.config/gtk-4.0 --backup $HOME/.config/gtk-4.0-bk 5 | cp -r -f $HOME/dotfiles/setup/gtk-3.0 $HOME/.config/ 6 | cp -r -f $HOME/dotfiles/setup/gtk-4.0 $HOME/.config/ 7 | echo ":: wl-gammarelay..." 8 | mkdir -p $HOME/.config/systemd/user/ 9 | cp $HOME/dotfiles/setup/wl-gammarelay.service $HOME/.config/systemd/user/ 10 | systemctl --user daemon-reload 11 | systemctl --user enable --now wl-gammarelay.service 12 | echo ":: Product Sans font" 13 | sudo cp -r $HOME/dotfiles/setup/google-sans /usr/share/fonts 14 | sudo fc-cache -f -v 15 | echo ":: Done!" 16 | -------------------------------------------------------------------------------- /setup/google-sans/ProductSans-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/setup/google-sans/ProductSans-Black.ttf -------------------------------------------------------------------------------- /setup/google-sans/ProductSans-BlackItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/setup/google-sans/ProductSans-BlackItalic.ttf -------------------------------------------------------------------------------- /setup/google-sans/ProductSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/setup/google-sans/ProductSans-Bold.ttf -------------------------------------------------------------------------------- /setup/google-sans/ProductSans-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/setup/google-sans/ProductSans-BoldItalic.ttf -------------------------------------------------------------------------------- /setup/google-sans/ProductSans-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/setup/google-sans/ProductSans-Italic.ttf -------------------------------------------------------------------------------- /setup/google-sans/ProductSans-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/setup/google-sans/ProductSans-Light.ttf -------------------------------------------------------------------------------- /setup/google-sans/ProductSans-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/setup/google-sans/ProductSans-LightItalic.ttf -------------------------------------------------------------------------------- /setup/google-sans/ProductSans-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/setup/google-sans/ProductSans-Medium.ttf -------------------------------------------------------------------------------- /setup/google-sans/ProductSans-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/setup/google-sans/ProductSans-MediumItalic.ttf -------------------------------------------------------------------------------- /setup/google-sans/ProductSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/setup/google-sans/ProductSans-Regular.ttf -------------------------------------------------------------------------------- /setup/google-sans/ProductSans-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/setup/google-sans/ProductSans-Thin.ttf -------------------------------------------------------------------------------- /setup/google-sans/ProductSans-ThinItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/setup/google-sans/ProductSans-ThinItalic.ttf -------------------------------------------------------------------------------- /setup/gtk-3.0/settings.ini: -------------------------------------------------------------------------------- 1 | [Settings] 2 | gtk-theme-name=adw-gtk3 3 | gtk-icon-theme-name=Tela-nord 4 | gtk-font-name=Product Sans 12 5 | gtk-cursor-theme-name=Bibata-Modern-Ice 6 | gtk-cursor-theme-size=24 7 | gtk-toolbar-style=GTK_TOOLBAR_ICONS 8 | gtk-toolbar-icon-size=GTK_ICON_SIZE_LARGE_TOOLBAR 9 | gtk-button-images=0 10 | gtk-menu-images=0 11 | gtk-enable-event-sounds=0 12 | gtk-enable-input-feedback-sounds=0 13 | gtk-xft-antialias=1 14 | gtk-xft-hinting=1 15 | gtk-xft-hintstyle=hintslight 16 | gtk-xft-rgba=rgb 17 | gtk-application-prefer-dark-theme=1 18 | -------------------------------------------------------------------------------- /setup/import_settings.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | from os import path 4 | import shutil 5 | 6 | settings = path.expanduser("~/dotfiles/.settings") 7 | settings_json = f"{settings}/settings.json" 8 | apps_json = f"{settings}/apps.json" 9 | 10 | 11 | files = { 12 | "settings": { 13 | f"{settings}/custom-color": "custom-color", 14 | f"{settings}/swww-anim": "swww-anim", 15 | f"{settings}/color-scheme": "color-scheme", 16 | f"{settings}/generation-scheme": "generation-scheme", 17 | f"{settings}/wallpaper-engine.sh": "wallpaper-engine" 18 | }, 19 | "apps": { 20 | f"{settings}/browser.sh": "browser", 21 | f"{settings}/editor.sh": "editor", 22 | f"{settings}/filemanager.sh": "filemanager", 23 | f"{settings}/terminal.sh": "terminal" 24 | } 25 | } 26 | 27 | if not path.isfile(settings_json): 28 | print(f":: File \"{settings_json}\" does not exist!") 29 | exit(1) 30 | if not path.isfile(apps_json): 31 | print(f":: File \"{apps_json}\" does not exist!") 32 | exit(1) 33 | 34 | print(":: Loading files") 35 | with open(settings_json) as f: 36 | settings_c = json.load(f) 37 | with open(apps_json) as f: 38 | apps_c = json.load(f) 39 | 40 | print(":: Importing") 41 | for file in files["apps"]: 42 | if path.isfile(file): 43 | with open(file) as f: 44 | apps_c[files["apps"][file]] = f.read().strip() 45 | else: 46 | print(f": File {file} doesn't exists") 47 | for file in files["settings"]: 48 | if path.isfile(file): 49 | with open(file) as f: 50 | settings_c[files["settings"][file]] = f.read().strip() 51 | else: 52 | print(f": File {file} doesn't exists") 53 | 54 | print(":: Saving") 55 | with open(settings_json, 'w') as f: 56 | json.dump(settings_c, f, indent=2) 57 | with open(apps_json, 'w') as f: 58 | json.dump(apps_c, f, indent=2) 59 | 60 | print(":: Backing up old files") 61 | old_files = [ 62 | f for f in os.listdir(settings) 63 | if os.path.isfile(os.path.join(settings, f)) 64 | ] 65 | backup_folder = f"{settings}/old" 66 | ignore = ["icon-theme", "settings.json", "apps.json"] 67 | os.makedirs(backup_folder, exist_ok=True) 68 | for x in old_files: 69 | if x.strip() not in ignore: 70 | shutil.move(f"{settings}/{x}", f"{backup_folder}/{x}") 71 | -------------------------------------------------------------------------------- /setup/wl-gammarelay.service: -------------------------------------------------------------------------------- 1 | 2 | [Unit] 3 | Description=wl-gammarelay service 4 | After=graphical-session.target 5 | ConditionEnvironment=WAYLAND_DISPLAY 6 | 7 | [Service] 8 | ExecStart=/usr/bin/wl-gammarelay-rs 9 | Restart=always 10 | Environment="XDG_RUNTIME_DIR=/run/user/%U" 11 | 12 | [Install] 13 | WantedBy=default.target 14 | -------------------------------------------------------------------------------- /swappy/config: -------------------------------------------------------------------------------- 1 | [Default] 2 | save_dir=$HOME/Pictures/screenshots 3 | save_filename_format=screenshot-%Y%m%d-%H%M%S.png 4 | show_panel=false 5 | line_size=5 6 | text_size=20 7 | text_font=sans-serif 8 | paint_mode=brush 9 | early_exit=false 10 | fill_shape=false 11 | -------------------------------------------------------------------------------- /update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | NOTIFICATION_SENT_FILE="/tmp/git_update_notification_sent" 3 | FORCE_UPDATE=false 4 | 5 | if [ "$1" == "--force" ]; then 6 | FORCE_UPDATE=true 7 | fi 8 | 9 | perform_update() { 10 | echo ":: Removing skip-worktree flags..." 11 | git ls-files -v | grep '^S' | awk '{print $2}' | xargs git update-index --no-skip-worktree 12 | 13 | BACKUP_DIR="$HOME/dotfiles/.backup" 14 | TIMESTAMP=$(date +%F_%H-%M-%S) 15 | 16 | if [ -d "$BACKUP_DIR" ]; then 17 | NEW_BACKUP_DIR="${BACKUP_DIR}_old/${TIMESTAMP}" 18 | mkdir -p "$NEW_BACKUP_DIR" 19 | echo ":: Moving existing backup to $NEW_BACKUP_DIR..." 20 | mv "$BACKUP_DIR" "$NEW_BACKUP_DIR" 21 | fi 22 | 23 | echo ":: Creating backup of modified files..." 24 | mkdir -p "$BACKUP_DIR" 25 | 26 | git diff --name-only | while read -r file; do 27 | if [ -f "$file" ]; then 28 | mkdir -p "$BACKUP_DIR/$(dirname "$file")" 29 | cp "$file" "$BACKUP_DIR/$file" 30 | fi 31 | done 32 | 33 | echo ":: Performing repository update..." 34 | git fetch origin 35 | 36 | CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) 37 | 38 | echo ":: Performing hard reset..." 39 | git reset --hard origin/$CURRENT_BRANCH 40 | 41 | echo ":: Running post-update script..." 42 | "$HOME/dotfiles/setup/after_update.sh" 43 | 44 | rm -f $NOTIFICATION_SENT_FILE 45 | } 46 | 47 | "$HOME/dotfiles/scripts/check_updates.sh" >/dev/null 48 | status=$? 49 | 50 | case $status in 51 | 0) 52 | echo ":: No updates available." 53 | if [ "$FORCE_UPDATE" == true ]; then 54 | echo ":: Forcing update despite no updates..." 55 | perform_update 56 | fi 57 | ;; 58 | 1) 59 | echo ":: Cannot update: Changes detected in files." 60 | if [ "$FORCE_UPDATE" == true ]; then 61 | echo ":: Forcing update despite local changes..." 62 | perform_update 63 | else 64 | echo ":: You can write \"$ git diff-index --name-only HEAD --\" to see which files have changed" 65 | echo ":: Use --force to ignore changes" 66 | exit 1 67 | fi 68 | ;; 69 | 2) 70 | echo ":: Updates are available." 71 | perform_update 72 | ;; 73 | 3) 74 | echo ":: Branches have diverged. Manual intervention may be required." 75 | if [ "$FORCE_UPDATE" == true ]; then 76 | echo ":: Forcing update despite branch divergence..." 77 | perform_update 78 | fi 79 | ;; 80 | *) 81 | echo ":: Unknown error." 82 | ;; 83 | esac 84 | -------------------------------------------------------------------------------- /wallpapers/birdandcat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/wallpapers/birdandcat.jpg -------------------------------------------------------------------------------- /wallpapers/default.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/wallpapers/default.jpg -------------------------------------------------------------------------------- /wallpapers/kath.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/wallpapers/kath.png -------------------------------------------------------------------------------- /wallpapers/lofi-late-night-cats-iz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/wallpapers/lofi-late-night-cats-iz.jpg -------------------------------------------------------------------------------- /wallpapers/luminism-morning-landscape-ks.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/wallpapers/luminism-morning-landscape-ks.jpg -------------------------------------------------------------------------------- /wallpapers/minimalist-moon-night-mountains.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koeqaife/hyprland-material-you/ec3b3d588c71306d3e0738971d76363370ea539d/wallpapers/minimalist-moon-night-mountains.jpg --------------------------------------------------------------------------------