Add screenshots
6
README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# Hypr!Lazer
|
||||
|
||||
An AGSv2 config that aims to replicate the design language of osu!lazer.
|
||||
|
||||
### Power
|
||||
![assets/screensohts/power.png]
|
||||
20
app.ts
@@ -2,13 +2,27 @@ import { App } from "astal/gtk3"
|
||||
import style from "./style.scss"
|
||||
import Bar from "./widget/Bar"
|
||||
import Hyprland from "gi://AstalHyprland"
|
||||
import launcher from "./widget/launcher"
|
||||
|
||||
const hyprland = Hyprland.get_default()
|
||||
|
||||
App.start({
|
||||
css: style,
|
||||
icons: "/home/protoshark/.config/ags/assets/",
|
||||
main() {
|
||||
hyprland.monitors.map((monitor) => Bar(monitor))
|
||||
icons: "/home/spingus/.config/ags/assets/",
|
||||
requestHandler: (request: string, res: (response: any) => void) => {
|
||||
if (request === "launch") {
|
||||
if (launcher()) {
|
||||
res("Opening launcher")
|
||||
} else {
|
||||
res("Closing launcher")
|
||||
}
|
||||
return
|
||||
}
|
||||
res("Unknown command")
|
||||
},
|
||||
main: () => {
|
||||
hyprland.monitors.map((mon) => {
|
||||
Bar(mon)
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
BIN
assets/archlinux.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
9
assets/archlinux.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M186.575 162.152C204.721 177.464 234.004 193.426 259.419 203.385C237.557 187.519 215.801 169.636 194.085 146.23C212.161 107.684 233.745 54.4437 255.997 0.0976562C292.277 92.7957 359.897 232.3 450.483 397.816C425.873 384.303 403.575 376.609 380.553 370.664C388.183 375.019 406.218 384.861 417.79 392.772C436.07 405.269 452.988 418.935 468.897 432.021C483.097 458.131 497.471 484.781 512 511.901C439.744 470.064 369.527 436.174 312 425.706C330.833 321.235 257.12 259.599 215.24 326.096C199.114 351.699 194.753 393.883 202.4 425.229C129.667 439.235 58.503 478.44 0 511.902C68.143 388.425 137.038 263.253 186.575 162.152Z" fill="url(#paint0_linear)"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear" x1="74.981" y1="436.949" x2="436.88" y2="74.9114" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#0072FF"/>
|
||||
<stop offset="1" stop-color="#00E5A1"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 983 B |
@@ -1,7 +0,0 @@
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
|
||||
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
|
||||
|
||||
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB |
BIN
assets/screenshots/battery.png
Normal file
|
After Width: | Height: | Size: 159 KiB |
BIN
assets/screenshots/bluetooth.png
Normal file
|
After Width: | Height: | Size: 139 KiB |
BIN
assets/screenshots/brightness.png
Normal file
|
After Width: | Height: | Size: 136 KiB |
BIN
assets/screenshots/media.png
Normal file
|
After Width: | Height: | Size: 540 KiB |
BIN
assets/screenshots/notification.png
Normal file
|
After Width: | Height: | Size: 132 KiB |
BIN
assets/screenshots/notifications.png
Normal file
|
After Width: | Height: | Size: 504 KiB |
BIN
assets/screenshots/power.png
Normal file
|
After Width: | Height: | Size: 108 KiB |
BIN
assets/screenshots/volume.png
Normal file
|
After Width: | Height: | Size: 279 KiB |
BIN
assets/screenshots/workspaces.png
Normal file
|
After Width: | Height: | Size: 64 KiB |
@@ -327,9 +327,9 @@ button {
|
||||
background: $background-3;
|
||||
border-radius: 10px;
|
||||
padding: 8px;
|
||||
box-shadow: 0 0 16px 4px black;
|
||||
box-shadow: 0 0 10px 4px black;
|
||||
min-width: 300px;
|
||||
margin: 12px 12px 40px 40px;
|
||||
margin: 20px 20px 20px 40px;
|
||||
}
|
||||
|
||||
.notifIcon {
|
||||
|
||||
@@ -37,7 +37,6 @@ export default function Bar(monitor: Hyprland.Monitor) {
|
||||
{workspaces(monitor)}
|
||||
<box halign={Gtk.Align.END}>
|
||||
{player()}
|
||||
{client()}
|
||||
<button><box>
|
||||
<label
|
||||
className="innerButton"
|
||||
|
||||
@@ -64,7 +64,7 @@ function BrightWindow() {
|
||||
className="toggleButton"
|
||||
onClicked={(self) => {
|
||||
toggleIndicator.toggleClassName("active", !sunset())
|
||||
execAsync("/home/protoshark/.config/scripts/sunset-toggle.sh")
|
||||
execAsync("/home/spingus/.config/scripts/sunset-toggle.sh")
|
||||
.then((out) => (console.log(out)))
|
||||
.catch((out) => (console.log(out)))
|
||||
}}
|
||||
|
||||
@@ -14,23 +14,24 @@ const apps = new Apps.Apps({
|
||||
})
|
||||
|
||||
function NewClient(client: Hyprland.Client) {
|
||||
let appsClass = null
|
||||
if (client) {
|
||||
if (client.class == "soffice") {
|
||||
client.class = ""
|
||||
let appsClass
|
||||
if (!client) {
|
||||
appsClass = null
|
||||
}
|
||||
appsClass = apps.exact_query(client.class)[0]
|
||||
else if (client.class === "soffice") {
|
||||
appsClass = apps.list.find(app => app.wmClass === "libreoffice-startcenter")
|
||||
} else {
|
||||
appsClass = apps.list.find(app => app.wmClass === client?.class)
|
||||
}
|
||||
let b = <box halign={Gtk.Align.END} className="clientLabel" visible={true}>
|
||||
return <box halign={Gtk.Align.END} className="clientLabel" visible={true}>
|
||||
<icon
|
||||
icon={(appsClass) ? appsClass.iconName : "hyprland"}
|
||||
icon={appsClass?.iconName ?? "hyprland"}
|
||||
css="font-size: 24px; margin-right: 4px;"
|
||||
/>
|
||||
<label css="font-family: comfortaa; font-size: 14px;">{
|
||||
(appsClass) ? appsClass.name : "Hyprland"
|
||||
appsClass?.name ?? "Hyprland"
|
||||
}</label>
|
||||
</box>
|
||||
return b
|
||||
}
|
||||
|
||||
export default function client() {
|
||||
|
||||
46
widget/launcher.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import { Astal, Gtk, Widget } from "astal/gtk3"
|
||||
import { EventBox, Scrollable } from "astal/gtk3/widget"
|
||||
import Apps from "gi://AstalApps"
|
||||
const { TOP, RIGHT, BOTTOM } = Astal.WindowAnchor
|
||||
const apps = new Apps.Apps({
|
||||
entryMultiplier: 1,
|
||||
categories_multiplier: 0,
|
||||
description_multiplier: 1,
|
||||
executable_multiplier: 1,
|
||||
name_multiplier: 2.5,
|
||||
keywordsMultiplier: 1,
|
||||
})
|
||||
|
||||
let launcherWindow
|
||||
|
||||
function entry(app: Apps.Application) {
|
||||
return <overlay
|
||||
valign={Gtk.Align.START}>
|
||||
<label
|
||||
css={`background: green; border: 4px solid yellow; min-height: 100px;`}>
|
||||
{app.name}</label>
|
||||
</overlay>
|
||||
}
|
||||
|
||||
export default function launcher() {
|
||||
if (launcherWindow) {
|
||||
launcherWindow.destroy()
|
||||
launcherWindow = null
|
||||
return false
|
||||
}
|
||||
launcherWindow = <window
|
||||
anchor={ TOP | RIGHT | BOTTOM }
|
||||
className="launcher"
|
||||
namespace="launcher"
|
||||
widthRequest={800}
|
||||
css="background: none;"
|
||||
layer={Astal.Layer.OVERLAY}>
|
||||
<overlay overlay=
|
||||
<eventbox onScroll={() => console.log("scroll")}><box vertical>
|
||||
{apps.list.map(app => entry(app))}
|
||||
</box></eventbox>>
|
||||
<box css="background: linear-gradient(90deg, rgba(0, 0, 0, 0), #000);"/>
|
||||
</overlay>
|
||||
</window>
|
||||
return true
|
||||
}
|
||||
@@ -5,9 +5,15 @@ import Pango from "gi://Pango?version=1.0"
|
||||
const notifs = Notif.get_default()
|
||||
|
||||
const { TOP, RIGHT, BOTTOM } = Astal.WindowAnchor
|
||||
const notifPlaceholder = "/home/protoshark/.config/ags/assets/notif.svg"
|
||||
const notifPlaceholder = "/home/spingus/.config/ags/assets/notif.svg"
|
||||
let notifWindow: Widget.Window
|
||||
let lastId: number
|
||||
|
||||
const wrap = (str: string, chars: number): string => {
|
||||
if (str.length <= chars)
|
||||
return str;
|
||||
return str.substring(0, chars) + "\n" + wrap(str.substring(chars), chars);
|
||||
}
|
||||
|
||||
function NewNotif(notif: Notif.Notification, inPanel: boolean = true) {
|
||||
return <box
|
||||
@@ -28,19 +34,13 @@ function NewNotif(notif: Notif.Notification, inPanel: boolean = true) {
|
||||
hexpand>
|
||||
<label
|
||||
halign={Gtk.Align.START}
|
||||
css="font-size: 16px;"
|
||||
wrap={true}
|
||||
maxWidthChars={20}
|
||||
wrapMode={Pango.WrapMode.WORD_CHAR}>
|
||||
{notif.summary.substring(0, 80)}
|
||||
css="font-size: 16px;">
|
||||
{wrap(notif.summary, 18)}
|
||||
</label>
|
||||
<label
|
||||
halign={Gtk.Align.START}
|
||||
css="font-size: 14px;"
|
||||
wrap={true}
|
||||
maxWidthChars={22}
|
||||
wrapMode={Pango.WrapMode.WORD_CHAR}>
|
||||
{notif.body.substring(0, 88)}
|
||||
css="font-size: 14px;">
|
||||
{wrap(notif.body, 22)}
|
||||
</label>
|
||||
</box>
|
||||
<box vertical valign={Gtk.Align.CENTER}>
|
||||
@@ -62,7 +62,6 @@ function NotifPanel() {
|
||||
<box>
|
||||
<button
|
||||
hexpand
|
||||
heightRequest={36}
|
||||
onClicked={() => {
|
||||
for (let n of notifs.notifications) {
|
||||
n.dismiss()
|
||||
@@ -88,11 +87,9 @@ function notify(notif: Notif.Notification) {
|
||||
let thisNotif = NewNotif(notif)
|
||||
if (notifWindow) {
|
||||
let os = notifWindow.get_child().overlays
|
||||
let top = 12
|
||||
for (let i = os.length-1; i > 0; i--) {
|
||||
top += thisNotif.get_preferred_height()[0] - 40
|
||||
if (os[i].get_preferred_width()[0] >= 352) {
|
||||
os[i].css = `margin-top: ${top}px;`
|
||||
os[i].css = `margin-top: ${(os[i+1]?.get_preferred_height()[0] ?? 20)+thisNotif.get_preferred_height()[0]-20}px;`
|
||||
}
|
||||
}
|
||||
notifWindow.get_child().add_overlay(thisNotif)
|
||||
@@ -100,8 +97,8 @@ function notify(notif: Notif.Notification) {
|
||||
} else {
|
||||
notifWindow = <window
|
||||
anchor={ TOP | RIGHT }
|
||||
marginTop={36}
|
||||
layer={Astal.Layer.OVERLAY}
|
||||
marginTop={36}
|
||||
css="background: transparent;"
|
||||
namespace="notification">
|
||||
<overlay overlay={thisNotif}>
|
||||
@@ -116,7 +113,8 @@ function notify(notif: Notif.Notification) {
|
||||
}
|
||||
setTimeout(() => {
|
||||
let os = notifWindow.get_child().overlays
|
||||
thisNotif.css = `margin-right: -352px; margin-top: ${thisNotif.get_preferred_height()[0]-thisNotif.get_child().get_preferred_height()[0]-52}px; transition: cubic-bezier(0.64, 0, 0.78, 0) 0.3s;`
|
||||
let thisIndex = os.findIndex(nb => nb == thisNotif)
|
||||
thisNotif.css = `margin-right: -352px; margin-top: ${(thisIndex === os.length-1) ? 20 : os[thisIndex+1].get_preferred_height()[0]+20}px; transition: cubic-bezier(0.64, 0, 0.78, 0) 0.3s;`
|
||||
setTimeout(() => {
|
||||
let os = notifWindow.get_child().overlays
|
||||
notifWindow.get_child().remove(thisNotif)
|
||||
@@ -128,12 +126,6 @@ function notify(notif: Notif.Notification) {
|
||||
}, 3000)
|
||||
}
|
||||
|
||||
function notifCount() {
|
||||
return <label css="padding-top: 2px;">
|
||||
{bind(notifs, "notifications").as(ns => ns.length)}
|
||||
</label>
|
||||
}
|
||||
|
||||
export default function notifWidget() {
|
||||
return <button
|
||||
onClicked={() => {
|
||||
@@ -145,11 +137,15 @@ export default function notifWidget() {
|
||||
}
|
||||
}}
|
||||
setup={(self) => self.hook(notifs, "notified", (_, id) => {
|
||||
notify(notifs.get_notification(id))
|
||||
if (lastId === id) {
|
||||
return
|
||||
}
|
||||
lastId = id
|
||||
let notif = notifs.get_notification(id)
|
||||
notify(notif)
|
||||
})}>
|
||||
<box>
|
||||
<icon icon="notif" css="color: white;" />
|
||||
{notifCount()}
|
||||
</box>
|
||||
</button>
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ function PowerWindow() {
|
||||
<box vertical css="padding: 6px 0;">
|
||||
{[
|
||||
["Lock", "bash -c 'pgrep -x hyprlock || hyprlock &'" ],
|
||||
["Suspend", "/home/protoshark/.config/scripts/lock.sh" ],
|
||||
["Suspend", "/home/spingus/.config/scripts/lock.sh" ],
|
||||
["Logout", "hyprctl dispatch exit" ],
|
||||
["Shutdown", "systemctl poweroff" ],
|
||||
["Reboot", "systemctl reboot" ],
|
||||
|
||||