Make Settings sidebar content scrollable
This commit is contained in:
@@ -11,6 +11,11 @@ Rectangle {
|
||||
|
||||
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";
|
||||
@@ -40,8 +45,15 @@ Rectangle {
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 18
|
||||
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 {
|
||||
@@ -103,149 +115,175 @@ Rectangle {
|
||||
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
|
||||
|
||||
// ── Search results ──────────────────────────────────────────────────
|
||||
// Typing searches the settings themselves, not the twelve page names.
|
||||
// "gaps", "wallpaper", and "screenshot" all used to find nothing, which
|
||||
// made the app feel far smaller than it is.
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: 3
|
||||
visible: root.query !== ""
|
||||
id: scrollContent
|
||||
|
||||
width: sidebarScroll.width
|
||||
|
||||
// ── Search results ──────────────────────────────────────────────
|
||||
// Typing searches the settings themselves, not page names.
|
||||
Column {
|
||||
id: searchResults
|
||||
|
||||
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
|
||||
spacing: 3
|
||||
visible: root.query !== ""
|
||||
|
||||
Text {
|
||||
width: parent.width
|
||||
height: 44
|
||||
radius: 10
|
||||
color: hitMouse.containsMouse ? Theme.alpha(Theme.fg, 0.08) : "transparent"
|
||||
border.width: 0
|
||||
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
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: 12
|
||||
anchors.rightMargin: 10
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 1
|
||||
Repeater {
|
||||
model: root.results
|
||||
|
||||
Text {
|
||||
width: parent.width
|
||||
text: hit.modelData.label
|
||||
color: Theme.fg
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSize
|
||||
elide: Text.ElideRight
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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 = "";
|
||||
MouseArea {
|
||||
id: hitMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.pageRequested(hit.modelData.page);
|
||||
searchInput.text = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: 4
|
||||
visible: root.query === ""
|
||||
Column {
|
||||
id: navigationList
|
||||
|
||||
Repeater {
|
||||
model: root.destinations
|
||||
width: parent.width
|
||||
spacing: 4
|
||||
visible: root.query === ""
|
||||
|
||||
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)
|
||||
Repeater {
|
||||
model: root.destinations
|
||||
|
||||
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 }
|
||||
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: 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
|
||||
}
|
||||
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)
|
||||
MouseArea {
|
||||
id: navMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: root.pageRequested(navItem.modelData.page)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -253,6 +291,8 @@ Rectangle {
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: healthFooter
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
Reference in New Issue
Block a user