361 lines
13 KiB
QML
361 lines
13 KiB
QML
import QtQuick
|
|
import qs.config
|
|
import qs.services
|
|
|
|
Rectangle {
|
|
id: root
|
|
|
|
property string selectedPage: "home"
|
|
property string query: searchInput.text.trim().toLowerCase()
|
|
signal pageRequested(string page)
|
|
|
|
readonly property var results: SettingsSearch.search(root.query)
|
|
|
|
onQueryChanged: {
|
|
if (sidebarScroll)
|
|
sidebarScroll.contentY = 0;
|
|
}
|
|
|
|
function pageLabel(page: string): string {
|
|
const found = root.destinations.find(item => item.page === page);
|
|
return found ? found.label : "Settings";
|
|
}
|
|
|
|
readonly property var destinations: [
|
|
{ page: "home", label: "Home", icon: "\u{F02DC}" },
|
|
{ page: "appearance", label: "Appearance", icon: "\u{F0E0D}" },
|
|
{ page: "displays", label: "Displays", icon: "\u{F0379}" },
|
|
{ page: "connectivity", label: "Network & Devices", icon: "\u{F08D4}" },
|
|
{ page: "home-phone", label: "Home & Phone", icon: "\u{F02DC}" },
|
|
{ page: "desktop", label: "Desktop & Dock", icon: "\u{F04A4}" },
|
|
{ page: "sound", label: "Sound", icon: "\u{F057E}" },
|
|
{ page: "notifications", label: "Notifications & Focus", icon: "\u{F009A}" },
|
|
{ page: "screen-intelligence", label: "Screen Intelligence", icon: "\u{F05A8}" },
|
|
{ page: "shortcuts", label: "Input & Shortcuts", icon: "\u{F030C}" },
|
|
{ page: "accessibility", label: "Accessibility", icon: "\u{F0208}" },
|
|
{ page: "power", label: "Power & Lock", icon: "\u{F0425}" },
|
|
{ page: "datetime", label: "Date & Time", icon: "\u{F0954}" },
|
|
{ page: "applications", label: "Applications", icon: "\u{F003B}" },
|
|
{ page: "services", label: "System Health", icon: "\u{F0493}" },
|
|
{ page: "about", label: "About Panama", icon: "\u{F02FD}" }
|
|
]
|
|
|
|
width: 272
|
|
color: Theme.alpha(Theme.bgDark, 0.96)
|
|
border.width: 0
|
|
|
|
Column {
|
|
id: sidebarHeader
|
|
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.top: parent.top
|
|
anchors.leftMargin: 18
|
|
anchors.rightMargin: 18
|
|
anchors.topMargin: 18
|
|
height: implicitHeight
|
|
spacing: 12
|
|
|
|
Text {
|
|
text: "PANAMA"
|
|
color: Theme.fg
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSizeLarge
|
|
font.weight: Font.DemiBold
|
|
font.letterSpacing: 2.2
|
|
}
|
|
|
|
Rectangle {
|
|
width: parent.width
|
|
height: 36
|
|
radius: 10
|
|
color: Theme.alpha(Theme.fg, searchArea.containsMouse || searchInput.activeFocus ? 0.105 : 0.065)
|
|
border.width: 1
|
|
border.color: searchInput.activeFocus ? Theme.alpha(Theme.accent, 0.5) : Theme.alpha(Theme.fg, 0.055)
|
|
|
|
Text {
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 11
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: "\u{F0349}"
|
|
color: Theme.fgDim
|
|
font.family: Theme.fontMono
|
|
font.pixelSize: 14
|
|
}
|
|
|
|
TextInput {
|
|
id: searchInput
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 35
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 10
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
color: Theme.fg
|
|
selectionColor: Theme.accent
|
|
selectedTextColor: Theme.bgDark
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSize
|
|
clip: true
|
|
|
|
Text {
|
|
anchors.fill: parent
|
|
visible: !searchInput.text && !searchInput.activeFocus
|
|
text: "Search settings"
|
|
color: Theme.fgMuted
|
|
font: searchInput.font
|
|
verticalAlignment: Text.AlignVCenter
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
id: searchArea
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.IBeamCursor
|
|
onClicked: searchInput.forceActiveFocus()
|
|
}
|
|
}
|
|
}
|
|
|
|
Flickable {
|
|
id: sidebarScroll
|
|
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.top: sidebarHeader.bottom
|
|
anchors.bottom: healthFooter.top
|
|
anchors.leftMargin: 18
|
|
anchors.rightMargin: 18
|
|
anchors.topMargin: 12
|
|
anchors.bottomMargin: 12
|
|
contentWidth: width
|
|
contentHeight: scrollContent.implicitHeight
|
|
flickableDirection: Flickable.VerticalFlick
|
|
boundsBehavior: Flickable.StopAtBounds
|
|
clip: true
|
|
|
|
Column {
|
|
id: scrollContent
|
|
|
|
width: sidebarScroll.width
|
|
|
|
// ── Search results ──────────────────────────────────────────────
|
|
// Typing searches the settings themselves, not page names.
|
|
Column {
|
|
id: searchResults
|
|
|
|
width: parent.width
|
|
spacing: 3
|
|
visible: root.query !== ""
|
|
|
|
Text {
|
|
width: parent.width
|
|
leftPadding: 4
|
|
bottomPadding: 4
|
|
text: root.results.length === 0
|
|
? "Nothing matches"
|
|
: root.results.length + (root.results.length === 1 ? " result" : " results")
|
|
color: Theme.fgMuted
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
}
|
|
|
|
Repeater {
|
|
model: root.results
|
|
|
|
Rectangle {
|
|
id: hit
|
|
|
|
required property var modelData
|
|
|
|
width: parent.width
|
|
height: 44
|
|
radius: 10
|
|
color: hitMouse.containsMouse ? Theme.alpha(Theme.fg, 0.08) : "transparent"
|
|
border.width: 0
|
|
|
|
Column {
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.leftMargin: 12
|
|
anchors.rightMargin: 10
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
spacing: 1
|
|
|
|
Text {
|
|
width: parent.width
|
|
text: hit.modelData.label
|
|
color: Theme.fg
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSize
|
|
elide: Text.ElideRight
|
|
}
|
|
|
|
Text {
|
|
width: parent.width
|
|
text: hit.modelData.kind === "shortcut"
|
|
? hit.modelData.detail
|
|
: root.pageLabel(hit.modelData.page)
|
|
color: hit.modelData.kind === "shortcut" ? Theme.accent : Theme.fgMuted
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
elide: Text.ElideRight
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
id: hitMouse
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: {
|
|
root.pageRequested(hit.modelData.page);
|
|
searchInput.text = "";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Column {
|
|
id: navigationList
|
|
|
|
width: parent.width
|
|
spacing: 4
|
|
visible: root.query === ""
|
|
|
|
Repeater {
|
|
model: root.destinations
|
|
|
|
Rectangle {
|
|
id: navItem
|
|
required property var modelData
|
|
width: parent.width
|
|
height: 40
|
|
radius: 10
|
|
color: modelData.page === root.selectedPage
|
|
? Theme.alpha(Theme.accent, 0.17)
|
|
: (navMouse.containsMouse ? Theme.alpha(Theme.fg, Theme.hoverAlpha * 0.55) : Theme.alpha(Theme.fg, 0))
|
|
border.width: modelData.page === root.selectedPage ? 1 : 0
|
|
border.color: Theme.alpha(Theme.accent, 0.26)
|
|
|
|
Rectangle {
|
|
width: 2
|
|
height: 18
|
|
radius: 1
|
|
anchors.left: parent.left
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
visible: navItem.modelData.page === root.selectedPage
|
|
gradient: Gradient {
|
|
GradientStop { position: 0; color: Theme.accent }
|
|
GradientStop { position: 1; color: Theme.accentSecondary }
|
|
}
|
|
}
|
|
|
|
Text {
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 13
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
width: 25
|
|
text: navItem.modelData.icon
|
|
color: navItem.modelData.page === root.selectedPage ? Theme.accent : Theme.fgDim
|
|
font.family: Theme.fontMono
|
|
font.pixelSize: 15
|
|
}
|
|
|
|
Text {
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 47
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 9
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: navItem.modelData.label
|
|
color: navItem.modelData.page === root.selectedPage ? Theme.fg : Theme.fgDim
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSize
|
|
font.weight: navItem.modelData.page === root.selectedPage ? Font.Medium : Font.Normal
|
|
elide: Text.ElideRight
|
|
}
|
|
|
|
MouseArea {
|
|
id: navMouse
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: root.pageRequested(navItem.modelData.page)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: healthFooter
|
|
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.bottom: parent.bottom
|
|
height: 54
|
|
activeFocusOnTab: true
|
|
color: footerTap.hovered || activeFocus
|
|
? Theme.alpha(Theme.fg, 0.07)
|
|
: Theme.alpha(Theme.bg, 0.35)
|
|
border.width: activeFocus ? 2 : 0
|
|
border.color: Theme.accent
|
|
|
|
function footerText(): string {
|
|
if (Health.checks.length === 0)
|
|
return Health.diagnosticUnavailable ? "Health check unavailable" : "Checking Panama desktop";
|
|
if (Health.status === "error")
|
|
return "Panama requires attention";
|
|
if (Health.status === "warning") {
|
|
const count = Health.summary.warnings + Health.summary.errors;
|
|
return count + (count === 1 ? " health observation" : " health observations");
|
|
}
|
|
return "Panama desktop is healthy";
|
|
}
|
|
|
|
function footerColor(): color {
|
|
if (Health.checks.length === 0)
|
|
return Health.diagnosticUnavailable ? Theme.danger : Theme.fgMuted;
|
|
if (Health.status === "error")
|
|
return Theme.danger;
|
|
if (Health.status === "warning")
|
|
return Theme.warn;
|
|
return Theme.ok;
|
|
}
|
|
|
|
Rectangle {
|
|
width: 7
|
|
height: 7
|
|
radius: 4
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 19
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
color: healthFooter.footerColor()
|
|
}
|
|
|
|
Text {
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 36
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 12
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: healthFooter.footerText()
|
|
color: Theme.fgDim
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
elide: Text.ElideRight
|
|
}
|
|
|
|
TapHandler {
|
|
id: footerTap
|
|
onTapped: root.pageRequested("services")
|
|
}
|
|
|
|
Keys.onReturnPressed: root.pageRequested("services")
|
|
Keys.onSpacePressed: root.pageRequested("services")
|
|
}
|
|
}
|