Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0a3fef0b1c | |||
| aace131a0e | |||
| 6117dca845 | |||
| 43a074f355 | |||
| 58af37ea8c | |||
| da76e6c12a | |||
| ce804942a9 |
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"WebFetch(domain:elkowar.github.io)",
|
||||
"WebFetch(domain:github.com)",
|
||||
"WebFetch(domain:raw.githubusercontent.com)",
|
||||
"WebSearch",
|
||||
"WebFetch(domain:deepwiki.com)",
|
||||
"Bash(amdgpu_top -J -s 1000 -d 1)",
|
||||
"Bash(amdgpu_top -J -s 1000 -n 1)",
|
||||
"Bash(sensors -j)"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,48 +1,108 @@
|
||||
.calendar-win {
|
||||
}
|
||||
|
||||
calendar {
|
||||
padding: 5pt;
|
||||
padding: $popup-scale * 1.75pt $popup-scale * 1pt;
|
||||
font-size: $popup-scale * 8pt;
|
||||
|
||||
:selected {
|
||||
color: $base0C;
|
||||
header {
|
||||
padding: $popup-scale * 2pt 0;
|
||||
@include color-body;
|
||||
}
|
||||
|
||||
.header {
|
||||
color: $base05;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
color: $base0C;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 20pt;
|
||||
color: $base0C;
|
||||
}
|
||||
|
||||
:indeterminate {
|
||||
color: $base03;
|
||||
}
|
||||
:selected { @include color-accent; }
|
||||
.highlight { @include color-accent; font-weight: bold; }
|
||||
:indeterminate { color: $base03; }
|
||||
}
|
||||
|
||||
.cal-box .sys-section-header { margin-bottom: $popup-scale * 4pt; }
|
||||
|
||||
|
||||
.hour, .month {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
.minute, .month {
|
||||
margin-top: -4pt;
|
||||
margin-top: $popup-scale * -4pt;
|
||||
}
|
||||
|
||||
|
||||
.date {
|
||||
color: $base0C;
|
||||
background-color: $base01;
|
||||
border-radius: $border-radius;
|
||||
@include color-accent;
|
||||
@include background-base;
|
||||
@include border-radius;
|
||||
}
|
||||
|
||||
.datetime {
|
||||
padding: $gaps-window;
|
||||
}
|
||||
|
||||
// Clock window accents
|
||||
.weather-accent { background-color: $base0A; }
|
||||
.cal-accent { background-color: $base0B; }
|
||||
.bri-accent { background-color: $base09; }
|
||||
.vol-accent { background-color: $base0D; }
|
||||
.quick-accent { background-color: $base0E; }
|
||||
|
||||
// Quick actions
|
||||
.quick-grid { margin-top: $popup-scale * 2pt; }
|
||||
|
||||
.quick-btn {
|
||||
@include background-base2;
|
||||
@include border-radius;
|
||||
padding: $popup-scale * 8pt $popup-scale * 4pt;
|
||||
margin: $popup-scale * 4px;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
border: none;
|
||||
|
||||
&:hover {
|
||||
@include background-active;
|
||||
.quick-icon, .quick-label {color: $base01;}
|
||||
}
|
||||
}
|
||||
|
||||
.quick-btn-active {
|
||||
.quick-icon { @include color-accent; }
|
||||
.quick-label { @include color-accent; }
|
||||
}
|
||||
|
||||
.quick-icon { font-size: 1.5em; @include color-body; }
|
||||
.quick-label { font-size: 0.68em; margin-top: $popup-scale * 3pt; @include color-body; }
|
||||
|
||||
// Weather section
|
||||
.weather-main { margin-bottom: $popup-scale * 8pt; }
|
||||
.weather-icon { font-size: 2.2em; margin-right: $popup-scale * 12pt; @include color-accent; }
|
||||
.weather-temp { font-size: 1.3em; font-weight: bold; @include color-base; }
|
||||
.weather-desc { font-size: 0.78em; @include color-body; }
|
||||
.weather-stats { margin-top: $popup-scale * 4pt; }
|
||||
|
||||
// Volume section
|
||||
.ctrl-row { margin-bottom: $popup-scale * 4pt; }
|
||||
.ctrl-icon { font-size: 1.1em; min-width: $popup-scale * 22pt; @include border-radius; @include color-body; }
|
||||
.ctrl-icon:hover { @include background-active; }
|
||||
.ctrl-muted { @include color-inactive; }
|
||||
.ctrl-value { font-size: 0.72em; min-width: $popup-scale * 28pt; @include color-active; }
|
||||
|
||||
scale.ctrl-slider.ctrl-slider-muted {
|
||||
trough {
|
||||
highlight { background-color: $base03; }
|
||||
slider { background-color: $base03; }
|
||||
}
|
||||
}
|
||||
|
||||
scale.ctrl-slider {
|
||||
padding: $popup-scale * 2pt $popup-scale * 4pt;
|
||||
trough {
|
||||
@include border-radius;
|
||||
@include background-base2;
|
||||
min-height: 5px;
|
||||
highlight { background-color: $base0C; @include border-radius; }
|
||||
}
|
||||
slider {
|
||||
background-color: $base07;
|
||||
min-height: 11px;
|
||||
min-width: 11px;
|
||||
@include border-radius;
|
||||
margin: -3px;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,3 +27,6 @@ $border-width: 2px;
|
||||
|
||||
$gaps-screen: 8px;
|
||||
$gaps-window: 4px;
|
||||
|
||||
$panel-font-size: 10pt;
|
||||
$popup-scale: 1;
|
||||
@@ -1,24 +1,36 @@
|
||||
// Bar icons
|
||||
.net-icon { font-size: 14px; padding: 3pt 0; }
|
||||
.net-active { color: $base07; }
|
||||
.net-dim { color: $base02; }
|
||||
.blt-on { color: $base07; }
|
||||
.blt-connected { color: $base0D; }
|
||||
.net-icon { font-size: 14px; padding: 3pt 0; }
|
||||
.net-active, .blt-on { @include color-base; }
|
||||
.net-dim { @include color-inactive; }
|
||||
.blt-connected { @include color-accent; }
|
||||
|
||||
// Popup window section accents
|
||||
.wifi-accent { background-color: $base0C; }
|
||||
.eth-accent { background-color: $base0B; }
|
||||
.blt-accent { background-color: $base0D; }
|
||||
.usb-accent { background-color: $base09; }
|
||||
|
||||
// Netinfo rows
|
||||
.netinfo-row { margin-bottom: 3pt; }
|
||||
.netinfo-label { font-size: 0.72em; color: $base04; min-width: 60px; }
|
||||
.netinfo-value { font-size: 0.72em; color: $base05; }
|
||||
.netinfo-dim { font-size: 0.72em; color: $base03; margin-bottom: 4pt; }
|
||||
.netinfo-row { margin-bottom: $popup-scale * 3pt; }
|
||||
.netinfo-label, .netinfo-value, .netinfo-dim { font-size: 0.72em; }
|
||||
.netinfo-label { @include color-active; min-width: $popup-scale * 60px; }
|
||||
.netinfo-value { @include color-body; }
|
||||
.netinfo-dim { color: $base03; margin-bottom: $popup-scale * 4pt; }
|
||||
|
||||
// Section toggle button
|
||||
.net-toggle-btn {
|
||||
padding: $popup-scale * 2pt $popup-scale * 4pt;
|
||||
@include border-radius;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
// Bluetooth device list
|
||||
.bt-device-row { margin-bottom: 4pt; }
|
||||
.bt-device-name { font-size: 0.78em; color: $base05; }
|
||||
.bt-device-btn { padding: 2pt 6pt; border-radius: $border-radius; font-size: 1em; }
|
||||
.bt-btn-on { color: $base0D; }
|
||||
.bt-btn-off { color: $base03; }
|
||||
.bt-device-row { margin-bottom: $popup-scale * 4pt; }
|
||||
.bt-device-name { font-size: 0.78em; @include color-body; }
|
||||
.bt-device-btn { padding: $popup-scale * 2pt $popup-scale * 6pt; @include border-radius; font-size: 1em; }
|
||||
|
||||
// Shared button states
|
||||
.net-toggle-btn:hover,
|
||||
.bt-device-btn:hover { @include background-active; }
|
||||
.net-toggle-on, .bt-btn-on { @include color-base; }
|
||||
.net-toggle-off, .bt-btn-off { @include color-inactive; }
|
||||
|
||||
@@ -1,26 +1,21 @@
|
||||
.powermenu-box {
|
||||
padding-left: 2.5rem;
|
||||
padding-right: 2.5rem;
|
||||
padding-top: 3rem;
|
||||
padding-bottom: 3rem;
|
||||
margin:0 0 0 0;
|
||||
}
|
||||
padding: 3rem 2.5rem;
|
||||
margin: 0;
|
||||
|
||||
.powermenu-entry {
|
||||
.powermenu-entry {
|
||||
margin: 0 0.5rem;
|
||||
}
|
||||
|
||||
.powermenu-button {
|
||||
background-color: $base02;
|
||||
border-radius: 1rem;
|
||||
transition: 0.3s;
|
||||
padding: 3.25rem 4rem;
|
||||
}
|
||||
.powermenu-button {
|
||||
@include background-active;
|
||||
border-radius: 1rem;
|
||||
transition: 0.3s;
|
||||
padding: 3.25rem 4rem;
|
||||
|
||||
.powermenu-button:hover {
|
||||
background-color:$base03;
|
||||
}
|
||||
&:hover { background-color: $base03; }
|
||||
}
|
||||
}
|
||||
|
||||
.powermenu-icon {
|
||||
.powermenu-icon {
|
||||
font-size: 4rem;
|
||||
}
|
||||
}
|
||||
@@ -1,75 +1,90 @@
|
||||
|
||||
.radio-win {
|
||||
//margin: $gaps-screen;
|
||||
//padding: .5em;
|
||||
}
|
||||
.radio-accent { background-color: $base0D; }
|
||||
|
||||
.album_art {
|
||||
background-repeat: no-repeat;
|
||||
background-size: 240px;
|
||||
min-height: 240px;
|
||||
min-width: 240px;
|
||||
margin: $gaps-screen;
|
||||
border-radius: $border-radius;
|
||||
// Now playing
|
||||
.radio-now-playing {
|
||||
margin-bottom: $popup-scale * 8pt;
|
||||
}
|
||||
|
||||
.song {
|
||||
color: $base0C;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
margin: 20px 0px 0px 0px;
|
||||
.radio-art {
|
||||
background-repeat: no-repeat;
|
||||
@include border-radius;
|
||||
@include background-base2;
|
||||
min-width: $popup-scale * 72px;
|
||||
min-height: $popup-scale * 72px;
|
||||
}
|
||||
|
||||
.artist {
|
||||
color: $base0E;
|
||||
font-size: 16px;
|
||||
font-weight: normal;
|
||||
margin: 0px 0px $gaps-screen 0px;
|
||||
.radio-art-icon {
|
||||
font-size: 2em;
|
||||
@include color-body;
|
||||
}
|
||||
|
||||
.btn_bar {
|
||||
color: $base05;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
margin: $gaps-screen 0px;
|
||||
.radio-song {
|
||||
font-size: 0.88em;
|
||||
font-weight: bold;
|
||||
@include color-base;
|
||||
margin-bottom: $popup-scale * 2pt;
|
||||
}
|
||||
|
||||
.btn_play {
|
||||
font-size: 48px;
|
||||
font-weight: bold;
|
||||
margin: 0 12px;
|
||||
.radio-artist {
|
||||
font-size: 0.74em;
|
||||
@include color-body;
|
||||
}
|
||||
|
||||
.btn_play:hover {
|
||||
color: $base07;
|
||||
// Controls
|
||||
.radio-controls {
|
||||
margin-top: $popup-scale * 6pt;
|
||||
}
|
||||
|
||||
|
||||
.station_list {
|
||||
border-right-color: $base03;
|
||||
border-right-style: solid;
|
||||
border-right-width: $border-width;
|
||||
margin-right: $gaps-screen;
|
||||
.radio-ctrl-btn {
|
||||
font-size: 2em;
|
||||
padding: $popup-scale * 4pt $popup-scale * 20pt;
|
||||
@include border-radius;
|
||||
@include color-body;
|
||||
&:hover { @include background-active; @include color-base; }
|
||||
}
|
||||
|
||||
.station_art {
|
||||
background-repeat: no-repeat;
|
||||
background-size: 50px;
|
||||
min-height: 50px;
|
||||
min-width: 50px;
|
||||
margin: $gaps-window;
|
||||
margin-right: $gaps-screen;
|
||||
background-color: $base00;
|
||||
border-radius: $border-radius;
|
||||
border-color: $base00;
|
||||
border-style: solid;
|
||||
border-width: $border-width;
|
||||
// Station list
|
||||
.station-list {}
|
||||
|
||||
scrollbar {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
min-width: 6px;
|
||||
}
|
||||
scrollbar trough {
|
||||
@include background-base2;
|
||||
@include border-radius;
|
||||
min-width: 6px;
|
||||
}
|
||||
scrollbar slider {
|
||||
background-color: $base04;
|
||||
@include border-radius;
|
||||
min-width: 6px;
|
||||
min-height: 20px;
|
||||
&:hover { background-color: $base05; }
|
||||
}
|
||||
|
||||
.station_art:hover {
|
||||
border-color: $base04;
|
||||
.station-row {
|
||||
padding: $popup-scale * 4pt $popup-scale * 3pt;
|
||||
@include border-radius;
|
||||
&:hover { @include background-base2; }
|
||||
}
|
||||
|
||||
.station_sel {
|
||||
border-color: $base03;
|
||||
.station-row-active {
|
||||
.station-name { @include color-accent; }
|
||||
}
|
||||
|
||||
.station-icon {
|
||||
background-repeat: no-repeat;
|
||||
@include border-radius;
|
||||
@include background-base2;
|
||||
min-width: $popup-scale * 28px;
|
||||
min-height: $popup-scale * 28px;
|
||||
margin-right: $popup-scale * 8pt;
|
||||
}
|
||||
|
||||
.station-name {
|
||||
font-size: 0.76em;
|
||||
@include color-body;
|
||||
}
|
||||
@@ -4,36 +4,24 @@
|
||||
.gpubar { color: $base0E; }
|
||||
.membar { color: $base08; }
|
||||
.batbar { color: $base0B; }
|
||||
.cpubar, .gpubar, .membar, .batbar { @include background-base2; margin: $gaps-window 0; }
|
||||
|
||||
.cpubar, .gpubar, .membar, .batbar {
|
||||
background-color: $bg0;
|
||||
margin: $gaps-window 0;
|
||||
}
|
||||
|
||||
// Window
|
||||
.sys-win {
|
||||
padding: 10pt;
|
||||
}
|
||||
|
||||
.sys-section {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.sys-section-header {
|
||||
margin-bottom: 10pt;
|
||||
}
|
||||
// Window chrome
|
||||
.sys-win { padding: $popup-scale * 10pt; font-size: $popup-scale * $panel-font-size; }
|
||||
.sys-section { margin-bottom: 0; }
|
||||
.sys-section-header { margin-bottom: $popup-scale * 10pt; }
|
||||
|
||||
.sys-label {
|
||||
font-size: 0.72em;
|
||||
font-weight: bold;
|
||||
letter-spacing: 0.14em;
|
||||
color: $base05;
|
||||
@include color-body;
|
||||
}
|
||||
|
||||
.section-accent {
|
||||
min-width: 3px;
|
||||
border-radius: 2px;
|
||||
margin-right: 8pt;
|
||||
margin-right: $popup-scale * 8pt;
|
||||
}
|
||||
|
||||
.cpu-accent { background-color: $base0C; }
|
||||
@@ -42,145 +30,64 @@
|
||||
.bat-accent { background-color: $base0B; }
|
||||
|
||||
.section-sep {
|
||||
background-color: $base02;
|
||||
background-color: $base03;
|
||||
min-height: 2px;
|
||||
margin: 6pt 0 10pt 0;
|
||||
margin: $popup-scale * 6pt 0 $popup-scale * 10pt;
|
||||
}
|
||||
|
||||
.sys-sublabel {
|
||||
font-size: 0.72em;
|
||||
color: $base04;
|
||||
margin-right: 8pt;
|
||||
}
|
||||
// All rings and progress tracks share the same background
|
||||
.cpu-usage-ring, .cpu-freq-ring,
|
||||
.gpu-ring, .gpu-freq-ring,
|
||||
.ram-ring, .swap-ring, .bat-ring,
|
||||
.vram-bar { @include background-base2; }
|
||||
|
||||
// CPU grid
|
||||
.cpu-usage-ring {
|
||||
color: $base0C;
|
||||
background-color: $bg0;
|
||||
margin: 3pt;
|
||||
}
|
||||
// Ring colors
|
||||
.cpu-usage-ring { color: $base0C; }
|
||||
.cpu-freq-ring, .gpu-freq-ring { color: $base0D; }
|
||||
.gpu-ring { color: $base0E; }
|
||||
.ram-ring { color: $base08; }
|
||||
.swap-ring { color: $base09; }
|
||||
|
||||
// Inner freq ring — margin shrinks it inside overlay for concentric effect
|
||||
// 0% = cpu min freq, 100% = cpu max freq
|
||||
.cpu-freq-ring {
|
||||
color: $base0D;
|
||||
background-color: $bg0;
|
||||
margin: 12px;
|
||||
}
|
||||
// Ring margins - freq rings use larger margins for concentric overlay effect
|
||||
.cpu-usage-ring, .gpu-ring { margin: $popup-scale * 3pt; }
|
||||
.ram-ring, .bat-ring { margin: $popup-scale * 4pt; }
|
||||
.swap-ring { margin: $popup-scale * 3.5pt; }
|
||||
.cpu-freq-ring { margin: $popup-scale * 12px; }
|
||||
.gpu-freq-ring { margin: $popup-scale * 13px; }
|
||||
|
||||
.cpu-core-label {
|
||||
font-size: 0.7em;
|
||||
color: $base05;
|
||||
}
|
||||
// Shared label patterns
|
||||
.gpu-ring-value, .gpu-stat-value, .ram-used-label { font-weight: bold; @include color-body; }
|
||||
.gpu-ring-value { font-size: 0.82em; }
|
||||
.gpu-stat-value { font-size: 0.85em; }
|
||||
.ram-used-label { font-size: 0.95em; }
|
||||
|
||||
// GPU rings
|
||||
.gpu-ring {
|
||||
color: $base0E;
|
||||
background-color: $bg0;
|
||||
margin: 3pt;
|
||||
}
|
||||
.gpu-ring-label, .gpu-stat-label,
|
||||
.vram-usage-label, .swap-section-label { font-size: 0.62em; @include color-active; }
|
||||
.gpu-ring-label, .vram-usage-label, .swap-section-label { margin-top: 2pt; }
|
||||
|
||||
.gpu-freq-ring {
|
||||
color: $base0D;
|
||||
background-color: $bg0;
|
||||
margin: 13px;
|
||||
}
|
||||
|
||||
.gpu-ring-value {
|
||||
font-size: 0.82em;
|
||||
font-weight: bold;
|
||||
color: $base05;
|
||||
}
|
||||
|
||||
.gpu-ring-label {
|
||||
font-size: 0.62em;
|
||||
color: $base04;
|
||||
margin-top: 2pt;
|
||||
}
|
||||
.cpu-core-label { font-size: 0.7em; @include color-active; }
|
||||
.bat-ring-label { font-size: 0.7em; @include color-body; }
|
||||
.ram-total-label { font-size: 0.72em; @include color-active; }
|
||||
|
||||
// GPU stats row
|
||||
.gpu-stats-row {
|
||||
margin-top: 6pt;
|
||||
margin-bottom: 2pt;
|
||||
}
|
||||
.gpu-stats-row { margin-top: $popup-scale * 6pt; margin-bottom: $popup-scale * 2pt; }
|
||||
|
||||
.gpu-stat-value {
|
||||
font-size: 0.85em;
|
||||
font-weight: bold;
|
||||
color: $base05;
|
||||
}
|
||||
|
||||
.gpu-stat-label {
|
||||
font-size: 0.62em;
|
||||
color: $base04;
|
||||
}
|
||||
|
||||
// VRAM bar
|
||||
.vram-row {
|
||||
margin-top: 6pt;
|
||||
}
|
||||
// VRAM
|
||||
.vram-row { margin-top: $popup-scale * 6pt; }
|
||||
|
||||
.vram-bar {
|
||||
background-color: $bg0;
|
||||
border-radius: $border-radius;
|
||||
padding: 4pt;
|
||||
@include border-radius;
|
||||
padding: $popup-scale * 2pt;
|
||||
}
|
||||
|
||||
.vram-bar trough * {
|
||||
background-color: $base0E;
|
||||
border-radius: $border-radius;
|
||||
}
|
||||
|
||||
.vram-usage-label {
|
||||
font-size: 0.62em;
|
||||
color: $base04;
|
||||
margin-top: 2pt;
|
||||
}
|
||||
|
||||
// RAM ring
|
||||
.ram-ring {
|
||||
color: $base08;
|
||||
background-color: $bg0;
|
||||
margin: 4pt;
|
||||
@include border-radius;
|
||||
}
|
||||
|
||||
// RAM cached ring overrides group background
|
||||
.ram-cached-ring {
|
||||
color: $base02;
|
||||
@include color-active;
|
||||
background-color: transparent;
|
||||
margin: 4pt;
|
||||
}
|
||||
|
||||
.ram-used-label {
|
||||
font-size: 0.95em;
|
||||
font-weight: bold;
|
||||
color: $base05;
|
||||
}
|
||||
|
||||
.ram-total-label {
|
||||
font-size: 0.72em;
|
||||
color: $base04;
|
||||
}
|
||||
|
||||
// Swap ring
|
||||
.swap-ring {
|
||||
color: $base09;
|
||||
background-color: $bg0;
|
||||
margin: 3pt;
|
||||
}
|
||||
|
||||
.swap-section-label {
|
||||
font-size: 0.62em;
|
||||
color: $base04;
|
||||
margin-top: 2pt;
|
||||
}
|
||||
|
||||
// Battery ring
|
||||
.bat-ring {
|
||||
background-color: $bg0;
|
||||
margin: 4pt;
|
||||
}
|
||||
|
||||
.bat-ring-label {
|
||||
font-size: 0.7em;
|
||||
color: $base05;
|
||||
margin: $popup-scale * 4pt;
|
||||
}
|
||||
|
||||
@@ -1,35 +1,28 @@
|
||||
.tray * {
|
||||
padding: $border-width 0px;
|
||||
padding: $border-width 0;
|
||||
}
|
||||
|
||||
.tray menu {
|
||||
background-color: $base01;
|
||||
color: $base07;
|
||||
@include border-radius;
|
||||
@include border-active;
|
||||
@include border-radius;
|
||||
@include border-active;
|
||||
@include background-base;
|
||||
@include color-base;
|
||||
|
||||
padding: 10px 0;
|
||||
|
||||
padding: 10px 0px;
|
||||
> menuitem {
|
||||
margin: 2px $border-width;
|
||||
padding: 0 10px;
|
||||
|
||||
>menuitem {
|
||||
margin: 2px $border-width;
|
||||
padding: 0px 10px;
|
||||
&:disabled label { @include color-active; }
|
||||
&:hover { @include background-accent; }
|
||||
}
|
||||
|
||||
&:disabled label {
|
||||
color: $base04;
|
||||
}
|
||||
separator {
|
||||
@include background-base2;
|
||||
padding-top: 1px;
|
||||
margin: 10px 0;
|
||||
|
||||
&:hover {
|
||||
background-color: $base0C;
|
||||
}
|
||||
}
|
||||
|
||||
separator {
|
||||
background-color: $base03;
|
||||
padding-top: 1px;
|
||||
margin:10px 0px;
|
||||
|
||||
&:last-child {
|
||||
padding: unset;
|
||||
}
|
||||
}
|
||||
&:last-child { padding: unset; }
|
||||
}
|
||||
}
|
||||
@@ -18,8 +18,45 @@
|
||||
border-color: $base04;
|
||||
}
|
||||
|
||||
@mixin test {
|
||||
@mixin background-base {
|
||||
background-color: $base01;
|
||||
}
|
||||
@mixin background-base2 {
|
||||
background-color: $base02;
|
||||
}
|
||||
@mixin background-active {
|
||||
background-color: $base04;
|
||||
}
|
||||
@mixin background-accent {
|
||||
background-color: $base0C;
|
||||
}
|
||||
@mixin color-base {
|
||||
color: $base07;
|
||||
}
|
||||
@mixin color-inactive {
|
||||
color: $base02;
|
||||
}
|
||||
@mixin color-active {
|
||||
color: $base04;
|
||||
}
|
||||
@mixin color-accent {
|
||||
color: $base0C;
|
||||
}
|
||||
@mixin color-body {
|
||||
color: $base05;
|
||||
}
|
||||
|
||||
@mixin panel-base {
|
||||
@include border-radius;
|
||||
@include border-inactive;
|
||||
@include background-base;
|
||||
@include color-base;
|
||||
}
|
||||
|
||||
@mixin mod-edge {
|
||||
border-right-style: none;
|
||||
border-bottom-right-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
|
||||
/* GENERAL */
|
||||
@@ -31,9 +68,9 @@
|
||||
}
|
||||
|
||||
tooltip {
|
||||
background: $base01;
|
||||
border: $border-width solid $base04;
|
||||
border-radius: $border-radius;
|
||||
@include border-active;
|
||||
@include border-radius;
|
||||
@include background-base;
|
||||
|
||||
label {
|
||||
font-size: 1rem;
|
||||
@@ -49,33 +86,17 @@ tooltip {
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.grey {
|
||||
color: $base02;
|
||||
}
|
||||
|
||||
.red {
|
||||
color: $base0F;
|
||||
}
|
||||
|
||||
.orange {
|
||||
color: $base08;
|
||||
}
|
||||
|
||||
.green {
|
||||
color: $base0B;
|
||||
}
|
||||
|
||||
.blue {
|
||||
color: $base0C;
|
||||
}
|
||||
/* WORKSPACE COLORS - emitted dynamically by scripts/workspaces as class names */
|
||||
.grey { color: $base02; }
|
||||
.red { color: $base0F; }
|
||||
.orange { color: $base08; }
|
||||
.green { color: $base0B; }
|
||||
.blue { color: $base0C; }
|
||||
|
||||
/* WINDOW WRAPPER CSS */
|
||||
|
||||
.winevent {
|
||||
background-color: $base01;
|
||||
color: $base07;
|
||||
@include border-radius;
|
||||
@include border-inactive;
|
||||
@include panel-base;
|
||||
}
|
||||
.winevent:hover {
|
||||
@include border-active;
|
||||
@@ -91,19 +112,12 @@ tooltip {
|
||||
/* MODULE WRAPPER CSS */
|
||||
|
||||
.modevent {
|
||||
background-color: $base01;
|
||||
color: $base07;
|
||||
@include border-radius;
|
||||
@include border-inactive;
|
||||
border-right-style: none;
|
||||
border-bottom-right-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
@include panel-base;
|
||||
@include mod-edge;
|
||||
}
|
||||
.modevent:hover {
|
||||
@include border-active;
|
||||
border-right-style: none;
|
||||
border-bottom-right-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
@include mod-edge;
|
||||
}
|
||||
|
||||
.modinner {
|
||||
|
||||
@@ -5,9 +5,12 @@
|
||||
(include "modules/systray.yuck")
|
||||
(include "modules/clock.yuck")
|
||||
|
||||
(include "windows/calendar.yuck")
|
||||
(defvar active-panel "")
|
||||
|
||||
(include "windows/sys.yuck")
|
||||
(include "windows/net.yuck")
|
||||
(include "windows/clock.yuck")
|
||||
(include "windows/popup.yuck")
|
||||
(include "windows/radio.yuck")
|
||||
(include "windows/powermenu.yuck")
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
(eventbox
|
||||
:onhover "${EWW_CMD} update date_rev=true"
|
||||
:onhoverlost "${EWW_CMD} update date_rev=false"
|
||||
:onclick "(sleep 0.1 && eww-open-on-current-screen calendar --toggle)"
|
||||
:onclick "(sleep 0.1 && scripts/panel-toggle clock)"
|
||||
:onrightclick "(sleep 0.1 && eww-open-on-current-screen powermenu --toggle)"
|
||||
(box
|
||||
:class "datetime"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
(deflisten net
|
||||
:initial '{"wifi":{"connected":false,"icon":"","ssid":""},"ethernet":{"connected":false}}'
|
||||
:initial '{"wifi":{"connected":false,"enabled":false,"icon":"","ssid":""},"ethernet":{"connected":false},"usb":{"connected":false}}'
|
||||
"scripts/net/net")
|
||||
|
||||
(deflisten bluetooth
|
||||
@@ -9,12 +9,17 @@
|
||||
(defwidget net-mod []
|
||||
(module
|
||||
(eventbox
|
||||
:onclick "(sleep 0.1 && eww-open-on-current-screen net --toggle)"
|
||||
:onclick "(sleep 0.1 && scripts/panel-toggle net)"
|
||||
(box :orientation "v"
|
||||
(label
|
||||
:class "net-icon ${net.ethernet.connected ? 'net-active' : 'net-dim'}"
|
||||
:tooltip {net.ethernet.connected ? "Ethernet: Connected" : "Ethernet: Disconnected"}
|
||||
:text "")
|
||||
(label
|
||||
:visible {net.usb.connected}
|
||||
:class "net-icon net-active"
|
||||
:tooltip "USB: Connected"
|
||||
:text "")
|
||||
(label
|
||||
:class "net-icon ${net.wifi.connected ? 'net-active' : 'net-dim'}"
|
||||
:tooltip {net.wifi.connected ? "WiFi: ${net.wifi.ssid}" : "WiFi: Disconnected"}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
(deflisten cpu :initial '{}' "scripts/sys/cpu")
|
||||
(deflisten gpu :initial '{"gfx_pct":0,"mem_pct":0,"media_pct":0,"sclk":0,"mclk":0,"sclk_pct":0,"mclk_pct":0,"vclk":0,"vclk_pct":0,"temp":0,"power":0,"vram_used":0,"vram_total":1}' "scripts/sys/gpu")
|
||||
(deflisten memory :initial '{"human":{"used":"0G","total":"0G","cached":"0G"},"used":0.0,"total":1.0,"cached":0.0}' "scripts/sys/memory")
|
||||
|
||||
@@ -7,7 +6,7 @@
|
||||
(defwidget sys-mod []
|
||||
(module
|
||||
(eventbox
|
||||
:onclick "(sleep 0.1 && eww-open-on-current-screen sys --toggle)"
|
||||
:onclick "(sleep 0.1 && scripts/panel-toggle sys)"
|
||||
(box :orientation "v"
|
||||
(circular-progress
|
||||
:value {EWW_CPU.avg}
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
BACKLIGHT="/sys/class/backlight"
|
||||
DEV=$(ls "$BACKLIGHT" 2>/dev/null | head -n1)
|
||||
|
||||
gen_output() {
|
||||
if [ -z "$DEV" ]; then
|
||||
echo '{"percent":0,"available":false}'
|
||||
return
|
||||
fi
|
||||
max=$(cat "$BACKLIGHT/$DEV/max_brightness")
|
||||
cur=$(cat "$BACKLIGHT/$DEV/actual_brightness" 2>/dev/null || cat "$BACKLIGHT/$DEV/brightness")
|
||||
percent=$(awk -v c="$cur" -v m="$max" 'BEGIN{print int(c/m*100+0.5)}')
|
||||
printf '{"percent":%d,"available":true}\n' "$percent"
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
set)
|
||||
[ -z "$DEV" ] && exit 0
|
||||
brightnessctl -d "$DEV" set "${2}%" -q 2>/dev/null
|
||||
;;
|
||||
*)
|
||||
gen_output
|
||||
[ -z "$DEV" ] && exit 0
|
||||
# Poll for changes every 2s (sysfs files don't support inotify reliably)
|
||||
while true; do sleep 2; gen_output; done
|
||||
;;
|
||||
esac
|
||||
@@ -6,6 +6,7 @@ emit() {
|
||||
if bluetoothctl show 2>/dev/null | grep -q "Powered: yes"; then
|
||||
powered=true
|
||||
while IFS= read -r line; do
|
||||
local mac info
|
||||
mac=$(echo "$line" | awk '{ print $2 }')
|
||||
info=$(bluetoothctl info "$mac" 2>/dev/null)
|
||||
if echo "$info" | grep -q "Connected: yes"; then
|
||||
@@ -20,8 +21,18 @@ emit() {
|
||||
}
|
||||
|
||||
emit
|
||||
bluetoothctl monitor 2>/dev/null | while IFS= read -r line; do
|
||||
case "$line" in
|
||||
*"Powered"*|*"Connected"*|*"Device"*) emit ;;
|
||||
esac
|
||||
|
||||
tmp=$(mktemp -d)
|
||||
pipe="$tmp/bt-events"
|
||||
mkfifo "$pipe"
|
||||
trap 'rm -rf "$tmp"; kill 0 2>/dev/null' EXIT INT TERM
|
||||
|
||||
# Poll every 2s as reliable fallback for missed events
|
||||
(while true; do sleep 2; echo poll; done) > "$pipe" &
|
||||
|
||||
# bluetoothctl monitor for reactive device connect/disconnect events
|
||||
(bluetoothctl monitor 2>/dev/null | grep --line-buffered -E "Powered|Connected|Device") > "$pipe" &
|
||||
|
||||
while IFS= read -r _ < "$pipe"; do
|
||||
emit
|
||||
done
|
||||
|
||||
@@ -16,8 +16,18 @@ emit() {
|
||||
}
|
||||
|
||||
emit
|
||||
bluetoothctl monitor 2>/dev/null | while IFS= read -r line; do
|
||||
case "$line" in
|
||||
*"Powered"*|*"Connected"*|*"Device"*) emit ;;
|
||||
esac
|
||||
|
||||
tmp=$(mktemp -d)
|
||||
pipe="$tmp/bt-dev-events"
|
||||
mkfifo "$pipe"
|
||||
trap 'rm -rf "$tmp"; kill 0 2>/dev/null' EXIT INT TERM
|
||||
|
||||
# Poll every 3s as fallback for missed events
|
||||
(while true; do sleep 3; echo poll; done) > "$pipe" &
|
||||
|
||||
# Reactive updates from D-Bus
|
||||
(bluetoothctl monitor 2>/dev/null | grep --line-buffered -E "Connected|Device|Powered") > "$pipe" &
|
||||
|
||||
while IFS= read -r _ < "$pipe"; do
|
||||
emit
|
||||
done
|
||||
|
||||
@@ -4,6 +4,13 @@ get_wifi_iface() {
|
||||
awk 'NR > 2 { gsub(":", "", $1); print $1; exit }' /proc/net/wireless
|
||||
}
|
||||
|
||||
get_usb_iface() {
|
||||
ip link 2>/dev/null | awk '
|
||||
/^[0-9]+: usb[0-9]/ { gsub(":", "", $2); print $2; exit }
|
||||
/^[0-9]+: enx/ { gsub(":", "", $2); print $2; exit }
|
||||
'
|
||||
}
|
||||
|
||||
signal_icon() {
|
||||
local dbm="$1"
|
||||
if [ -z "$dbm" ]; then echo ""; return; fi
|
||||
@@ -27,8 +34,18 @@ make_content() {
|
||||
[ "$eth_state" = "UP" ] && eth_connected=true
|
||||
fi
|
||||
|
||||
# WiFi — use IP presence as connection indicator (more reliable than wpa_cli)
|
||||
local wifi_connected=false wifi_icon="" wifi_ssid=""
|
||||
# USB tethering
|
||||
local usb_iface usb_connected=false
|
||||
usb_iface=$(get_usb_iface)
|
||||
if [ -n "$usb_iface" ] && ip -4 addr show "$usb_iface" 2>/dev/null | grep -q "inet "; then
|
||||
usb_connected=true
|
||||
fi
|
||||
|
||||
# WiFi - use IP presence as connection indicator (more reliable than wpa_cli)
|
||||
local wifi_connected=false wifi_enabled=false wifi_icon="" wifi_ssid=""
|
||||
if ! rfkill list wlan 2>/dev/null | grep -q "Soft blocked: yes"; then
|
||||
wifi_enabled=true
|
||||
fi
|
||||
if [ -n "$wifi_iface" ] && ip -4 addr show "$wifi_iface" 2>/dev/null | grep -q "inet "; then
|
||||
wifi_connected=true
|
||||
wifi_ssid=$(wpa_cli -g "/run/wpa_supplicant/$wifi_iface" status 2>/dev/null \
|
||||
@@ -37,8 +54,8 @@ make_content() {
|
||||
wifi_icon=$(signal_icon "$signal")
|
||||
fi
|
||||
|
||||
printf '{"wifi":{"connected":%s,"icon":"%s","ssid":"%s"},"ethernet":{"connected":%s}}\n' \
|
||||
"$wifi_connected" "$wifi_icon" "$wifi_ssid" "$eth_connected"
|
||||
printf '{"wifi":{"connected":%s,"enabled":%s,"icon":"%s","ssid":"%s"},"ethernet":{"connected":%s},"usb":{"connected":%s}}\n' \
|
||||
"$wifi_connected" "$wifi_enabled" "$wifi_icon" "$wifi_ssid" "$eth_connected" "$usb_connected"
|
||||
}
|
||||
|
||||
make_content
|
||||
|
||||
@@ -4,6 +4,13 @@ get_wifi_iface() {
|
||||
awk 'NR > 2 { gsub(":", "", $1); print $1; exit }' /proc/net/wireless
|
||||
}
|
||||
|
||||
get_usb_iface() {
|
||||
ip link 2>/dev/null | awk '
|
||||
/^[0-9]+: usb[0-9]/ { gsub(":", "", $2); print $2; exit }
|
||||
/^[0-9]+: enx/ { gsub(":", "", $2); print $2; exit }
|
||||
'
|
||||
}
|
||||
|
||||
freq_band() {
|
||||
local f="$1"
|
||||
if [ "$f" -ge 6000 ] 2>/dev/null; then echo "6 GHz"
|
||||
@@ -51,11 +58,19 @@ make_content() {
|
||||
fi
|
||||
fi
|
||||
|
||||
local usb_iface usb_ip=""
|
||||
usb_iface=$(get_usb_iface)
|
||||
if [ -n "$usb_iface" ] && ip -4 addr show "$usb_iface" 2>/dev/null | grep -q "inet "; then
|
||||
usb_ip=$(ip -4 addr show "$usb_iface" | awk '/inet / { print $2 }')
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2059
|
||||
printf '{"wifi":{"ssid":"%s","ip":"%s","freq":%s,"band":"%s","gen":"%s","signal":%s},' \
|
||||
"$wifi_ssid" "$wifi_ip" "${wifi_freq:-0}" "$wifi_band" "$wifi_gen" "${wifi_signal:-0}"
|
||||
printf '"ethernet":{"state":"%s","ip":"%s","speed":"%s","interface":"%s"}}\n' \
|
||||
printf '"ethernet":{"state":"%s","ip":"%s","speed":"%s","interface":"%s"},' \
|
||||
"$eth_state" "$eth_ip" "$eth_speed" "${eth_iface:-}"
|
||||
printf '"usb":{"interface":"%s","ip":"%s"}}\n' \
|
||||
"${usb_iface:-}" "$usb_ip"
|
||||
}
|
||||
|
||||
make_content
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
case "$1" in
|
||||
status)
|
||||
pgrep -x wlsunset >/dev/null 2>&1 && echo true || echo false
|
||||
;;
|
||||
*)
|
||||
if pgrep -x wlsunset >/dev/null 2>&1; then
|
||||
pkill -x wlsunset && echo false
|
||||
else
|
||||
wlsunset -T 4500 -t 3200 & echo true
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env bash
|
||||
PANEL="$1"
|
||||
|
||||
# Drop concurrent invocations, but recover from stale locks (dead processes)
|
||||
LOCK="/tmp/eww_panel_toggle.lock"
|
||||
if [ -f "$LOCK" ] && kill -0 "$(cat "$LOCK" 2>/dev/null)" 2>/dev/null; then
|
||||
exit 0
|
||||
fi
|
||||
echo $$ > "$LOCK"
|
||||
trap 'rm -f "$LOCK"' EXIT
|
||||
|
||||
CURRENT=$(eww get active-panel 2>/dev/null | tr -d '"')
|
||||
|
||||
open_popup() {
|
||||
local screen
|
||||
screen=$(hyprctl monitors -j 2>/dev/null | jq -r '.[] | select(.focused == true) | .name' | head -n1)
|
||||
if [ -n "$screen" ]; then
|
||||
eww open popup --screen "$screen"
|
||||
else
|
||||
eww open popup
|
||||
fi
|
||||
}
|
||||
|
||||
if [ "$CURRENT" = "$PANEL" ]; then
|
||||
eww update active-panel=""
|
||||
eww close popup 2>/dev/null
|
||||
else
|
||||
eww update active-panel="$PANEL"
|
||||
open_popup
|
||||
fi
|
||||
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
current=$(eww state 2>/dev/null | grep '^power-save:' | awk '{print $2}')
|
||||
if [ "$current" = "true" ]; then
|
||||
powerprofilesctl set balanced 2>/dev/null || true
|
||||
echo false
|
||||
else
|
||||
powerprofilesctl set power-saver 2>/dev/null || true
|
||||
echo true
|
||||
fi
|
||||
@@ -1,106 +1,224 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
get_time_ms() {
|
||||
date -u +%s%3N
|
||||
}
|
||||
|
||||
URL_BASE="https://www.radiorecord.ru/api"
|
||||
|
||||
MPV_PID_FILE="/tmp/mpv_radio_pid"
|
||||
RADIO_ID_FILE="/tmp/radio_id"
|
||||
|
||||
STATIONS="[]"
|
||||
STATION_IDS='[507,522,523,536,537,42532,42602]'
|
||||
|
||||
PID=$( [ -e "$MPV_PID_FILE" ] && cat "$MPV_PID_FILE" || echo 0 )
|
||||
RADIO_ID=$( [ -e "$RADIO_ID_FILE" ] && cat "$RADIO_ID_FILE" || echo 0 )
|
||||
RADIO_URL=""
|
||||
INFO='{"id":null,"artist":null,"song":null,"image600":null}'
|
||||
PAUSED=$(( $PID == 0 || $RADIO_ID == 0 ? 1 : 0 ))
|
||||
# Custom (non-radiorecord) stations
|
||||
# id must be a unique integer >= 1000000 to avoid collision with radiorecord IDs.
|
||||
# icon_fill_white: URL to station icon image, or "" for none.
|
||||
CUSTOM_STATIONS='[
|
||||
]'
|
||||
|
||||
STATIONS="[]"
|
||||
DEFAULT_INFO='{"artist":"","song":"","image600":""}'
|
||||
DEFAULT_MEDIA='{"player":"","status":"Stopped","artist":"","title":"","art":""}'
|
||||
|
||||
PID=$([ -e "$MPV_PID_FILE" ] && cat "$MPV_PID_FILE" || echo 0)
|
||||
RADIO_ID=$([ -e "$RADIO_ID_FILE" ] && cat "$RADIO_ID_FILE" || echo 0)
|
||||
PAUSED=$(( PID == 0 ? 1 : 0 ))
|
||||
INFO="$DEFAULT_INFO"
|
||||
MEDIA="$DEFAULT_MEDIA"
|
||||
STATUS="{}"
|
||||
|
||||
get_radio() {
|
||||
echo "$STATIONS" | jq -r --argjson sel_id "$RADIO_ID" 'map(select(.id == $sel_id)).[0]'
|
||||
get_stations() {
|
||||
local rr
|
||||
rr=$(curl -s --compressed "$URL_BASE/stations/" 2>/dev/null \
|
||||
| jq --argjson ids "$STATION_IDS" \
|
||||
'.result.stations | map(select(.id | IN($ids[]))) | map({id, title, stream_hls, icon_fill_white, "radiorecord": true})' 2>/dev/null)
|
||||
jq -n \
|
||||
--argjson rr "${rr:-[]}" \
|
||||
--argjson custom "$CUSTOM_STATIONS" \
|
||||
'$rr + ($custom | map(. + {"radiorecord": false}))'
|
||||
}
|
||||
|
||||
get_song() {
|
||||
echo $(curl -s "$URL_BASE/station/history/?id=$RADIO_ID" | jq '.result.history[0] | ({id, artist, song, image600})')
|
||||
curl -s --compressed "$URL_BASE/station/history/?id=$RADIO_ID" \
|
||||
| jq '.result.history[0] | {artist, song, image600}'
|
||||
}
|
||||
|
||||
|
||||
update() {
|
||||
PID=$( [ -e "$MPV_PID_FILE" ] && cat "$MPV_PID_FILE" || echo 0 )
|
||||
RADIO_ID=$( [ -e "$RADIO_ID_FILE" ] && cat "$RADIO_ID_FILE" || echo 0 )
|
||||
PAUSED=$(( $PID == 0 && $RADIO_ID > 0 ? 1 : 0 ))
|
||||
get_stream_url() {
|
||||
echo "$STATIONS" | jq -r --argjson id "$RADIO_ID" 'map(select(.id == $id))[0].stream_hls // empty'
|
||||
}
|
||||
|
||||
start() {
|
||||
STATIONS=$(curl -s "$URL_BASE/stations/" | jq --argjson ids '[507,522,523,536,537,42532,42602]' '.result.stations | map(select(.id | IN($ids[]))) | map({id, title, stream_hls, icon_fill_white})')
|
||||
RADIO_URL=$(get_radio | jq -r '.stream_hls')
|
||||
if [ "$PAUSED" = 0 ]; then
|
||||
kill -9 $PID
|
||||
get_player_info() {
|
||||
local player status artist title art
|
||||
# exclude mpv (radio) so it never appears as "external player"
|
||||
player=$(playerctl -l 2>/dev/null | grep -Ev '^mpv' | head -1)
|
||||
if [ -z "$player" ]; then
|
||||
echo '{"player":"","status":"Stopped","artist":"","title":"","art":""}'
|
||||
return
|
||||
fi
|
||||
mpv "$RADIO_URL" & echo $! > "$MPV_PID_FILE"
|
||||
echo $RADIO_ID > "$RADIO_ID_FILE"
|
||||
status=$(playerctl -p "$player" status 2>/dev/null || echo "Stopped")
|
||||
artist=$(playerctl -p "$player" metadata artist 2>/dev/null || echo "")
|
||||
title=$(playerctl -p "$player" metadata title 2>/dev/null || echo "")
|
||||
art=$(playerctl -p "$player" metadata mpris:artUrl 2>/dev/null || echo "")
|
||||
jq -cnr --arg player "$player" --arg status "$status" \
|
||||
--arg artist "$artist" --arg title "$title" --arg art "$art" \
|
||||
'{player:$player, status:$status, artist:$artist, title:$title, art:$art}'
|
||||
}
|
||||
|
||||
update_state() {
|
||||
PID=$([ -e "$MPV_PID_FILE" ] && cat "$MPV_PID_FILE" || echo 0)
|
||||
RADIO_ID=$([ -e "$RADIO_ID_FILE" ] && cat "$RADIO_ID_FILE" || echo 0)
|
||||
if [ "$PID" -gt 0 ] && ! kill -0 "$PID" 2>/dev/null; then
|
||||
PID=0
|
||||
rm -f "$MPV_PID_FILE"
|
||||
fi
|
||||
PAUSED=$(( PID == 0 ? 1 : 0 ))
|
||||
}
|
||||
|
||||
toggle() {
|
||||
if [ "$PAUSED" = 1 ]; then
|
||||
echo $RADIO_ID $PID
|
||||
start
|
||||
emit_status() {
|
||||
jq -cnr \
|
||||
--argjson stations "${STATIONS:-[]}" \
|
||||
--argjson radio_id "${RADIO_ID:-0}" \
|
||||
--argjson is_paused "${PAUSED:-1}" \
|
||||
--argjson info "${INFO:-$DEFAULT_INFO}" \
|
||||
--argjson media "${MEDIA:-$DEFAULT_MEDIA}" \
|
||||
'{"is_paused": $is_paused, "song": $info, "radio": $radio_id, "stations": $stations, "media": $media}'
|
||||
}
|
||||
|
||||
get_mpv_node() {
|
||||
wpctl status 2>/dev/null | awk '
|
||||
/Streams:/ { in_s = 1 }
|
||||
/Sinks:|Sources:|Clients:/ { in_s = 0 }
|
||||
in_s && /[0-9]+\..*mpv/ { match($0, /[0-9]+/); print substr($0, RSTART, RLENGTH); exit }
|
||||
'
|
||||
}
|
||||
|
||||
get_volume() {
|
||||
if [ "$PID" -gt 0 ] && kill -0 "$PID" 2>/dev/null; then
|
||||
local node_id; node_id=$(get_mpv_node)
|
||||
[ -n "$node_id" ] && wpctl get-volume "$node_id" 2>/dev/null \
|
||||
| awk '{printf "%d", $2 * 100}'
|
||||
else
|
||||
kill -9 "$PID"
|
||||
rm -f $MPV_PID_FILE
|
||||
local player; player=$(playerctl -l 2>/dev/null | grep -Ev '^mpv' | head -1)
|
||||
[ -n "$player" ] && playerctl -p "$player" volume 2>/dev/null \
|
||||
| awk '{printf "%d", $1 * 100}'
|
||||
fi
|
||||
}
|
||||
|
||||
status() {
|
||||
echo $(jq -cnr --argjson pid "$PID" --argjson stations "$STATIONS" --argjson radio_id "$RADIO_ID" --argjson is_paused "$PAUSED" --argjson info "$INFO" '{"is_paused": $is_paused, "song": $info, "radio": $radio_id, "stations": $stations}')
|
||||
do_vol() {
|
||||
local vol="${1%.*}"
|
||||
if [ "$PID" -gt 0 ] && kill -0 "$PID" 2>/dev/null; then
|
||||
local node_id; node_id=$(get_mpv_node)
|
||||
[ -n "$node_id" ] && wpctl set-volume "$node_id" "${vol}%"
|
||||
else
|
||||
playerctl volume "$(awk -v v="$vol" 'BEGIN{printf "%.2f", v/100}')" 2>/dev/null
|
||||
fi
|
||||
eww update radio-vol="$vol"
|
||||
}
|
||||
|
||||
do_mute() {
|
||||
if [ "$PID" -gt 0 ] && kill -0 "$PID" 2>/dev/null; then
|
||||
local node_id; node_id=$(get_mpv_node)
|
||||
if [ -n "$node_id" ]; then
|
||||
wpctl set-mute "$node_id" toggle
|
||||
if wpctl get-volume "$node_id" 2>/dev/null | grep -q MUTED; then
|
||||
eww update radio-muted=true
|
||||
else
|
||||
eww update radio-muted=false
|
||||
fi
|
||||
fi
|
||||
else
|
||||
wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
|
||||
if wpctl get-volume @DEFAULT_AUDIO_SINK@ 2>/dev/null | grep -q MUTED; then
|
||||
eww update radio-muted=true
|
||||
else
|
||||
eww update radio-muted=false
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
do_start() {
|
||||
[ "$RADIO_ID" -le 0 ] && return
|
||||
STATIONS=$(get_stations)
|
||||
RADIO_URL=$(get_stream_url)
|
||||
[ -z "$RADIO_URL" ] || [ "$RADIO_URL" = "null" ] && return
|
||||
[ "$PID" -gt 0 ] && kill "$PID" 2>/dev/null
|
||||
nohup mpv --no-video --quiet "$RADIO_URL" >/dev/null 2>&1 &
|
||||
echo $! > "$MPV_PID_FILE"
|
||||
echo "$RADIO_ID" > "$RADIO_ID_FILE"
|
||||
}
|
||||
|
||||
status_loop() {
|
||||
STATUS=$(status)
|
||||
echo $STATUS
|
||||
STATIONS=$(curl -s "$URL_BASE/stations/" | jq --argjson ids '[507,522,523,536,537,42532,42602]' '.result.stations | map(select(.id | IN($ids[]))) | map({id, title, stream_hls, icon_fill_white})')
|
||||
last_time_info=0
|
||||
last_time=0
|
||||
STATIONS=$(get_stations)
|
||||
echo "$(emit_status)"
|
||||
|
||||
last_pid_check=0
|
||||
last_song_fetch=0
|
||||
last_media_fetch=0
|
||||
|
||||
while true; do
|
||||
current_time=$(get_time_ms)
|
||||
delta=$((current_time - last_time))
|
||||
delta_i=$((current_time - last_time_info))
|
||||
if [[ $delta -gt 1000 ]]; then
|
||||
PID=$( [ -e "$MPV_PID_FILE" ] && cat "$MPV_PID_FILE" || echo 0 )
|
||||
RADIO_ID=$( [ -e "$RADIO_ID_FILE" ] && cat "$RADIO_ID_FILE" || echo 0 )
|
||||
PAUSED=$(( $PID == 0 && $RADIO_ID > 0 ? 1 : 0 ))
|
||||
NEW_STATUS=$(status)
|
||||
if [[ "$NEW_STATUS" != "$STATUS" ]]; then
|
||||
STATUS=$NEW_STATUS
|
||||
echo $STATUS
|
||||
fi
|
||||
last_time=$current_time
|
||||
now=$(date -u +%s%3N)
|
||||
|
||||
if (( now - last_pid_check > 1000 )); then
|
||||
update_state
|
||||
NEW_STATUS=$(emit_status)
|
||||
if [ "$NEW_STATUS" != "$STATUS" ]; then STATUS=$NEW_STATUS; echo "$STATUS"; fi
|
||||
last_pid_check=$now
|
||||
fi
|
||||
if [[ $delta_i -gt 15000 ]]; then
|
||||
if [ "$PAUSED" = 1 ]; then
|
||||
INFO="{\"id\":null,\"artist\":null,\"song\":null,\"image600\": \"$(get_radio | jq -r '.icon_fill_white')\"}"
|
||||
|
||||
if (( now - last_song_fetch > 15000 )); then
|
||||
if [ "$PAUSED" = 0 ]; then
|
||||
IS_RR=$(echo "$STATIONS" | jq --argjson id "$RADIO_ID" 'map(select(.id == $id))[0].radiorecord // true')
|
||||
if [ "$IS_RR" = "true" ]; then
|
||||
FETCHED=$(get_song)
|
||||
INFO=$(echo "$INFO" "$FETCHED" | jq -s '
|
||||
reduce .[] as $x ({}; . + ($x | with_entries(select(.value != null))))')
|
||||
else
|
||||
STATION_TITLE=$(echo "$STATIONS" | jq -r --argjson id "$RADIO_ID" 'map(select(.id == $id))[0].title // ""')
|
||||
INFO=$(jq -cnr --arg title "$STATION_TITLE" '{artist:"",song:$title,image600:""}')
|
||||
fi
|
||||
else
|
||||
INFO=$(echo "$INFO" "$(get_song)" | jq -s ' reduce .[] as $item ( {}; . + (
|
||||
reduce ($item | to_entries[]) as $entry ( {}; if $entry.value != null then .[$entry.key] = $entry.value else . end
|
||||
)) )')
|
||||
STATION_IMG=$(echo "$STATIONS" \
|
||||
| jq -r --argjson id "$RADIO_ID" 'map(select(.id == $id))[0].icon_fill_white // ""')
|
||||
STATION_TITLE=$(echo "$STATIONS" \
|
||||
| jq -r --argjson id "$RADIO_ID" 'map(select(.id == $id))[0].title // ""')
|
||||
INFO=$(jq -cnr --arg img "$STATION_IMG" --arg title "$STATION_TITLE" \
|
||||
'{artist:"",song:$title,image600:$img}')
|
||||
fi
|
||||
last_time_info=$current_time
|
||||
NEW_STATUS=$(emit_status)
|
||||
if [ "$NEW_STATUS" != "$STATUS" ]; then STATUS=$NEW_STATUS; echo "$STATUS"; fi
|
||||
last_song_fetch=$now
|
||||
fi
|
||||
|
||||
if (( now - last_media_fetch > 3000 )); then
|
||||
MEDIA=$(get_player_info)
|
||||
NEW_STATUS=$(emit_status)
|
||||
if [ "$NEW_STATUS" != "$STATUS" ]; then STATUS=$NEW_STATUS; echo "$STATUS"; fi
|
||||
VOL=$(get_volume)
|
||||
[ -n "$VOL" ] && eww update radio-vol="$VOL" 2>/dev/null
|
||||
last_media_fetch=$now
|
||||
fi
|
||||
|
||||
sleep 0.5
|
||||
done
|
||||
}
|
||||
|
||||
# Main script
|
||||
case "$1" in
|
||||
"start")
|
||||
RADIO_ID=$2
|
||||
start
|
||||
start)
|
||||
RADIO_ID="$2"
|
||||
echo "$RADIO_ID" > "$RADIO_ID_FILE"
|
||||
do_start
|
||||
;;
|
||||
"toggle")
|
||||
toggle
|
||||
vol)
|
||||
do_vol "$2"
|
||||
;;
|
||||
mute)
|
||||
update_state
|
||||
do_mute
|
||||
;;
|
||||
toggle)
|
||||
update_state
|
||||
if [ "$PAUSED" = 1 ]; then
|
||||
[ "$RADIO_ID" -gt 0 ] && do_start
|
||||
else
|
||||
[ "$PID" -gt 0 ] && kill "$PID" 2>/dev/null
|
||||
rm -f "$MPV_PID_FILE"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
status_loop
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
DIR="$HOME/Pictures/Screenshots"
|
||||
mkdir -p "$DIR"
|
||||
FILE="$DIR/$(date +%Y-%m-%d_%H-%M-%S).png"
|
||||
grim -g "$(slurp)" "$FILE" && wl-copy < "$FILE"
|
||||
@@ -1 +0,0 @@
|
||||
#!/usr/bin/env zsh
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
volicons=("" "" "")
|
||||
|
||||
vol() { wpctl get-volume @DEFAULT_AUDIO_"$1"@ | awk '{print int($2*100)}'; }
|
||||
ismuted() { wpctl get-volume @DEFAULT_AUDIO_"$1"@ | rg -qi muted; echo -n $?; }
|
||||
setvol() { wpctl set-volume @DEFAULT_AUDIO_"$1"@ "$(awk -v n="$2" 'BEGIN{print n/100}')"; }
|
||||
setmute() { wpctl set-mute @DEFAULT_AUDIO_"$1"@ toggle; }
|
||||
|
||||
gen_output() {
|
||||
percent=$(vol "SINK")
|
||||
lvl=$(awk -v n="$percent" 'BEGIN{print int(n/34)}')
|
||||
sink_muted=$(ismuted "SINK")
|
||||
source_muted=$(ismuted "SOURCE")
|
||||
sink=$(wpctl inspect @DEFAULT_AUDIO_SINK@ 2>/dev/null | grep -m1 'node\.nick' | sed 's/.*= "\(.*\)"/\1/')
|
||||
|
||||
[ "$sink_muted" = 0 ] && icon="" || icon="${volicons[$lvl]}"
|
||||
[ "$source_muted" = 0 ] && mic_icon="" || mic_icon=""
|
||||
|
||||
printf '{"icon":"%s","percent":%s,"sink_muted":%s,"mic_icon":"%s","microphone":%s,"source_muted":%s,"sink":"%s"}\n' \
|
||||
"$icon" "$percent" "$([ "$sink_muted" = 0 ] && echo true || echo false)" \
|
||||
"$mic_icon" "$(vol SOURCE)" "$([ "$source_muted" = 0 ] && echo true || echo false)" "$sink"
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
mute) setmute "$2" ;;
|
||||
setvol) setvol "$2" "$3" ;;
|
||||
*)
|
||||
gen_output
|
||||
|
||||
tmp=$(mktemp -d)
|
||||
pipe="$tmp/vol-events"
|
||||
mkfifo "$pipe"
|
||||
trap 'rm -rf "$tmp"; kill 0 2>/dev/null' EXIT INT TERM
|
||||
|
||||
# 1s polling fallback
|
||||
(while true; do sleep 1; echo poll; done) > "$pipe" &
|
||||
# PipeWire property-change events (fires on mute/volume change)
|
||||
(pw-cli -m 2>/dev/null | grep --line-buffered "changed") > "$pipe" &
|
||||
|
||||
while IFS= read -r _ < "$pipe"; do
|
||||
gen_output
|
||||
done
|
||||
;;
|
||||
esac
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
#!/usr/bin/env bash
|
||||
nohup bash "$HOME/.config/script/wallpaper.sh" >/dev/null 2>&1 &
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
FALLBACK='{"temp":0,"feelslike":0,"humidity":0,"wind":0,"desc":"Unavailable","icon":"","city":""}'
|
||||
CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/eww"
|
||||
LOC_CACHE="$CACHE_DIR/weather-location"
|
||||
UA="eww-bar/1.0 cedric.hoelzl@gmail.com"
|
||||
|
||||
mkdir -p "$CACHE_DIR"
|
||||
|
||||
get_location() {
|
||||
# Cache location for 1 hour; IP rarely changes
|
||||
if [ -f "$LOC_CACHE" ] && [ -n "$(find "$LOC_CACHE" -mmin -60 2>/dev/null)" ]; then
|
||||
cat "$LOC_CACHE"
|
||||
return 0
|
||||
fi
|
||||
data=$(curl -sf --max-time 5 "http://ip-api.com/json?fields=lat,lon,city") || return 1
|
||||
echo "$data" | tee "$LOC_CACHE"
|
||||
}
|
||||
|
||||
icon_for() {
|
||||
case "$1" in
|
||||
*thunder*) echo "" ;;
|
||||
*snow*|*sleet*) echo "" ;;
|
||||
heavyrain*|*heavyrainshowers*) echo "" ;;
|
||||
*rain*|*shower*) echo "" ;;
|
||||
fog*) echo "" ;;
|
||||
cloudy*) echo "" ;;
|
||||
partlycloudy*) echo "" ;;
|
||||
fair*|clearsky*) echo "" ;;
|
||||
*) echo "" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
desc_for() {
|
||||
case "$(echo "$1" | sed 's/_day//;s/_night//;s/_polartwilight//')" in
|
||||
clearsky) echo "Clear sky" ;;
|
||||
fair) echo "Fair" ;;
|
||||
partlycloudy) echo "Partly cloudy" ;;
|
||||
cloudy) echo "Cloudy" ;;
|
||||
fog) echo "Foggy" ;;
|
||||
lightrain) echo "Light rain" ;;
|
||||
rain) echo "Rain" ;;
|
||||
heavyrain) echo "Heavy rain" ;;
|
||||
lightrainshowers) echo "Light showers" ;;
|
||||
rainshowers) echo "Rain showers" ;;
|
||||
heavyrainshowers) echo "Heavy showers" ;;
|
||||
lightrainandthunder) echo "Light rain & thunder" ;;
|
||||
rainandthunder) echo "Rain & thunder" ;;
|
||||
heavyrainandthunder) echo "Heavy rain & thunder" ;;
|
||||
*showersandthunder) echo "Showers & thunder" ;;
|
||||
lightsleet|lightsleetshowers) echo "Light sleet" ;;
|
||||
sleet|sleetshowers) echo "Sleet" ;;
|
||||
heavysleet|heavysleetshowers) echo "Heavy sleet" ;;
|
||||
*sleetandthunder) echo "Sleet & thunder" ;;
|
||||
lightsnow|lightsnowshowers) echo "Light snow" ;;
|
||||
snow|snowshowers) echo "Snow" ;;
|
||||
heavysnow|heavysnowshowers) echo "Heavy snow" ;;
|
||||
*snowandthunder) echo "Snow & thunder" ;;
|
||||
*) echo "$1" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
fetch() {
|
||||
loc=$(get_location) || { echo "$FALLBACK"; return; }
|
||||
lat=$(echo "$loc" | jq -r '.lat')
|
||||
lon=$(echo "$loc" | jq -r '.lon')
|
||||
city=$(echo "$loc" | jq -r '.city')
|
||||
|
||||
data=$(curl -sf --max-time 8 \
|
||||
-H "User-Agent: $UA" \
|
||||
-H "Accept: application/json" \
|
||||
"https://api.met.no/weatherapi/locationforecast/2.0/compact?lat=$lat&lon=$lon") \
|
||||
|| { echo "$FALLBACK"; return; }
|
||||
|
||||
d='.properties.timeseries[0].data'
|
||||
temp=$( echo "$data" | jq -r "${d}.instant.details.air_temperature | round")
|
||||
humidity=$(echo "$data" | jq -r "${d}.instant.details.relative_humidity | round")
|
||||
wind_ms=$( echo "$data" | jq -r "${d}.instant.details.wind_speed")
|
||||
wind=$( echo "$wind_ms" | awk '{printf "%d", $1 * 3.6}')
|
||||
code=$( echo "$data" | jq -r \
|
||||
"(${d}.next_1_hours.summary.symbol_code) // (${d}.next_6_hours.summary.symbol_code) // \"cloudy\"")
|
||||
|
||||
# Simplified apparent temperature: wind chill below 10°C, else = temp
|
||||
feelslike=$(echo "$temp $wind" | awk '{
|
||||
t=$1; v=$2
|
||||
if (v > 4.8 && t < 10)
|
||||
printf "%d", 13.12 + 0.6215*t - 11.37*(v^0.16) + 0.3965*t*(v^0.16)
|
||||
else
|
||||
printf "%d", t
|
||||
}')
|
||||
|
||||
icon=$(icon_for "$code")
|
||||
desc=$(desc_for "$code")
|
||||
|
||||
printf '{"temp":%s,"feelslike":%s,"humidity":%s,"wind":%s,"desc":"%s","icon":"%s","city":"%s"}\n' \
|
||||
"$temp" "$feelslike" "$humidity" "$wind" "$desc" "$icon" "$city"
|
||||
}
|
||||
|
||||
fetch
|
||||
while true; do sleep 600; fetch; done
|
||||
@@ -1,9 +0,0 @@
|
||||
(defwindow calendar
|
||||
:monitor 0
|
||||
:geometry (geometry
|
||||
:x "0%"
|
||||
:y "0%"
|
||||
:anchor "bottom right"
|
||||
:width "0px"
|
||||
:height "0px")
|
||||
(window (calendar)))
|
||||
@@ -0,0 +1,126 @@
|
||||
|
||||
(deflisten weather
|
||||
:initial '{"temp":0,"feelslike":0,"humidity":0,"wind":0,"desc":"","icon":"","city":""}'
|
||||
"scripts/weather")
|
||||
|
||||
(deflisten volume
|
||||
:initial '{"icon":"","percent":50,"sink_muted":false,"mic_icon":"","microphone":50,"source_muted":false,"sink":""}'
|
||||
"scripts/volume")
|
||||
|
||||
(deflisten brightness
|
||||
:initial '{"percent":0,"available":false}'
|
||||
"scripts/brightness")
|
||||
|
||||
; --- Weather ---
|
||||
|
||||
(defwidget weather-section []
|
||||
(box :orientation "v" :space-evenly false :class "sys-section"
|
||||
(section-header
|
||||
:title {weather.city != "" ? "Weather · ${weather.city}" : "Weather"}
|
||||
:accent "weather-accent")
|
||||
(box :orientation "h" :space-evenly false :halign "center" :class "weather-main"
|
||||
(label :class "weather-icon" :valign "center" :text {weather.icon})
|
||||
(box :orientation "v" :space-evenly false :valign "center"
|
||||
(label :class "weather-temp" :text "${weather.temp}°C")
|
||||
(label :class "weather-desc" :text {weather.desc})))
|
||||
(box :orientation "h" :space-evenly true :class "weather-stats"
|
||||
(box :orientation "v" :space-evenly false :halign "center"
|
||||
(label :class "gpu-stat-value" :text "${weather.feelslike}°C")
|
||||
(label :class "gpu-stat-label" :text "feels like"))
|
||||
(box :orientation "v" :space-evenly false :halign "center"
|
||||
(label :class "gpu-stat-value" :text "${weather.humidity}%")
|
||||
(label :class "gpu-stat-label" :text "humidity"))
|
||||
(box :orientation "v" :space-evenly false :halign "center"
|
||||
(label :class "gpu-stat-value" :text "${weather.wind} km/h")
|
||||
(label :class "gpu-stat-label" :text "wind")))))
|
||||
|
||||
; --- Volume ---
|
||||
|
||||
(defwidget vol-row [icon value onchange onclick muted]
|
||||
(box :orientation "h" :space-evenly false :valign "center" :class "ctrl-row"
|
||||
(button
|
||||
:class "ctrl-icon ${muted ? 'ctrl-muted' : ''}"
|
||||
:onclick onclick
|
||||
(label :text icon))
|
||||
(scale
|
||||
:min 0 :max 100 :value value
|
||||
:hexpand true
|
||||
:class "ctrl-slider ${muted ? 'ctrl-slider-muted' : ''}"
|
||||
:onchange {muted ? "true" : onchange})
|
||||
(label :class "ctrl-value ${muted ? 'ctrl-muted' : ''}" :halign "end" :text "${value}%")))
|
||||
|
||||
(defwidget volume-section []
|
||||
(box :orientation "v" :space-evenly false :class "sys-section"
|
||||
(section-header
|
||||
:title {volume.sink != "" ? "Volume · ${volume.sink}" : "Volume"}
|
||||
:accent "vol-accent")
|
||||
(vol-row
|
||||
:icon {volume.icon}
|
||||
:value {volume.percent}
|
||||
:muted {volume.sink_muted}
|
||||
:onchange "scripts/volume setvol SINK {}"
|
||||
:onclick "scripts/volume mute SINK")
|
||||
(vol-row
|
||||
:icon {volume.mic_icon}
|
||||
:value {volume.microphone}
|
||||
:muted {volume.source_muted}
|
||||
:onchange "scripts/volume setvol SOURCE {}"
|
||||
:onclick "scripts/volume mute SOURCE")))
|
||||
|
||||
; --- Quick Actions ---
|
||||
|
||||
(defvar power-save false)
|
||||
(defvar night-light false)
|
||||
|
||||
(defwidget quick-btn [icon label onclick active]
|
||||
(button :class "quick-btn ${active ? 'quick-btn-active' : ''}"
|
||||
:onclick onclick
|
||||
(box :orientation "v" :space-evenly false :halign "center" :valign "center"
|
||||
(label :class "quick-icon" :text icon)
|
||||
(label :class "quick-label" :text label))))
|
||||
|
||||
(defwidget quick-section []
|
||||
(box :orientation "v" :space-evenly false :class "sys-section"
|
||||
(section-header :title "Quick Actions" :accent "quick-accent")
|
||||
(box :orientation "v" :space-evenly false :class "quick-grid" :spacing 4
|
||||
(box :orientation "h" :space-evenly true
|
||||
(quick-btn :icon "" :label "Wallpaper" :onclick "scripts/wallpaper" :active false)
|
||||
(quick-btn :icon "" :label "Power Save" :onclick "eww update power-save=$(scripts/power-save)" :active {power-save})
|
||||
(quick-btn :icon "" :label "Night Light" :onclick "eww update night-light=$(scripts/nightlight)" :active {night-light}))
|
||||
(box :orientation "h" :space-evenly true
|
||||
(quick-btn :icon "" :label "Screenshot" :onclick "scripts/screenshot" :active false)
|
||||
(quick-btn :icon "" :label "Lock" :onclick "swaylock" :active false)
|
||||
(quick-btn :icon "" :label "Color Pick" :onclick "hyprpicker -a" :active false)))))
|
||||
|
||||
; --- Brightness ---
|
||||
|
||||
(defwidget brightness-section []
|
||||
(box :orientation "v" :space-evenly false :class "sys-section"
|
||||
:visible {brightness.available}
|
||||
(section-header :title "Brightness" :accent "bri-accent")
|
||||
(box :orientation "h" :space-evenly false :valign "center" :class "ctrl-row"
|
||||
(label :class "ctrl-icon" :text "")
|
||||
(scale
|
||||
:min 1 :max 100 :value {brightness.percent}
|
||||
:hexpand true
|
||||
:class "ctrl-slider"
|
||||
:onchange "scripts/brightness set {}")
|
||||
(label :class "ctrl-value" :halign "end" :text "${brightness.percent}%"))))
|
||||
|
||||
; --- Root ---
|
||||
|
||||
(defwidget clock-win []
|
||||
(box :class "sys-win" :orientation "v" :space-evenly false
|
||||
(volume-section)
|
||||
(brightness-section)
|
||||
(box :class "section-sep")
|
||||
(quick-section)
|
||||
(box :class "section-sep")
|
||||
(weather-section)
|
||||
(box :class "section-sep")
|
||||
(box :orientation "v" :space-evenly false :class "sys-section cal-box"
|
||||
(section-header :title "Calendar" :accent "cal-accent")
|
||||
(calendar :show-week-numbers false))
|
||||
))
|
||||
|
||||
|
||||
@@ -1,25 +1,37 @@
|
||||
|
||||
(defpoll netinfo
|
||||
:interval "5s"
|
||||
:initial '{"wifi":{"ssid":"","ip":"","freq":0,"band":"","gen":"","signal":0},"ethernet":{"state":"down","ip":"","speed":"","interface":""}}'
|
||||
(deflisten netinfo
|
||||
:initial '{"wifi":{"ssid":"","ip":"","freq":0,"band":"","gen":"","signal":0},"ethernet":{"state":"down","ip":"","speed":"","interface":""},"usb":{"interface":"","ip":""}}'
|
||||
"scripts/net/netinfo")
|
||||
|
||||
(deflisten bt-devices
|
||||
:initial "[]"
|
||||
"scripts/net/bt-devices")
|
||||
|
||||
; --- Shared row widget ---
|
||||
; --- Shared widgets ---
|
||||
|
||||
(defwidget netinfo-row [label value]
|
||||
(box :orientation "h" :space-evenly false :class "netinfo-row"
|
||||
(label :class "netinfo-label" :halign "start" :text label)
|
||||
(label :class "netinfo-value" :halign "end" :hexpand true :text value)))
|
||||
|
||||
(defwidget section-header-toggle [title accent enabled onclick icon-on icon-off]
|
||||
(box :orientation "h" :space-evenly false :valign "center" :class "sys-section-header"
|
||||
(box :class "section-accent ${accent}")
|
||||
(label :class "sys-label" :text title :hexpand true :halign "start")
|
||||
(button
|
||||
:class "net-toggle-btn ${enabled ? 'net-toggle-on' : 'net-toggle-off'}"
|
||||
:onclick onclick
|
||||
(label :text {enabled ? icon-on : icon-off}))))
|
||||
|
||||
; --- WiFi ---
|
||||
|
||||
(defwidget wifi-net-section []
|
||||
(box :orientation "v" :space-evenly false :class "sys-section"
|
||||
(section-header :title "WiFi" :accent "wifi-accent")
|
||||
(section-header-toggle
|
||||
:title "WiFi" :accent "wifi-accent"
|
||||
:enabled {net.wifi.enabled}
|
||||
:onclick {net.wifi.enabled ? "rfkill block wlan" : "rfkill unblock wlan"}
|
||||
:icon-on "" :icon-off "")
|
||||
(box :orientation "v" :space-evenly false
|
||||
:visible {net.wifi.connected}
|
||||
(netinfo-row :label "SSID" :value {netinfo.wifi.ssid})
|
||||
@@ -28,7 +40,15 @@
|
||||
(netinfo-row :label "Freq" :value "${netinfo.wifi.freq} MHz · ${netinfo.wifi.band} · ${netinfo.wifi.gen}"))
|
||||
(label :class "netinfo-dim" :halign "start"
|
||||
:visible {!net.wifi.connected}
|
||||
:text "Not connected")))
|
||||
:text {net.wifi.enabled ? "Not connected" : "Disabled"})))
|
||||
|
||||
; --- USB ---
|
||||
|
||||
(defwidget usb-net-section []
|
||||
(box :orientation "v" :space-evenly false :class "sys-section"
|
||||
(section-header :title "USB" :accent "usb-accent")
|
||||
(netinfo-row :label "Interface" :value {netinfo.usb.interface})
|
||||
(netinfo-row :label "IP" :value {netinfo.usb.ip})))
|
||||
|
||||
; --- Ethernet ---
|
||||
|
||||
@@ -57,26 +77,29 @@
|
||||
|
||||
(defwidget bluetooth-net-section []
|
||||
(box :orientation "v" :space-evenly false :class "sys-section"
|
||||
(section-header :title "Bluetooth" :accent "blt-accent")
|
||||
(box :orientation "v" :space-evenly false
|
||||
(for device in {bt-devices}
|
||||
(bt-device-row :device {device})))))
|
||||
(section-header-toggle
|
||||
:title "Bluetooth" :accent "blt-accent"
|
||||
:enabled {bluetooth.powered}
|
||||
:onclick {bluetooth.powered ? "bluetoothctl power off" : "bluetoothctl power on"}
|
||||
:icon-on "" :icon-off "")
|
||||
(scroll :vscroll true :hscroll false :height 90
|
||||
:visible {bluetooth.powered}
|
||||
(box :orientation "v" :space-evenly false
|
||||
(for device in {bt-devices}
|
||||
(bt-device-row :device {device}))))
|
||||
(label :class "netinfo-dim" :halign "start"
|
||||
:visible {!bluetooth.powered}
|
||||
:text "Disabled")))
|
||||
|
||||
; --- Root ---
|
||||
|
||||
(defwidget net-win []
|
||||
(box :class "sys-win" :space-evenly false :orientation "v"
|
||||
(wifi-net-section)
|
||||
(box :class "section-sep")
|
||||
(box :visible {net.usb.connected} :space-evenly false :orientation "v"
|
||||
(usb-net-section)
|
||||
(box :class "section-sep"))
|
||||
(ethernet-net-section)
|
||||
(box :class "section-sep")
|
||||
(wifi-net-section)
|
||||
(box :class "section-sep")
|
||||
(bluetooth-net-section)))
|
||||
|
||||
(defwindow net
|
||||
:monitor 0
|
||||
:stacking "overlay"
|
||||
:geometry (geometry
|
||||
:x "0%" :y "0%"
|
||||
:anchor "bottom right"
|
||||
:width "300px" :height "0px")
|
||||
(window (net-win)))
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
(defwidget popup-win []
|
||||
(box :space-evenly false :orientation "v"
|
||||
(revealer :reveal {active-panel == "sys"} :transition "slidedown" :duration 120
|
||||
(sys-win))
|
||||
(revealer :reveal {active-panel == "net"} :transition "slidedown" :duration 120
|
||||
(net-win))
|
||||
(revealer :reveal {active-panel == "clock"} :transition "slidedown" :duration 120
|
||||
(clock-win))
|
||||
(revealer :reveal {active-panel == "radio"} :transition "slidedown" :duration 120
|
||||
(radio-win))))
|
||||
|
||||
(defwindow popup
|
||||
:monitor 0
|
||||
:stacking "overlay"
|
||||
:geometry (geometry
|
||||
:x "0%" :y "0%"
|
||||
:anchor "bottom right"
|
||||
:width "320px" :height "0px")
|
||||
(window (popup-win)))
|
||||
@@ -1,111 +1,82 @@
|
||||
(deflisten radio :initial '{"is_paused":1,"song":{"artist":"","song":"","image600":"https://www.radiorecord.ru/upload/stations_images/record_image600_white_fill.png"},"stations":[]}' "scripts/radio")
|
||||
(defvar radio_rev false)
|
||||
|
||||
(defwindow radio
|
||||
:monitor 0
|
||||
:geometry (geometry
|
||||
:x "0%"
|
||||
:y "0%"
|
||||
:anchor "bottom right"
|
||||
:width "0px"
|
||||
:height "0px")
|
||||
(window (radio-win)))
|
||||
|
||||
(deflisten radio
|
||||
:initial '{"is_paused":1,"song":{"artist":"","song":"","image600":""},"radio":0,"stations":[],"media":{"player":"","status":"Stopped","artist":"","title":"","art":""}}'
|
||||
"scripts/radio")
|
||||
(defvar radio-vol 80)
|
||||
(defvar radio-muted false)
|
||||
|
||||
(defwidget radio-win []
|
||||
(box
|
||||
:space-evenly false
|
||||
:orientation "h"
|
||||
(revealer
|
||||
:visible radio_rev
|
||||
:reveal radio_rev
|
||||
:transition "slideleft"
|
||||
(radio-selector))
|
||||
(box
|
||||
:space-evenly false
|
||||
:orientation "v"
|
||||
(box :class "sys-win" :orientation "v" :space-evenly false
|
||||
|
||||
(box
|
||||
:class "album_art"
|
||||
:style "background-size:cover; background-image: url('${radio.song.image600?:'https://www.radiorecord.ru/upload/stations_images/record_image600_white_fill.png'}');")
|
||||
(box
|
||||
:space-evenly false
|
||||
:orientation "v"
|
||||
(label
|
||||
:halign "center"
|
||||
:class "song"
|
||||
:wrap "true"
|
||||
:limit-width 18
|
||||
:text "${radio.song.song?:'...'}")
|
||||
(label
|
||||
:halign "center"
|
||||
:class "artist"
|
||||
:wrap "true"
|
||||
:limit-width 22
|
||||
:text "${radio.song.artist?:'...'}")
|
||||
(box
|
||||
:space-evenly true
|
||||
:orientation "h"
|
||||
:halign "center"
|
||||
:class "btn_bar"
|
||||
; --- Now Playing ---
|
||||
(box :orientation "v" :space-evenly false :class "sys-section"
|
||||
(section-header :title "Media" :accent "radio-accent")
|
||||
(box :orientation "h" :space-evenly false :valign "center" :spacing 10 :class "radio-now-playing"
|
||||
(box :class "radio-art"
|
||||
:style "background-image: url('${radio.is_paused == 0 ? radio.song.image600 : (radio.media.status != 'Stopped' ? radio.media.art : radio.song.image600)}'); background-size: cover; background-position: center;"
|
||||
(label :class "radio-art-icon" :halign "center" :valign "center"
|
||||
:visible {radio.is_paused == 0
|
||||
? radio.song.image600 == ""
|
||||
: (radio.media.status != "Stopped"
|
||||
? radio.media.art == ""
|
||||
: radio.song.image600 == "")}
|
||||
:text ""))
|
||||
(box :orientation "v" :space-evenly false :hexpand true :valign "center"
|
||||
(label :class "radio-song" :halign "start" :wrap true :limit-width 20
|
||||
:text {radio.is_paused == 0
|
||||
? (radio.song.song != "" ? radio.song.song : "Tuning in...")
|
||||
: (radio.media.status != "Stopped"
|
||||
? (radio.media.title != "" ? radio.media.title : "Playing")
|
||||
: (radio.song.song != "" ? radio.song.song : "Nothing playing"))})
|
||||
(label :class "radio-artist" :halign "start" :wrap true :limit-width 22
|
||||
:text {radio.is_paused == 0
|
||||
? radio.song.artist
|
||||
: (radio.media.status != "Stopped"
|
||||
? (radio.media.artist != "" ? radio.media.artist : radio.media.player)
|
||||
: "")})))
|
||||
|
||||
(button
|
||||
:class "btn_left"
|
||||
:onclick "${EWW_CMD} update radio_rev=${!radio_rev}"
|
||||
(box ""))
|
||||
; Controls - hidden only in placeholder state
|
||||
(box :visible {radio.is_paused == 0 || radio.radio > 0 || radio.media.status != "Stopped"}
|
||||
:orientation "v" :space-evenly false :class "radio-controls"
|
||||
(box :orientation "h" :space-evenly true :halign "center"
|
||||
(button :visible {radio.is_paused == 1 && radio.media.status != "Stopped"}
|
||||
:class "radio-ctrl-btn" :timeout "2s" :onclick "playerctl previous"
|
||||
(label :text ""))
|
||||
(button :class "radio-ctrl-btn" :timeout "2s"
|
||||
:onclick {radio.is_paused == 1 && radio.media.status != "Stopped" ? "playerctl play-pause" : "scripts/radio toggle"}
|
||||
(label :text {radio.is_paused == 0 ? "" : (radio.media.status == "Playing" ? "" : "")}))
|
||||
(button :visible {radio.is_paused == 1 && radio.media.status != "Stopped"}
|
||||
:class "radio-ctrl-btn" :timeout "2s" :onclick "playerctl next"
|
||||
(label :text "")))
|
||||
(vol-row
|
||||
:icon ""
|
||||
:value {radio-vol}
|
||||
:onchange "scripts/radio vol {}"
|
||||
:onclick "scripts/radio mute"
|
||||
:muted {radio-muted})))
|
||||
|
||||
(button
|
||||
:class "btn_play"
|
||||
:timeout "2s"
|
||||
:onclick "scripts/radio toggle"
|
||||
"${radio.is_paused==1 ? "" : ""}")
|
||||
(box :class "section-sep")
|
||||
|
||||
(button
|
||||
:class "btn_right"
|
||||
:onclick ""
|
||||
(box :visible false ""))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
(defwidget radio-selector []
|
||||
(scroll
|
||||
:active true
|
||||
:vscroll true
|
||||
:hscroll false
|
||||
|
||||
(box
|
||||
:class "station_list"
|
||||
:space-evenly false
|
||||
:orientation "v"
|
||||
|
||||
(for station in {radio.stations}
|
||||
; --- Stations ---
|
||||
(box :orientation "v" :space-evenly false :class "sys-section"
|
||||
(section-header :title "Radio Stations" :accent "radio-accent")
|
||||
(scroll :vscroll true :hscroll false :height 130
|
||||
(box :class "station-list" :space-evenly false :orientation "v"
|
||||
(for station in {radio.stations}
|
||||
(button
|
||||
:class "station_art ${(radio.radio == station.id)?'station_sel':''}"
|
||||
:timeout "2s"
|
||||
:onclick "scripts/radio start ${station.id}"
|
||||
:tooltip "${station.title}"
|
||||
:style "background-size:cover; background-image: url('${station.icon_fill_white}');"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
:class "station-row ${radio.radio == station.id ? 'station-row-active' : ''}"
|
||||
:timeout "2s"
|
||||
:onclick "scripts/radio start ${station.id}"
|
||||
:tooltip {station.title}
|
||||
(box :orientation "h" :space-evenly false :valign "center"
|
||||
(box :class "station-icon"
|
||||
:style "background-image: url('${station.icon_fill_white}'); background-size: contain; background-position: center;")
|
||||
(label :class "station-name" :text {station.title}
|
||||
:hexpand true :halign "start" :limit-width 16)))))))))
|
||||
|
||||
(defwidget radio-mod []
|
||||
(module
|
||||
(box
|
||||
:orientation "v"
|
||||
(button
|
||||
:onclick "(sleep 0.1 && eww-open-on-current-screen radio --toggle --no-daemonize)"
|
||||
(label
|
||||
:show-truncated false
|
||||
:class "icon-text"
|
||||
:text "")
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(eventbox
|
||||
:onclick "(sleep 0.1 && scripts/panel-toggle radio)"
|
||||
(box :orientation "v"
|
||||
(label :show-truncated false :class "icon-text" :text "")))))
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
(box :orientation "v" :space-evenly false :class "sys-section"
|
||||
(section-header :title "GPU" :accent "gpu-accent")
|
||||
(box :orientation "h" :space-evenly true
|
||||
; GFX — outer: activity%, inner: clock% of range
|
||||
; GFX - outer: activity%, inner: clock% of range
|
||||
(box :orientation "v" :space-evenly false :halign "center"
|
||||
(overlay
|
||||
(circular-progress :width 68 :height 68
|
||||
@@ -84,7 +84,7 @@
|
||||
(box :halign "center" :valign "center"
|
||||
(label :class "gpu-ring-value" :text "${round(gpu.gfx_pct, 0)}%")))
|
||||
(label :class "gpu-ring-label" :text "GFX" :halign "center"))
|
||||
; Memory — outer: activity%, inner: memory clock% of range
|
||||
; Memory - outer: activity%, inner: memory clock% of range
|
||||
(box :orientation "v" :space-evenly false :halign "center"
|
||||
(overlay
|
||||
(circular-progress :width 68 :height 68
|
||||
@@ -99,7 +99,7 @@
|
||||
(box :halign "center" :valign "center"
|
||||
(label :class "gpu-ring-value" :text "${round(gpu.mem_pct, 0)}%")))
|
||||
(label :class "gpu-ring-label" :text "Mem" :halign "center"))
|
||||
; Media — outer: activity%, inner: video clock% of GPU clock max
|
||||
; Media - outer: activity%, inner: video clock% of GPU clock max
|
||||
(box :orientation "v" :space-evenly false :halign "center"
|
||||
(overlay
|
||||
(circular-progress :width 68 :height 68
|
||||
@@ -161,7 +161,7 @@
|
||||
(box :orientation "v" :space-evenly false :halign "center" :valign "center"
|
||||
(overlay
|
||||
(circular-progress
|
||||
:width 60 :height 60
|
||||
:width 72 :height 72
|
||||
:value {100*swap.used/swap.total}
|
||||
:start-at 0 :clockwise true :thickness 7
|
||||
:class "swap-ring"
|
||||
@@ -209,14 +209,3 @@
|
||||
(bat-sys-win)
|
||||
)
|
||||
)
|
||||
|
||||
(defwindow sys
|
||||
:monitor 0
|
||||
:stacking "overlay"
|
||||
:geometry (geometry
|
||||
:x "0%"
|
||||
:y "0%"
|
||||
:anchor "bottom right"
|
||||
:width "320px"
|
||||
:height "0px")
|
||||
(window (sys-win)))
|
||||
|
||||
@@ -59,6 +59,9 @@ in {
|
||||
|
||||
$gaps-screen: ${config.colorScheme.palette.gaps-screen}px;
|
||||
$gaps-window: ${config.colorScheme.palette.gaps-window}px;
|
||||
|
||||
$panel-font-size: 10pt;
|
||||
$popup-scale: 1.25;
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ in {
|
||||
|
||||
brightnessctl
|
||||
awww
|
||||
playerctl
|
||||
];
|
||||
|
||||
xdg.mimeApps = {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
|
||||
startupScript = pkgs.writeShellScriptBin "hyprland-start" ''
|
||||
eww open bar &
|
||||
awww-daemon &
|
||||
|
||||
sleep 2
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{ ... }: {
|
||||
{ lib, ... }: {
|
||||
services.fwupd.enable = true;
|
||||
hardware.enableAllFirmware = false;
|
||||
services.power-profiles-daemon.enable = lib.mkDefault true;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{ lib, config, pkgs, ... }: {
|
||||
config = lib.mkIf (config.syscfg.make.power) {
|
||||
services.power-profiles-daemon.enable = false; # conflicts with TLP
|
||||
services.tlp = {
|
||||
enable = true;
|
||||
settings = {
|
||||
|
||||
Reference in New Issue
Block a user