Add .config/DankMaterialShell/firefox.css

Add .config/DankMaterialShell/plugin_settings.json
Add .config/DankMaterialShell/plugins/dankDesktopWeather.meta
Add .config/DankMaterialShell/plugins/dankHooks.meta
Add .config/DankMaterialShell/plugins/desktopCommand/LICENSE
Add .config/DankMaterialShell/plugins/desktopCommand/README.md
Add .config/DankMaterialShell/plugins/desktopCommand/Settings.qml
Add .config/DankMaterialShell/plugins/desktopCommand/Widget.qml
Add .config/DankMaterialShell/plugins/desktopCommand/assets/screenshot.jpg
Add .config/DankMaterialShell/plugins/desktopCommand/.git/HEAD
Add .config/DankMaterialShell/plugins/desktopCommand/.git/config
Add .config/DankMaterialShell/plugins/desktopCommand/.git/index
Add .config/DankMaterialShell/plugins/desktopCommand/.git/objects/info/.keep
Add .config/DankMaterialShell/plugins/desktopCommand/.git/objects/pack/pack-c2ca48eacecc3ab45931476641d058a89d755775.idx
Add .config/DankMaterialShell/plugins/desktopCommand/.git/objects/pack/pack-c2ca48eacecc3ab45931476641d058a89d755775.rev
Add .config/DankMaterialShell/plugins/desktopCommand/.git/objects/pack/pack-c2ca48eacecc3ab45931476641d058a89d755775.pack
Add .config/DankMaterialShell/plugins/desktopCommand/.git/refs/heads/main
Add .config/DankMaterialShell/plugins/desktopCommand/.git/refs/remotes/origin/main
Add .config/DankMaterialShell/plugins/desktopCommand/.git/refs/tags/.keep
Add .config/DankMaterialShell/plugins/desktopCommand/.gitignore
Add .config/DankMaterialShell/plugins/desktopCommand/wrapCommand
Add .config/DankMaterialShell/plugins/desktopCommand/plugin.json
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankActions/DankActionsSettings.qml
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankActions/DankActionsWidget.qml
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankActions/plugin.json
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankBatteryAlerts/DankBatteryAlerts.qml
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankBatteryAlerts/DankBatteryAlertsSettings.qml
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankBatteryAlerts/plugin.json
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankDesktopWeather/DankDesktopWeather.qml
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankDesktopWeather/DankDesktopWeatherSettings.qml
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankDesktopWeather/plugin.json
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankHooks/DankHooks.qml
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankHooks/DankHooksSettings.qml
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankHooks/README.md
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankHooks/plugin.json
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankPomodoroTimer/DankPomodoroSettings.qml
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankPomodoroTimer/DankPomodoroWidget.qml
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/DankPomodoroTimer/plugin.json
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/LICENSE
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/README.md
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.git/HEAD
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.git/config
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.git/index
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.git/objects/info/.keep
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.git/objects/pack/pack-3221a15c022ef4a7bb6bf2c47e40068b66b3588b.idx
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.git/objects/pack/pack-3221a15c022ef4a7bb6bf2c47e40068b66b3588b.rev
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.git/objects/pack/pack-9aca069a8b76b40fcc472eba1ed9b8219a87776b.idx
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.git/objects/pack/pack-9aca069a8b76b40fcc472eba1ed9b8219a87776b.rev
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.git/objects/pack/pack-e6f6cdfe9914bfb4a5717ef6036821794d59ab4b.idx
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.git/objects/pack/pack-e6f6cdfe9914bfb4a5717ef6036821794d59ab4b.rev
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.git/objects/pack/pack-3221a15c022ef4a7bb6bf2c47e40068b66b3588b.pack
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.git/objects/pack/pack-9aca069a8b76b40fcc472eba1ed9b8219a87776b.pack
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.git/objects/pack/pack-e6f6cdfe9914bfb4a5717ef6036821794d59ab4b.pack
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.git/refs/heads/master
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.git/refs/remotes/origin/master
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.git/refs/tags/.keep
Add .config/DankMaterialShell/plugins/.repos/0026f1eba8dedaec/.gitignore
Add .config/DankMaterialShell/plugins/emojiLauncher/EmojiLauncher.qml
Add .config/DankMaterialShell/plugins/emojiLauncher/EmojiLauncherSettings.qml
Add .config/DankMaterialShell/plugins/emojiLauncher/LICENSE
Add .config/DankMaterialShell/plugins/emojiLauncher/README.md
Add .config/DankMaterialShell/plugins/emojiLauncher/catalog.js
Add .config/DankMaterialShell/plugins/emojiLauncher/data/emojis.txt
Add .config/DankMaterialShell/plugins/emojiLauncher/data/math.txt
Add .config/DankMaterialShell/plugins/emojiLauncher/data/nerdfont.txt
Add .config/DankMaterialShell/plugins/emojiLauncher/.git/HEAD
Add .config/DankMaterialShell/plugins/emojiLauncher/.git/config
Add .config/DankMaterialShell/plugins/emojiLauncher/.git/index
Add .config/DankMaterialShell/plugins/emojiLauncher/.git/objects/info/.keep
Add .config/DankMaterialShell/plugins/emojiLauncher/.git/objects/pack/pack-e04a5b1ea381dc3a792b8bf08cf70e735b195c0d.idx
Add .config/DankMaterialShell/plugins/emojiLauncher/.git/objects/pack/pack-e04a5b1ea381dc3a792b8bf08cf70e735b195c0d.rev
Add .config/DankMaterialShell/plugins/emojiLauncher/.git/objects/pack/pack-e04a5b1ea381dc3a792b8bf08cf70e735b195c0d.pack
Add .config/DankMaterialShell/plugins/emojiLauncher/.git/refs/heads/main
Add .config/DankMaterialShell/plugins/emojiLauncher/.git/refs/remotes/origin/main
Add .config/DankMaterialShell/plugins/emojiLauncher/.git/refs/tags/.keep
Add .config/DankMaterialShell/plugins/emojiLauncher/plugin.json
Add .config/DankMaterialShell/plugins/emojiLauncher/screenshot.png
Add .config/DankMaterialShell/plugins/emojiLauncher/scripts/generate_catalog.py
Add .config/DankMaterialShell/plugins/mediaPlayer/MediaPlayerSettings.qml
Add .config/DankMaterialShell/plugins/mediaPlayer/MediaPlayerTab.qml
Add .config/DankMaterialShell/plugins/mediaPlayer/README.md
Add .config/DankMaterialShell/plugins/mediaPlayer/.git/HEAD
Add .config/DankMaterialShell/plugins/mediaPlayer/.git/config
Add .config/DankMaterialShell/plugins/mediaPlayer/.git/index
Add .config/DankMaterialShell/plugins/mediaPlayer/.git/objects/info/.keep
Add .config/DankMaterialShell/plugins/mediaPlayer/.git/objects/pack/pack-0b9cb33f7da23f6ff361ee3aa5117928714bc3be.idx
Add .config/DankMaterialShell/plugins/mediaPlayer/.git/objects/pack/pack-0b9cb33f7da23f6ff361ee3aa5117928714bc3be.rev
Add .config/DankMaterialShell/plugins/mediaPlayer/.git/objects/pack/pack-0b9cb33f7da23f6ff361ee3aa5117928714bc3be.pack
Add .config/DankMaterialShell/plugins/mediaPlayer/.git/refs/heads/main
Add .config/DankMaterialShell/plugins/mediaPlayer/.git/refs/remotes/origin/main
Add .config/DankMaterialShell/plugins/mediaPlayer/.git/refs/tags/.keep
Add .config/DankMaterialShell/plugins/mediaPlayer/plugin.json
Add .config/DankMaterialShell/plugins/mediaPlayer/screenshot_8.png
Add .config/DankMaterialShell/plugins/dankDesktopWeather
Add .config/DankMaterialShell/plugins/dankHooks
Add .config/DankMaterialShell/settings.json
This commit is contained in:
Lewis Wynne 2026-01-07 15:09:11 +00:00
parent 9d16d6e6b0
commit b18328bbad
96 changed files with 24119 additions and 0 deletions

