a little Frutiger Aero

This commit is contained in:
agryphus 2025-03-13 13:52:19 -04:00
parent d60aa6a4bc
commit 0bcc07d035
20 changed files with 520 additions and 104 deletions

View file

@ -1,18 +0,0 @@
pragma Singleton
import QtQuick
import Quickshell
Singleton {
id: root
property var popupContext: PopupContext {};
property var date: new Date()
Timer {
interval: 1000
repeat: true
running: true
onTriggered: root.date = new Date()
}
}

View file

@ -0,0 +1,103 @@
pragma Singleton
import QtQuick
import Quickshell
Singleton {
property Item get: black
Item {
id: windowsXP
property string barBgColor: "#235EDC"
property string buttonBorderColor: "#99000000"
property bool buttonBorderShadow: false
property bool onTop: false
property string iconColor: "green"
property string iconPressedColor: "green"
property Gradient barGradient: black.barGradient
property Gradient buttonInactiveGradientV: Gradient {
GradientStop { position: 0.0; color: "#55FFFFFF" }
GradientStop { position: 0.3; color: "#22FFFFFF" }
}
property Gradient buttonInactiveGradientH: Gradient {
orientation: Gradient.Horizontal
GradientStop { position: 0.0; color: "#55FFFFFF" }
GradientStop { position: 0.1; color: "#00000000" }
}
property Gradient buttonActiveGradient: Gradient {
GradientStop { position: 0.0; color: "#99000000" }
GradientStop { position: 0.3; color: "#55000000" }
GradientStop { position: 1.0; color: "#55000000" }
}
}
Item {
id: black
property string barBgColor: "#cc000000"
property string buttonBorderColor: "#44FFFFFF"
property bool buttonBorderShadow: true
property bool onTop: true
property string iconColor: "blue"
property string iconPressedColor: "dark_blue"
property Gradient barGradient: Gradient {
GradientStop { position: 0.0; color: "#55FFFFFF" }
GradientStop { position: 0.4; color: "#00FFFFFF" }
GradientStop { position: 0.8; color: "#00FFFFFF" }
GradientStop { position: 1.0; color: "#AA000000" }
}
property Gradient buttonInactiveGradientV: Gradient {
GradientStop { position: 0.0; color: "#33FFFFFF" }
GradientStop { position: 0.3; color: "#55000000" }
}
property Gradient buttonInactiveGradientH: Gradient {
orientation: Gradient.Horizontal
GradientStop { position: 0.0; color: "#55FFFFFF" }
GradientStop { position: 0.1; color: "#00000000" }
}
property Gradient buttonActiveGradient: Gradient {
GradientStop { position: 0.92; color: "#FF000000" }
GradientStop { position: 0.93; color: "#FFFFFFFF" }
GradientStop { position: 1.0; color: "#FFFFFFFF" }
}
}
Item {
id: black_bright
property string barBgColor: black.barBgColor
property string buttonBorderColor: windowsXP.buttonBorderColor
property bool buttonBorderShadow: windowsXP.buttonBorderShadow
property bool onTop: black.onTop
property string iconColor: "orange"
property string iconPressedColor: "orange"
property Gradient barGradient: black.barGradient
property Gradient buttonInactiveGradientV: windowsXP.buttonInactiveGradientV
property Gradient buttonInactiveGradientH: windowsXP.buttonInactiveGradientH
property Gradient buttonActiveGradient: windowsXP.buttonActiveGradient
}
Item {
id: black_flat
property string barBgColor: "#cc000000"
property string buttonBorderColor: "#01000000" // Making this transparent breaks things
property bool buttonBorderShadow: false
property bool onTop: true
property string iconColor: ""
property string iconPressedColor: ""
property Gradient barGradient: Gradient {
GradientStop { position: 0.0; color: "transparent" }
}
property Gradient buttonInactiveGradientV: Gradient {
GradientStop { position: 0.0; color: "transparent" }
}
property Gradient buttonInactiveGradientH: Gradient {
orientation: Gradient.Horizontal
GradientStop { position: 0.0; color: "transparent" }
}
property Gradient buttonActiveGradient: black.buttonActiveGradient
}
}

View file

