feat: initial commit for pixel-snapping components and helpers

This commit is contained in:
2026-10-29 17:34:57 +01:00
parent 9d8bde1413
commit 9cbb90f9e1
163 changed files with 2671 additions and 951 deletions
+1 -1
View File
@@ -148,7 +148,7 @@ Item {
target.contentY = 0
}
RowLayout {
SnapLayout {
id: header
anchors.left: parent.left
+6 -2
View File
@@ -5,6 +5,7 @@ import QtQuick
import QtQuick.Layouts
import ZShell.Llm
import ZShell.Config
import ZShell.Components
import qs.Modules.Sidebar.Chat.Content
import qs.Services
import qs.Components
@@ -165,13 +166,16 @@ Item {
}
}
ColumnLayout {
SnapLayout {
id: fabMenu
anchors.bottom: fabRoot.top
anchors.right: fabRoot.right
anchors.bottomMargin: Tokens.padding.medium
orientation: Qt.Vertical
spacing: Tokens.spacing.small
Repeater {
id: fabRep
@@ -277,7 +281,7 @@ Item {
}
]
RowLayout {
SnapLayout {
id: fabMenuItemInner
anchors.centerIn: parent
@@ -26,11 +26,13 @@ Item {
border.width: 1
border.color: Colors.palette.m3outlineVariant
ColumnLayout {
SnapLayout {
id: approvalLayout
anchors.fill: parent
anchors.margins: Tokens.padding.medium
spacing: Tokens.spacing.small
orientation: Qt.Vertical
CustomText {
id: requestHeader
@@ -187,19 +189,22 @@ Item {
}
}
ColumnLayout {
SnapLayout {
id: toolList
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.margins: Tokens.padding.medium
spacing: Tokens.spacing.extraSmall
orientation: Qt.Vertical
Repeater {
id: repeater
model: root.current.pendingToolCalls?.slice(0, 4) ?? []
delegate: RowLayout {
delegate: SnapLayout {
id: toolText
required property var modelData
@@ -304,7 +309,7 @@ Item {
Anim {}
}
RowLayout {
SnapLayout {
id: collapsedRow
anchors.top: parent.top
@@ -312,6 +317,8 @@ Item {
anchors.right: parent.right
anchors.margins: Tokens.padding.medium
spacing: Tokens.spacing.extraSmall
IconButton {
id: toolExpandBtn
@@ -1,8 +1,8 @@
import QtQuick
import QtQuick.Effects
import QtQuick.Shapes
import QtQuick.Layouts
import Quickshell
import ZShell.Components
import ZShell.Config
import ZShell.Llm
import qs.Components
@@ -143,7 +143,7 @@ CustomRect {
onTriggered: refresh()
}
RowLayout {
SnapLayout {
id: headerRow
anchors.top: parent.top
@@ -152,6 +152,7 @@ CustomRect {
anchors.topMargin: Tokens.padding.small
anchors.leftMargin: Tokens.padding.small
anchors.rightMargin: Tokens.padding.small
spacing: Tokens.spacing.small
Item {
@@ -1,5 +1,6 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell.Llm
import ZShell.Config
import qs.Modules.Sidebar.Chat
@@ -1,10 +1,12 @@
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import qs.Components
import qs.Services
ColumnLayout {
SnapLayout {
orientation: Qt.Vertical
id: root
spacing: Tokens.spacing.small
+3 -1
View File
@@ -4,6 +4,7 @@ import ZShell.Llm
import ZShell.Config
import qs.Components
import qs.Services
import ZShell.Components
Item {
id: root
@@ -78,7 +79,7 @@ Item {
color: Colors.palette.m3errorContainer
implicitHeight: errorInner.implicitHeight + errorInner.anchors.margins * 2
ColumnLayout {
SnapLayout {
id: errorInner
anchors.top: parent.top
@@ -87,6 +88,7 @@ Item {
anchors.margins: Tokens.padding.medium
spacing: Tokens.spacing.small
orientation: Qt.Vertical
CustomText {
id: header
@@ -212,12 +212,14 @@ Item {
clip: true
implicitHeight: innerLayout.implicitHeight + innerLayout.anchors.margins * 2
ColumnLayout {
SnapLayout {
id: innerLayout
anchors.bottomMargin: Tokens.padding.largeIncreased
anchors.fill: parent
anchors.margins: Tokens.padding.extraLarge
spacing: 0
orientation: Qt.Vertical
CustomText {
font: Tokens.font.title.builders.large.weight(Font.Normal).build()
@@ -264,7 +266,7 @@ Item {
}
}
RowLayout {
SnapLayout {
id: layout
anchors.left: parent.left
@@ -274,6 +276,8 @@ Item {
anchors.leftMargin: Tokens.padding.large
anchors.rightMargin: Tokens.padding.large
spacing: Tokens.spacing.extraSmall
CustomText {
id: name
@@ -313,8 +317,9 @@ Item {
}
}
RowLayout {
SnapLayout {
Layout.alignment: Qt.AlignRight
spacing: Tokens.spacing.extraSmall
TextButton {
@@ -43,7 +43,7 @@ Item {
}
}
RowLayout {
SnapLayout {
id: layout
anchors.top: parent.top
@@ -160,7 +160,7 @@ Item {
implicitWidth: ListView.view.width
implicitHeight: header.implicitHeight + content.implicitHeight + content.anchors.topMargin
RowLayout {
SnapLayout {
id: header
anchors.left: parent.left
+1
View File
@@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import QtQuick.Controls
import Quickshell
import ZShell.Blobs
+11 -4
View File
@@ -1,5 +1,7 @@
pragma ComponentBehavior: Bound
import ZShell
import ZShell.Components
import ZShell.Config
import ZShell.Llm
import QtQuick
@@ -22,21 +24,25 @@ Item {
target: ChatState
}
ColumnLayout {
SnapLayout {
id: layout
anchors.fill: parent
spacing: Tokens.spacing.small
orientation: Qt.Vertical
Tabs {
id: tabs
Layout.fillWidth: true
Layout.preferredHeight: ChatState.isWindow || !Config.llm.enabled ? 0 : implicitHeight
Layout.preferredHeight: ZUtils.snap(ChatState.isWindow || !Config.llm.enabled ? 0 : implicitHeight, root)
screenState: root.screenState
nonAnimWidth: layout.width
visible: height > 0
}
Item {
id: tabContent
Layout.fillHeight: true
Layout.fillWidth: true
clip: true
@@ -161,10 +167,11 @@ Item {
}
CustomRect {
id: separator
Layout.fillWidth: true
Layout.topMargin: Tokens.padding.small - layout.spacing
Layout.topMargin: ZUtils.snap(Tokens.padding.small - layout.spacing, root)
color: Colors.tPalette.m3outlineVariant
implicitHeight: 1
implicitHeight: Math.abs(pages.x) > root.width / 2 ? ZUtils.snapFloor(1, root) : ZUtils.snap(1, root)
}
}
}
+5 -5
View File
@@ -7,6 +7,7 @@ import ZShell.Config
import qs.Components
import qs.Services
import qs.Daemons
import ZShell.Components
CustomRect {
id: root
@@ -26,8 +27,7 @@ CustomRect {
state: expanded ? "expanded" : ""
Behavior on implicitHeight {
Anim {
}
Anim {}
}
states: State {
name: "expanded"
@@ -116,14 +116,14 @@ CustomRect {
anchors.topMargin: Tokens.spacing.extraSmall
shouldBeActive: root.expanded
sourceComponent: ExpandedBody {
}
sourceComponent: ExpandedBody {}
}
component ExpandedBody: ColumnLayout {
component ExpandedBody: SnapLayout {
readonly property alias body: bodyText
spacing: Tokens.spacing.medium
orientation: Qt.Vertical
CustomText {
id: bodyText
+83 -90
View File
@@ -5,6 +5,7 @@ import QtQuick.Layouts
import Quickshell
import Quickshell.Widgets
import ZShell.Config
import ZShell.Components
import qs.Components
import qs.Effects
import qs.Services
@@ -16,115 +17,107 @@ Item {
required property NotifServer.Notif notif
Layout.fillWidth: true
implicitHeight: flickable.contentHeight
implicitHeight: actionList.implicitHeight
CustomFlickable {
id: flickable
SnapLayout {
id: actionList
anchors.fill: parent
contentHeight: actionList.implicitHeight
contentWidth: Math.max(width, actionList.implicitWidth)
spacing: Tokens.spacing.extraSmall
RowLayout {
id: actionList
Repeater {
model: [
{
isClose: true
},
...(root.notif?.actions ?? []),
{
isCopy: true
}
]
anchors.fill: parent
spacing: Tokens.spacing.extraSmall
CustomRect {
id: action
Repeater {
model: [
{
isClose: true
},
...(root.notif?.actions ?? []),
{
isCopy: true
required property var modelData
Layout.fillHeight: true
Layout.fillWidth: true
Layout.preferredWidth: implicitWidth + (actionStateLayer.pressed ? Tokens.padding.large : 0)
color: Colors.layer(Colors.palette.m3surfaceContainerHighest, 4)
implicitHeight: actionInner.implicitHeight + Tokens.padding.small
implicitWidth: actionInner.implicitWidth + Tokens.padding.medium * 2
radius: actionStateLayer.pressed ? Tokens.rounding.medium / 2 : Tokens.rounding.large
Behavior on Layout.preferredWidth {
Anim {
type: Anim.FastSpatial
}
]
}
Behavior on radius {
Anim {
type: Anim.FastSpatial
}
}
CustomRect {
id: action
Timer {
id: copyTimer
required property var modelData
interval: 3000
Layout.fillHeight: true
Layout.fillWidth: true
Layout.preferredWidth: implicitWidth + (actionStateLayer.pressed ? Tokens.padding.large : 0)
color: Colors.layer(Colors.palette.m3surfaceContainerHighest, 4)
implicitHeight: actionInner.implicitHeight + Tokens.padding.small
implicitWidth: actionInner.implicitWidth + Tokens.padding.medium * 2
radius: actionStateLayer.pressed ? Tokens.rounding.medium / 2 : Tokens.rounding.large
onTriggered: actionInner.item.text = "content_copy"
}
Behavior on Layout.preferredWidth {
Anim {
type: Anim.FastSpatial
StateLayer {
id: actionStateLayer
onClicked: {
if (action.modelData.isClose) {
root.notif.close();
} else if (action.modelData.isCopy) {
Quickshell.clipboardText = root.notif.body;
actionInner.item.text = "inventory";
copyTimer.start();
} else if (action.modelData.invoke) {
action.modelData.invoke();
} else if (!root.notif.resident) {
root.notif.close();
}
}
Behavior on radius {
Anim {
type: Anim.FastSpatial
}
}
Loader {
id: actionInner
anchors.centerIn: parent
sourceComponent: action.modelData.isClose || action.modelData.isCopy ? iconBtn : root.notif?.hasActionIcons ? iconComp : textComp
}
Component {
id: iconBtn
MaterialIcon {
animate: action.modelData.isCopy ?? false
color: Colors.palette.m3onSurfaceVariant
text: action.modelData.isCopy ? "content_copy" : "close"
}
}
Timer {
id: copyTimer
Component {
id: iconComp
interval: 3000
onTriggered: actionInner.item.text = "content_copy"
IconImage {
asynchronous: true
source: Quickshell.iconPath(action.modelData.identifier)
}
}
StateLayer {
id: actionStateLayer
Component {
id: textComp
onClicked: {
if (action.modelData.isClose) {
root.notif.close();
} else if (action.modelData.isCopy) {
Quickshell.clipboardText = root.notif.body;
actionInner.item.text = "inventory";
copyTimer.start();
} else if (action.modelData.invoke) {
action.modelData.invoke();
} else if (!root.notif.resident) {
root.notif.close();
}
}
}
Loader {
id: actionInner
anchors.centerIn: parent
sourceComponent: action.modelData.isClose || action.modelData.isCopy ? iconBtn : root.notif?.hasActionIcons ? iconComp : textComp
}
Component {
id: iconBtn
MaterialIcon {
animate: action.modelData.isCopy ?? false
color: Colors.palette.m3onSurfaceVariant
text: action.modelData.isCopy ? "content_copy" : "close"
}
}
Component {
id: iconComp
IconImage {
asynchronous: true
source: Quickshell.iconPath(action.modelData.identifier)
}
}
Component {
id: textComp
CustomText {
color: Colors.palette.m3onSurfaceVariant
text: action.modelData.text
}
CustomText {
color: Colors.palette.m3onSurfaceVariant
text: action.modelData.text
}
}
}
+7 -5
View File
@@ -1,13 +1,14 @@
pragma ComponentBehavior: Bound
import qs.Components
import ZShell.Config
import qs.Modules
import qs.Daemons
import Quickshell
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import ZShell.Config
import qs.Components
import qs.Modules
import qs.Daemons
import qs.Services
Item {
@@ -80,8 +81,9 @@ Item {
Behavior on opacity {
Anim {}
}
sourceComponent: ColumnLayout {
sourceComponent: SnapLayout {
spacing: 20
orientation: Qt.Vertical
CustomText {
Layout.alignment: Qt.AlignHCenter
+24 -14
View File
@@ -9,6 +9,7 @@ import qs.Components
import qs.Services
import qs.Helpers
import qs.Daemons
import ZShell.Components
CustomRect {
id: root
@@ -52,8 +53,7 @@ CustomRect {
radius: Tokens.rounding.large
Behavior on implicitHeight {
Anim {
}
Anim {}
}
Component.onDestruction: {
@@ -61,13 +61,16 @@ CustomRect {
screenState.expandedNotifs.splice(screenState.expandedNotifs.indexOf(modelData), 1);
}
RowLayout {
SnapLayout {
id: content
anchors.left: parent.left
anchors.margins: Tokens.padding.small
anchors.right: parent.right
anchors.top: parent.top
objectName: "notif-content"
spacing: Tokens.spacing.medium
Item {
@@ -148,24 +151,29 @@ CustomRect {
}
}
Column {
SnapLayout {
id: column
Layout.fillWidth: true
spacing: root.expanded ? Math.round(Tokens.spacing.extraSmall) : 0
orientation: Qt.Vertical
objectName: "notif-column"
Behavior on spacing {
Anim {
}
Anim {}
}
RowLayout {
SnapLayout {
id: header
anchors.left: parent.left
anchors.right: parent.right
Layout.fillWidth: true
spacing: Tokens.spacing.small
objectName: "notif-header"
CustomText {
Layout.fillWidth: true
color: Colors.palette.m3onSurfaceVariant
@@ -191,12 +199,14 @@ CustomRect {
onClicked: root.toggleExpand(!root.expanded)
}
RowLayout {
SnapLayout {
id: expandBtn
anchors.centerIn: parent
spacing: Tokens.spacing.extraSmall
objectName: "notif-expand"
CustomText {
id: groupCount
@@ -214,12 +224,10 @@ CustomRect {
text: "expand_more"
Behavior on Layout.topMargin {
Anim {
}
Anim {}
}
Behavior on rotation {
Anim {
}
Anim {}
}
}
}
@@ -229,6 +237,8 @@ CustomRect {
NotifGroupList {
id: notifList
Layout.fillWidth: true
container: root.container
expanded: root.expanded
notifs: root.notifs
+3 -8
View File
@@ -18,8 +18,6 @@ LazyListView {
signal requestToggleExpand(expand: bool)
anchors.left: parent.left
anchors.right: parent.right
asynchronous: true
cacheBuffer: 400
implicitHeight: contentHeight
@@ -59,18 +57,15 @@ LazyListView {
}
}
Behavior on scale {
Anim {
}
Anim {}
}
Behavior on x {
Anim {
}
Anim {}
}
Behavior on y {
enabled: notif.LazyListView.ready
Anim {
}
Anim {}
}
Component.onCompleted: modelData?.lock(this)
+3 -2
View File
@@ -4,6 +4,7 @@ import QtQuick
import QtQuick.Layouts
import QtQuick.Templates
import Quickshell
import ZShell.Components
import ZShell.Config
import qs.Components
import qs.Services
@@ -27,7 +28,7 @@ Item {
currentIndex: root.screenState.sidebarTab
implicitHeight: contentHeight
contentItem: RowLayout {
contentItem: SnapLayout {
spacing: 0
Repeater {
@@ -105,7 +106,7 @@ Item {
implicitWidth: Math.max(icon.width, label.width)
StateLayer {
color: tab.current ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
color: tab.current ? Colors.palette.m3primary : Colors.palette.m3onSurface
radius: Tokens.rounding.small
onClicked: root.screenState.sidebarTab = tab.TabBar.index
+10 -6
View File
@@ -3,8 +3,10 @@ pragma ComponentBehavior: Bound
import Quickshell
import QtQuick
import QtQuick.Layouts
import qs.Components
import ZShell.Components
import ZShell
import ZShell.Config
import qs.Components
import qs.Helpers
import qs.Services
@@ -15,17 +17,18 @@ CustomRect {
Layout.fillWidth: true
color: Colors.tPalette.m3surfaceContainer
implicitHeight: layout.implicitHeight + layout.anchors.margins * 2
implicitHeight: ZUtils.snap(layout.implicitHeight + layout.anchors.margins * 2, root)
radius: Tokens.rounding.small
ColumnLayout {
SnapLayout {
orientation: Qt.Vertical
id: layout
anchors.fill: parent
anchors.margins: Tokens.padding.large
spacing: Tokens.spacing.medium
RowLayout {
SnapLayout {
spacing: Tokens.spacing.medium
z: 1
@@ -50,7 +53,8 @@ CustomRect {
}
}
ColumnLayout {
SnapLayout {
orientation: Qt.Vertical
Layout.fillWidth: true
spacing: 0
@@ -194,7 +198,7 @@ CustomRect {
Component {
id: recordingControls
RowLayout {
SnapLayout {
spacing: Tokens.spacing.medium
CustomRect {
@@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import Quickshell
import Quickshell.Widgets
import ZShell.Models
@@ -11,7 +12,8 @@ import qs.Paths
import ZShell.Config
import qs.Services
ColumnLayout {
SnapLayout {
orientation: Qt.Vertical
id: root
required property ScreenState screenState
@@ -24,7 +26,7 @@ ColumnLayout {
onClicked: root.screenState.recordingListExpanded = !root.screenState.recordingListExpanded
RowLayout {
SnapLayout {
spacing: Tokens.spacing.small
MaterialIcon {
@@ -74,7 +76,7 @@ ColumnLayout {
to: 1
}
}
delegate: RowLayout {
delegate: SnapLayout {
id: recording
property string baseName
@@ -168,7 +170,8 @@ ColumnLayout {
Behavior on opacity {
Anim {}
}
sourceComponent: ColumnLayout {
sourceComponent: SnapLayout {
orientation: Qt.Vertical
spacing: Tokens.spacing.small
MaterialIcon {
@@ -191,7 +194,7 @@ ColumnLayout {
}
}
RowLayout {
SnapLayout {
spacing: Tokens.spacing.small
MaterialIcon {
+2 -1
View File
@@ -45,7 +45,8 @@ CustomRect {
implicitHeight: layout.implicitHeight + Tokens.padding.extraLargeIncreased
radius: Tokens.rounding.small
ColumnLayout {
SnapLayout {
orientation: Qt.Vertical
id: layout
anchors.fill: parent
+8 -4
View File
@@ -2,22 +2,26 @@ import Quickshell
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import ZShell
import qs.Components
import qs.Modules.Sidebar.Utils.Cards
import ZShell.Components
Item {
id: root
required property ScreenState screenState
implicitHeight: layout.implicitHeight
implicitWidth: layout.implicitWidth
implicitHeight: ZUtils.snap(layout.implicitHeight, root)
implicitWidth: ZUtils.snap(layout.implicitWidth, root)
ColumnLayout {
SnapLayout {
id: layout
anchors.fill: parent
spacing: 8
spacing: Tokens.spacing.small
orientation: Qt.Vertical
IdleInhibit {}
+12 -7
View File
@@ -1,8 +1,10 @@
import qs.Components
import ZShell.Config
import qs.Helpers
import QtQuick
import QtQuick.Layouts
import ZShell
import ZShell.Config
import ZShell.Components
import qs.Components
import qs.Helpers
import qs.Services
CustomRect {
@@ -11,21 +13,22 @@ CustomRect {
Layout.fillWidth: true
clip: true
color: Colors.tPalette.m3surfaceContainer
implicitHeight: layout.implicitHeight + (IdleInhibitor.enabled ? activeChip.implicitHeight + activeChip.anchors.topMargin : 0) + 18 * 2
implicitHeight: ZUtils.snap((layout.implicitHeight + (IdleInhibitor.enabled ? activeChip.implicitHeight + activeChip.anchors.topMargin : 0) + 18 * 2), root)
radius: Tokens.rounding.small
Behavior on implicitHeight {
Anim {}
}
RowLayout {
SnapLayout {
id: layout
anchors.left: parent.left
anchors.margins: 18
anchors.right: parent.right
anchors.top: parent.top
spacing: 10
spacing: Tokens.spacing.medium
CustomRect {
color: IdleInhibitor.enabled ? Colors.palette.m3secondary : Colors.palette.m3secondaryContainer
@@ -43,9 +46,11 @@ CustomRect {
}
}
ColumnLayout {
SnapLayout {
Layout.fillWidth: true
spacing: 0
orientation: Qt.Vertical
CustomText {
Layout.fillWidth: true