View file

@ -0,0 +1,644 @@
import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Services
import qs.Widgets
import qs.Modules.Plugins
PluginSettings {
id: root
pluginId: "dankActions"
property string editingVariantId: ""
function loadVariantForEditing(variantData) {
editingVariantId = variantData.id || ""
nameField.text = variantData.name || ""
iconField.text = variantData.icon || ""
displayTextField.text = variantData.displayText || ""
displayCommandField.text = variantData.displayCommand || ""
clickCommandField.text = variantData.clickCommand || ""
middleClickCommandField.text = variantData.middleClickCommand || ""
rightClickCommandField.text = variantData.rightClickCommand || ""
updateIntervalField.text = (variantData.updateInterval || 0).toString()
showIconToggle.checked = variantData.showIcon !== undefined ? variantData.showIcon : true
showTextToggle.checked = variantData.showText !== undefined ? variantData.showText : true
}
function clearForm() {
editingVariantId = ""
nameField.text = ""
iconField.text = ""
displayTextField.text = ""
displayCommandField.text = ""
clickCommandField.text = ""
middleClickCommandField.text = ""
rightClickCommandField.text = ""
updateIntervalField.text = "0"
showIconToggle.checked = true
showTextToggle.checked = true
}
StyledText {
width: parent.width
text: "Custom Action Manager"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Bold
color: Theme.surfaceText
}
StyledText {
width: parent.width
text: "Create custom widgets that execute commands and display dynamic output"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
}
StyledRect {
width: parent.width
height: addActionColumn.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Theme.surfaceContainerHigh
Column {
id: addActionColumn
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
StyledText {
text: root.editingVariantId ? "Edit Action" : "Create New Action"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
DankButton {
text: "Cancel"
iconName: "close"
visible: root.editingVariantId !== ""
onClicked: root.clearForm()
}
}
Row {
width: parent.width
spacing: Theme.spacingM
Column {
width: (parent.width - Theme.spacingM) / 2
spacing: Theme.spacingXS
StyledText {
text: "Variant Name *"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
DankTextField {
id: nameField
width: parent.width
placeholderText: "e.g., Power Profile"
keyNavigationTab: iconField
onFocusStateChanged: hasFocus => {
if (hasFocus) root.ensureItemVisible(nameField)
}
}
}
Column {
width: (parent.width - Theme.spacingM) / 2
spacing: Theme.spacingXS
StyledText {
text: "Icon Name"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
DankTextField {
id: iconField
width: parent.width
placeholderText: "e.g., power_settings_new"
keyNavigationBacktab: nameField
keyNavigationTab: displayTextField
onFocusStateChanged: hasFocus => {
if (hasFocus) root.ensureItemVisible(iconField)
}
}
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
StyledText {
text: "Static Display Text (optional)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
DankTextField {
id: displayTextField
width: parent.width
placeholderText: "Text to show (or leave empty if using command output)"
keyNavigationBacktab: iconField
keyNavigationTab: displayCommandField
onFocusStateChanged: hasFocus => {
if (hasFocus) root.ensureItemVisible(displayTextField)
}
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
StyledText {
text: "Display Command (optional)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
DankTextField {
id: displayCommandField
width: parent.width
placeholderText: 'e.g., echo "Hello World" or powerprofilesctl get'
keyNavigationBacktab: displayTextField
keyNavigationTab: clickCommandField
onFocusStateChanged: hasFocus => {
if (hasFocus) root.ensureItemVisible(displayCommandField)
}
}
StyledText {
text: "Command output will replace static text. Runs on widget load."
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
StyledText {
text: "Left Click Command (optional)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
DankTextField {
id: clickCommandField
width: parent.width
placeholderText: "e.g., notify-send 'Clicked!' or cycle-power-profile.sh"
keyNavigationBacktab: displayCommandField
keyNavigationTab: middleClickCommandField
onFocusStateChanged: hasFocus => {
if (hasFocus) root.ensureItemVisible(clickCommandField)
}
}
StyledText {
text: "Command to run on left click. After completion, display command refreshes."
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
StyledText {
text: "Middle Click Command (optional)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
DankTextField {
id: middleClickCommandField
width: parent.width
placeholderText: "e.g., notify-send 'Middle clicked!'"
keyNavigationBacktab: clickCommandField
keyNavigationTab: rightClickCommandField
onFocusStateChanged: hasFocus => {
if (hasFocus) root.ensureItemVisible(middleClickCommandField)
}
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
StyledText {
text: "Right Click Command (optional)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
DankTextField {
id: rightClickCommandField
width: parent.width
placeholderText: "e.g., notify-send 'Right clicked!'"
keyNavigationBacktab: middleClickCommandField
keyNavigationTab: updateIntervalField
onFocusStateChanged: hasFocus => {
if (hasFocus) root.ensureItemVisible(rightClickCommandField)
}
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
StyledText {
text: "Update Interval (seconds, 0 = disabled)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
DankTextField {
id: updateIntervalField
width: parent.width
placeholderText: "0"
text: "0"
keyNavigationBacktab: rightClickCommandField
onFocusStateChanged: hasFocus => {
if (hasFocus) root.ensureItemVisible(updateIntervalField)
}
}
StyledText {
text: "Automatically re-run display command every N seconds. Set to 0 to disable."
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
}
Row {
width: parent.width
spacing: Theme.spacingL
Column {
spacing: Theme.spacingXS
StyledText {
text: "Show Icon"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
DankToggle {
id: showIconToggle
checked: true
onToggled: isChecked => {
checked = isChecked
}
}
}
Column {
spacing: Theme.spacingXS
StyledText {
text: "Show Text"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
DankToggle {
id: showTextToggle
checked: true
onToggled: isChecked => {
checked = isChecked
}
}
}
}
DankButton {
text: root.editingVariantId ? "Update Action" : "Create Action"
iconName: root.editingVariantId ? "check" : "add"
onClicked: {
if (!nameField.text) {
ToastService.showError("Please enter a variant name")
return
}
var interval = parseInt(updateIntervalField.text) || 0
if (interval < 0) {
ToastService.showError("Update interval must be 0 or greater")
return
}
var variantConfig = {
icon: iconField.text || "terminal",
displayText: displayTextField.text || "",
displayCommand: displayCommandField.text || "",
clickCommand: clickCommandField.text || "",
middleClickCommand: middleClickCommandField.text || "",
rightClickCommand: rightClickCommandField.text || "",
updateInterval: interval,
showIcon: showIconToggle.checked,
showText: showTextToggle.checked
}
if (root.editingVariantId) {
variantConfig.name = nameField.text
updateVariant(root.editingVariantId, variantConfig)
} else {
createVariant(nameField.text, variantConfig)
}
root.clearForm()
}
}
}
}
StyledRect {
width: parent.width
height: Math.max(200, variantsColumn.implicitHeight + Theme.spacingL * 2)
radius: Theme.cornerRadius
color: Theme.surfaceContainerHigh
Column {
id: variantsColumn
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
StyledText {
text: "Existing Actions"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
}
ListView {
width: parent.width
height: Math.max(100, contentHeight)
clip: true
spacing: Theme.spacingXS
model: root.variantsModel
delegate: StyledRect {
required property var model
width: ListView.view.width
height: variantColumn.implicitHeight + Theme.spacingM * 2
radius: Theme.cornerRadius
color: variantMouseArea.containsMouse ? Theme.surfaceContainerHighest : Theme.surfaceContainer
Column {
id: variantColumn
anchors.fill: parent
anchors.margins: Theme.spacingM
spacing: Theme.spacingXS
Row {
width: parent.width
spacing: Theme.spacingM
Item {
width: Theme.iconSize
height: Theme.iconSize
anchors.verticalCenter: parent.verticalCenter
DankIcon {
anchors.centerIn: parent
name: model.icon || "terminal"
size: Theme.iconSize
color: Theme.surfaceText
}
}
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: 2
width: parent.width - Theme.iconSize - (editButton.width + deleteButton.width + Theme.spacingXS) - Theme.spacingM * 3
StyledText {
text: model.name || "Unnamed"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
width: parent.width
elide: Text.ElideRight
}
StyledText {
text: {
var parts = []
if (model.displayText) parts.push("Text: " + model.displayText)
if (model.displayCommand) parts.push("Cmd: " + model.displayCommand)
if (model.updateInterval && model.updateInterval > 0) parts.push("Update: " + model.updateInterval + "s")
return parts.join(" | ") || "No display config"
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
width: parent.width
elide: Text.ElideRight
}
StyledText {
text: {
var actions = []
if (model.clickCommand) actions.push("L: " + model.clickCommand)
if (model.middleClickCommand) actions.push("M: " + model.middleClickCommand)
if (model.rightClickCommand) actions.push("R: " + model.rightClickCommand)
return actions.join(" | ") || "No click actions"
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
width: parent.width
elide: Text.ElideRight
}
}
Row {
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingXS
Rectangle {
id: editButton
width: 32
height: 32
radius: 16
color: editArea.containsMouse ? Theme.primary : "transparent"
DankIcon {
anchors.centerIn: parent
name: "edit"
size: 16
color: editArea.containsMouse ? Theme.onPrimary : Theme.surfaceVariantText
}
MouseArea {
id: editArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
root.loadVariantForEditing(model)
}
}
}
Rectangle {
id: deleteButton
width: 32
height: 32
radius: 16
color: deleteArea.containsMouse ? Theme.error : "transparent"
DankIcon {
anchors.centerIn: parent
name: "delete"
size: 16
color: deleteArea.containsMouse ? Theme.onError : Theme.surfaceVariantText
}
MouseArea {
id: deleteArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
removeVariant(model.id)
}
}
}
}
}
}
MouseArea {
id: variantMouseArea
anchors.fill: parent
hoverEnabled: true
propagateComposedEvents: true
}
}
StyledText {
anchors.centerIn: parent
text: "No actions created yet"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
visible: variantsModel.count === 0
}
}
}
}
StyledRect {
width: parent.width
height: examplesColumn.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Theme.surface
Column {
id: examplesColumn
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
spacing: Theme.spacingM
DankIcon {
name: "lightbulb"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Usage Examples"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
Column {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: "• Power Profile Cycler"
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "Display: powerprofilesctl get\nClick: powerprofilesctl set $(powerprofilesctl list | grep -v \"$(powerprofilesctl get)\" | head -1)"
font.pixelSize: Theme.fontSizeSmall
font.family: "monospace"
color: Theme.surfaceVariantText
wrapMode: Text.Wrap
width: parent.width
leftPadding: Theme.spacingM
}
StyledText {
text: "• System Uptime"
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "Display: uptime -p | sed 's/up //'\nClick: notify-send \"Uptime\" \"$(uptime -p)\""
font.pixelSize: Theme.fontSizeSmall
font.family: "monospace"
color: Theme.surfaceVariantText
wrapMode: Text.Wrap
width: parent.width
leftPadding: Theme.spacingM
}
StyledText {
text: "• Custom Greeting"
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "Display: echo \"Hello $(whoami)!\"\nClick: notify-send \"Hi!\" \"Welcome back!\""
font.pixelSize: Theme.fontSizeSmall
font.family: "monospace"
color: Theme.surfaceVariantText
wrapMode: Text.Wrap
width: parent.width
leftPadding: Theme.spacingM
}
}
StyledText {
text: "After creating actions, add them to your bar from Bar Settings → Add Widget"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
}
}
}

View file

@ -0,0 +1,263 @@
import QtQuick
import Quickshell
import Quickshell.Io
import qs.Common
import qs.Services
import qs.Widgets
import qs.Modules.Plugins
PluginComponent {
id: root
property string variantId: ""
property var variantData: null
property string displayIcon: "terminal"
property string displayText: ""
property string displayCommand: ""
property string clickCommand: ""
property string middleClickCommand: ""
property string rightClickCommand: ""
property int updateInterval: 0
property bool showIcon: true
property bool showText: true
property string currentOutput: ""
property bool isLoading: false
onVariantDataChanged: {
updatePropertiesFromVariantData()
}
Connections {
target: PluginService
function onPluginDataChanged(changedPluginId) {
if (changedPluginId === "dankActions" && variantId) {
const newData = PluginService.getPluginVariantData("dankActions", variantId)
if (newData) {
variantData = newData
}
}
}
}
function updatePropertiesFromVariantData() {
if (!variantData) {
displayIcon = "terminal"
displayText = ""
displayCommand = ""
clickCommand = ""
middleClickCommand = ""
rightClickCommand = ""
updateInterval = 0
showIcon = true
showText = true
currentOutput = ""
return
}
displayIcon = variantData.icon || "terminal"
displayText = variantData.displayText || ""
displayCommand = variantData.displayCommand || ""
clickCommand = variantData.clickCommand || ""
middleClickCommand = variantData.middleClickCommand || ""
rightClickCommand = variantData.rightClickCommand || ""
updateInterval = variantData.updateInterval || 0
showIcon = variantData.showIcon !== undefined ? variantData.showIcon : true
showText = variantData.showText !== undefined ? variantData.showText : true
if (displayCommand) {
Qt.callLater(refreshOutput)
} else {
currentOutput = displayText
}
if (updateInterval > 0) {
updateTimer.restart()
}
}
onDisplayCommandChanged: {
if (displayCommand) {
Qt.callLater(refreshOutput)
} else {
currentOutput = displayText
}
}
onDisplayTextChanged: {
if (!displayCommand) {
currentOutput = displayText
}
}
onUpdateIntervalChanged: {
if (updateInterval > 0) {
updateTimer.restart()
} else {
updateTimer.stop()
}
}
Component.onCompleted: {
if (displayCommand) {
Qt.callLater(refreshOutput)
} else {
currentOutput = displayText
}
if (updateInterval > 0) {
updateTimer.start()
}
}
Timer {
id: updateTimer
interval: root.updateInterval * 1000
repeat: true
running: false
onTriggered: {
if (root.displayCommand) {
root.refreshOutput()
}
}
}
function refreshOutput() {
if (!displayCommand) {
currentOutput = displayText
return
}
isLoading = true
displayProcess.running = true
}
function executeCommand(command) {
if (!command) return
isLoading = true
actionProcess.command = ["sh", "-c", command]
actionProcess.running = true
}
Process {
id: displayProcess
command: ["sh", "-c", root.displayCommand]
running: false
stdout: SplitParser {
onRead: data => {
root.currentOutput = data.trim()
}
}
onExited: (exitCode, exitStatus) => {
root.isLoading = false
if (exitCode !== 0) {
console.warn("CustomActions: Display command failed with code", exitCode)
}
}
}
Process {
id: actionProcess
command: ["sh", "-c", ""]
running: false
onExited: (exitCode, exitStatus) => {
root.isLoading = false
if (exitCode === 0) {
if (root.displayCommand) {
root.refreshOutput()
}
} else {
console.warn("CustomActions: Action command failed with code", exitCode)
}
}
}
pillClickAction: () => {
if (root.clickCommand) {
root.executeCommand(root.clickCommand)
}
}
horizontalBarPill: Component {
MouseArea {
implicitWidth: contentRow.implicitWidth
implicitHeight: contentRow.implicitHeight
acceptedButtons: Qt.MiddleButton | Qt.RightButton
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: (mouse) => {
if (mouse.button === Qt.MiddleButton && root.middleClickCommand) {
root.executeCommand(root.middleClickCommand)
} else if (mouse.button === Qt.RightButton && root.rightClickCommand) {
root.executeCommand(root.rightClickCommand)
}
}
Row {
id: contentRow
spacing: Theme.spacingXS
DankIcon {
name: root.displayIcon
size: Theme.iconSize - 6
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
visible: root.showIcon
}
StyledText {
text: root.currentOutput || ""
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
visible: root.showText && root.currentOutput
}
}
}
}
verticalBarPill: Component {
MouseArea {
implicitWidth: contentColumn.implicitWidth
implicitHeight: contentColumn.implicitHeight
acceptedButtons: Qt.MiddleButton | Qt.RightButton
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: (mouse) => {
if (mouse.button === Qt.MiddleButton && root.middleClickCommand) {
root.executeCommand(root.middleClickCommand)
} else if (mouse.button === Qt.RightButton && root.rightClickCommand) {
root.executeCommand(root.rightClickCommand)
}
}
Column {
id: contentColumn
spacing: Theme.spacingXS
DankIcon {
name: root.displayIcon
size: Theme.iconSize - 6
color: Theme.surfaceText
anchors.horizontalCenter: parent.horizontalCenter
visible: root.showIcon
}
StyledText {
text: root.currentOutput || ""
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
anchors.horizontalCenter: parent.horizontalCenter
visible: root.showText && root.currentOutput
}
}
}
}
}

View file

@ -0,0 +1,16 @@
{
"id": "dankActions",
"name": "Dank Actions",
"description": "Execute custom commands with dynamic output display and configurable icons",
"version": "1.0.4",
"license": "MIT",
"author": "Avenge Media",
"icon": "terminal",
"firstParty": true,
"component": "./DankActionsWidget.qml",
"settings": "./DankActionsSettings.qml",
"permissions": [
"settings_read",
"settings_write"
]
}