mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-06 05:25:41 -05:00
337 lines
14 KiB
QML
337 lines
14 KiB
QML
import QtQuick
|
|
import QtQuick.Controls
|
|
import QtQuick.Effects
|
|
import Quickshell
|
|
import Quickshell.Wayland
|
|
import qs.Common
|
|
import qs.Widgets
|
|
|
|
Rectangle {
|
|
id: root
|
|
|
|
property string currentIcon: ""
|
|
property string currentText: ""
|
|
property string iconType: "icon" // "icon" or "text"
|
|
|
|
signal iconSelected(string iconName, string iconType)
|
|
|
|
width: 240
|
|
height: 32
|
|
radius: Theme.cornerRadius
|
|
color: Theme.surfaceContainer
|
|
border.color: dropdownLoader.active ? Theme.primary : (mouseArea.containsMouse ? Theme.outline : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.5))
|
|
border.width: 1
|
|
|
|
property var iconCategories: [{
|
|
"name": "Workspace",
|
|
"icons": ["work", "laptop", "desktop_windows", "code", "terminal", "build", "settings", "folder", "view_module", "dashboard", "apps", "grid_view"]
|
|
}, {
|
|
"name": "Development",
|
|
"icons": ["code", "terminal", "bug_report", "build", "engineering", "integration_instructions", "data_object", "schema", "api", "webhook"]
|
|
}, {
|
|
"name": "Communication",
|
|
"icons": ["chat", "mail", "forum", "message", "video_call", "call", "contacts", "group", "notifications", "campaign"]
|
|
}, {
|
|
"name": "Media",
|
|
"icons": ["music_note", "headphones", "mic", "videocam", "photo", "movie", "library_music", "album", "radio", "volume_up"]
|
|
}, {
|
|
"name": "System",
|
|
"icons": ["memory", "storage", "developer_board", "monitor", "keyboard", "mouse", "battery_std", "wifi", "bluetooth", "security"]
|
|
}, {
|
|
"name": "Navigation",
|
|
"icons": ["home", "arrow_forward", "arrow_back", "expand_more", "expand_less", "menu", "close", "search", "filter_list", "sort"]
|
|
}, {
|
|
"name": "Actions",
|
|
"icons": ["add", "remove", "edit", "delete", "save", "download", "upload", "share", "content_copy", "content_paste", "content_cut", "undo", "redo"]
|
|
}, {
|
|
"name": "Status",
|
|
"icons": ["check", "close", "error", "warning", "info", "done", "pending", "schedule", "update", "sync", "offline_bolt"]
|
|
}, {
|
|
"name": "Fun",
|
|
"icons": ["celebration", "cake", "star", "favorite", "pets", "sports_esports", "local_fire_department", "bolt", "auto_awesome", "diamond"]
|
|
}]
|
|
|
|
MouseArea {
|
|
id: mouseArea
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
onClicked: {
|
|
dropdownLoader.active = !dropdownLoader.active
|
|
}
|
|
}
|
|
|
|
Row {
|
|
anchors.left: parent.left
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.leftMargin: Theme.spacingS
|
|
spacing: Theme.spacingS
|
|
|
|
DankIcon {
|
|
name: root.iconType === "icon"
|
|
&& root.currentIcon ? root.currentIcon : (root.iconType
|
|
=== "text" ? "text_fields" : "add")
|
|
size: 16
|
|
color: root.currentIcon
|
|
|| root.currentText ? Theme.surfaceText : Theme.outline
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
}
|
|
|
|
StyledText {
|
|
text: {
|
|
if (root.iconType === "text" && root.currentText)
|
|
return root.currentText
|
|
if (root.iconType === "icon" && root.currentIcon)
|
|
return root.currentIcon
|
|
return "Choose icon or text"
|
|
}
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
color: root.currentIcon
|
|
|| root.currentText ? Theme.surfaceText : Theme.outline
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
width: 160
|
|
elide: Text.ElideRight
|
|
}
|
|
}
|
|
|
|
DankIcon {
|
|
name: dropdownLoader.active ? "expand_less" : "expand_more"
|
|
size: 16
|
|
color: Theme.outline
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: Theme.spacingS
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
}
|
|
|
|
Loader {
|
|
id: dropdownLoader
|
|
active: false
|
|
asynchronous: true
|
|
|
|
sourceComponent: PanelWindow {
|
|
id: dropdownPopup
|
|
|
|
visible: true
|
|
implicitWidth: 320
|
|
implicitHeight: Math.min(500, dropdownContent.implicitHeight + 32)
|
|
color: "transparent"
|
|
WlrLayershell.layer: WlrLayershell.Overlay
|
|
WlrLayershell.exclusiveZone: -1
|
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
|
|
|
|
anchors {
|
|
top: true
|
|
left: true
|
|
right: true
|
|
bottom: true
|
|
}
|
|
|
|
// Click outside to close
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onClicked: dropdownLoader.active = false
|
|
}
|
|
|
|
Rectangle {
|
|
width: 320
|
|
height: Math.min(500, dropdownContent.implicitHeight + 32)
|
|
x: {
|
|
// Get the root picker's position relative to the screen
|
|
var pickerPos = root.mapToItem(null, 0, 0)
|
|
return Math.max(16, Math.min(pickerPos.x,
|
|
parent.width - width - 16))
|
|
}
|
|
y: {
|
|
// Position below the picker button
|
|
var pickerPos = root.mapToItem(null, 0, root.height + 4)
|
|
return Math.max(16, Math.min(pickerPos.y,
|
|
parent.height - height - 16))
|
|
}
|
|
radius: Theme.cornerRadius
|
|
color: Theme.surface
|
|
border.color: Theme.outline
|
|
border.width: 1
|
|
|
|
// Prevent this from closing the dropdown when clicked
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
// Don't propagate clicks to parent
|
|
}
|
|
|
|
layer.enabled: true
|
|
layer.effect: MultiEffect {
|
|
shadowEnabled: true
|
|
shadowColor: Theme.shadowDark
|
|
shadowBlur: 0.8
|
|
shadowHorizontalOffset: 0
|
|
shadowVerticalOffset: 4
|
|
}
|
|
|
|
DankFlickable {
|
|
anchors.fill: parent
|
|
anchors.margins: Theme.spacingS
|
|
contentHeight: dropdownContent.height
|
|
clip: true
|
|
|
|
Column {
|
|
id: dropdownContent
|
|
width: parent.width
|
|
spacing: Theme.spacingM
|
|
|
|
// Custom text section
|
|
Rectangle {
|
|
width: parent.width
|
|
height: customTextSection.implicitHeight + Theme.spacingS * 2
|
|
radius: Theme.cornerRadius
|
|
color: Qt.rgba(Theme.surfaceVariant.r,
|
|
Theme.surfaceVariant.g,
|
|
Theme.surfaceVariant.b, 0.3)
|
|
|
|
Column {
|
|
id: customTextSection
|
|
anchors.fill: parent
|
|
anchors.margins: Theme.spacingS
|
|
spacing: Theme.spacingS
|
|
|
|
StyledText {
|
|
text: "Custom Text"
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
font.weight: Font.Medium
|
|
color: Theme.surfaceText
|
|
}
|
|
|
|
Rectangle {
|
|
width: parent.width
|
|
height: 28
|
|
radius: Theme.cornerRadius
|
|
color: Theme.surfaceContainer
|
|
border.color: customTextInput.activeFocus ? Theme.primary : Theme.outline
|
|
border.width: 1
|
|
|
|
Row {
|
|
anchors.left: parent.left
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.leftMargin: Theme.spacingS
|
|
spacing: Theme.spacingS
|
|
|
|
DankIcon {
|
|
name: "text_fields"
|
|
size: 14
|
|
color: Theme.outline
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
}
|
|
|
|
TextInput {
|
|
id: customTextInput
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
width: 200
|
|
text: root.iconType === "text" ? root.currentText : ""
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
color: Theme.surfaceText
|
|
selectByMouse: true
|
|
|
|
onEditingFinished: {
|
|
var trimmedText = text.trim()
|
|
if (trimmedText) {
|
|
root.iconSelected(
|
|
trimmedText,
|
|
"text")
|
|
dropdownLoader.active = false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
StyledText {
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: Theme.spacingS + 14 + Theme.spacingS
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: "1-2 characters"
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
color: Theme.outline
|
|
opacity: 0.6
|
|
visible: customTextInput.text === ""
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Icon categories
|
|
Repeater {
|
|
model: root.iconCategories
|
|
|
|
Column {
|
|
width: parent.width
|
|
spacing: Theme.spacingS
|
|
|
|
StyledText {
|
|
text: modelData.name
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
font.weight: Font.Medium
|
|
color: Theme.surfaceText
|
|
}
|
|
|
|
Flow {
|
|
width: parent.width
|
|
spacing: 4
|
|
|
|
Repeater {
|
|
model: modelData.icons
|
|
|
|
Rectangle {
|
|
width: 36
|
|
height: 36
|
|
radius: Theme.cornerRadius
|
|
color: iconMouseArea.containsMouse ? Theme.primaryHover : "transparent"
|
|
border.color: root.currentIcon === modelData ? Theme.primary : "transparent"
|
|
border.width: 2
|
|
|
|
DankIcon {
|
|
name: modelData
|
|
size: 20
|
|
color: root.currentIcon === modelData ? Theme.primary : Theme.surfaceText
|
|
anchors.centerIn: parent
|
|
}
|
|
|
|
MouseArea {
|
|
id: iconMouseArea
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: {
|
|
root.iconSelected(
|
|
modelData,
|
|
"icon")
|
|
dropdownLoader.active = false
|
|
}
|
|
}
|
|
|
|
Behavior on color {
|
|
ColorAnimation {
|
|
duration: Theme.shortDuration
|
|
easing.type: Theme.standardEasing
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function setIcon(iconName, type) {
|
|
if (type === "text") {
|
|
root.currentText = iconName
|
|
root.currentIcon = ""
|
|
root.iconType = "text"
|
|
} else {
|
|
root.currentIcon = iconName
|
|
root.currentText = ""
|
|
root.iconType = "icon"
|
|
}
|
|
}
|
|
}
|