@ -1,49 +1,98 @@
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import Quickshell.Hyprland
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import "blocks" as Blocks import "blocks" as Blocks
import "root:/"
Scope { Scope {
Variants { Variants {
model: Quickshell.screens model: Quickshell.screens
PanelWindow { PanelWindow {
id: bar
property var modelData property var modelData
screen: modelData screen: modelData
color: "#cc000000" color: Theme.get.barBgColor
height: 27
Rectangle {
id: highlight
anchors.fill: parent
gradient: Theme.get.barGradient
}
height: 30
visible: true
IpcHandler {
target: "bar"
function toggleVis(): void {
visible = !visible;
}
}
anchors { anchors {
top: true top: Theme.get.onTop
bottom: !Theme.get.onTop
left: true left: true
right: true right: true
} }
RowLayout { RowLayout {
id: allBlocks
spacing: 0 spacing: 0
width: parent.width anchors.fill: parent
height: parent.height
// Left side // Left side
RowLayout { RowLayout {
spacing: 0 id: leftBlocks
spacing: 10
Layout.alignment: Qt.AlignLeft Layout.alignment: Qt.AlignLeft
Layout.fillWidth: true
Blocks.Icon {} Blocks.Icon {}
Blocks.Workspaces {} Blocks.Workspaces {}
Blocks.ActiveWorkspace {} }
Blocks.ActiveWorkspace {
id: activeWorkspace
Layout.leftMargin: 10
anchors.centerIn: undefined
chopLength: {
var space = Math.floor(bar.width - (rightBlocks.implicitWidth + leftBlocks.implicitWidth))
return space * 0.08;
}
text: {
var str = activeWindowTitle
return str.length > chopLength ? str.slice(0, chopLength) + '...' : str;
}
color: {
return Hyprland.focusedMonitor == Hyprland.monitorFor(screen)
? "#FFFFFF" : "#CCCCCC"
}
}
// Without this filler item, the active window block will be centered
// despite setting left alignment
Item {
Layout.fillWidth: true
} }
// Right side // Right side
RowLayout { RowLayout {
id: rightBlocks
spacing: 0 spacing: 0
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
Layout.fillWidth: true
Blocks.SystemTray {} Blocks.SystemTray {}
Blocks.Test {}
Blocks.Notifications {}
Blocks.Memory {} Blocks.Memory {}
Blocks.Sound {} Blocks.Sound {}
Blocks.Battery {} Blocks.Battery {}

View file

@ -4,8 +4,11 @@ import Quickshell
Rectangle { Rectangle {
id: root id: root
Layout.preferredWidth: wsText.implicitWidth + 10 Layout.preferredWidth: contentContainer.implicitWidth + 10
Layout.preferredHeight: 27 Layout.preferredHeight: 30
property Item content
property Item mouseArea: mouseArea
property string text property string text
property bool dim: false property bool dim: false
@ -14,9 +17,7 @@ Rectangle {
property int leftPadding property int leftPadding
property int rightPadding property int rightPadding
property string fgColor: "white" property string hoveredBgColor: "#666666"
property string dimFgColor: "#999999"
property string hoveredBgColor: "#444444"
// Background color // Background color
color: { color: {
@ -40,28 +41,13 @@ Rectangle {
} }
} }
BarText { Item {
id: wsText // Contents of the bar block
text: root.text id: contentContainer
anchors { implicitWidth: content.implicitWidth
left: parent.left implicitHeight: content.implicitHeight
right: parent.right anchors.centerIn: parent
leftMargin: root.leftPadding children: content
rightMargin: root.rightPadding
verticalCenter: parent.verticalCenter
}
color: {
if (mouseArea.containsMouse || !root.dim)
return fgColor
return dimFgColor
}
Behavior on color {
ColorAnimation {
duration: 100
}
}
} }
MouseArea { MouseArea {
@ -76,11 +62,11 @@ Rectangle {
Rectangle { Rectangle {
id: wsLine id: wsLine
width: parent.width width: parent.width
height: 3 height: 2
color: { color: {
if (parent.underline) if (parent.underline)
return fgColor; return "white";
return "transparent"; return "transparent";
} }
anchors.bottom: parent.bottom anchors.bottom: parent.bottom

View file

@ -1,39 +1,57 @@
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import Quickshell.Widgets
import QtQuick import QtQuick
import QtQuick.Layouts
import QtQuick.Effects
import Qt5Compat.GraphicalEffects
Item { Text {
property string text
property string color: "white"
property string mainFont: "FiraCode" property string mainFont: "FiraCode"
property string symbolFont: "Symbols Nerd Font Mono" property string symbolFont: "Symbols Nerd Font Mono"
property int pointSize: 11 property int pointSize: 12
property int symbolSize: pointSize * 1.37
property string symbolText
property bool dim
text: wrapSymbols(symbolText)
anchors.centerIn: parent
color: dim ? "#CCCCCC" : "white"
textFormat: Text.RichText
font {
family: mainFont
pointSize: pointSize
}
implicitWidth: thetext.implicitWidth Text {
implicitHeight: thetext.implicitHeight visible: false
id: textcopy
text: parent.text
textFormat: parent.textFormat
color: parent.color
font: parent.font
}
DropShadow {
anchors.fill: parent
horizontalOffset: 1
verticalOffset: 1
color: "#000000"
source: textcopy
}
function wrapSymbols(text) { function wrapSymbols(text) {
if (!text)
return ""
const isSymbol = (codePoint) => const isSymbol = (codePoint) =>
(codePoint >= 0xE000 && codePoint <= 0xF8FF) // Private Use Area (codePoint >= 0xE000 && codePoint <= 0xF8FF) // Private Use Area
|| (codePoint >= 0xF0000 && codePoint <= 0xFFFFF) // Supplementary Private Use Area-A || (codePoint >= 0xF0000 && codePoint <= 0xFFFFF) // Supplementary Private Use Area-A
|| (codePoint >= 0x100000 && codePoint <= 0x10FFFF); // Supplementary Private Use Area-B || (codePoint >= 0x100000 && codePoint <= 0x10FFFF); // Supplementary Private Use Area-B
return text.replace(/./gu, (c) => isSymbol(c.codePointAt(0)) return text.replace(/./gu, (c) => isSymbol(c.codePointAt(0))
? `<span style='font-family: ${symbolFont}; letter-spacing: -5px; font-size: ${pointSize + 4}px'>${c}</span>` ? `<span style='font-family: ${symbolFont}; letter-spacing: -5px; font-size: ${symbolSize}px'>${c}</span>`
// ? c
: c); : c);
} }
Text {
id: thetext
text: wrapSymbols(parent.text)
color: parent.color
anchors.centerIn: parent
font {
family: parent.mainFont
pointSize: parent.pointSize
}
textFormat: Text.RichText
}
} }

View file

@ -1,15 +1,16 @@
import QtQuick import QtQuick
import QtQuick.Layouts
import Quickshell.Io import Quickshell.Io
import Quickshell.Hyprland import Quickshell.Hyprland
import "../" import "../"
BarText { BarText {
text: { // text: {
var str = activeWindowTitle // var str = activeWindowTitle
return str.length > chopLength ? str.slice(0, chopLength) + '...' : str; // return str.length > chopLength ? str.slice(0, chopLength) + '...' : str;
} // }
property int chopLength: 70 property int chopLength
property string activeWindowTitle property string activeWindowTitle
Process { Process {

View file

@ -4,7 +4,9 @@ import "../"
BarBlock { BarBlock {
property string battery property string battery
text: battery content: BarText {
symbolText: battery
}
Process { Process {
id: batteryProc id: batteryProc

View file

@ -3,6 +3,8 @@ import "../"
BarBlock { BarBlock {
id: text id: text
text: ` ${Datetime.date}` content: BarText {
symbolText: ` ${Datetime.date}`
}
} }

View file

@ -1,11 +1,66 @@
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import Quickshell import Quickshell
import Quickshell.Io
import Quickshell.Widgets
import Qt5Compat.GraphicalEffects
import "../" import "../"
import "root:/"
BarBlock { BarBlock {
Layout.preferredWidth: 30 id: root
rightPadding: 5 Layout.preferredWidth: 40
text: ""
content: BarText {
text: ""
pointSize: 17
anchors.horizontalCenterOffset: -2
}
// content: IconImage {
// id: theicon
// visible: false
// anchors.centerIn: parent
// source: "image://icon/extra-nixos"
// implicitSize: 20
// }
// DropShadow {
// anchors.fill: parent
// horizontalOffset: 1
// verticalOffset: 1
// radius: 6.0
// samples: 20
// color: "#000000"
// source: parent.content
// }
// IconImage {
// anchors.centerIn: parent
// source: "image://icon/extra-nixos"
// implicitSize: 20
// }
Image {
anchors.fill: parent
source: mouseArea.containsMouse
? "../images/" + Theme.get.iconPressedColor + ".png"
: "../images/" + Theme.get.iconColor + ".png";
visible: true
z: -1
}
color: "transparent"
Process {
id: neofetch
running: false
command: [ "sh", "-c", "hyprctl dispatch exec [floating] \
\"foot -W 95x22 -e zsh -c 'neofetch; while true; do; done'\"" ]
stdout: SplitParser {
onRead: data => console.log(`line read: ${data}`)
}
}
onClicked: function() {
neofetch.running = true
}
} }

View file

@ -6,7 +6,9 @@ import "../"
BarBlock { BarBlock {
id: text id: text
text: ` ${Math.floor(percentFree)}%` content: BarText {
symbolText: ` ${Math.floor(percentFree)}%`
}
property real percentFree property real percentFree

View file

@ -7,9 +7,13 @@ import "../"
BarBlock { BarBlock {
id: text id: text
text: ` ${Math.floor(sink?.audio.volume * 100)}%` content: BarText {
symbolText: ` ${Math.floor(volume * 100)}%`
}
property PwNode sink: Pipewire.defaultAudioSink property PwNode sink: Pipewire.defaultAudioSink
property real volume: sink?.audio.volume
PwObjectTracker { objects: [ sink ] } PwObjectTracker { objects: [ sink ] }
} }

View file

@ -4,13 +4,20 @@ import QtQuick.Layouts
import Quickshell import Quickshell
import Quickshell.Widgets import Quickshell.Widgets
import Quickshell.Services.SystemTray import Quickshell.Services.SystemTray
import "../" as Bar import "root:/bar"
RowLayout { RowLayout {
spacing: 5 spacing: 5
Repeater { Repeater {
model: SystemTray.items model: ScriptModel {
values: {[...SystemTray.items.values]
.filter((item) => {
return (item.id != "spotify-client"
&& item.id != "chrome_status_icon_1")
})
}
}
MouseArea { MouseArea {
id: delegate id: delegate
@ -43,7 +50,6 @@ RowLayout {
id: icon id: icon
anchors.centerIn: parent anchors.centerIn: parent
source: item.icon source: item.icon
implicitSize: 16 implicitSize: 16
} }
@ -62,7 +68,7 @@ RowLayout {
} }
} }
Bar.Tooltip { Tooltip {
relativeItem: delegate.containsMouse ? delegate : null relativeItem: delegate.containsMouse ? delegate : null
Label { Label {

View file

@ -3,6 +3,8 @@ import "../"
BarBlock { BarBlock {
id: text id: text
text: ` ${Datetime.time}` content: BarText {
symbolText: ` ${Datetime.time}`
}
} }

View file

@ -2,6 +2,8 @@ import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import Quickshell import Quickshell
import Quickshell.Hyprland import Quickshell.Hyprland
import Quickshell.Widgets
import Qt5Compat.GraphicalEffects
import "root:/" import "root:/"
import "../" import "../"
@ -43,21 +45,223 @@ RowLayout {
property bool hasClients: ws.name.length > 2 property bool hasClients: ws.name.length > 2
dim: true dim: true
underline: isActive || isOpen underline: false
border.color: Theme.get.buttonBorderColor
radius: 5
gradient: isActive || isOpen ? Theme.get.buttonActiveGradient : Theme.get.buttonInactiveGradientV
Layout.preferredWidth: content.width + 20
Rectangle {
visible: !isActive && !isOpen
gradient: Theme.get.buttonInactiveGradientH
implicitWidth: parent.width
implicitHeight: parent.height
radius: parent.radius
z:-1
}
Rectangle {
visible: Theme.get.buttonBorderShadow
implicitWidth: parent.width - 1
implicitHeight: parent.height - 1
radius: parent.radius
color: "transparent" // Transparent fill
border.color: parent.isActive || parent.isOpen ? "transparent" : "black" // Inner border color
border.width: 1 // Inner border width
x: 1
y: 1
z: -1
}
onClicked: function() { onClicked: function() {
Hyprland.dispatch(`workspace ${ws.id}`); Hyprland.dispatch(`workspace ${ws.id}`);
} }
leftPadding: hasClients ? 2 : 0
text: { content: RowLayout {
if (isActive) { spacing: 0
if (!hasClients) anchors.centerIn: parent
return `<span style='color:${fgColor};'>${ws.name}</span>`
var split_i = ws.id > 9 ? 3 : 2 Repeater {
return `<span style='color:${fgColor};'>${ws.name.slice(0, split_i)}</span>${ws.name.slice(split_i)}` id: therepeater
model: ScriptModel {
values: getChunks(ws.name)
}
delegate: Item {
property bool showText: modelData.type === "text" && modelData.value.length > 0
property bool showIcon: modelData.type === "icon"
// property int symbolSize: 18
property int symbolSize: 22
property int spacerSize: 3
implicitWidth: {
if (showText)
return thetext.implicitWidth
if (showIcon)
return symbolSize
return spacerSize;
}
implicitHeight: {
if (showText)
return thetext.implicitHeight
if (showIcon)
return symbolSize
return spacerSize;
}
Layout.alignment: Qt.AlignCenter
Loader {
id: thetext
anchors.centerIn: parent
active: modelData.type === "text"
sourceComponent: BarText {
text: modelData.value
dim: !isActive
// pointSize: 10
}
}
Loader {
id: theicon
anchors.centerIn: parent
active: modelData.type === "icon"
sourceComponent: Item {
implicitWidth: inside.implicitWidth
implicitHeight: inside.implicitHeight
IconImage {
id: inside
anchors.centerIn: parent
source: modelData.source
implicitSize: symbolSize
opacity: modelData.active ? 1 : 0.7
mipmap: true
}
DropShadow {
anchors.fill: parent
verticalOffset: 1
horizontalOffset: 1
radius: 8.0
color: "#000000"
source: inside
opacity: modelData.active ? 1 : 0.7
}
Rectangle {
visible: modelData.mult > 1
width: 10
height: width
radius: width / 2
color: "black"
opacity: 0.8
BarText {
text: modelData.mult
pointSize: 10
dim: !isActive
style: Text.Outline
styleColor: "black"
}
}
}
}
}
} }
return ws.name
} }
} }
} }
function getChunks(text) {
let chunks = [];
let buffer = ""; // Temporary storage for text segments
let symbolChunkInd = {}
let nextIsActive = false
for (let c of text) {
if (c === "󰀦") {
nextIsActive = true
continue
}
if (!(c in symbolImgMap)) {
buffer += c;
nextIsActive = false
continue;
}
if (buffer.length > 0 && !/^\s*$/.test(buffer)) {
chunks.push({
type: "text",
value: buffer,
});
buffer = ""; // Reset text buffer
}
if (!(c in symbolChunkInd)) {
if (chunks[chunks.length - 1].type == "icon") {
chunks.push({type: "spacer"})
}
symbolChunkInd[c] = chunks.length
chunks.push({
type: "icon",
active: nextIsActive,
source: `image://icon/${symbolImgMap[c]}`,
mult: 1, // multiplicity; how many times this symbol was seen
});
} else {
chunks[symbolChunkInd[c]].mult++
if (nextIsActive)
chunks[symbolChunkInd[c]].active = true;
}
nextIsActive = false
}
if (buffer.length > 0 && !/^\s*$/.test(buffer)) {
chunks.push({ type: "text", value: buffer})
}
return chunks;
}
property var symbolImgMap: {
"": "extra-scale-vim",
"󰇥": "extra-scale-yazi",
// "󰇧": "extra-zen",
"󰇧": "extra-scale-firefox",
"󰒱": "extra-scale-slack",
"": "extra-scale-terminal-thin",
"": "extra-scale-firefox",
"": "extra-scale-element-desktop",
"󰊴": "extra-scale-discord-circle-dark",
"": "extra-scale-chromium",
// "": "chromium",
"󰽉": "libreoffice-draw",
"󰷈": "libreoffice-writer",
"": "libreoffice-calc",
"󰈩": "libreoffice-impress",
// "󰭹": "signal-desktop",
"󰭹": "extra-signal-simple",
"": "extra-zathura",
"": "extra-spotify",
// "": "extra-scale-spotify",
"": "extra-steam",
"": "extra-scale-bluetooth",
"": "extra-anki",
"": "extra-scale-gimp",
"": "extra-ghidra",
// "󰄄": "com.obsproject.Studio",
"󰄄": "extra-scale-obs",
"": "extra-scale-photos",
"": "extra-anki",
"": "extra-mpv",
"": "extra-virtualbox",
"": "extra-scale-emacs",
"": "monero",
"󰻎": "extra-scale-system-explorer-outline",
"󱍼": "extra-scale-vlc",
"": "com.usebottles.bottles",
"": "Zoom",
}
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View file

@ -1,8 +1,8 @@
//@ pragma UseQApplication //@ pragma UseQApplication
import Quickshell import Quickshell
import "bar" as Bar import "bar"
ShellRoot { ShellRoot {
Bar.Bar {} Bar {}
} }