diff --git a/config/ags/config.js b/config/ags/config.js new file mode 100644 index 0000000..278bf35 --- /dev/null +++ b/config/ags/config.js @@ -0,0 +1,31 @@ +"use strict"; +import GLib from 'gi://GLib'; +import App from 'resource:///com/github/Aylur/ags/app.js' +import userOptions from './modules/.configuration/user_options.js'; +import Overview from './modules/overview/main.js'; + +const COMPILED_STYLE_DIR = `${GLib.get_user_config_dir()}/ags/user/` + +async function applyStyle() { + + App.resetCss(); + App.applyCss(`${COMPILED_STYLE_DIR}/style.css`); + console.log('[LOG] Styles loaded') +} +applyStyle().catch(print); + +const Windows = () => [ + Overview() +]; +const CLOSE_ANIM_TIME = 210; +App.config({ + css: `${COMPILED_STYLE_DIR}/style.css`, + stackTraceOnError: true, + closeWindowDelay: { + 'sideright': CLOSE_ANIM_TIME, + 'sideleft': CLOSE_ANIM_TIME, + 'osk': CLOSE_ANIM_TIME, + }, + windows: Windows().flat(1), +}); + diff --git a/config/ags/modules/.configuration/user_options.js b/config/ags/modules/.configuration/user_options.js new file mode 100644 index 0000000..0c76a54 --- /dev/null +++ b/config/ags/modules/.configuration/user_options.js @@ -0,0 +1,121 @@ + +import userOverrides from '../../user_options.js'; + +// Defaults +let configOptions = { + // General stuff + 'ai': { + 'defaultGPTProvider': "openai", + 'defaultTemperature': 0.9, + 'enhancements': true, + 'useHistory': true, + 'writingCursor': " ...", // Warning: Using weird characters can mess up Markdown rendering + }, + 'animations': { + 'choreographyDelay': 35, + 'durationSmall': 110, + 'durationLarge': 180, + }, + 'appearance': { + 'keyboardUseFlag': false, // Use flag emoji instead of abbreviation letters + }, + 'apps': { + 'imageViewer': "loupe", + 'terminal': "foot", // This is only for shell actions + }, + 'battery': { + 'low': 20, + 'critical': 10, + }, + 'music': { + 'preferredPlayer': "plasma-browser-integration", + }, + 'onScreenKeyboard': { + 'layout': "qwerty_full", // See modules/onscreenkeyboard/onscreenkeyboard.js for available layouts + }, + 'overview': { + 'scale': 0.18, // Relative to screen size + 'numOfRows': 2, + 'numOfCols': 5, + 'wsNumScale': 0.09, + 'wsNumMarginScale': 0.07, + }, + 'sidebar': { + 'imageColumns': 2, + 'imageBooruCount': 20, + 'imageAllowNsfw': false, + }, + 'search': { + 'engineBaseUrl': "https://www.google.com/search?q=", + 'excludedSites': [], //add site to exclude from result. eg: "quora.com" + }, + 'time': { + // See https://docs.gtk.org/glib/method.DateTime.format.html + // Here's the 12h format: "%I:%M%P" + // For seconds, add "%S" and set interval to 1000 + 'format': "%H:%M", + 'interval': 5000, + 'dateFormatLong': "%A, %d/%m", // On bar + 'dateInterval': 5000, + 'dateFormat': "%d/%m", // On notif time + }, + 'weather': { + 'city': "", + }, + 'workspaces': { + 'shown': 10, + }, + // Longer stuff + 'icons': { + substitutions: { + 'code-url-handler': "visual-studio-code", + 'Code': "visual-studio-code", + 'GitHub Desktop': "github-desktop", + 'Minecraft* 1.20.1': "minecraft", + 'gnome-tweaks': "org.gnome.tweaks", + 'pavucontrol-qt': "pavucontrol", + 'wps': "wps-office2019-kprometheus", + 'wpsoffice': "wps-office2019-kprometheus", + '': "image-missing", + } + }, + 'keybinds': { + // Format: Mod1+Mod2+key. CaSe SeNsItIvE! + // Modifiers: Shift Ctrl Alt Hyper Meta + // See https://docs.gtk.org/gdk3/index.html#constants for the other keys (they are listed as KEY_key) + 'overview': { + 'altMoveLeft': "Ctrl+b", + 'altMoveRight': "Ctrl+f", + 'deleteToEnd': "Ctrl+k", + }, + 'sidebar': { + 'apis': { + 'nextTab': "Page_Down", + 'prevTab': "Page_Up", + }, + 'options': { // Right sidebar + 'nextTab': "Page_Down", + 'prevTab': "Page_Up", + }, + 'pin': "Ctrl+p", + 'cycleTab': "Ctrl+Tab", + 'nextTab': "Ctrl+Page_Down", + 'prevTab': "Ctrl+Page_Up", + }, + }, +} + +// Override defaults with user's options +function overrideConfigRecursive(userOverrides, configOptions = {}) { + for (const [key, value] of Object.entries(userOverrides)) { + if (typeof value === 'object') { + overrideConfigRecursive(value, configOptions[key]); + } else { + configOptions[key] = value; + } + } +} +overrideConfigRecursive(userOverrides, configOptions); + +globalThis['userOptions'] = configOptions; +export default configOptions; \ No newline at end of file diff --git a/config/ags/modules/.miscutils/icons.js b/config/ags/modules/.miscutils/icons.js new file mode 100644 index 0000000..fb1e20d --- /dev/null +++ b/config/ags/modules/.miscutils/icons.js @@ -0,0 +1,13 @@ +const { Gtk } = imports.gi; + +export function iconExists(iconName) { + let iconTheme = Gtk.IconTheme.get_default(); + return iconTheme.has_icon(iconName); +} + +export function substitute(str) { + if(userOptions.icons.substitutions[str]) return userOptions.icons.substitutions[str]; + + if (!iconExists(str)) str = str.toLowerCase().replace(/\s+/g, '-'); // Turn into kebab-case + return str; +} \ No newline at end of file diff --git a/config/ags/modules/.miscutils/mathfuncs.js b/config/ags/modules/.miscutils/mathfuncs.js new file mode 100644 index 0000000..ba1c0b5 --- /dev/null +++ b/config/ags/modules/.miscutils/mathfuncs.js @@ -0,0 +1,4 @@ + +export function clamp(x, min, max) { + return Math.min(Math.max(x, min), max); +} \ No newline at end of file diff --git a/config/ags/modules/.miscutils/system.js b/config/ags/modules/.miscutils/system.js new file mode 100644 index 0000000..ef7d15c --- /dev/null +++ b/config/ags/modules/.miscutils/system.js @@ -0,0 +1,54 @@ +const { GLib } = imports.gi; +import Variable from 'resource:///com/github/Aylur/ags/variable.js'; +import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; +const { execAsync, exec } = Utils; + +export const distroID = exec(`bash -c 'cat /etc/os-release | grep "^ID=" | cut -d "=" -f 2 | sed "s/\\"//g"'`).trim(); +export const isDebianDistro = (distroID == 'linuxmint' || distroID == 'ubuntu' || distroID == 'debian' || distroID == 'zorin' || distroID == 'popos' || distroID == 'raspbian' || distroID == 'kali'); +export const isArchDistro = (distroID == 'arch' || distroID == 'endeavouros' || distroID == 'cachyos'); +export const hasFlatpak = !!exec(`bash -c 'command -v flatpak'`); + +const LIGHTDARK_FILE_LOCATION = `${GLib.get_user_cache_dir()}/ags/user/colormode.txt`; +const colorMode = Utils.exec('bash -c "sed -n \'1p\' $HOME/.cache/ags/user/colormode.txt"'); +export let darkMode = Variable(!(Utils.readFile(LIGHTDARK_FILE_LOCATION).split('\n')[0].trim() == 'light')); +export const hasPlasmaIntegration = !!Utils.exec('bash -c "command -v plasma-browser-integration-host"'); + +export const getDistroIcon = () => { + // Arches + if(distroID == 'arch') return 'arch-symbolic'; + if(distroID == 'endeavouros') return 'endeavouros-symbolic'; + if(distroID == 'cachyos') return 'cachyos-symbolic'; + // Funny flake + if(distroID == 'nixos') return 'nixos-symbolic'; + // Cool thing + if(distroID == 'fedora') return 'fedora-symbolic'; + // Debians + if(distroID == 'linuxmint') return 'ubuntu-symbolic'; + if(distroID == 'ubuntu') return 'ubuntu-symbolic'; + if(distroID == 'debian') return 'debian-symbolic'; + if(distroID == 'zorin') return 'ubuntu-symbolic'; + if(distroID == 'popos') return 'ubuntu-symbolic'; + if(distroID == 'raspbian') return 'debian-symbolic'; + if(distroID == 'kali') return 'debian-symbolic'; + return 'linux-symbolic'; +} + +export const getDistroName = () => { + // Arches + if(distroID == 'arch') return 'Arch Linux'; + if(distroID == 'endeavouros') return 'EndeavourOS'; + if(distroID == 'cachyos') return 'CachyOS'; + // Funny flake + if(distroID == 'nixos') return 'NixOS'; + // Cool thing + if(distroID == 'fedora') return 'Fedora'; + // Debians + if(distroID == 'linuxmint') return 'Linux Mint'; + if(distroID == 'ubuntu') return 'Ubuntu'; + if(distroID == 'debian') return 'Debian'; + if(distroID == 'zorin') return 'Zorin'; + if(distroID == 'popos') return 'Pop!_OS'; + if(distroID == 'raspbian') return 'Raspbian'; + if(distroID == 'kali') return 'Kali Linux'; + return 'Linux'; +} diff --git a/config/ags/modules/.widgethacks/advancedrevealers.js b/config/ags/modules/.widgethacks/advancedrevealers.js new file mode 100644 index 0000000..3f12793 --- /dev/null +++ b/config/ags/modules/.widgethacks/advancedrevealers.js @@ -0,0 +1,86 @@ +import Widget from 'resource:///com/github/Aylur/ags/widget.js'; + +const { Revealer, Scrollable } = Widget; + +export const MarginRevealer = ({ + transition = 'slide_down', + child, + revealChild, + showClass = 'element-show', // These are for animation curve, they don't really hide + hideClass = 'element-hide', // Don't put margins in these classes! + extraSetup = () => { }, + ...rest +}) => { + const widget = Scrollable({ + ...rest, + attribute: { + 'revealChild': true, // It'll be set to false after init if it's supposed to hide + 'transition': transition, + 'show': () => { + if (widget.attribute.revealChild) return; + widget.hscroll = 'never'; + widget.vscroll = 'never'; + child.toggleClassName(hideClass, false); + child.toggleClassName(showClass, true); + widget.attribute.revealChild = true; + child.css = 'margin: 0px;'; + }, + 'hide': () => { + if (!widget.attribute.revealChild) return; + child.toggleClassName(hideClass, true); + child.toggleClassName(showClass, false); + widget.attribute.revealChild = false; + if (widget.attribute.transition == 'slide_left') + child.css = `margin-right: -${child.get_allocated_width()}px;`; + else if (widget.attribute.transition == 'slide_right') + child.css = `margin-left: -${child.get_allocated_width()}px;`; + else if (widget.attribute.transition == 'slide_up') + child.css = `margin-bottom: -${child.get_allocated_height()}px;`; + else if (widget.attribute.transition == 'slide_down') + child.css = `margin-top: -${child.get_allocated_height()}px;`; + }, + 'toggle': () => { + if (widget.attribute.revealChild) widget.attribute.hide(); + else widget.attribute.show(); + }, + }, + child: child, + hscroll: `${revealChild ? 'never' : 'always'}`, + vscroll: `${revealChild ? 'never' : 'always'}`, + setup: (self) => { + extraSetup(self); + } + }); + child.toggleClassName(`${revealChild ? showClass : hideClass}`, true); + return widget; +} + +// TODO: Allow reveal update. Currently this just helps at declaration +export const DoubleRevealer = ({ + transition1 = 'slide_right', + transition2 = 'slide_left', + duration1 = 150, + duration2 = 150, + child, + revealChild, + ...rest +}) => { + const r2 = Revealer({ + transition: transition2, + transitionDuration: duration2, + revealChild: revealChild, + child: child, + }); + const r1 = Revealer({ + transition: transition1, + transitionDuration: duration1, + revealChild: revealChild, + child: r2, + ...rest, + }) + r1.toggleRevealChild = (value) => { + r1.revealChild = value; + r2.revealChild = value; + } + return r1; +} diff --git a/config/ags/modules/.widgethacks/popupwindow.js b/config/ags/modules/.widgethacks/popupwindow.js new file mode 100644 index 0000000..26dad59 --- /dev/null +++ b/config/ags/modules/.widgethacks/popupwindow.js @@ -0,0 +1,32 @@ +import App from 'resource:///com/github/Aylur/ags/app.js'; +import Widget from 'resource:///com/github/Aylur/ags/widget.js'; +const { Box, Window } = Widget; + + +export default ({ + name, + child, + showClassName = "", + hideClassName = "", + ...props +}) => { + return Window({ + name, + visible: false, + layer: 'overlay', + ...props, + + child: Box({ + setup: (self) => { + self.hook(App, (self, currentName, visible) => { + if (currentName === name) { + self.toggleClassName(hideClassName, !visible); + } + }).keybind("Escape", () => App.closeWindow(name)) + if (showClassName !== "" && hideClassName !== "") + self.className = `${showClassName} ${hideClassName}`; + }, + child: child, + }), + }); +} \ No newline at end of file diff --git a/config/ags/modules/.widgetutils/clickthrough.js b/config/ags/modules/.widgetutils/clickthrough.js new file mode 100644 index 0000000..505f141 --- /dev/null +++ b/config/ags/modules/.widgetutils/clickthrough.js @@ -0,0 +1,4 @@ +import Cairo from 'gi://cairo?version=1.0'; + +export const dummyRegion = new Cairo.Region(); +export const enableClickthrough = (self) => self.input_shape_combine_region(dummyRegion); \ No newline at end of file diff --git a/config/ags/modules/.widgetutils/cursorhover.js b/config/ags/modules/.widgetutils/cursorhover.js new file mode 100644 index 0000000..89be913 --- /dev/null +++ b/config/ags/modules/.widgetutils/cursorhover.js @@ -0,0 +1,57 @@ +const { Gdk } = imports.gi; + +export function setupCursorHover(button) { // Hand pointing cursor on hover + const display = Gdk.Display.get_default(); + button.connect('enter-notify-event', () => { + const cursor = Gdk.Cursor.new_from_name(display, 'pointer'); + button.get_window().set_cursor(cursor); + }); + + button.connect('leave-notify-event', () => { + const cursor = Gdk.Cursor.new_from_name(display, 'default'); + button.get_window().set_cursor(cursor); + }); + +} + +export function setupCursorHoverAim(button) { // Crosshair cursor on hover + button.connect('enter-notify-event', () => { + const display = Gdk.Display.get_default(); + const cursor = Gdk.Cursor.new_from_name(display, 'crosshair'); + button.get_window().set_cursor(cursor); + }); + + button.connect('leave-notify-event', () => { + const display = Gdk.Display.get_default(); + const cursor = Gdk.Cursor.new_from_name(display, 'default'); + button.get_window().set_cursor(cursor); + }); +} + +export function setupCursorHoverGrab(button) { // Hand ready to grab on hover + button.connect('enter-notify-event', () => { + const display = Gdk.Display.get_default(); + const cursor = Gdk.Cursor.new_from_name(display, 'grab'); + button.get_window().set_cursor(cursor); + }); + + button.connect('leave-notify-event', () => { + const display = Gdk.Display.get_default(); + const cursor = Gdk.Cursor.new_from_name(display, 'default'); + button.get_window().set_cursor(cursor); + }); +} + +export function setupCursorHoverInfo(button) { // "?" mark cursor on hover + const display = Gdk.Display.get_default(); + button.connect('enter-notify-event', () => { + const cursor = Gdk.Cursor.new_from_name(display, 'help'); + button.get_window().set_cursor(cursor); + }); + + button.connect('leave-notify-event', () => { + const cursor = Gdk.Cursor.new_from_name(display, 'default'); + button.get_window().set_cursor(cursor); + }); +} + diff --git a/config/ags/modules/.widgetutils/keybind.js b/config/ags/modules/.widgetutils/keybind.js new file mode 100644 index 0000000..eda7877 --- /dev/null +++ b/config/ags/modules/.widgetutils/keybind.js @@ -0,0 +1,25 @@ +const { Gdk } = imports.gi; + +const MODS = { + 'Shift': Gdk.ModifierType.SHIFT_MASK, + 'Ctrl': Gdk.ModifierType.CONTROL_MASK, + 'Alt': Gdk.ModifierType.ALT_MASK, + 'Hyper': Gdk.ModifierType.HYPER_MASK, + 'Meta': Gdk.ModifierType.META_MASK +} + +export const checkKeybind = (event, keybind) => { + const pressedModMask = event.get_state()[1]; + const pressedKey = event.get_keyval()[1]; + const keys = keybind.split('+'); + for (let i = 0; i < keys.length; i++) { + if (keys[i] in MODS) { + if (!(pressedModMask & MODS[keys[i]])) { + return false; + } + } else if (pressedKey !== Gdk[`KEY_${keys[i]}`]) { + return false; + } + } + return true; +} diff --git a/config/ags/modules/overview/actions.js b/config/ags/modules/overview/actions.js new file mode 100644 index 0000000..766cf45 --- /dev/null +++ b/config/ags/modules/overview/actions.js @@ -0,0 +1,28 @@ +import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; +import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js'; + +function moveClientToWorkspace(address, workspace) { + Utils.execAsync(['bash', '-c', `hyprctl dispatch movetoworkspacesilent ${workspace},address:${address} &`]); +} + +export function dumpToWorkspace(from, to) { + if (from == to) return; + Hyprland.clients.forEach(client => { + if (client.workspace.id == from) { + moveClientToWorkspace(client.address, to); + } + }); +} + +export function swapWorkspace(workspaceA, workspaceB) { + if (workspaceA == workspaceB) return; + const clientsA = []; + const clientsB = []; + Hyprland.clients.forEach(client => { + if (client.workspace.id == workspaceA) clientsA.push(client.address); + if (client.workspace.id == workspaceB) clientsB.push(client.address); + }); + + clientsA.forEach((address) => moveClientToWorkspace(address, workspaceB)); + clientsB.forEach((address) => moveClientToWorkspace(address, workspaceA)); +} \ No newline at end of file diff --git a/config/ags/modules/overview/main.js b/config/ags/modules/overview/main.js new file mode 100644 index 0000000..1f5348d --- /dev/null +++ b/config/ags/modules/overview/main.js @@ -0,0 +1,18 @@ +import Widget from 'resource:///com/github/Aylur/ags/widget.js'; +import { SearchAndWindows } from "./windowcontent.js"; +import PopupWindow from '../.widgethacks/popupwindow.js'; + +export default (id = '') => PopupWindow({ + name: `overview${id}`, + exclusivity: 'ignore', + keymode: 'exclusive', + visible: false, + // anchor: ['middle'], + layer: 'overlay', + child: Widget.Box({ + vertical: true, + children: [ + SearchAndWindows(), + ] + }), +}) diff --git a/config/ags/modules/overview/miscfunctions.js b/config/ags/modules/overview/miscfunctions.js new file mode 100644 index 0000000..187ee6e --- /dev/null +++ b/config/ags/modules/overview/miscfunctions.js @@ -0,0 +1,155 @@ +const { Gio, GLib } = imports.gi; +import App from 'resource:///com/github/Aylur/ags/app.js'; +import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; +const { execAsync, exec } = Utils; +// import Todo from "../../services/todo.js"; +import { darkMode } from '../.miscutils/system.js'; + +export function hasUnterminatedBackslash(inputString) { + // Use a regular expression to match a trailing odd number of backslashes + const regex = /\\+$/; + return regex.test(inputString); +} + +export function launchCustomCommand(command) { + const args = command.toLowerCase().split(' '); + if (args[0] == '>raw') { // Mouse raw input + Utils.execAsync('hyprctl -j getoption input:accel_profile') + .then((output) => { + const value = JSON.parse(output)["str"].trim(); + if (value != "[[EMPTY]]" && value != "") { + execAsync(['bash', '-c', `hyprctl keyword input:accel_profile '[[EMPTY]]'`]).catch(print); + } + else { + execAsync(['bash', '-c', `hyprctl keyword input:accel_profile flat`]).catch(print); + } + }) + } + else if (args[0] == '>img') { // Change wallpaper + execAsync([`bash`, `-c`, `${App.configDir}/scripts/color_generation/switchwall.sh`, `&`]).catch(print); + } + else if (args[0] == '>color') { // Generate colorscheme from color picker + execAsync([`bash`, `-c`, `${App.configDir}/scripts/color_generation/switchcolor.sh --pick`, `&`]).catch(print); + } + else if (args[0] == '>light') { // Light mode + darkMode.value = false; + execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_cache_dir()}/ags/user && sed -i "1s/.*/light/" ${GLib.get_user_cache_dir()}/ags/user/colormode.txt`]) + .then(execAsync(['bash', '-c', `${App.configDir}/scripts/color_generation/switchcolor.sh`])) + .catch(print); + } + else if (args[0] == '>dark') { // Dark mode + darkMode.value = true; + execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_cache_dir()}/ags/user && sed -i "1s/.*/dark/" ${GLib.get_user_cache_dir()}/ags/user/colormode.txt`]) + .then(execAsync(['bash', '-c', `${App.configDir}/scripts/color_generation/switchcolor.sh`])) + .catch(print); + } + else if (args[0] == '>badapple') { // Black and white + execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_cache_dir()}/ags/user && sed -i "3s/.*/monochrome/" ${GLib.get_user_cache_dir()}/ags/user/colormode.txt`]) + .then(execAsync(['bash', '-c', `${App.configDir}/scripts/color_generation/switchcolor.sh`])) + .catch(print); + } + else if (args[0] == '>material') { // Use material colors + execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_cache_dir()}/ags/user && echo "material" > ${GLib.get_user_cache_dir()}/ags/user/colorbackend.txt`]).catch(print) + .then(execAsync(['bash', '-c', `${App.configDir}/scripts/color_generation/switchwall.sh --noswitch`]).catch(print)) + .catch(print); + } + else if (args[0] == '>pywal') { // Use Pywal (ik it looks shit but I'm not removing) + execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_cache_dir()}/ags/user && echo "pywal" > ${GLib.get_user_cache_dir()}/ags/user/colorbackend.txt`]).catch(print) + .then(execAsync(['bash', '-c', `${App.configDir}/scripts/color_generation/switchwall.sh --noswitch`]).catch(print)) + .catch(print); + } + else if (args[0] == '>todo') { // Todo + Todo.add(args.slice(1).join(' ')); + } + else if (args[0] == '>shutdown') { // Shut down + execAsync([`bash`, `-c`, `systemctl poweroff || loginctl poweroff`]).catch(print); + } + else if (args[0] == '>reboot') { // Reboot + execAsync([`bash`, `-c`, `systemctl reboot || loginctl reboot`]).catch(print); + } + else if (args[0] == '>sleep') { // Sleep + execAsync([`bash`, `-c`, `systemctl suspend || loginctl suspend`]).catch(print); + } + else if (args[0] == '>logout') { // Log out + execAsync([`bash`, `-c`, `pkill Hyprland || pkill sway`]).catch(print); + } +} + +export function execAndClose(command, terminal) { + App.closeWindow('overview'); + if (terminal) { + execAsync([`bash`, `-c`, `${userOptions.apps.terminal} fish -C "${command}"`, `&`]).catch(print); + } + else + execAsync(command).catch(print); +} + +export function couldBeMath(str) { + const regex = /^[0-9.+*/-]/; + return regex.test(str); +} + +export function expandTilde(path) { + if (path.startsWith('~')) { + return GLib.get_home_dir() + path.slice(1); + } else { + return path; + } +} + +function getFileIcon(fileInfo) { + let icon = fileInfo.get_icon(); + if (icon) { + // Get the icon's name + return icon.get_names()[0]; + } else { + // Default icon for files + return 'text-x-generic'; + } +} + +export function ls({ path = '~', silent = false }) { + let contents = []; + try { + let expandedPath = expandTilde(path); + if (expandedPath.endsWith('/')) + expandedPath = expandedPath.slice(0, -1); + let folder = Gio.File.new_for_path(expandedPath); + + let enumerator = folder.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null); + let fileInfo; + while ((fileInfo = enumerator.next_file(null)) !== null) { + let fileName = fileInfo.get_display_name(); + let fileType = fileInfo.get_file_type(); + + let item = { + parentPath: expandedPath, + name: fileName, + type: fileType === Gio.FileType.DIRECTORY ? 'folder' : 'file', + icon: getFileIcon(fileInfo), + }; + + // Add file extension for files + if (fileType === Gio.FileType.REGULAR) { + let fileExtension = fileName.split('.').pop(); + item.type = `${fileExtension}`; + } + + contents.push(item); + contents.sort((a, b) => { + const aIsFolder = a.type.startsWith('folder'); + const bIsFolder = b.type.startsWith('folder'); + if (aIsFolder && !bIsFolder) { + return -1; + } else if (!aIsFolder && bIsFolder) { + return 1; + } else { + return a.name.localeCompare(b.name); // Sort alphabetically within folders and files + } + }); + } + } catch (e) { + if (!silent) console.log(e); + } + return contents; +} diff --git a/config/ags/modules/overview/overview_hyprland.js b/config/ags/modules/overview/overview_hyprland.js new file mode 100644 index 0000000..034d6c8 --- /dev/null +++ b/config/ags/modules/overview/overview_hyprland.js @@ -0,0 +1,423 @@ +// TODO +// - Make client destroy/create not destroy and recreate the whole thing +// - Active ws hook optimization: only update when moving to next group +// +const { Gdk, Gtk } = imports.gi; +const { Gravity } = imports.gi.Gdk; +import { SCREEN_HEIGHT, SCREEN_WIDTH } from '../../variables.js'; +import App from 'resource:///com/github/Aylur/ags/app.js'; +import Variable from 'resource:///com/github/Aylur/ags/variable.js'; +import Widget from 'resource:///com/github/Aylur/ags/widget.js'; +import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; + +import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js'; +const { execAsync, exec } = Utils; +import { setupCursorHoverGrab } from '../.widgetutils/cursorhover.js'; +import { dumpToWorkspace, swapWorkspace } from "./actions.js"; +import { substitute } from "../.miscutils/icons.js"; + +const NUM_OF_WORKSPACES_SHOWN = userOptions.overview.numOfCols * userOptions.overview.numOfRows; +const TARGET = [Gtk.TargetEntry.new('text/plain', Gtk.TargetFlags.SAME_APP, 0)]; +const POPUP_CLOSE_TIME = 100; // ms + +const overviewTick = Variable(false); + +export default () => { + const clientMap = new Map(); + let workspaceGroup = 0; + const ContextMenuWorkspaceArray = ({ label, actionFunc, thisWorkspace }) => Widget.MenuItem({ + label: `${label}`, + setup: (menuItem) => { + let submenu = new Gtk.Menu(); + submenu.className = 'menu'; + + const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN; + const startWorkspace = offset + 1; + const endWorkspace = startWorkspace + NUM_OF_WORKSPACES_SHOWN - 1; + for (let i = startWorkspace; i <= endWorkspace; i++) { + let button = new Gtk.MenuItem({ + label: `Workspace ${i}` + }); + button.connect("activate", () => { + // execAsync([`${onClickBinary}`, `${thisWorkspace}`, `${i}`]).catch(print); + actionFunc(thisWorkspace, i); + overviewTick.setValue(!overviewTick.value); + }); + submenu.append(button); + } + menuItem.set_reserve_indicator(true); + menuItem.set_submenu(submenu); + } + }) + + const Window = ({ address, at: [x, y], size: [w, h], workspace: { id, name }, class: c, title, xwayland }, screenCoords) => { + const revealInfoCondition = (Math.min(w, h) * userOptions.overview.scale > 70); + if (w <= 0 || h <= 0 || (c === '' && title === '') || c.endsWith('-dropterm')) return null; + // Non-primary monitors + if (screenCoords.x != 0) x -= screenCoords.x; + if (screenCoords.y != 0) y -= screenCoords.y; + // Other offscreen adjustments + if (x + w <= 0) x += (Math.floor(x / SCREEN_WIDTH) * SCREEN_WIDTH); + else if (x < 0) { w = x + w; x = 0; } + if (y + h <= 0) x += (Math.floor(y / SCREEN_HEIGHT) * SCREEN_HEIGHT); + else if (y < 0) { h = y + h; y = 0; } + // Truncate if offscreen + if (x + w > SCREEN_WIDTH) w = SCREEN_WIDTH - x; + if (y + h > SCREEN_HEIGHT) h = SCREEN_HEIGHT - y; + + const appIcon = Widget.Icon({ + icon: substitute(c), + size: Math.min(w, h) * userOptions.overview.scale / 2.5, + }); + return Widget.Button({ + attribute: { + address, x, y, w, h, ws: id, + updateIconSize: (self) => { + appIcon.size = Math.min(self.attribute.w, self.attribute.h) * userOptions.overview.scale / 2.5; + }, + }, + className: 'overview-tasks-window', + hpack: 'start', + vpack: 'start', + css: ` + margin-left: ${Math.round(x * userOptions.overview.scale)}px; + margin-top: ${Math.round(y * userOptions.overview.scale)}px; + margin-right: -${Math.round((x + w) * userOptions.overview.scale)}px; + margin-bottom: -${Math.round((y + h) * userOptions.overview.scale)}px; + `, + onClicked: (self) => { + App.closeWindow('overview'); + Utils.timeout(POPUP_CLOSE_TIME, () => Hyprland.messageAsync(`dispatch focuswindow address:${address}`)); + }, + onMiddleClickRelease: () => Hyprland.messageAsync(`dispatch closewindow address:${address}`), + onSecondaryClick: (button) => { + button.toggleClassName('overview-tasks-window-selected', true); + const menu = Widget.Menu({ + className: 'menu', + children: [ + Widget.MenuItem({ + child: Widget.Label({ + xalign: 0, + label: "Close (Middle-click)", + }), + onActivate: () => Hyprland.messageAsync(`dispatch closewindow address:${address}`), + }), + ContextMenuWorkspaceArray({ + label: "Dump windows to workspace", + actionFunc: dumpToWorkspace, + thisWorkspace: Number(id) + }), + ContextMenuWorkspaceArray({ + label: "Swap windows with workspace", + actionFunc: swapWorkspace, + thisWorkspace: Number(id) + }), + ], + }); + menu.connect("deactivate", () => { + button.toggleClassName('overview-tasks-window-selected', false); + }) + menu.connect("selection-done", () => { + button.toggleClassName('overview-tasks-window-selected', false); + }) + menu.popup_at_widget(button.get_parent(), Gravity.SOUTH, Gravity.NORTH, null); // Show menu below the button + button.connect("destroy", () => menu.destroy()); + }, + child: Widget.Box({ + homogeneous: true, + child: Widget.Box({ + vertical: true, + vpack: 'center', + className: 'spacing-v-5', + children: [ + appIcon, + // TODO: Add xwayland tag instead of just having italics + Widget.Revealer({ + transition: 'slide_down', + revealChild: revealInfoCondition, + child: Widget.Label({ + maxWidthChars: 10, // Doesn't matter what number + truncate: 'end', + className: `${xwayland ? 'txt txt-italic' : 'txt'}`, + css: ` + font-size: ${Math.min(SCREEN_WIDTH, SCREEN_HEIGHT) * userOptions.overview.scale / 14.6}px; + margin: 0px ${Math.min(SCREEN_WIDTH, SCREEN_HEIGHT) * userOptions.overview.scale / 10}px; + `, + // If the title is too short, include the class + label: (title.length <= 1 ? `${c}: ${title}` : title), + }) + }) + ] + }) + }), + tooltipText: `${c}: ${title}`, + setup: (button) => { + setupCursorHoverGrab(button); + + button.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, TARGET, Gdk.DragAction.MOVE); + button.drag_source_set_icon_name(substitute(c)); + // button.drag_source_set_icon_gicon(icon); + + button.connect('drag-begin', (button) => { // On drag start, add the dragging class + button.toggleClassName('overview-tasks-window-dragging', true); + }); + button.connect('drag-data-get', (_w, _c, data) => { // On drag finish, give address + data.set_text(address, address.length); + button.toggleClassName('overview-tasks-window-dragging', false); + }); + }, + }); + } + + const Workspace = (index) => { + // const fixed = Widget.Fixed({ + // attribute: { + // put: (widget, x, y) => { + // fixed.put(widget, x, y); + // }, + // move: (widget, x, y) => { + // fixed.move(widget, x, y); + // }, + // } + // }); + const fixed = Widget.Box({ + attribute: { + put: (widget, x, y) => { + if (!widget.attribute) return; + // Note: x and y are already multiplied by userOptions.overview.scale + const newCss = ` + margin-left: ${Math.round(x)}px; + margin-top: ${Math.round(y)}px; + margin-right: -${Math.round(x + (widget.attribute.w * userOptions.overview.scale))}px; + margin-bottom: -${Math.round(y + (widget.attribute.h * userOptions.overview.scale))}px; + `; + widget.css = newCss; + fixed.pack_start(widget, false, false, 0); + }, + move: (widget, x, y) => { + if (!widget) return; + if (!widget.attribute) return; + // Note: x and y are already multiplied by userOptions.overview.scale + const newCss = ` + margin-left: ${Math.round(x)}px; + margin-top: ${Math.round(y)}px; + margin-right: -${Math.round(x + (widget.attribute.w * userOptions.overview.scale))}px; + margin-bottom: -${Math.round(y + (widget.attribute.h * userOptions.overview.scale))}px; + `; + widget.css = newCss; + }, + } + }) + const WorkspaceNumber = ({ index, ...rest }) => Widget.Label({ + className: 'overview-tasks-workspace-number', + label: `${index}`, + css: ` + margin: ${Math.min(SCREEN_WIDTH, SCREEN_HEIGHT) * userOptions.overview.scale * userOptions.overview.wsNumMarginScale}px; + font-size: ${SCREEN_HEIGHT * userOptions.overview.scale * userOptions.overview.wsNumScale}px; + `, + setup: (self) => self.hook(Hyprland.active.workspace, (self) => { + // Update when going to new ws group + const currentGroup = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN); + self.label = `${currentGroup * NUM_OF_WORKSPACES_SHOWN + index}`; + }), + ...rest, + }) + const widget = Widget.Box({ + className: 'overview-tasks-workspace', + vpack: 'center', + css: ` + min-width: ${SCREEN_WIDTH * userOptions.overview.scale}px; + min-height: ${SCREEN_HEIGHT * userOptions.overview.scale}px; + `, + children: [Widget.EventBox({ + hexpand: true, + vexpand: true, + onPrimaryClick: () => { + App.closeWindow('overview'); + Utils.timeout(POPUP_CLOSE_TIME, () => Hyprland.messageAsync(`dispatch workspace ${index}`)); + }, + setup: (eventbox) => { + eventbox.drag_dest_set(Gtk.DestDefaults.ALL, TARGET, Gdk.DragAction.COPY); + eventbox.connect('drag-data-received', (_w, _c, _x, _y, data) => { + const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN; + Hyprland.messageAsync(`dispatch movetoworkspacesilent ${index + offset},address:${data.get_text()}`) + overviewTick.setValue(!overviewTick.value); + }); + }, + child: Widget.Overlay({ + child: Widget.Box({}), + overlays: [ + WorkspaceNumber({ index: index, hpack: 'start', vpack: 'start' }), + fixed + ] + }), + })], + }); + const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN; + fixed.attribute.put(WorkspaceNumber(offset + index), 0, 0); + widget.clear = () => { + const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN; + clientMap.forEach((client, address) => { + if (!client) return; + if ((client.attribute.ws <= offset || client.attribute.ws > offset + NUM_OF_WORKSPACES_SHOWN) || + (client.attribute.ws == offset + index)) { + client.destroy(); + client = null; + clientMap.delete(address); + } + }); + } + widget.set = (clientJson, screenCoords) => { + let c = clientMap.get(clientJson.address); + if (c) { + if (c.attribute?.ws !== clientJson.workspace.id) { + c.destroy(); + c = null; + clientMap.delete(clientJson.address); + } + else if (c) { + c.attribute.w = clientJson.size[0]; + c.attribute.h = clientJson.size[1]; + c.attribute.updateIconSize(c); + fixed.attribute.move(c, + Math.max(0, clientJson.at[0] * userOptions.overview.scale), + Math.max(0, clientJson.at[1] * userOptions.overview.scale) + ); + return; + } + } + const newWindow = Window(clientJson, screenCoords); + if (newWindow === null) return; + // clientMap.set(clientJson.address, newWindow); + fixed.attribute.put(newWindow, + Math.max(0, newWindow.attribute.x * userOptions.overview.scale), + Math.max(0, newWindow.attribute.y * userOptions.overview.scale) + ); + clientMap.set(clientJson.address, newWindow); + }; + widget.unset = (clientAddress) => { + const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN; + let c = clientMap.get(clientAddress); + if (!c) return; + c.destroy(); + c = null; + clientMap.delete(clientAddress); + }; + widget.show = () => { + fixed.show_all(); + } + return widget; + }; + + const arr = (s, n) => { + const array = []; + for (let i = 0; i < n; i++) + array.push(s + i); + + return array; + }; + + const OverviewRow = ({ startWorkspace, workspaces, windowName = 'overview' }) => Widget.Box({ + children: arr(startWorkspace, workspaces).map(Workspace), + attribute: { + monitorMap: [], + getMonitorMap: (box) => { + execAsync('hyprctl -j monitors').then(monitors => { + box.attribute.monitorMap = JSON.parse(monitors).reduce((acc, item) => { + acc[item.id] = { x: item.x, y: item.y }; + return acc; + }, {}); + }); + }, + update: (box) => { + const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN; + if (!App.getWindow(windowName).visible) return; + Hyprland.messageAsync('j/clients').then(clients => { + const allClients = JSON.parse(clients); + const kids = box.get_children(); + kids.forEach(kid => kid.clear()); + for (let i = 0; i < allClients.length; i++) { + const client = allClients[i]; + const childID = client.workspace.id - (offset + startWorkspace); + if (offset + startWorkspace <= client.workspace.id && + client.workspace.id <= offset + startWorkspace + workspaces) { + const screenCoords = box.attribute.monitorMap[client.monitor]; + if (kids[childID]) { + kids[childID].set(client, screenCoords); + } + continue; + } + } + kids.forEach(kid => kid.show()); + }).catch(print); + }, + updateWorkspace: (box, id) => { + const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN; + if (!( // Not in range, ignore + offset + startWorkspace <= id && + id <= offset + startWorkspace + workspaces + )) return; + // if (!App.getWindow(windowName).visible) return; + Hyprland.messageAsync('j/clients').then(clients => { + const allClients = JSON.parse(clients); + const kids = box.get_children(); + for (let i = 0; i < allClients.length; i++) { + const client = allClients[i]; + if (client.workspace.id != id) continue; + const screenCoords = box.attribute.monitorMap[client.monitor]; + kids[id - (offset + startWorkspace)]?.set(client, screenCoords); + } + kids[id - (offset + startWorkspace)]?.show(); + }).catch(print); + }, + }, + setup: (box) => { + box.attribute.getMonitorMap(box); + box + .hook(overviewTick, (box) => box.attribute.update(box)) + .hook(Hyprland, (box, clientAddress) => { + const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN; + const kids = box.get_children(); + const client = Hyprland.getClient(clientAddress); + if (!client) return; + const id = client.workspace.id; + + box.attribute.updateWorkspace(box, id); + kids[id - (offset + startWorkspace)]?.unset(clientAddress); + }, 'client-removed') + .hook(Hyprland, (box, clientAddress) => { + const client = Hyprland.getClient(clientAddress); + if (!client) return; + box.attribute.updateWorkspace(box, client.workspace.id); + }, 'client-added') + .hook(Hyprland.active.workspace, (box) => { + // Full update when going to new ws group + const previousGroup = box.attribute.workspaceGroup; + const currentGroup = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN); + if (currentGroup !== previousGroup) { + box.attribute.update(box); + box.attribute.workspaceGroup = currentGroup; + } + }) + .hook(App, (box, name, visible) => { // Update on open + if (name == 'overview' && visible) box.attribute.update(box); + }) + }, + }); + + return Widget.Revealer({ + revealChild: true, + transition: 'slide_down', + transitionDuration: userOptions.animations.durationLarge, + child: Widget.Box({ + vertical: true, + className: 'overview-tasks', + children: Array.from({ length: userOptions.overview.numOfRows }, (_, index) => + OverviewRow({ + startWorkspace: 1 + index * userOptions.overview.numOfCols, + workspaces: userOptions.overview.numOfCols, + }) + ) + }), + }); +} \ No newline at end of file diff --git a/config/ags/modules/overview/searchbuttons.js b/config/ags/modules/overview/searchbuttons.js new file mode 100644 index 0000000..f5892f3 --- /dev/null +++ b/config/ags/modules/overview/searchbuttons.js @@ -0,0 +1,163 @@ +const { Gtk } = imports.gi; +import App from 'resource:///com/github/Aylur/ags/app.js'; +import Widget from 'resource:///com/github/Aylur/ags/widget.js'; +import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; +const { execAsync, exec } = Utils; +import { searchItem } from './searchitem.js'; +import { execAndClose, couldBeMath, launchCustomCommand } from './miscfunctions.js'; + +export const DirectoryButton = ({ parentPath, name, type, icon }) => { + const actionText = Widget.Revealer({ + revealChild: false, + transition: "crossfade", + transitionDuration: userOptions.animations.durationLarge, + child: Widget.Label({ + className: 'overview-search-results-txt txt txt-small txt-action', + label: 'Open', + }) + }); + const actionTextRevealer = Widget.Revealer({ + revealChild: false, + transition: "slide_left", + transitionDuration: userOptions.animations.durationSmall, + child: actionText, + }); + return Widget.Button({ + className: 'overview-search-result-btn', + onClicked: () => { + App.closeWindow('overview'); + execAsync(['bash', '-c', `xdg-open '${parentPath}/${name}'`, `&`]).catch(print); + }, + child: Widget.Box({ + children: [ + Widget.Box({ + vertical: false, + children: [ + Widget.Box({ + className: 'overview-search-results-icon', + homogeneous: true, + child: Widget.Icon({ + icon: icon, + }), + }), + Widget.Label({ + className: 'overview-search-results-txt txt txt-norm', + label: name, + }), + Widget.Box({ hexpand: true }), + actionTextRevealer, + ] + }) + ] + }), + setup: (self) => self + .on('focus-in-event', (button) => { + actionText.revealChild = true; + actionTextRevealer.revealChild = true; + }) + .on('focus-out-event', (button) => { + actionText.revealChild = false; + actionTextRevealer.revealChild = false; + }) + , + }) +} + +export const CalculationResultButton = ({ result, text }) => searchItem({ + materialIconName: '󱖦 ', + name: `Math result`, + actionName: "Copy", + content: `${result}`, + onActivate: () => { + App.closeWindow('overview'); + execAsync(['wl-copy', `${result}`]).catch(print); + }, +}); + +export const DesktopEntryButton = (app) => { + const actionText = Widget.Revealer({ + revealChild: false, + transition: "crossfade", + transitionDuration: userOptions.animations.durationLarge, + child: Widget.Label({ + className: 'overview-search-results-txt txt txt-small txt-action', + label: 'Launch', + }) + }); + const actionTextRevealer = Widget.Revealer({ + revealChild: false, + transition: "slide_left", + transitionDuration: userOptions.animations.durationSmall, + child: actionText, + }); + return Widget.Button({ + className: 'overview-search-result-btn', + onClicked: () => { + App.closeWindow('overview'); + app.launch(); + }, + child: Widget.Box({ + children: [ + Widget.Box({ + vertical: false, + children: [ + Widget.Box({ + className: 'overview-search-results-icon', + homogeneous: true, + child: Widget.Icon({ + icon: app.iconName, + }), + }), + Widget.Label({ + className: 'overview-search-results-txt txt txt-norm', + label: app.name, + }), + Widget.Box({ hexpand: true }), + actionTextRevealer, + ] + }) + ] + }), + setup: (self) => self + .on('focus-in-event', (button) => { + actionText.revealChild = true; + actionTextRevealer.revealChild = true; + }) + .on('focus-out-event', (button) => { + actionText.revealChild = false; + actionTextRevealer.revealChild = false; + }) + , + }) +} + +export const ExecuteCommandButton = ({ command, terminal = false }) => searchItem({ + materialIconName: `${terminal ? 'terminal' : ' '}`, + name: `Run command`, + actionName: `Execute ${terminal ? 'in terminal' : ''}`, + content: `${command}`, + onActivate: () => execAndClose(command, terminal), + extraClassName: 'techfont', +}) + +export const CustomCommandButton = ({ text = '' }) => searchItem({ + materialIconName: ' ', + name: 'Action', + actionName: 'Run', + content: `${text}`, + onActivate: () => { + App.closeWindow('overview'); + launchCustomCommand(text); + }, +}); + +export const SearchButton = ({ text = '' }) => searchItem({ + materialIconName: '󰜏 ', + name: 'Search the web', + actionName: 'Go', + content: `${text}`, + onActivate: () => { + App.closeWindow('overview'); + execAsync(['bash', '-c', `xdg-open '${userOptions.search.engineBaseUrl}${text} ${['', ...userOptions.search.excludedSites].join(' -site:')}' &`]).catch(print); + }, +}); \ No newline at end of file diff --git a/config/ags/modules/overview/searchitem.js b/config/ags/modules/overview/searchitem.js new file mode 100644 index 0000000..2a3303a --- /dev/null +++ b/config/ags/modules/overview/searchitem.js @@ -0,0 +1,65 @@ +import Widget from 'resource:///com/github/Aylur/ags/widget.js'; + +export const searchItem = ({ materialIconName, name, actionName, content, onActivate, extraClassName = '', ...rest }) => { + const actionText = Widget.Revealer({ + revealChild: false, + transition: "crossfade", + transitionDuration: userOptions.animations.durationLarge, + child: Widget.Label({ + className: 'overview-search-results-txt txt txt-small txt-action', + label: `${actionName}`, + }) + }); + const actionTextRevealer = Widget.Revealer({ + revealChild: false, + transition: "slide_left", + transitionDuration: userOptions.animations.durationSmall, + child: actionText, + }) + return Widget.Button({ + className: `overview-search-result-btn txt ${extraClassName}`, + onClicked: onActivate, + child: Widget.Box({ + children: [ + Widget.Box({ + vertical: false, + children: [ + Widget.Label({ + className: `icon-material overview-search-results-icon`, + label: `${materialIconName}`, + }), + Widget.Box({ + vertical: true, + children: [ + Widget.Label({ + hpack: 'start', + className: 'overview-search-results-txt txt-smallie txt-subtext', + label: `${name}`, + truncate: "end", + }), + Widget.Label({ + hpack: 'start', + className: 'overview-search-results-txt txt-norm', + label: `${content}`, + truncate: "end", + }), + ] + }), + Widget.Box({ hexpand: true }), + actionTextRevealer, + ], + }) + ] + }), + setup: (self) => self + .on('focus-in-event', (button) => { + actionText.revealChild = true; + actionTextRevealer.revealChild = true; + }) + .on('focus-out-event', (button) => { + actionText.revealChild = false; + actionTextRevealer.revealChild = false; + }) + , + }); +} diff --git a/config/ags/modules/overview/windowcontent.js b/config/ags/modules/overview/windowcontent.js new file mode 100644 index 0000000..7a19dd3 --- /dev/null +++ b/config/ags/modules/overview/windowcontent.js @@ -0,0 +1,262 @@ +const { Gdk, Gtk } = imports.gi; +import App from 'resource:///com/github/Aylur/ags/app.js'; +import Widget from 'resource:///com/github/Aylur/ags/widget.js'; +import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; + +import Applications from 'resource:///com/github/Aylur/ags/service/applications.js'; +const { execAsync, exec } = Utils; +import { execAndClose, expandTilde, hasUnterminatedBackslash, couldBeMath, launchCustomCommand, ls } from './miscfunctions.js'; +import { + CalculationResultButton, CustomCommandButton, DirectoryButton, + DesktopEntryButton, ExecuteCommandButton, SearchButton +} from './searchbuttons.js'; +import { checkKeybind } from '../.widgetutils/keybind.js'; + +// Add math funcs +const { abs, sin, cos, tan, cot, asin, acos, atan, acot } = Math; +const pi = Math.PI; +// trigonometric funcs for deg +const sind = x => sin(x * pi / 180); +const cosd = x => cos(x * pi / 180); +const tand = x => tan(x * pi / 180); +const cotd = x => cot(x * pi / 180); +const asind = x => asin(x) * 180 / pi; +const acosd = x => acos(x) * 180 / pi; +const atand = x => atan(x) * 180 / pi; +const acotd = x => acot(x) * 180 / pi; + +const MAX_RESULTS = 10; +const OVERVIEW_SCALE = 0.18; // = overview workspace box / screen size +const OVERVIEW_WS_NUM_SCALE = 0.0; +const OVERVIEW_WS_NUM_MARGIN_SCALE = 0.07; +const TARGET = [Gtk.TargetEntry.new('text/plain', Gtk.TargetFlags.SAME_APP, 0)]; + +function iconExists(iconName) { + let iconTheme = Gtk.IconTheme.get_default(); + return iconTheme.has_icon(iconName); +} + +const OptionalOverview = async () => { + try { + return (await import('./overview_hyprland.js')).default(); + } catch { + return Widget.Box({}); + // return (await import('./overview_hyprland.js')).default(); + } +}; + +const overviewContent = await OptionalOverview(); + +export const SearchAndWindows = () => { + var _appSearchResults = []; + + const ClickToClose = ({ ...props }) => Widget.EventBox({ + ...props, + onPrimaryClick: () => App.closeWindow('overview'), + onSecondaryClick: () => App.closeWindow('overview'), + onMiddleClick: () => App.closeWindow('overview'), + }); + const resultsBox = Widget.Box({ + className: 'overview-search-results', + vertical: true, + vexpand: true, + }); + const resultsRevealer = Widget.Revealer({ + transitionDuration: userOptions.animations.durationLarge, + revealChild: false, + transition: 'slide_down', + // duration: 200, + hpack: 'center', + child: resultsBox, + }); + const entryPromptRevealer = Widget.Revealer({ + transition: 'crossfade', + transitionDuration: userOptions.animations.durationLarge, + revealChild: true, + hpack: 'center', + child: Widget.Label({ + className: 'overview-search-prompt txt-small txt', + label: 'Type to search' + }), + }); + + const entryIconRevealer = Widget.Revealer({ + transition: 'crossfade', + transitionDuration: userOptions.animations.durationLarge, + revealChild: false, + hpack: 'end', + child: Widget.Label({ + className: 'txt txt-large icon-material overview-search-icon', + label: ' ', + }), + }); + + const entryIcon = Widget.Box({ + className: 'overview-search-prompt-box', + setup: box => box.pack_start(entryIconRevealer, true, true, 0), + }); + + const entry = Widget.Entry({ + className: 'overview-search-box txt-small txt', + hpack: 'center', + onAccept: (self) => { // This is when you hit Enter + const text = self.text; + if (text.length == 0) return; + const isAction = text.startsWith('>'); + const isDir = (['/', '~'].includes(entry.text[0])); + + if (couldBeMath(text)) { // Eval on typing is dangerous, this is a workaround + try { + const fullResult = eval(text.replace(/\^/g, "**")); + // copy + execAsync(['wl-copy', `${fullResult}`]).catch(print); + App.closeWindow('overview'); + return; + } catch (e) { + // console.log(e); + } + } + if (isDir) { + App.closeWindow('overview'); + execAsync(['bash', '-c', `xdg-open "${expandTilde(text)}"`, `&`]).catch(print); + return; + } + if (_appSearchResults.length > 0) { + App.closeWindow('overview'); + _appSearchResults[0].launch(); + return; + } + else if (text[0] == '>') { // Custom commands + App.closeWindow('overview'); + launchCustomCommand(text); + return; + } + // Fallback: Execute command + if (!isAction && exec(`bash -c "command -v ${text.split(' ')[0]}"`) != '') { + if (text.startsWith('sudo')) + execAndClose(text, true); + else + execAndClose(text, false); + } + + else { + App.closeWindow('overview'); + execAsync(['bash', '-c', `xdg-open '${userOptions.search.engineBaseUrl}${text} ${['', ...userOptions.search.excludedSites].join(' -site:')}' &`]).catch(print); + } + }, + onChange: (entry) => { // this is when you type + const isAction = entry.text[0] == '>'; + const isDir = (['/', '~'].includes(entry.text[0])); + resultsBox.get_children().forEach(ch => ch.destroy()); + + // check empty if so then dont do stuff + if (entry.text == '') { + resultsRevealer.revealChild = false; + overviewContent.revealChild = true; + entryPromptRevealer.revealChild = true; + entryIconRevealer.revealChild = false; + entry.toggleClassName('overview-search-box-extended', false); + return; + } + const text = entry.text; + resultsRevealer.revealChild = true; + overviewContent.revealChild = false; + entryPromptRevealer.revealChild = false; + entryIconRevealer.revealChild = true; + entry.toggleClassName('overview-search-box-extended', true); + _appSearchResults = Applications.query(text); + + // Calculate + if (couldBeMath(text)) { // Eval on typing is dangerous; this is a small workaround. + try { + const fullResult = eval(text.replace(/\^/g, "**")); + resultsBox.add(CalculationResultButton({ result: fullResult, text: text })); + } catch (e) { + // console.log(e); + } + } + if (isDir) { + var contents = []; + contents = ls({ path: text, silent: true }); + contents.forEach((item) => { + resultsBox.add(DirectoryButton(item)); + }) + } + if (isAction) { // Eval on typing is dangerous, this is a workaround. + resultsBox.add(CustomCommandButton({ text: entry.text })); + } + // Add application entries + let appsToAdd = MAX_RESULTS; + _appSearchResults.forEach(app => { + if (appsToAdd == 0) return; + resultsBox.add(DesktopEntryButton(app)); + appsToAdd--; + }); + + // Fallbacks + // if the first word is an actual command + if (!isAction && !hasUnterminatedBackslash(text) && exec(`bash -c "command -v ${text.split(' ')[0]}"`) != '') { + resultsBox.add(ExecuteCommandButton({ command: entry.text, terminal: entry.text.startsWith('sudo') })); + } + + // Add fallback: search + resultsBox.add(SearchButton({ text: entry.text })); + resultsBox.show_all(); + }, + }); + return Widget.Box({ + vertical: true, + children: [ + ClickToClose({ // Top margin. Also works as a click-outside-to-close thing + child: Widget.Box({ + className: 'bar-height', + }) + }), + Widget.Box({ + hpack: 'center', + children: [ + entry, + Widget.Box({ + className: 'overview-search-icon-box', + setup: (box) => { + box.pack_start(entryPromptRevealer, true, true, 0) + }, + }), + entryIcon, + ] + }), + overviewContent, + resultsRevealer, + ], + setup: (self) => self + .hook(App, (_b, name, visible) => { + if (name == 'overview' && !visible) { + resultsBox.children = []; + entry.set_text(''); + } + }) + .on('key-press-event', (widget, event) => { // Typing + const keyval = event.get_keyval()[1]; + const modstate = event.get_state()[1]; + if (checkKeybind(event, userOptions.keybinds.overview.altMoveLeft)) + entry.set_position(Math.max(entry.get_position() - 1, 0)); + else if (checkKeybind(event, userOptions.keybinds.overview.altMoveRight)) + entry.set_position(Math.min(entry.get_position() + 1, entry.get_text().length)); + else if (checkKeybind(event, userOptions.keybinds.overview.deleteToEnd)) { + const text = entry.get_text(); + const pos = entry.get_position(); + const newText = text.slice(0, pos); + entry.set_text(newText); + entry.set_position(newText.length); + } + else if (!(modstate & Gdk.ModifierType.CONTROL_MASK)) { // Ctrl not held + if (keyval >= 32 && keyval <= 126 && widget != entry) { + Utils.timeout(1, () => entry.grab_focus()); + entry.set_text(entry.text + String.fromCharCode(keyval)); + entry.set_position(-1); + } + } + }) + , + }); +}; diff --git a/config/ags/user/style.css b/config/ags/user/style.css new file mode 100644 index 0000000..0519fb1 --- /dev/null +++ b/config/ags/user/style.css @@ -0,0 +1,198 @@ +*:not(popover) { + all: unset; +} + +@import '../../../.cache/wal/colors-waybar.css'; +/* @import '../../../.cache/wal/colors-waybar-rgba.css'; */ + +/* define some colors */ +@define-color border-color @color2; +@define-color border-color-alt @color7; +@define-color text-color rgba(255, 255, 255, 0.7); +@define-color noti-bg rgba(0, 0, 0, 0.4); +@define-color noti-bg-alt #111111; + +widget { + border-radius: 0.818rem; + -gtk-outline-radius: 0.818rem; +} + +.overview-window { + margin-top: 2.727rem; +} + +.overview-search-box { + transition: 300ms cubic-bezier(0, 0.55, 0.45, 1); + border-radius: 1.705rem; + -gtk-outline-radius: 1.705rem; + border-top: 1px solid @border-color; + border-left: 1px solid @border-color-alt; + border-right: 1px solid @border-color-alt; + border-bottom: 1px solid @border-color; + /* box-shadow: 0px 2px 3px alpha(@color0, 0.45); */ + margin: 0.476rem; + min-width: 13.636rem; + min-height: 3.409rem; + padding: 0rem 1.364rem; + padding-right: 2.864rem; + background-color: @noti-bg; + color: @text-color; + caret-color: inherit; + font-weight: bolder; +} +.overview-search-box selection { + background-color: @noti-bg; + color: @text-color; +} + +.overview-search-box-extended { + min-width: 25.909rem; + caret-color: #FDD9FD; +} + +.overview-search-prompt { + color: @text-color; +} + +.overview-search-icon { + margin: 0rem 1.023rem; +} + +.overview-search-prompt-box { + margin-left: -18.545rem; + margin-right: 0.544rem; +} + +.overview-search-icon-box { + margin-left: -18.545rem; + margin-right: 0.544rem; +} + +.overview-search-results { + border-radius: 1.705rem; + -gtk-outline-radius: 1.705rem; + border-top: 1px solid @border-color; + border-left: 1px solid @border-color-alt; + border-right: 1px solid @border-color-alt; + border-bottom: 1px solid @border-color; + box-shadow: 0px 2px 3px @color9; + margin: 0.476rem; + min-width: 28.773rem; + padding: 0.682rem; + background-color: @noti-bg; + color: @text-color; + font-weight: bold; +} + +.overview-search-results-icon { + margin: 0rem 0.682rem; + font-size: 2.386rem; + min-width: 2.386rem; + min-height: 2.386rem; +} + +.overview-search-results-txt { + margin-right: 0.682rem; +} + +.overview-search-results-txt-cmd { + margin-right: 0.682rem; + font-family: "JetBrains Mono NF", "JetBrains Mono Nerd Font", "JetBrains Mono NL", "SpaceMono NF", "SpaceMono Nerd Font", monospace; + font-size: 1.227rem; +} + +.overview-search-result-btn { + border-radius: 1.159rem; + -gtk-outline-radius: 1.159rem; + padding: 0.341rem; + min-width: 2.386rem; + min-height: 2.386rem; + caret-color: transparent; +} + +.overview-search-result-btn:hover, +.overview-search-result-btn:focus { + background-color: alpha(@color7, 0.9); + color: alpha(@color0, 0.7); +} + +.overview-search-result-btn:active { + background-color: alpha(@color7, 0.9); + color: @color4; +} + +.overview-tasks { + border-radius: 1.705rem; + -gtk-outline-radius: 1.705rem; + border-top: 1px solid @border-color; + border-left: 1px solid @border-color-alt; + border-right: 1px solid @border-color-alt; + border-bottom: 1px solid @border-color; + box-shadow: 0px 2px 3px @color5; + margin: 0.476rem; + padding: 0.341rem; + /* background-color: rgba(49, 50, 68, 0.8); */ + background-color: @noti-bg; + color: #EBDFED; +} + +.overview-tasks-workspace { + border-radius: 1.159rem; + -gtk-outline-radius: 1.159rem; + margin: 0.341rem; + /* background-color: #26233A; */ + background-image: url('../../rofi/.current_wallpaper'); + background-size: cover; + background-position: center; + border: 0.068rem solid alpha(@color4, 0.5); +} + +.overview-tasks-workspace-number { + font-family: "Open Sans", "Noto Sans", sans-serif; + color: #CFC2D3; +} + +.overview-tasks-window { + border-radius: 1.159rem; + -gtk-outline-radius: 1.159rem; + transition: 300ms cubic-bezier(0.1, 1, 0, 1); + background-color: alpha(@color3, .7); + /* background-color: @color_a3; */ + /* background-color: rgba(46, 40, 50, 0.8); */ + color: #EBDFED; + border: 0.068rem solid @color7; +} + +.overview-tasks-window:hover, +.overview-tasks-window:focus { + background-color: alpha(@color9, 0.8); +} + +.overview-tasks-window:active { + background-color: alpha(@color9, 0.8); +} + +.overview-tasks-window-selected { + background-color: alpha(@color9, 0.8); +} + +.overview-tasks-window-dragging { + opacity: 0.2; +} + +.growingRadial { + transition: 300ms cubic-bezier(0.2, 0, 0, 1); +} + +.fadingRadial { + transition: 50ms cubic-bezier(0.2, 0, 0, 1); +} + +.sidebar-pinned { + margin: 0rem; + border-radius: 0rem; + border-bottom-right-radius: 1.705rem; + border: 0rem solid; +} + +/*# sourceMappingURL=style.css.map */ diff --git a/config/ags/user_options.js b/config/ags/user_options.js new file mode 100644 index 0000000..9105dec --- /dev/null +++ b/config/ags/user_options.js @@ -0,0 +1,21 @@ + +const userConfigOptions = { + // For every option, see ~/.config/ags/modules/.configuration/user_options.js + // (vscode users ctrl+click this: file://./modules/.configuration/user_options.js) + // (vim users: `:vsp` to split window, move cursor to this path, press `gf`. `Ctrl-w` twice to switch between) + // options listed in this file will override the default ones in the above file + // Here's an example + 'overview':{ + 'scale': 0.15, + 'numOfRows': 2 + }, + 'keybinds': { + 'sidebar': { + 'pin': "Ctrl+p", + 'nextTab': "Ctrl+Page_Down", + 'prevTab': "Ctrl+Page_Up", + }, + }, +} + +export default userConfigOptions; diff --git a/config/ags/variables.js b/config/ags/variables.js new file mode 100644 index 0000000..ec4aede --- /dev/null +++ b/config/ags/variables.js @@ -0,0 +1,21 @@ +const { Gtk } = imports.gi; +import Variable from 'resource:///com/github/Aylur/ags/variable.js'; +import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; +const { exec, execAsync } = Utils; + +Gtk.IconTheme.get_default().append_search_path(`${App.configDir}/assets/icons`); + +// Screen size +export const SCREEN_WIDTH = Number(exec(`bash -c "xrandr --current | grep '*' | uniq | awk '{print $1}' | cut -d 'x' -f1 | head -1" | awk '{print $1}'`)); +export const SCREEN_HEIGHT = Number(exec(`bash -c "xrandr --current | grep '*' | uniq | awk '{print $1}' | cut -d 'x' -f2 | head -1" | awk '{print $1}'`)); + +// Mode switching +export const currentShellMode = Variable('normal', {}) // normal, focus +globalThis['currentMode'] = currentShellMode; +globalThis['cycleMode'] = () => { + if (currentShellMode.value === 'normal') { + currentShellMode.value = 'focus'; + } else { + currentShellMode.value = 'normal'; + } +} diff --git a/config/hypr/UserConfigs/Startup_Apps.conf b/config/hypr/UserConfigs/Startup_Apps.conf index 78d0636..2f529d6 100644 --- a/config/hypr/UserConfigs/Startup_Apps.conf +++ b/config/hypr/UserConfigs/Startup_Apps.conf @@ -23,6 +23,7 @@ exec-once = $scriptsDir/Polkit.sh exec-once = waybar & exec-once = nm-applet --indicator & exec-once = swaync & +exec-once = ags & #exec-once = blueman-applet & #exec-once = rog-control-center & diff --git a/config/hypr/UserConfigs/UserKeybinds.conf b/config/hypr/UserConfigs/UserKeybinds.conf index 7ffd702..eede166 100644 --- a/config/hypr/UserConfigs/UserKeybinds.conf +++ b/config/hypr/UserConfigs/UserKeybinds.conf @@ -15,6 +15,9 @@ $UserScripts = $HOME/.config/hypr/UserScripts #bindr = $mainMod, $mainMod_L, exec, pkill rofi || rofi -show drun -modi drun,filebrowser,run,window # Super Key to Launch rofi menu bind = $mainMod, D, exec, pkill rofi || rofi -show drun -modi drun,filebrowser,run,window +# ags overview +bind = $mainMod, A, exec, pkill rofi || true && ags -t 'overview' + bind = $mainMod, Return, exec, $term # Launch terminal bind = $mainMod, T, exec, $files diff --git a/config/hypr/UserConfigs/WindowRules.conf b/config/hypr/UserConfigs/WindowRules.conf index 1cf2366..c07094b 100644 --- a/config/hypr/UserConfigs/WindowRules.conf +++ b/config/hypr/UserConfigs/WindowRules.conf @@ -1,6 +1,7 @@ # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ # # See https://wiki.hyprland.org/Configuring/Window-Rules/ for more +#windowrule windowrule = float, org.kde.polkit-kde-authentication-agent-1 windowrule = float, nm-connection-editor|blueman-manager windowrule = float, pavucontrol @@ -9,24 +10,25 @@ windowrule = float, onedriver|onedriver-launcher windowrule = float, eog windowrule = float, zoom windowrule = float, rofi -windowrule = float, gnome-system-monitor +windowrule = float, ^(gnome-system-monitor|org.gnome.SystemMonitor)$ windowrule = float, yad windowrule = float, ^(wihotspot-gui)$ # wifi hotspot windowrule = float, ^(evince)$ # document viewer -windowrule = float, ^(file-roller)$ # archive manager +windowrule = float, ^(file-roller|org.gnome.FileRoller)$ # archive manager #windowrule = noblur,gamescope #windowrule = fullscreen,gamescope #windowrule = workspace 6 silent,^(gamescope)$ windowrule = center,^(pavucontrol) +windowrule = float, org.gnome.SystemMonitor -# windowrule v2 +# windowrule v2 move to workspace windowrulev2 = workspace 1, class:^([Tt]hunderbird)$ windowrulev2 = workspace 2, class:^([Ff]irefox)$ windowrulev2 = workspace 2, class:^(org.mozilla.firefox)$ windowrulev2 = workspace 2, class:^([Ff]irefox-esr)$ -windowrulev2 = workspace 2, class:^(Microsoft-edge-beta)$ -windowrulev2 = workspace 3, class:^([Tt]hunar)$ +windowrulev2 = workspace 2, class:^([Mm]icrosoft-edge(-stable|-beta|-dev|-unstable)?)$ +#windowrulev2 = workspace 3, class:^([Tt]hunar)$ windowrulev2 = workspace 4, class:^(com.obsproject.Studio)$ windowrulev2 = workspace 5 silent, class:^([Ss]team)$,title:^([Ss]team)$ windowrulev2 = workspace 5 silent, class:^(lutris)$ @@ -40,24 +42,16 @@ windowrulev2 = float, class:([Tt]hunar), title:(File Operation Progress) windowrulev2 = float, class:([Tt]hunar), title:(Confirm to replace files) windowrulev2 = float, class:(xdg-desktop-portal-gtk) windowrulev2 = float, class:(org.gnome.Calculator), title:(Calculator) -windowrulev2 = float, class:(codium), title:(Add Folder to Workspace) -windowrulev2 = float, class:(codium-url-handler), title:(Add Folder to Workspace) -windowrulev2 = float, class:(VSCodium), title:(Add Folder to Workspace) +windowrulev2 = float, class:(codium|codium-url-handler|VSCodium), title:(Add Folder to Workspace) -#opacity (transparent) #enable as desired +# windowrule v2 - opacity #enable as desired windowrulev2 = opacity 0.9 0.6, class:^([Rr]ofi)$ -windowrulev2 = opacity 0.9 0.7, class:^(Brave-browser)$ -windowrulev2 = opacity 0.9 0.7, class:^(Brave-browser-dev)$ +windowrulev2 = opacity 0.9 0.7, class:^(Brave-browser(-beta|-dev)?)$ windowrulev2 = opacity 0.9 0.7, class:^([Ff]irefox)$ windowrulev2 = opacity 0.9 0.7, class:^(org.mozilla.firefox)$ windowrulev2 = opacity 0.9 0.7, class:^([Ff]irefox-esr)$ -windowrulev2 = opacity 0.9 0.7, class:^([Mm]icrosoft-edge-stable)$ -windowrulev2 = opacity 0.9 0.7, class:^([Mm]icrosoft-edge-beta)$ -windowrulev2 = opacity 0.9 0.7, class:^([Mm]icrosoft-edge-dev)$ -windowrulev2 = opacity 0.9 0.8, class:^(google-chrome)$ -windowrulev2 = opacity 0.9 0.8, class:^(google-chrome-beta)$ -windowrulev2 = opacity 0.9 0.8, class:^(google-chrome-dev)$ -windowrulev2 = opacity 0.9 0.8, class:^(google-chrome-unstable)$ +windowrulev2 = opacity 0.9 0.8, class:^([Mm]icrosoft-edge(-stable|-beta|-dev|-unstable)?)$ +windowrulev2 = opacity 0.9 0.8, class:^(google-chrome(-beta|-dev|-unstable)?)$ windowrulev2 = opacity 0.94 0.86, class:^(chrome-.+-Default)$ # Chrome PWAs windowrulev2 = opacity 0.9 0.8, class:^([Tt]hunar)$ windowrulev2 = opacity 0.8 0.6, class:^(pcmanfm-qt)$ @@ -66,21 +60,26 @@ windowrulev2 = opacity 0.9 0.8, class:^(deluge)$ windowrulev2 = opacity 0.9 0.8, class:^(Alacritty)$ windowrulev2 = opacity 0.9 0.8, class:^(kitty)$ windowrulev2 = opacity 0.9 0.7, class:^(mousepad)$ -windowrulev2 = opacity 0.9 0.7, class:^(codium-url-handler)$ -windowrulev2 = opacity 0.9 0.7, class:^(VSCodium)$ +windowrulev2 = opacity 0.9 0.7, class:^(VSCodium|codium-url-handler)$ windowrulev2 = opacity 0.9 0.7, class:^(yad)$ windowrulev2 = opacity 0.9 0.7, class:^(com.obsproject.Studio)$ windowrulev2 = opacity 0.9 0.7, class:^([Aa]udacious)$ windowrulev2 = opacity 0.9 0.8, class:^(org.gnome.Nautilus)$ -windowrulev2 = opacity 0.9 0.8, class:^(code-url-handler)$ -windowrulev2 = opacity 0.9 0.8, class:^(VSCode)$ +windowrulev2 = opacity 0.9 0.8, class:^(VSCode|code-url-handler)$ windowrulev2 = opacity 0.9 0.8, class:^(jetbrains-studio)$ # Android Studio windowrulev2 = opacity 0.94 0.86, class:^(discord)$ windowrulev2 = opacity 0.9 0.8, class:^(org.telegram.desktop)$ windowrulev2 = opacity 0.94 0.86, class:^(gnome-disks)$ windowrulev2 = opacity 0.9 0.8, class:^(org.gnome.baobab)$ windowrulev2 = opacity 0.9 0.8, class:^(seahorse)$ # gnome-keyring gui +windowrulev2 = opacity 0.82 0.75, class:^(gnome-system-monitor|org.gnome.SystemMonitor)$ +windowrulev2 = opacity 0.9 0.8, class:^(xdg-desktop-portal-gtk)$ # gnome-keyring gui +# windowrule v2 - size +windowrulev2 = size 70% 70%, class:^(gnome-system-monitor|org.gnome.SystemMonitor)$ +windowrulev2 = size 70% 70%, class:^(xdg-desktop-portal-gtk)$ +windowrulev2 = size 70% 70%, class:^(evince)$ +windowrulev2 = size 60% 70%, class:^(file-roller|org.gnome.FileRoller)$ #layerrule = unset,class:^([Rr]ofi)$ #layerrule = blur,class:^([Rr]ofi)$ diff --git a/config/hypr/UserScripts/Weather.py b/config/hypr/UserScripts/Weather.py index 14c9cfe..046dbcd 100755 --- a/config/hypr/UserScripts/Weather.py +++ b/config/hypr/UserScripts/Weather.py @@ -3,7 +3,7 @@ import subprocess from pyquery import PyQuery # install using `pip install pyquery` import json - +import os # original code https://gist.github.com/Surendrajat/ff3876fd2166dd86fb71180f4e9342d7 # weather icons @@ -122,3 +122,15 @@ out_data = { "class": status_code, } print(json.dumps(out_data)) + +simple_weather =f"{icon} {status}\n" + \ + f" {temp} ({temp_feel_text})\n" + \ + f"{wind_text}\n" + \ + f"{humidity_text}\n" + \ + f"{visbility_text} AQI {air_quality_index}\n" + +try: + with open(os.path.expanduser("~/.cache/.weather_cache"), "w") as file: + file.write(simple_weather) +except: + pass \ No newline at end of file diff --git a/config/hypr/UserScripts/Weather.sh b/config/hypr/UserScripts/Weather.sh index 4004871..f916b02 100755 --- a/config/hypr/UserScripts/Weather.sh +++ b/config/hypr/UserScripts/Weather.sh @@ -78,3 +78,7 @@ esac #echo $temp $condition echo -e "{\"text\":\""$temperature $condition"\", \"alt\":\""${weather[0]}"\", \"tooltip\":\""${weather[0]}: $temperature ${weather[1]}"\"}" + +cached_weather=" $temperature \n$condition ${weather[1]}" + +echo -e $cached_weather > ~/.cache/.weather_cache \ No newline at end of file diff --git a/config/hypr/configs/Keybinds.conf b/config/hypr/configs/Keybinds.conf index 1cc8e2a..2cdd9cd 100644 --- a/config/hypr/configs/Keybinds.conf +++ b/config/hypr/configs/Keybinds.conf @@ -30,7 +30,6 @@ bind = $mainMod ALT, L, exec, $scriptsDir/ChangeLayout.sh # Toggle Master or Dwi bind = $mainMod ALT, V, exec, $scriptsDir/ClipManager.sh # Clipboard Manager bind = $mainMod SHIFT, N, exec, swaync-client -t -sw # swayNC panel bind = SHIFT, ALT_L, exec, $scriptsDir/SwitchKeyboardLayout.sh # Switch Keyboard Layout -bind = $mainMod, A, exec, ags -t 'overview' # FEATURES / EXTRAS (UserScripts) bind = $mainMod, E, exec, $UserScripts/QuickEdit.sh # Quick Edit Hyprland Settings @@ -77,7 +76,7 @@ bind = $mainMod, Print, exec, $scriptsDir/ScreenShot.sh --now bind = $mainMod SHIFT, Print, exec, $scriptsDir/ScreenShot.sh --area bind = $mainMod CTRL, Print, exec, $scriptsDir/ScreenShot.sh --in5 #screenshot in 5 secs bind = $mainMod ALT, Print, exec, $scriptsDir/ScreenShot.sh --in10 #screenshot in 10 secs -bind = ALT, Print, exec, $scriptsDir/ScreenShot.sh --active #screenshot in 10 secs +bind = ALT, Print, exec, $scriptsDir/ScreenShot.sh --active #take screenshot of active window # screenshot with swappy (another screenshot tool) bind = $mainMod SHIFT, S, exec, $scriptsDir/ScreenShot.sh --swappy diff --git a/config/hypr/hyprlock.conf b/config/hypr/hyprlock.conf index 3aa029d..38c927a 100644 --- a/config/hypr/hyprlock.conf +++ b/config/hypr/hyprlock.conf @@ -110,7 +110,7 @@ label { # weather edit specific location. Note, this cause a 2-4 seconds delay in locking label { monitor = - text = cmd[update:3600000] ping -c 1 wttr.in > /dev/null && curl -s 'wttr.in?format=2' # For specific location : wttr.in/busan?format=2 + text = cmd[update:3600000] [ -f ~/.cache/.weather_cache ] && cat ~/.cache/.weather_cache color = $color10 font_size = 24 font_family = JetBrains Mono Nerd Font 10 diff --git a/config/hypr/scripts/DarkLight.sh b/config/hypr/scripts/DarkLight.sh index 6c9f610..f9d2a93 100755 --- a/config/hypr/scripts/DarkLight.sh +++ b/config/hypr/scripts/DarkLight.sh @@ -9,6 +9,7 @@ dark_wallpapers="$wallpaper_base_path/Dark" light_wallpapers="$wallpaper_base_path/Light" hypr_config_path="$HOME/.config/hypr" swaync_style="$HOME/.config/swaync/style.css" +ags_style="$HOME/.config/ags/user/style.css" SCRIPTSDIR="$HOME/.config/hypr/scripts" notif="$HOME/.config/swaync/images/bell.png" dark_rofi_pywal="$HOME/.cache/wal/colors-rofi-dark.rasi" @@ -74,6 +75,17 @@ else sed -i '/@define-color noti-bg-alt/s/#.*;/#F0F0F0;/' "${swaync_style}" fi +# ags color change +if [ "$next_mode" = "Dark" ]; then + sed -i '/@define-color noti-bg/s/rgba([0-9]*,\s*[0-9]*,\s*[0-9]*,\s*[0-9.]*);/rgba(0, 0, 0, 0.4);/' "${ags_style}" + sed -i '/@define-color text-color/s/rgba([0-9]*,\s*[0-9]*,\s*[0-9]*,\s*[0-9.]*);/rgba(255, 255, 255, 0.7);/' "${ags_style}" + sed -i '/@define-color noti-bg-alt/s/#.*;/#111111;/' "${ags_style}" +else + sed -i '/@define-color noti-bg/s/rgba([0-9]*,\s*[0-9]*,\s*[0-9]*,\s*[0-9.]*);/rgba(255, 255, 255, 0.4);/' "${ags_style}" + sed -i '/@define-color text-color/s/rgba([0-9]*,\s*[0-9]*,\s*[0-9]*,\s*[0-9.]*);/rgba(0, 0, 0, 0.7);/' "${ags_style}" + sed -i '/@define-color noti-bg-alt/s/#.*;/#F0F0F0;/' "${ags_style}" +fi + # Set Dynamic Wallpaper for Dark or Light Mode if [ "$next_mode" = "Dark" ]; then next_wallpaper="$(find "${dark_wallpapers}" -type f \( -iname "*.jpg" -o -iname "*.png" \) -print0 | shuf -n1 -z | xargs -0)" diff --git a/config/hypr/scripts/Refresh.sh b/config/hypr/scripts/Refresh.sh index bf806e0..aeae77d 100755 --- a/config/hypr/scripts/Refresh.sh +++ b/config/hypr/scripts/Refresh.sh @@ -1,6 +1,6 @@ #!/bin/bash # /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ## -# Scripts for refreshing waybar, rofi, swaync, pywal colors +# Scripts for refreshing ags waybar, rofi, swaync, pywal colors SCRIPTSDIR=$HOME/.config/hypr/scripts UserScripts=$HOME/.config/hypr/UserScripts @@ -22,6 +22,7 @@ for _prs in "${_ps[@]}"; do fi done +# quit ags ags -q sleep 0.3 diff --git a/config/hypr/scripts/RefreshNoWaybar.sh b/config/hypr/scripts/RefreshNoWaybar.sh index 689bccf..42d67ad 100755 --- a/config/hypr/scripts/RefreshNoWaybar.sh +++ b/config/hypr/scripts/RefreshNoWaybar.sh @@ -25,6 +25,9 @@ for _prs in "${_ps[@]}"; do fi done +# quit ags +ags -q + # Pywal refresh ${SCRIPTSDIR}/PywalSwww.sh & diff --git a/config/hypr/scripts/Wlogout.sh b/config/hypr/scripts/Wlogout.sh index 58e1fd6..f374653 100755 --- a/config/hypr/scripts/Wlogout.sh +++ b/config/hypr/scripts/Wlogout.sh @@ -4,12 +4,14 @@ # wlogout (Power, Screen Lock, Suspend, etc) # Set variables for parameters -A_2160=680 -B_2160=750 -A_1440=500 -B_1440=550 -A_1080=400 -B_1080=400 +A_2160=450 +B_2160=450 +A_1600=400 +B_1600=400 +A_1440=350 +B_1440=350 +A_1080=50 +B_1080=50 A_720=50 B_720=50 @@ -23,22 +25,33 @@ fi resolution=$(hyprctl -j monitors | jq -r '.[] | select(.focused==true) | .height / .scale' | awk -F'.' '{print $1}') hypr_scale=$(hyprctl -j monitors | jq -r '.[] | select(.focused==true) | .scale') -echo "Detected Resolution: $resolution" - # Set parameters based on screen resolution and scaling factor if ((resolution >= 2160)); then - wlogout --protocol layer-shell -b 3 -T $(awk "BEGIN {printf \"%.0f\", $A_2160 * 2160 * $hypr_scale / $resolution}") -B $(awk "BEGIN {printf \"%.0f\", $B_2160 * 2160 * $hypr_scale / $resolution}") & - echo "Setting parameters for resolution >= 2160p" -elif ((resolution >= 1440)); then - wlogout --protocol layer-shell -b 6 -T $(awk "BEGIN {printf \"%.0f\", $A_1440 * 1440 * $hypr_scale / $resolution}") -B $(awk "BEGIN {printf \"%.0f\", $B_1440 * 1440 * $hypr_scale / $resolution}") & - echo "Setting parameters for resolution >= 1440p" -elif ((resolution >= 1080)); then - wlogout --protocol layer-shell -b 6 -T $(awk "BEGIN {printf \"%.0f\", $A_1080 * 1080 * $hypr_scale / $resolution}") -B $(awk "BEGIN {printf \"%.0f\", $B_1080 * 1080 * $hypr_scale / $resolution}") & - echo "Setting parameters for resolution >= 1080p" -elif ((resolution > 720)); then - wlogout --protocol layer-shell -b 3 -T $(awk "BEGIN {printf \"%.0f\", $A_720 * 720 * $hypr_scale / $resolution}") -B $(awk "BEGIN {printf \"%.0f\", $B_720 * 720 * $hypr_scale / $resolution}") & - echo "Setting parameters for resolution >= 720p" + T_val=$(awk "BEGIN {printf \"%.0f\", $A_2160 * 2160 * $hypr_scale / $resolution}") + B_val=$(awk "BEGIN {printf \"%.0f\", $B_2160 * 2160 * $hypr_scale / $resolution}") + echo "Setting parameters for resolution >= 4k" + wlogout --protocol layer-shell -b 6 -T $T_val -B $B_val & +elif ((resolution >= 1600 && resolution < 2160)); then + T_val=$(awk "BEGIN {printf \"%.0f\", $A_1600 * 1600 * $hypr_scale / $resolution}") + B_val=$(awk "BEGIN {printf \"%.0f\", $B_1600 * 1600 * $hypr_scale / $resolution}") + echo "Setting parameters for resolution >= 2.5k and < 4k" + wlogout --protocol layer-shell -b 6 -T $T_val -B $B_val & +elif ((resolution >= 1440 && resolution < 1600)); then + T_val=$(awk "BEGIN {printf \"%.0f\", $A_1440 * 1440 * $hypr_scale / $resolution}") + B_val=$(awk "BEGIN {printf \"%.0f\", $B_1440 * 1440 * $hypr_scale / $resolution}") + echo "Setting parameters for resolution >= 2k and < 2.5k" + wlogout --protocol layer-shell -b 6 -T $T_val -B $B_val & +elif ((resolution >= 1080 && resolution < 1440)); then + T_val=$(awk "BEGIN {printf \"%.0f\", $A_1080 * 1080 * $hypr_scale / $resolution}") + B_val=$(awk "BEGIN {printf \"%.0f\", $B_1080 * 1080 * $hypr_scale / $resolution}") + echo "Setting parameters for resolution >= 1080p and < 2k" + wlogout --protocol layer-shell -b 3 -T $T_val -B $B_val & +elif ((resolution >= 720 && resolution < 1080)); then + T_val=$(awk "BEGIN {printf \"%.0f\", $A_720 * 720 * $hypr_scale / $resolution}") + B_val=$(awk "BEGIN {printf \"%.0f\", $B_720 * 720 * $hypr_scale / $resolution}") + echo "Setting parameters for resolution >= 720p and < 1080p" + wlogout --protocol layer-shell -b 3 -T $T_val -B $B_val & else + echo "Setting default parameters" wlogout & - echo "Setting default parameters for resolution <= 720p" -fi \ No newline at end of file +fi diff --git a/config/hypr/v2.2.10 b/config/hypr/v2.2.11 similarity index 100% rename from config/hypr/v2.2.10 rename to config/hypr/v2.2.11 diff --git a/config/rofi/config-compact.rasi b/config/rofi/config-compact.rasi index e35ec79..2c72252 100644 --- a/config/rofi/config-compact.rasi +++ b/config/rofi/config-compact.rasi @@ -10,32 +10,31 @@ configuration { /* ---- Window ---- */ window { - width: 24%; + width: 50%; border-radius: 15px; } /* ---- Inputbar ---- */ inputbar { - background-image: url("~/.config/rofi/.current_wallpaper", width); + background-image: url("~/.config/rofi/.current_wallpaper", width); } /* ---- Imagebox ---- */ imagebox { orientation: vertical; - children: - [ "entry", "listview"]; + children: [ "entry", "listview"]; } /* ---- Entry input ---- */ entry { - width: 18%; + width: 23%; placeholder: " View / Edit Hyprland Configs"; } /* ---- Listview ---- */ listview { - columns: 1; - lines: 10; + columns: 2; + lines: 5; spacing: 4px; scrollbar: false; border-radius: 12px; diff --git a/config/rofi/config-long.rasi b/config/rofi/config-long.rasi index b75d3d5..2341e5f 100644 --- a/config/rofi/config-long.rasi +++ b/config/rofi/config-long.rasi @@ -5,7 +5,7 @@ /* ---- Window ---- */ window { - width: 50%; + width: 50%; } /* ---- Entry ---- */ @@ -16,5 +16,6 @@ entry { /* ---- Listview ---- */ listview { columns: 1; - lines: 10; + lines: 8; + scrollbar: true; } \ No newline at end of file diff --git a/config/rofi/config-rofi-Beats.rasi b/config/rofi/config-rofi-Beats.rasi index efd6703..82de4a6 100644 --- a/config/rofi/config-rofi-Beats.rasi +++ b/config/rofi/config-rofi-Beats.rasi @@ -10,5 +10,5 @@ entry { /* ---- Listview ---- */ listview { - lines: 10; + lines: 6; } \ No newline at end of file diff --git a/config/rofi/config-waybar-style.rasi b/config/rofi/config-waybar-style.rasi index 55c6156..aebe686 100644 --- a/config/rofi/config-waybar-style.rasi +++ b/config/rofi/config-waybar-style.rasi @@ -22,6 +22,7 @@ entry { /* ---- Listview ---- */ listview { columns: 2; - lines: 8; - scrollbar: false; + lines: 6; + scrollbar: true; } + diff --git a/config/rofi/config.rasi b/config/rofi/config.rasi index 5a161f2..2c8b965 100755 --- a/config/rofi/config.rasi +++ b/config/rofi/config.rasi @@ -84,7 +84,7 @@ entry { background-color: @background-alt; text-color: inherit; cursor: text; - placeholder: " Search "; // << Search symbol + placeholder: "🔎 Search "; // << Search symbol placeholder-color: inherit; } @@ -107,7 +107,7 @@ listview { scrollbar: false; layout: vertical; reverse: false; - fixed-height: true; + fixed-height: false; fixed-columns: true; spacing: 10px; background-color: transparent; @@ -141,6 +141,14 @@ button selected { text-color: @text-selected; } +/* ---- Scrollbar ---- */ +scrollbar { + width: 4px ; + border: 0; + handle-color: @border-color; + handle-width: 8px ; + padding: 0; +} /* ---- Elements ---- */ element { @@ -152,7 +160,6 @@ element { cursor: pointer; } - element normal.normal { background-color: inherit; text-color: inherit; diff --git a/config/rofi/resolution/1080p/config.rasi b/config/rofi/resolution/1080p/config.rasi index 5a161f2..2c8b965 100755 --- a/config/rofi/resolution/1080p/config.rasi +++ b/config/rofi/resolution/1080p/config.rasi @@ -84,7 +84,7 @@ entry { background-color: @background-alt; text-color: inherit; cursor: text; - placeholder: " Search "; // << Search symbol + placeholder: "🔎 Search "; // << Search symbol placeholder-color: inherit; } @@ -107,7 +107,7 @@ listview { scrollbar: false; layout: vertical; reverse: false; - fixed-height: true; + fixed-height: false; fixed-columns: true; spacing: 10px; background-color: transparent; @@ -141,6 +141,14 @@ button selected { text-color: @text-selected; } +/* ---- Scrollbar ---- */ +scrollbar { + width: 4px ; + border: 0; + handle-color: @border-color; + handle-width: 8px ; + padding: 0; +} /* ---- Elements ---- */ element { @@ -152,7 +160,6 @@ element { cursor: pointer; } - element normal.normal { background-color: inherit; text-color: inherit; diff --git a/config/rofi/resolution/1440p/config.rasi b/config/rofi/resolution/1440p/config.rasi old mode 100644 new mode 100755 index 1ed7973..ae3a7b7 --- a/config/rofi/resolution/1440p/config.rasi +++ b/config/rofi/resolution/1440p/config.rasi @@ -84,7 +84,7 @@ entry { background-color: @background-alt; text-color: @text-selected; cursor: text; - placeholder: " Search "; // << Search symbol + placeholder: "🔎 Search "; // << Search symbol placeholder-color: inherit; } @@ -107,7 +107,7 @@ listview { scrollbar: false; layout: vertical; reverse: false; - fixed-height: true; + fixed-height: false; fixed-columns: true; spacing: 10px; background-color: transparent; @@ -141,6 +141,14 @@ button selected { text-color: @text-selected; } +/* ---- Scrollbar ---- */ +scrollbar { + width: 4px ; + border: 0; + handle-color: @border-color; + handle-width: 8px ; + padding: 0; +} /* ---- Elements ---- */ element { @@ -152,7 +160,6 @@ element { cursor: pointer; } - element normal.normal { background-color: inherit; text-color: inherit; diff --git a/config/waybar/modules b/config/waybar/modules index f42f89d..a2357e2 100644 --- a/config/waybar/modules +++ b/config/waybar/modules @@ -192,7 +192,7 @@ "critical": 15 }, "format": "{icon} {capacity}%", - "format-charging": "{capacity}%", + "format-charging": " {capacity}%", "format-plugged": "󱘖 {capacity}%", "format-alt-click": "click", "format-full": "{icon} Full", diff --git a/config/waybar/style/Catppuccin-Latte.css b/config/waybar/style/[Catppuccin] Latte.css similarity index 100% rename from config/waybar/style/Catppuccin-Latte.css rename to config/waybar/style/[Catppuccin] Latte.css diff --git a/config/waybar/style/Catppuccin-Mocha.css b/config/waybar/style/[Catppuccin] Mocha.css similarity index 100% rename from config/waybar/style/Catppuccin-Mocha.css rename to config/waybar/style/[Catppuccin] Mocha.css diff --git a/config/waybar/style/[Colored] Translucent.css b/config/waybar/style/[Colored] Translucent.css index 5998227..37931d5 100644 --- a/config/waybar/style/[Colored] Translucent.css +++ b/config/waybar/style/[Colored] Translucent.css @@ -50,17 +50,13 @@ window#waybar.empty #window { tooltip { background: #1e1e2e; - opacity: 0.8; + opacity: 0.6; border-radius: 10px; border-width: 2px; border-style: solid; border-color: #11111b; } -tooltip label{ - color: #cdd6f4; -} - #workspaces button { background-color: transparent; color: #ffffff; diff --git a/config/waybar/style/[Colorful] Aurora Blossom.css b/config/waybar/style/[Colorful] Aurora Blossom.css index 9eab49a..d785453 100644 --- a/config/waybar/style/[Colorful] Aurora Blossom.css +++ b/config/waybar/style/[Colorful] Aurora Blossom.css @@ -32,6 +32,7 @@ tooltip { tooltip label{ color: black; } + /*-----module groups----*/ .modules-right { background-image: linear-gradient(45deg, #7287fd 10%, #209fb5 54%, #8839ef 90%); diff --git a/config/waybar/style/Purpl.css b/config/waybar/style/[Dark] Purpl.css similarity index 100% rename from config/waybar/style/Purpl.css rename to config/waybar/style/[Dark] Purpl.css diff --git a/config/waybar/style/Crimson.css b/config/waybar/style/[Extra] Crimson.css similarity index 99% rename from config/waybar/style/Crimson.css rename to config/waybar/style/[Extra] Crimson.css index 89a3b9c..c6530e1 100644 --- a/config/waybar/style/Crimson.css +++ b/config/waybar/style/[Extra] Crimson.css @@ -34,12 +34,12 @@ window#waybar.empty #window { } tooltip { - background: #1e1e2e; + background: #240303; border-radius: 10px; border-width: 2px; border-style: solid; border-color: #11111b; - color: #cba6f7; + color: wheat; } /*-----module groups----*/ diff --git a/config/waybar/style/Mauve.css b/config/waybar/style/[Extra] Mauve.css similarity index 100% rename from config/waybar/style/Mauve.css rename to config/waybar/style/[Extra] Mauve.css diff --git a/config/waybar/style/Rose Pine.css b/config/waybar/style/[Extra] Rose Pine.css similarity index 100% rename from config/waybar/style/Rose Pine.css rename to config/waybar/style/[Extra] Rose Pine.css diff --git a/config/waybar/style/Simple Pink.css b/config/waybar/style/[Extra] Simple Pink.css similarity index 100% rename from config/waybar/style/Simple Pink.css rename to config/waybar/style/[Extra] Simple Pink.css diff --git a/config/waybar/style/[Bordered Pywal] Chroma Fusion Edge.css b/config/waybar/style/[Pywal Bordered] Chroma Fusion Edge.css similarity index 97% rename from config/waybar/style/[Bordered Pywal] Chroma Fusion Edge.css rename to config/waybar/style/[Pywal Bordered] Chroma Fusion Edge.css index 04ca924..8997795 100644 --- a/config/waybar/style/[Bordered Pywal] Chroma Fusion Edge.css +++ b/config/waybar/style/[Pywal Bordered] Chroma Fusion Edge.css @@ -47,6 +47,15 @@ window#waybar.empty #window { } +tooltip { + background-color: transparent; + border-radius: 10px; + border-width: 1px; + border-style: solid; + border-color: #11111b; + color: @border-color; +} + #backlight, #backlight-slider, #battery, diff --git a/config/waybar/style/[Pywal] Chroma Fusion.css b/config/waybar/style/[Pywal] Chroma Fusion.css index 90e2e7a..00e50ef 100644 --- a/config/waybar/style/[Pywal] Chroma Fusion.css +++ b/config/waybar/style/[Pywal] Chroma Fusion.css @@ -46,6 +46,15 @@ window#waybar.empty #window { } +tooltip { + background-color: @background-module; + border-radius: 10px; + border-width: 2px; + border-style: solid; + border-color: #11111b; + color: @color2; +} + #backlight, #backlight-slider, #battery, diff --git a/config/waybar/style/[Pywal] Chroma Tally.css b/config/waybar/style/[Pywal] Chroma Tally.css index 41a15f3..fe3bc0f 100644 --- a/config/waybar/style/[Pywal] Chroma Tally.css +++ b/config/waybar/style/[Pywal] Chroma Tally.css @@ -62,6 +62,12 @@ window#waybar { } +tooltip { + background: #1e1e2e; + opacity: 0.8; + border-radius: 6px; +} + #backlight, #backlight-slider, #battery, diff --git a/config/waybar/style/[Transparent] Crystal Clear.css b/config/waybar/style/[Transparent] Crystal Clear.css index 430072d..0003efe 100644 --- a/config/waybar/style/[Transparent] Crystal Clear.css +++ b/config/waybar/style/[Transparent] Crystal Clear.css @@ -33,14 +33,6 @@ window#waybar.empty #window { background-color: transparent; } -tooltip { - background: #1e1e2e; - border-radius: 10px; - border-width: 2px; - border-style: solid; - border-color: #11111b; - color: #cba6f7; -} /*-----module groups----*/ .modules-right {