summaryrefslogtreecommitdiff
path: root/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS
diff options
context:
space:
mode:
Diffstat (limited to 'raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS')
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ColorDemoPlugin/ColorDemoSettings.qml32
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ColorDemoPlugin/ColorDemoWidget.qml57
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ColorDemoPlugin/plugin.json12
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterDetailExample/DetailExampleWidget.qml138
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterDetailExample/plugin.json12
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterExample/ControlCenterExampleWidget.qml68
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterExample/plugin.json12
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleDesktopClock/DesktopClock.qml172
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleDesktopClock/DesktopClockSettings.qml45
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleDesktopClock/plugin.json17
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/EmojiSettings.qml97
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/EmojiWidget.qml151
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/README.md52
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/plugin.json16
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/README.md116
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/VariantSettings.qml303
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/VariantWidget.qml57
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/plugin.json16
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/LauncherExampleLauncher.qml140
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/LauncherExampleSettings.qml244
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/README.md244
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/plugin.json17
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherImageExample/LauncherImageExample.qml113
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherImageExample/README.md43
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherImageExample/plugin.json14
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/POPOUT_SERVICE.md294
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/PopoutControlSettings.qml98
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/PopoutControlWidget.qml93
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/README.md208
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/plugin.json13
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/QuickNotesExample/QuickNotesLauncher.qml174
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/QuickNotesExample/QuickNotesSettings.qml263
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/QuickNotesExample/plugin.json17
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/README.md1665
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/THEME_REFERENCE.md132
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/README.md37
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/WallpaperWatcherDaemon.qml66
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/WallpaperWatcherSettings.qml24
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/plugin.json16
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/plugin-schema.json115
40 files changed, 0 insertions, 5403 deletions
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ColorDemoPlugin/ColorDemoSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ColorDemoPlugin/ColorDemoSettings.qml
deleted file mode 100644
index 1307fad..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ColorDemoPlugin/ColorDemoSettings.qml
+++ /dev/null
@@ -1,32 +0,0 @@
-import QtQuick
-import qs.Common
-import qs.Modules.Plugins
-import qs.Widgets
-
-PluginSettings {
- id: root
- pluginId: "colorDemo"
-
- StyledText {
- width: parent.width
- text: "Color Demo Settings"
- font.pixelSize: Theme.fontSizeLarge
- font.weight: Font.Bold
- color: Theme.surfaceText
- }
-
- StyledText {
- width: parent.width
- text: "Choose a custom color to display in the bar widget"
- font.pixelSize: Theme.fontSizeSmall
- color: Theme.surfaceVariantText
- wrapMode: Text.WordWrap
- }
-
- ColorSetting {
- settingKey: "customColor"
- label: "Custom Color"
- description: "Choose a custom color to display in the widget"
- defaultValue: Theme.primary
- }
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ColorDemoPlugin/ColorDemoWidget.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ColorDemoPlugin/ColorDemoWidget.qml
deleted file mode 100644
index 6b90845..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ColorDemoPlugin/ColorDemoWidget.qml
+++ /dev/null
@@ -1,57 +0,0 @@
-import QtQuick
-import qs.Common
-import qs.Services
-import qs.Widgets
-import qs.Modules.Plugins
-
-PluginComponent {
- id: root
-
- property color customColor: pluginData.customColor || Theme.primary
-
- horizontalBarPill: Component {
- Row {
- spacing: Theme.spacingS
-
- Rectangle {
- width: 20
- height: 20
- radius: 4
- color: root.customColor
- border.color: Theme.outlineStrong
- border.width: 1
- anchors.verticalCenter: parent.verticalCenter
- }
-
- StyledText {
- text: root.customColor.toString()
- font.pixelSize: Theme.fontSizeSmall
- color: Theme.surfaceText
- anchors.verticalCenter: parent.verticalCenter
- }
- }
- }
-
- verticalBarPill: Component {
- Column {
- spacing: Theme.spacingXS
-
- Rectangle {
- width: 20
- height: 20
- radius: 4
- color: root.customColor
- border.color: Theme.outlineStrong
- border.width: 1
- anchors.horizontalCenter: parent.horizontalCenter
- }
-
- StyledText {
- text: root.customColor.toString()
- font.pixelSize: Theme.fontSizeSmall
- color: Theme.surfaceText
- anchors.horizontalCenter: parent.horizontalCenter
- }
- }
- }
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ColorDemoPlugin/plugin.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ColorDemoPlugin/plugin.json
deleted file mode 100644
index 45bf33a..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ColorDemoPlugin/plugin.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "id": "colorDemo",
- "name": "Color Demo",
- "description": "Demonstrates color picker plugin setting",
- "version": "1.0.0",
- "author": "DMS",
- "icon": "palette",
- "type": "widget",
- "component": "./ColorDemoWidget.qml",
- "settings": "./ColorDemoSettings.qml",
- "permissions": ["settings_read", "settings_write"]
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterDetailExample/DetailExampleWidget.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterDetailExample/DetailExampleWidget.qml
deleted file mode 100644
index 7d61900..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterDetailExample/DetailExampleWidget.qml
+++ /dev/null
@@ -1,138 +0,0 @@
-import QtQuick
-import QtQuick.Controls
-import Quickshell
-import qs.Common
-import qs.Services
-import qs.Widgets
-import qs.Modules.Plugins
-
-PluginComponent {
- id: root
-
- property bool isEnabled: pluginData.isEnabled || false
- property var options: pluginData.options || ["Option A", "Option B", "Option C"]
-
- ccWidgetIcon: isEnabled ? "settings" : "settings"
- ccWidgetPrimaryText: "Detail Example"
- ccWidgetSecondaryText: {
- if (isEnabled) {
- const selected = pluginData.selectedOption || "Option A"
- return selected
- }
- return "Disabled"
- }
- ccWidgetIsActive: isEnabled
-
- onCcWidgetToggled: {
- isEnabled = !isEnabled
- if (pluginService) {
- pluginService.savePluginData("controlCenterDetailExample", "isEnabled", isEnabled)
- }
- }
-
- ccDetailContent: Component {
- Rectangle {
- id: detailRoot
- implicitHeight: detailColumn.implicitHeight + Theme.spacingM * 2
- radius: Theme.cornerRadius
- color: Theme.surfaceContainerHigh
- border.width: 0
- visible: true
-
- property var options: ["Option A", "Option B", "Option C"]
- property string currentSelection: SettingsData.getPluginSetting("controlCenterDetailExample", "selectedOption", "Option A")
-
- Column {
- id: detailColumn
- anchors.fill: parent
- anchors.margins: Theme.spacingM
- spacing: Theme.spacingS
-
- StyledText {
- text: "Detail Example Settings"
- font.pixelSize: Theme.fontSizeLarge
- color: Theme.surfaceText
- font.weight: Font.Medium
- }
-
- StyledText {
- text: "Select an option below:"
- font.pixelSize: Theme.fontSizeSmall
- color: Theme.surfaceVariantText
- }
-
- Repeater {
- model: detailRoot.options
-
- Rectangle {
- width: parent.width
- height: 40
- radius: Theme.cornerRadius
- color: optionMouseArea.containsMouse ? Theme.surfaceContainerHighest : "transparent"
- border.color: detailRoot.currentSelection === modelData ? Theme.primary : "transparent"
- border.width: detailRoot.currentSelection === modelData ? 2 : 0
-
- MouseArea {
- id: optionMouseArea
- anchors.fill: parent
- hoverEnabled: true
- cursorShape: Qt.PointingHandCursor
- z: 100
- onClicked: {
- SettingsData.setPluginSetting("controlCenterDetailExample", "selectedOption", modelData)
- detailRoot.currentSelection = modelData
- PluginService.pluginDataChanged("controlCenterDetailExample")
- ToastService.showInfo("Option Selected", modelData)
- }
- }
-
- Row {
- anchors.fill: parent
- anchors.leftMargin: Theme.spacingM
- anchors.rightMargin: Theme.spacingM
- spacing: Theme.spacingS
- enabled: false
-
- DankIcon {
- name: detailRoot.currentSelection === modelData ? "radio_button_checked" : "radio_button_unchecked"
- color: detailRoot.currentSelection === modelData ? Theme.primary : Theme.surfaceVariantText
- size: Theme.iconSize
- anchors.verticalCenter: parent.verticalCenter
- }
-
- StyledText {
- text: modelData
- color: detailRoot.currentSelection === modelData ? Theme.primary : Theme.surfaceText
- font.pixelSize: Theme.fontSizeMedium
- anchors.verticalCenter: parent.verticalCenter
- }
- }
- }
- }
- }
- }
- }
-
- horizontalBarPill: Component {
- Row {
- spacing: Theme.spacingXS
-
- DankIcon {
- name: root.isEnabled ? "settings" : "settings_off"
- color: root.isEnabled ? Theme.primary : Theme.surfaceVariantText
- font.pixelSize: Theme.iconSize - 4
- anchors.verticalCenter: parent.verticalCenter
- }
-
- StyledText {
- text: {
- const selected = root.pluginData.selectedOption || "Option A"
- return selected.substring(0, 1)
- }
- color: root.isEnabled ? Theme.primary : Theme.surfaceVariantText
- font.pixelSize: Theme.fontSizeMedium
- anchors.verticalCenter: parent.verticalCenter
- }
- }
- }
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterDetailExample/plugin.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterDetailExample/plugin.json
deleted file mode 100644
index 00fc9f9..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterDetailExample/plugin.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "id": "controlCenterDetailExample",
- "name": "CC Detail Example",
- "description": "Example plugin with Control Center detail dropdown",
- "version": "1.0.0",
- "author": "DankMaterialShell",
- "type": "widget",
- "capabilities": ["control-center"],
- "component": "./DetailExampleWidget.qml",
- "icon": "settings",
- "permissions": ["settings_read", "settings_write"]
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterExample/ControlCenterExampleWidget.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterExample/ControlCenterExampleWidget.qml
deleted file mode 100644
index 450d538..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterExample/ControlCenterExampleWidget.qml
+++ /dev/null
@@ -1,68 +0,0 @@
-import QtQuick
-import Quickshell
-import qs.Common
-import qs.Services
-import qs.Widgets
-import qs.Modules.Plugins
-
-PluginComponent {
- id: root
-
- property bool isEnabled: pluginData.isEnabled || false
- property int clickCount: pluginData.clickCount || 0
-
- ccWidgetIcon: isEnabled ? "toggle_on" : "toggle_off"
- ccWidgetPrimaryText: "Example Toggle"
- ccWidgetSecondaryText: isEnabled ? `Active • ${clickCount} clicks` : "Inactive"
- ccWidgetIsActive: isEnabled
-
- onCcWidgetToggled: {
- isEnabled = !isEnabled
- clickCount += 1
- if (pluginService) {
- pluginService.savePluginData("controlCenterExample", "isEnabled", isEnabled)
- pluginService.savePluginData("controlCenterExample", "clickCount", clickCount)
- }
- ToastService.showInfo("Example Toggle", isEnabled ? "Activated!" : "Deactivated!")
- }
-
- horizontalBarPill: Component {
- Row {
- spacing: Theme.spacingXS
-
- DankIcon {
- name: root.isEnabled ? "toggle_on" : "toggle_off"
- color: root.isEnabled ? Theme.primary : Theme.surfaceVariantText
- font.pixelSize: Theme.iconSize - 4
- anchors.verticalCenter: parent.verticalCenter
- }
-
- StyledText {
- text: `${root.clickCount}`
- color: root.isEnabled ? Theme.primary : Theme.surfaceVariantText
- font.pixelSize: Theme.fontSizeMedium
- anchors.verticalCenter: parent.verticalCenter
- }
- }
- }
-
- verticalBarPill: Component {
- Column {
- spacing: Theme.spacingXS
-
- DankIcon {
- name: root.isEnabled ? "toggle_on" : "toggle_off"
- color: root.isEnabled ? Theme.primary : Theme.surfaceVariantText
- font.pixelSize: Theme.iconSize - 4
- anchors.horizontalCenter: parent.horizontalCenter
- }
-
- StyledText {
- text: `${root.clickCount}`
- color: root.isEnabled ? Theme.primary : Theme.surfaceVariantText
- font.pixelSize: Theme.fontSizeSmall
- anchors.horizontalCenter: parent.horizontalCenter
- }
- }
- }
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterExample/plugin.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterExample/plugin.json
deleted file mode 100644
index f573ae6..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ControlCenterExample/plugin.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "id": "controlCenterExample",
- "name": "CC Toggle Example",
- "description": "Example plugin with Control Center toggle widget",
- "version": "1.0.0",
- "author": "DankMaterialShell",
- "type": "widget",
- "capabilities": ["control-center"],
- "component": "./ControlCenterExampleWidget.qml",
- "icon": "toggle_on",
- "permissions": ["settings_read", "settings_write"]
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleDesktopClock/DesktopClock.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleDesktopClock/DesktopClock.qml
deleted file mode 100644
index 55ac34c..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleDesktopClock/DesktopClock.qml
+++ /dev/null
@@ -1,172 +0,0 @@
-import QtQuick
-import Quickshell
-import qs.Common
-import qs.Modules.Plugins
-
-DesktopPluginComponent {
- id: root
-
- minWidth: 120
- minHeight: 120
-
- property bool showSeconds: pluginData.showSeconds ?? true
- property bool showDate: pluginData.showDate ?? true
- property string clockStyle: pluginData.clockStyle ?? "analog"
- property real backgroundOpacity: (pluginData.backgroundOpacity ?? 50) / 100
-
- SystemClock {
- id: systemClock
- precision: root.showSeconds ? SystemClock.Seconds : SystemClock.Minutes
- }
-
- Rectangle {
- id: background
- anchors.fill: parent
- radius: Theme.cornerRadius
- color: Theme.surfaceContainer
- opacity: root.backgroundOpacity
- }
-
- Loader {
- anchors.fill: parent
- anchors.margins: Theme.spacingM
- sourceComponent: root.clockStyle === "digital" ? digitalClock : analogClock
- }
-
- Component {
- id: analogClock
-
- Item {
- id: analogClockRoot
-
- property real clockSize: Math.min(width, height) - (root.showDate ? 30 : 0)
-
- Item {
- id: clockFace
- width: analogClockRoot.clockSize
- height: analogClockRoot.clockSize
- anchors.horizontalCenter: parent.horizontalCenter
- anchors.top: parent.top
- anchors.topMargin: Theme.spacingS
-
- Repeater {
- model: 12
-
- Rectangle {
- required property int index
- property real markAngle: index * 30
- property real markRadius: clockFace.width / 2 - 8
-
- x: clockFace.width / 2 + markRadius * Math.sin(markAngle * Math.PI / 180) - width / 2
- y: clockFace.height / 2 - markRadius * Math.cos(markAngle * Math.PI / 180) - height / 2
- width: index % 3 === 0 ? 8 : 4
- height: width
- radius: width / 2
- color: index % 3 === 0 ? Theme.primary : Theme.outlineVariant
- }
- }
-
- Rectangle {
- id: hourHand
- property int hours: systemClock.date?.getHours() % 12 ?? 0
- property int minutes: systemClock.date?.getMinutes() ?? 0
-
- x: clockFace.width / 2 - width / 2
- y: clockFace.height / 2 - height + 4
- width: 6
- height: clockFace.height * 0.25
- radius: 3
- color: Theme.primary
- antialiasing: true
- transformOrigin: Item.Bottom
- rotation: (hours + minutes / 60) * 30
- }
-
- Rectangle {
- id: minuteHand
- property int minutes: systemClock.date?.getMinutes() ?? 0
- property int seconds: systemClock.date?.getSeconds() ?? 0
-
- x: clockFace.width / 2 - width / 2
- y: clockFace.height / 2 - height + 4
- width: 4
- height: clockFace.height * 0.35
- radius: 2
- color: Theme.onSurface
- antialiasing: true
- transformOrigin: Item.Bottom
- rotation: (minutes + seconds / 60) * 6
- }
-
- Rectangle {
- id: secondHand
- visible: root.showSeconds
- property int seconds: systemClock.date?.getSeconds() ?? 0
-
- x: clockFace.width / 2 - width / 2
- y: clockFace.height / 2 - height + 4
- width: 2
- height: clockFace.height * 0.4
- radius: 1
- color: Theme.error
- antialiasing: true
- transformOrigin: Item.Bottom
- rotation: seconds * 6
- }
-
- Rectangle {
- anchors.centerIn: parent
- width: 10
- height: 10
- radius: 5
- color: Theme.primary
- }
- }
-
- Text {
- visible: root.showDate
- anchors.horizontalCenter: parent.horizontalCenter
- anchors.bottom: parent.bottom
- anchors.bottomMargin: Theme.spacingXS
- text: systemClock.date?.toLocaleDateString(I18n.locale(), "ddd, MMM d") ?? ""
- font.pixelSize: Theme.fontSizeSmall
- font.weight: Font.Medium
- color: Theme.surfaceText
- }
- }
- }
-
- Component {
- id: digitalClock
-
- Item {
- id: digitalRoot
-
- property real timeFontSize: Math.min(width * 0.16, height * (root.showDate ? 0.4 : 0.5))
- property real dateFontSize: Math.max(Theme.fontSizeSmall, timeFontSize * 0.35)
-
- Text {
- id: timeText
- anchors.horizontalCenter: parent.horizontalCenter
- anchors.verticalCenter: parent.verticalCenter
- anchors.verticalCenterOffset: root.showDate ? -digitalRoot.dateFontSize * 0.8 : 0
- text: systemClock.date?.toLocaleTimeString(Qt.locale(), root.showSeconds ? "hh:mm:ss" : "hh:mm") ?? ""
- font.pixelSize: digitalRoot.timeFontSize
- font.weight: Font.Bold
- font.family: "monospace"
- color: Theme.primary
- }
-
- Text {
- id: dateText
- visible: root.showDate
- anchors.horizontalCenter: parent.horizontalCenter
- anchors.top: timeText.bottom
- anchors.topMargin: Theme.spacingXS
- text: systemClock.date?.toLocaleDateString(I18n.locale(), "ddd, MMM d") ?? ""
- font.pixelSize: digitalRoot.dateFontSize
- color: Theme.surfaceText
- }
- }
- }
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleDesktopClock/DesktopClockSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleDesktopClock/DesktopClockSettings.qml
deleted file mode 100644
index 94063b7..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleDesktopClock/DesktopClockSettings.qml
+++ /dev/null
@@ -1,45 +0,0 @@
-import QtQuick
-import qs.Common
-import qs.Modules.Plugins
-
-PluginSettings {
- id: root
- pluginId: "exampleDesktopClock"
-
- SelectionSetting {
- settingKey: "clockStyle"
- label: I18n.tr("Clock Style")
- options: [
- {
- label: I18n.tr("Analog"),
- value: "analog"
- },
- {
- label: I18n.tr("Digital"),
- value: "digital"
- }
- ]
- defaultValue: "analog"
- }
-
- ToggleSetting {
- settingKey: "showSeconds"
- label: I18n.tr("Show Seconds")
- defaultValue: true
- }
-
- ToggleSetting {
- settingKey: "showDate"
- label: I18n.tr("Show Date")
- defaultValue: true
- }
-
- SliderSetting {
- settingKey: "backgroundOpacity"
- label: I18n.tr("Background Opacity")
- defaultValue: 50
- minimum: 0
- maximum: 100
- unit: "%"
- }
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleDesktopClock/plugin.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleDesktopClock/plugin.json
deleted file mode 100644
index efa80c8..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleDesktopClock/plugin.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "id": "exampleDesktopClock",
- "name": "Desktop Clock",
- "description": "An example desktop widget displaying an analog clock",
- "version": "1.0.0",
- "author": "DankMaterialShell",
- "type": "desktop",
- "capabilities": ["desktop-widget", "clock"],
- "component": "./DesktopClock.qml",
- "icon": "schedule",
- "settings": "./DesktopClockSettings.qml",
- "requires_dms": ">=1.2.0",
- "permissions": [
- "settings_read",
- "settings_write"
- ]
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/EmojiSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/EmojiSettings.qml
deleted file mode 100644
index aa38bc9..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/EmojiSettings.qml
+++ /dev/null
@@ -1,97 +0,0 @@
-import QtQuick
-import qs.Common
-import qs.Widgets
-import qs.Modules.Plugins
-
-PluginSettings {
- id: root
- pluginId: "exampleEmojiPlugin"
-
- // Header section to explain what this plugin does
- StyledText {
- width: parent.width
- text: "Emoji Cycler Settings"
- font.pixelSize: Theme.fontSizeLarge
- font.weight: Font.Bold
- color: Theme.surfaceText
- }
-
- StyledText {
- width: parent.width
- text: "Configure which emojis appear in your bar, how quickly they cycle, and how many show at once."
- font.pixelSize: Theme.fontSizeSmall
- color: Theme.surfaceVariantText
- wrapMode: Text.WordWrap
- }
-
- // Dropdown to select which emoji set to use
- SelectionSetting {
- settingKey: "emojiSet"
- label: "Emoji Set"
- description: "Choose which collection of emojis to cycle through"
- options: [
- {label: "Happy & Sad", value: "happySad"},
- {label: "Hearts", value: "hearts"},
- {label: "Hand Gestures", value: "hands"},
- {label: "All Mixed", value: "mixed"}
- ]
- defaultValue: "happySad"
-
- // Update the actual emoji array when selection changes
- onValueChanged: {
- const sets = {
- "happySad": ["😊", "😢", "😂", "😭", "😍", "😡"],
- "hearts": ["❤️", "🧡", "💛", "💚", "💙", "💜", "🖤", "🤍"],
- "hands": ["👍", "👎", "👊", "✌️", "🤘", "👌", "✋", "🤚"],
- "mixed": ["😊", "❤️", "👍", "🎉", "🔥", "✨", "🌟", "💯"]
- }
- const newEmojis = sets[value] || sets["happySad"]
- root.saveValue("emojis", newEmojis)
- }
-
- Component.onCompleted: {
- // Initialize the emojis array on first load
- const currentSet = value || defaultValue
- const sets = {
- "happySad": ["😊", "😢", "😂", "😭", "😍", "😡"],
- "hearts": ["❤️", "🧡", "💛", "💚", "💙", "💜", "🖤", "🤍"],
- "hands": ["👍", "👎", "👊", "✌️", "🤘", "👌", "✋", "🤚"],
- "mixed": ["😊", "❤️", "👍", "🎉", "🔥", "✨", "🌟", "💯"]
- }
- const emojis = sets[currentSet] || sets["happySad"]
- root.saveValue("emojis", emojis)
- }
- }
-
- // Slider to control how fast emojis cycle (in milliseconds)
- SliderSetting {
- settingKey: "cycleInterval"
- label: "Cycle Speed"
- description: "How quickly emojis rotate (in seconds)"
- defaultValue: 3000
- minimum: 500
- maximum: 10000
- unit: "ms"
- leftIcon: "schedule"
- }
-
- // Slider to control max emojis shown in the bar
- SliderSetting {
- settingKey: "maxBarEmojis"
- label: "Max Bar Emojis"
- description: "Maximum number of emojis to display in the bar at once"
- defaultValue: 3
- minimum: 1
- maximum: 8
- unit: ""
- rightIcon: "emoji_emotions"
- }
-
- StyledText {
- width: parent.width
- text: "💡 Tip: Click the emoji widget in your bar to open the emoji picker and copy any emoji to your clipboard!"
- font.pixelSize: Theme.fontSizeSmall
- color: Theme.surfaceVariantText
- wrapMode: Text.WordWrap
- }
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/EmojiWidget.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/EmojiWidget.qml
deleted file mode 100644
index 6142692..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/EmojiWidget.qml
+++ /dev/null
@@ -1,151 +0,0 @@
-import QtQuick
-import Quickshell
-import qs.Common
-import qs.Services
-import qs.Widgets
-import qs.Modules.Plugins
-
-PluginComponent {
- id: root
-
- layerNamespacePlugin: "emoji-cycler"
-
- property var enabledEmojis: pluginData.emojis || ["😊", "😢", "❤️"]
- property int cycleInterval: pluginData.cycleInterval || 3000
- property int maxBarEmojis: pluginData.maxBarEmojis || 3
-
- property int currentIndex: 0
- property var displayedEmojis: []
-
- Timer {
- interval: root.cycleInterval
- running: true
- repeat: true
- onTriggered: {
- if (root.enabledEmojis.length > 0) {
- root.currentIndex = (root.currentIndex + 1) % root.enabledEmojis.length
- root.updateDisplayedEmojis()
- }
- }
- }
-
- function updateDisplayedEmojis() {
- const maxToShow = Math.min(root.maxBarEmojis, root.enabledEmojis.length)
- let emojis = []
- for (let i = 0; i < maxToShow; i++) {
- const idx = (root.currentIndex + i) % root.enabledEmojis.length
- emojis.push(root.enabledEmojis[idx])
- }
- root.displayedEmojis = emojis
- }
-
- Component.onCompleted: {
- updateDisplayedEmojis()
- }
-
- onEnabledEmojisChanged: updateDisplayedEmojis()
- onMaxBarEmojisChanged: updateDisplayedEmojis()
-
- horizontalBarPill: Component {
- Row {
- id: emojiRow
- spacing: Theme.spacingXS
-
- Repeater {
- model: root.displayedEmojis
- StyledText {
- text: modelData
- font.pixelSize: Theme.fontSizeLarge
- }
- }
- }
- }
-
- verticalBarPill: Component {
- Column {
- id: emojiColumn
- spacing: Theme.spacingXS
-
- Repeater {
- model: root.displayedEmojis
- StyledText {
- text: modelData
- font.pixelSize: Theme.fontSizeMedium
- anchors.horizontalCenter: parent.horizontalCenter
- }
- }
- }
- }
-
- popoutContent: Component {
- PopoutComponent {
- id: popoutColumn
-
- headerText: "Emoji Picker"
- detailsText: "Click an emoji to copy it to clipboard"
- showCloseButton: true
-
- property var allEmojis: [
- "😀", "😃", "😄", "😁", "😆", "😅", "🤣", "😂", "🙂", "🙃",
- "😉", "😊", "😇", "🥰", "😍", "🤩", "😘", "😗", "😚", "😙",
- "😋", "😛", "😜", "🤪", "😝", "🤑", "🤗", "🤭", "🤫", "🤔",
- "🤐", "🤨", "😐", "😑", "😶", "😏", "😒", "🙄", "😬", "🤥",
- "😌", "😔", "😪", "🤤", "😴", "😷", "🤒", "🤕", "🤢", "🤮",
- "🤧", "🥵", "🥶", "😶‍🌫️", "😵", "😵‍💫", "🤯", "🤠", "🥳", "😎",
- "🤓", "🧐", "😕", "😟", "🙁", "☹️", "😮", "😯", "😲", "😳",
- "🥺", "😦", "😧", "😨", "😰", "😥", "😢", "😭", "😱", "😖",
- "😣", "😞", "😓", "😩", "😫", "🥱", "😤", "😡", "😠", "🤬",
- "❤️", "🧡", "💛", "💚", "💙", "💜", "🖤", "🤍", "🤎", "💔",
- "❤️‍🔥", "❤️‍🩹", "💕", "💞", "💓", "💗", "💖", "💘", "💝", "💟",
- "👍", "👎", "👊", "✊", "🤛", "🤜", "🤞", "✌️", "🤟", "🤘",
- "👌", "🤌", "🤏", "👈", "👉", "👆", "👇", "☝️", "✋", "🤚"
- ]
-
- Item {
- width: parent.width
- implicitHeight: root.popoutHeight - popoutColumn.headerHeight - popoutColumn.detailsHeight - Theme.spacingXL
-
- DankGridView {
- id: emojiGrid
- anchors.horizontalCenter: parent.horizontalCenter
- width: Math.floor(parent.width / 50) * 50
- height: parent.height
- clip: true
- cellWidth: 50
- cellHeight: 50
- model: popoutColumn.allEmojis
-
- delegate: StyledRect {
- width: 45
- height: 45
- radius: Theme.cornerRadius
- color: emojiMouseArea.containsMouse ? Theme.surfaceContainerHighest : Theme.surfaceContainerHigh
- border.width: 0
-
- StyledText {
- anchors.centerIn: parent
- text: modelData
- font.pixelSize: Theme.fontSizeXLarge
- }
-
- MouseArea {
- id: emojiMouseArea
- anchors.fill: parent
- hoverEnabled: true
- cursorShape: Qt.PointingHandCursor
-
- onClicked: {
- Quickshell.execDetached(["dms", "cl", "copy", modelData])
- ToastService.showInfo("Copied " + modelData + " to clipboard")
- popoutColumn.closePopout()
- }
- }
- }
- }
- }
- }
- }
-
- popoutWidth: 400
- popoutHeight: 500
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/README.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/README.md
deleted file mode 100644
index 9102dda..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/README.md
+++ /dev/null
@@ -1,52 +0,0 @@
-# Emoji Cycler Plugin
-
-An example dms plugin that displays cycling emojis in your bar with an emoji picker popout.
-
-## Features
-
-- **Cycling Emojis**: Automatically rotates through your selected emoji set in the bar
-- **Emoji Picker**: Click the widget to open a grid of 120+ emojis
-- **Copy to Clipboard**: Click any emoji in the picker to copy it to clipboard
-- **Customizable**: Choose emoji sets, cycle speed, and max emojis shown
-
-## Installation
-
-1. Copy this directory to `~/.config/DankMaterialShell/plugins/ExampleEmojiPlugin`
-2. Open DMS Settings → Plugins
-3. Click "Scan for Plugins"
-4. Enable "Emoji Cycler"
-5. Add `exampleEmojiPlugin` to your DankBar widget list
-
-## Settings
-
-### Emoji Set
-Choose from different emoji collections:
-- **Happy & Sad**: Mix of emotional faces
-- **Hearts**: Various colored hearts
-- **Hand Gestures**: Thumbs up, peace signs, etc.
-- **All Mixed**: A bit of everything
-
-### Cycle Speed
-Control how fast emojis rotate (500ms - 10000ms)
-
-### Max Bar Emojis
-How many emojis to display at once (1-8)
-
-## Usage
-
-**In the bar**: Watch emojis cycle through automatically
-**Click the widget**: Opens emoji picker with 120+ emojis
-**Click any emoji**: Copies it to clipboard and shows toast
-
-## Example Code Highlights
-
-This plugin demonstrates:
-- Using `PluginComponent` for bar integration
-- `SelectionSetting`, `SliderSetting` for configuration
-- Timer-based animation
-- Popout content with grid layout
-- External command execution (`Quickshell.execDetached`)
-- Toast notifications (`ToastService.show`)
-- Dynamic settings loading/saving
-
-Perfect template for creating your own DMS plugins!
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/plugin.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/plugin.json
deleted file mode 100644
index ef16d01..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleEmojiPlugin/plugin.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "id": "exampleEmojiPlugin",
- "name": "Emoji Cycler",
- "description": "Display cycling emojis in your bar with a handy emoji picker popout",
- "version": "1.0.0",
- "author": "AvengeMedia",
- "type": "widget",
- "capabilities": ["emoji-search", "clipboard", "dankbar-widget"],
- "component": "./EmojiWidget.qml",
- "icon": "mood",
- "settings": "./EmojiSettings.qml",
- "permissions": [
- "settings_read",
- "settings_write"
- ]
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/README.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/README.md
deleted file mode 100644
index 833572e..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/README.md
+++ /dev/null
@@ -1,116 +0,0 @@
-# Example with Variants Plugin
-
-This plugin demonstrates the dynamic variant system for DankMaterialShell plugins.
-
-## What are Variants?
-
-Variants allow a single plugin to create multiple widget instances with different configurations. Each variant appears as a separate widget option in the Bar Settings "Add Widget" menu.
-
-## How It Works
-
-### Plugin Architecture
-
-1. **Single Component**: The plugin defines one widget component (`VariantWidget.qml`)
-2. **Variant Data**: Each variant stores its configuration in plugin settings
-3. **Dynamic Creation**: Variants are created through the plugin's settings UI
-4. **Widget ID Format**: Variants use the format `pluginId:variantId` (e.g., `exampleVariants:variant_1234567890`)
-
-### Widget Properties
-
-Each variant widget receives:
-- `pluginService`: Reference to PluginService
-- `pluginId`: The base plugin ID (e.g., "exampleVariants")
-- `variantId`: The specific variant ID (e.g., "variant_1234567890")
-- `variantData`: The variant's configuration object
-
-### Variant Configuration
-
-This example stores:
-```javascript
-{
- id: "variant_1234567890",
- name: "My Variant",
- text: "Display Text",
- icon: "star",
- color: "#FF5722"
-}
-```
-
-## Creating Your Own Variant Plugin
-
-### 1. Widget Component
-
-Create a widget that accepts variant data:
-
-```qml
-Rectangle {
- property var pluginService: null
- property string pluginId: ""
- property string variantId: ""
- property var variantData: null
-
- // Use variantData for configuration
- property string displayText: variantData?.text || "Default"
-}
-```
-
-### 2. Settings Component
-
-Provide UI to manage variants:
-
-```qml
-FocusScope {
- property var pluginService: null
-
- // Create variant
- pluginService.createPluginVariant(pluginId, variantName, variantConfig)
-
- // Remove variant
- pluginService.removePluginVariant(pluginId, variantId)
-
- // Update variant
- pluginService.updatePluginVariant(pluginId, variantId, variantConfig)
-
- // Get all variants
- var variants = pluginService.getPluginVariants(pluginId)
-}
-```
-
-### 3. Plugin Manifest
-
-Standard plugin manifest - no special configuration needed:
-
-```json
-{
- "id": "yourPlugin",
- "name": "Your Plugin",
- "component": "./Widget.qml",
- "settings": "./Settings.qml"
-}
-```
-
-## Use Cases
-
-- **Script Runner**: Multiple variants running different scripts
-- **System Monitors**: Different monitoring targets (CPU, GPU, Network)
-- **Quick Launchers**: Different apps or commands per variant
-- **Custom Indicators**: Different data sources or APIs
-- **Time Zones**: Multiple clocks for different time zones
-
-## API Reference
-
-### PluginService Functions
-
-- `getPluginVariants(pluginId)`: Get all variants for a plugin
-- `getAllPluginVariants()`: Get all variants across all plugins
-- `createPluginVariant(pluginId, name, config)`: Create new variant
-- `removePluginVariant(pluginId, variantId)`: Delete variant
-- `updatePluginVariant(pluginId, variantId, config)`: Update variant
-- `getPluginVariantData(pluginId, variantId)`: Get specific variant data
-
-### Widget Properties
-
-- `pluginId`: Base plugin identifier
-- `variantId`: Variant identifier (null if no variant)
-- `variantData`: Variant configuration object
-- `pluginService`: PluginService reference
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/VariantSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/VariantSettings.qml
deleted file mode 100644
index d5ea1d2..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/VariantSettings.qml
+++ /dev/null
@@ -1,303 +0,0 @@
-import QtQuick
-import QtQuick.Controls
-import qs.Common
-import qs.Services
-import qs.Widgets
-import qs.Modules.Plugins
-
-PluginSettings {
- id: root
- pluginId: "exampleVariants"
-
- onVariantsChanged: {
- variantsModel.clear()
- for (var i = 0; i < variants.length; i++) {
- variantsModel.append(variants[i])
- }
- }
-
- StyledText {
- width: parent.width
- text: "Variant Manager"
- font.pixelSize: Theme.fontSizeLarge
- font.weight: Font.Bold
- color: Theme.surfaceText
- }
-
- StyledText {
- width: parent.width
- text: "Create multiple widget variants with different text, icons, and colors"
- font.pixelSize: Theme.fontSizeSmall
- color: Theme.surfaceVariantText
- wrapMode: Text.WordWrap
- }
-
- StyledRect {
- width: parent.width
- height: addVariantColumn.implicitHeight + Theme.spacingL * 2
- radius: Theme.cornerRadius
- color: Theme.surfaceContainerHigh
-
- Column {
- id: addVariantColumn
- anchors.fill: parent
- anchors.margins: Theme.spacingL
- spacing: Theme.spacingM
-
- StyledText {
- text: "Add New Variant"
- font.pixelSize: Theme.fontSizeMedium
- font.weight: Font.Medium
- color: Theme.surfaceText
- }
-
- Row {
- width: parent.width
- spacing: Theme.spacingM
-
- Column {
- width: (parent.width - Theme.spacingM * 2) / 3
- spacing: Theme.spacingXS
-
- StyledText {
- text: "Name"
- font.pixelSize: Theme.fontSizeSmall
- color: Theme.surfaceVariantText
- }
-
- DankTextField {
- id: nameField
- width: parent.width
- placeholderText: "Variant Name"
- }
- }
-
- Column {
- width: (parent.width - Theme.spacingM * 2) / 3
- spacing: Theme.spacingXS
-
- StyledText {
- text: "Icon"
- font.pixelSize: Theme.fontSizeSmall
- color: Theme.surfaceVariantText
- }
-
- DankTextField {
- id: iconField
- width: parent.width
- placeholderText: "star"
- }
- }
-
- Column {
- width: (parent.width - Theme.spacingM * 2) / 3
- spacing: Theme.spacingXS
-
- StyledText {
- text: "Text"
- font.pixelSize: Theme.fontSizeSmall
- color: Theme.surfaceVariantText
- }
-
- DankTextField {
- id: textField
- width: parent.width
- placeholderText: "Display Text"
- }
- }
- }
-
- DankButton {
- text: "Create Variant"
- iconName: "add"
- onClicked: {
- if (!nameField.text) {
- ToastService.showError("Please enter a variant name")
- return
- }
-
- var variantConfig = {
- text: textField.text || nameField.text,
- icon: iconField.text || "widgets"
- }
-
- createVariant(nameField.text, variantConfig)
- ToastService.showInfo("Variant created: " + nameField.text)
-
- nameField.text = ""
- iconField.text = ""
- textField.text = ""
- }
- }
- }
- }
-
- 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 Variants"
- 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: ListModel {
- id: variantsModel
- }
-
- delegate: StyledRect {
- required property var model
- width: ListView.view.width
- height: variantRow.implicitHeight + Theme.spacingM * 2
- radius: Theme.cornerRadius
- color: variantMouseArea.containsMouse ? Theme.surfaceContainerHighest : Theme.surfaceContainer
-
- Row {
- id: variantRow
- anchors.fill: parent
- anchors.margins: Theme.spacingM
- spacing: Theme.spacingM
-
- Item {
- width: Theme.iconSize
- height: Theme.iconSize
- anchors.verticalCenter: parent.verticalCenter
-
- DankIcon {
- anchors.centerIn: parent
- name: model.icon || "widgets"
- size: Theme.iconSize
- color: Theme.surfaceText
- width: Theme.iconSize
- height: Theme.iconSize
- clip: true
- }
- }
-
- Column {
- anchors.verticalCenter: parent.verticalCenter
- spacing: Theme.spacingXS
- width: parent.width - Theme.iconSize - deleteButton.width - Theme.spacingM * 4
-
- StyledText {
- text: model.name || "Unnamed"
- font.pixelSize: Theme.fontSizeMedium
- color: Theme.surfaceText
- width: parent.width
- elide: Text.ElideRight
- }
-
- StyledText {
- text: "Text: " + (model.text || "") + " | Icon: " + (model.icon || "")
- font.pixelSize: Theme.fontSizeSmall
- color: Theme.surfaceVariantText
- width: parent.width
- elide: Text.ElideRight
- }
- }
-
- Rectangle {
- id: deleteButton
- width: 32
- height: 32
- radius: 16
- color: deleteArea.containsMouse ? Theme.error : "transparent"
- anchors.verticalCenter: parent.verticalCenter
-
- 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)
- ToastService.showInfo("Variant removed: " + model.name)
- }
- }
- }
- }
-
- MouseArea {
- id: variantMouseArea
- anchors.fill: parent
- hoverEnabled: true
- propagateComposedEvents: true
- }
- }
-
- StyledText {
- anchors.centerIn: parent
- text: "No variants created yet"
- font.pixelSize: Theme.fontSizeSmall
- color: Theme.surfaceVariantText
- visible: variantsModel.count === 0
- }
- }
- }
- }
-
- StyledRect {
- width: parent.width
- height: instructionsColumn.implicitHeight + Theme.spacingL * 2
- radius: Theme.cornerRadius
- color: Theme.surface
-
- Column {
- id: instructionsColumn
- anchors.fill: parent
- anchors.margins: Theme.spacingL
- spacing: Theme.spacingM
-
- Row {
- spacing: Theme.spacingM
-
- DankIcon {
- name: "info"
- size: Theme.iconSize
- color: Theme.primary
- anchors.verticalCenter: parent.verticalCenter
- }
-
- StyledText {
- text: "How to Use Variants"
- font.pixelSize: Theme.fontSizeMedium
- font.weight: Font.Medium
- color: Theme.surfaceText
- anchors.verticalCenter: parent.verticalCenter
- }
- }
-
- StyledText {
- text: "1. Create variants with different names, icons, and text\n2. Go to Bar Settings and click 'Add Widget'\n3. Each variant will appear as a separate widget option\n4. Add variants to your bar just like any other widget"
- font.pixelSize: Theme.fontSizeSmall
- color: Theme.surfaceVariantText
- wrapMode: Text.WordWrap
- width: parent.width
- lineHeight: 1.4
- }
- }
- }
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/VariantWidget.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/VariantWidget.qml
deleted file mode 100644
index e5b077f..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/VariantWidget.qml
+++ /dev/null
@@ -1,57 +0,0 @@
-import QtQuick
-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 displayText: variantData?.text || "Default Text"
- property string displayIcon: variantData?.icon || "widgets"
-
- horizontalBarPill: Component {
- Row {
- spacing: 3
-
- DankIcon {
- name: root.displayIcon
- size: Theme.iconSize - 8
- color: Theme.surfaceText
- anchors.verticalCenter: parent.verticalCenter
- }
-
- StyledText {
- text: root.displayText
- font.pixelSize: Theme.fontSizeSmall
- font.weight: Font.Medium
- color: Theme.surfaceText
- anchors.verticalCenter: parent.verticalCenter
- }
- }
- }
-
- verticalBarPill: Component {
- Column {
- spacing: 1
-
- DankIcon {
- name: root.displayIcon
- size: Theme.iconSize - 8
- color: Theme.surfaceText
- anchors.horizontalCenter: parent.horizontalCenter
- }
-
- StyledText {
- text: root.displayText
- font.pixelSize: Theme.fontSizeSmall
- font.weight: Font.Medium
- color: Theme.surfaceText
- anchors.horizontalCenter: parent.horizontalCenter
- }
- }
- }
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/plugin.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/plugin.json
deleted file mode 100644
index 9e3cad4..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/ExampleWithVariants/plugin.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "id": "exampleVariants",
- "name": "Example with Variants",
- "description": "Demonstrates dynamic variant creation for plugins",
- "version": "1.0.0",
- "author": "DMS",
- "type": "widget",
- "capabilities": ["multiple-usecases", "variants"],
- "component": "./VariantWidget.qml",
- "icon": "widgets",
- "settings": "./VariantSettings.qml",
- "permissions": [
- "settings_read",
- "settings_write"
- ]
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/LauncherExampleLauncher.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/LauncherExampleLauncher.qml
deleted file mode 100644
index 81040b6..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/LauncherExampleLauncher.qml
+++ /dev/null
@@ -1,140 +0,0 @@
-import QtQuick
-import Quickshell
-import qs.Services
-
-Item {
- id: root
-
- // Plugin properties
- property var pluginService: null
- property string trigger: "#"
-
- // Plugin interface signals
- signal itemsChanged()
-
- Component.onCompleted: {
- console.info("LauncherExample: Plugin loaded")
-
- // Load custom trigger from settings
- if (pluginService) {
- trigger = pluginService.loadPluginData("launcherExample", "trigger", "#")
- }
- }
-
- // Required function: Get items for launcher
- function getItems(query) {
- const baseItems = [
- {
- name: "Test Item 1",
- icon: "material:lightbulb",
- comment: "This is a test item that shows a toast notification",
- action: "toast:Test Item 1 executed!",
- categories: ["LauncherExample"]
- },
- {
- name: "Test Item 2",
- icon: "material:star",
- comment: "Another test item with different action",
- action: "toast:Test Item 2 clicked!",
- categories: ["LauncherExample"]
- },
- {
- name: "Test Item 3",
- icon: "material:favorite",
- comment: "Third test item for demonstration",
- action: "toast:Test Item 3 activated!",
- categories: ["LauncherExample"]
- },
- {
- name: "Unicode Icon Example",
- icon: "unicode:🚀",
- comment: "Demonstrates unicode/emoji icon support",
- action: "toast:Unicode icons work great!",
- categories: ["LauncherExample"]
- },
- {
- name: "Example Copy Action",
- icon: "material:content_copy",
- comment: "Demonstrates copying text to clipboard",
- action: "copy:This text was copied by the launcher plugin!",
- categories: ["LauncherExample"]
- },
- {
- name: "Example Script Action",
- icon: "material:terminal",
- comment: "Demonstrates running a simple command",
- action: "script:echo 'Hello from launcher plugin!'",
- categories: ["LauncherExample"]
- }
- ]
-
- if (!query || query.length === 0) {
- return baseItems
- }
-
- // Filter items based on query
- const lowerQuery = query.toLowerCase()
- return baseItems.filter(item => {
- return item.name.toLowerCase().includes(lowerQuery) ||
- item.comment.toLowerCase().includes(lowerQuery)
- })
- }
-
- // Required function: Execute item action
- function executeItem(item) {
- if (!item || !item.action) {
- console.warn("LauncherExample: Invalid item or action")
- return
- }
-
- console.log("LauncherExample: Executing item:", item.name, "with action:", item.action)
-
- const actionParts = item.action.split(":")
- const actionType = actionParts[0]
- const actionData = actionParts.slice(1).join(":")
-
- switch (actionType) {
- case "toast":
- showToast(actionData)
- break
- case "copy":
- copyToClipboard(actionData)
- break
- case "script":
- runScript(actionData)
- break
- default:
- console.warn("LauncherExample: Unknown action type:", actionType)
- showToast("Unknown action: " + actionType)
- }
- }
-
- // Helper functions for different action types
- function showToast(message) {
- if (typeof ToastService !== "undefined") {
- ToastService.showInfo("LauncherExample", message)
- } else {
- console.log("LauncherExample Toast:", message)
- }
- }
-
- function copyToClipboard(text) {
- Quickshell.execDetached(["dms", "cl", "copy", text])
- showToast("Copied to clipboard: " + text)
- }
-
- function runScript(command) {
- console.log("LauncherExample: Would run script:", command)
- showToast("Script executed: " + command)
-
- // In a real plugin, you might create a Process component here
- // For demo purposes, we just show what would happen
- }
-
- // Watch for trigger changes
- onTriggerChanged: {
- if (pluginService) {
- pluginService.savePluginData("launcherExample", "trigger", trigger)
- }
- }
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/LauncherExampleSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/LauncherExampleSettings.qml
deleted file mode 100644
index e30aaa8..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/LauncherExampleSettings.qml
+++ /dev/null
@@ -1,244 +0,0 @@
-import QtQuick
-import QtQuick.Controls
-import qs.Widgets
-
-FocusScope {
- id: root
-
- property var pluginService: null
-
- implicitHeight: settingsColumn.implicitHeight
- height: implicitHeight
-
- Column {
- id: settingsColumn
- anchors.fill: parent
- anchors.margins: 16
- spacing: 16
-
- Text {
- text: "Launcher Example Plugin Settings"
- font.pixelSize: 18
- font.weight: Font.Bold
- color: "#FFFFFF"
- }
-
- Text {
- text: "This plugin demonstrates the launcher plugin system with example items and actions."
- font.pixelSize: 14
- color: "#CCFFFFFF"
- wrapMode: Text.WordWrap
- width: parent.width - 32
- }
-
- Rectangle {
- width: parent.width - 32
- height: 1
- color: "#30FFFFFF"
- }
-
- Column {
- spacing: 12
- width: parent.width - 32
-
- Text {
- text: "Trigger Configuration"
- font.pixelSize: 16
- font.weight: Font.Medium
- color: "#FFFFFF"
- }
-
- Text {
- text: noTriggerToggle.checked ? "Items will always show in the launcher (no trigger needed)." : "Set the trigger text to activate this plugin. Type the trigger in the launcher to filter to this plugin's items."
- font.pixelSize: 12
- color: "#CCFFFFFF"
- wrapMode: Text.WordWrap
- width: parent.width
- }
-
- Row {
- spacing: 12
-
- CheckBox {
- id: noTriggerToggle
- text: "No trigger (always show)"
- checked: loadSettings("noTrigger", false)
-
- contentItem: Text {
- text: noTriggerToggle.text
- font.pixelSize: 14
- color: "#FFFFFF"
- leftPadding: noTriggerToggle.indicator.width + 8
- verticalAlignment: Text.AlignVCenter
- }
-
- indicator: Rectangle {
- implicitWidth: 20
- implicitHeight: 20
- radius: 4
- border.color: noTriggerToggle.checked ? "#4CAF50" : "#60FFFFFF"
- border.width: 2
- color: noTriggerToggle.checked ? "#4CAF50" : "transparent"
-
- Rectangle {
- width: 12
- height: 12
- anchors.centerIn: parent
- radius: 2
- color: "#FFFFFF"
- visible: noTriggerToggle.checked
- }
- }
-
- onCheckedChanged: {
- saveSettings("noTrigger", checked)
- if (checked) {
- saveSettings("trigger", "")
- } else {
- saveSettings("trigger", triggerField.text || "#")
- }
- }
- }
- }
-
- Row {
- spacing: 12
- anchors.left: parent.left
- anchors.right: parent.right
- visible: !noTriggerToggle.checked
-
- Text {
- text: "Trigger:"
- font.pixelSize: 14
- color: "#FFFFFF"
- anchors.verticalCenter: parent.verticalCenter
- }
-
- DankTextField {
- id: triggerField
- width: 100
- height: 40
- text: loadSettings("trigger", "#")
- placeholderText: "#"
- backgroundColor: "#30FFFFFF"
- textColor: "#FFFFFF"
-
- onTextEdited: {
- const newTrigger = text.trim()
- saveSettings("trigger", newTrigger || "#")
- saveSettings("noTrigger", newTrigger === "")
- }
- }
-
- Text {
- text: "Examples: #, !, @, !ex, etc."
- font.pixelSize: 12
- color: "#AAFFFFFF"
- anchors.verticalCenter: parent.verticalCenter
- }
- }
- }
-
- Rectangle {
- width: parent.width - 32
- height: 1
- color: "#30FFFFFF"
- }
-
- Column {
- spacing: 8
- width: parent.width - 32
-
- Text {
- text: "Example Items:"
- font.pixelSize: 14
- font.weight: Font.Medium
- color: "#FFFFFF"
- }
-
- Column {
- spacing: 4
- leftPadding: 16
-
- Text {
- text: "• Test Item 1, 2, 3 - Show toast notifications"
- font.pixelSize: 12
- color: "#CCFFFFFF"
- }
-
- Text {
- text: "• Example Copy Action - Copy text to clipboard"
- font.pixelSize: 12
- color: "#CCFFFFFF"
- }
-
- Text {
- text: "• Example Script Action - Demonstrate script execution"
- font.pixelSize: 12
- color: "#CCFFFFFF"
- }
- }
- }
-
- Rectangle {
- width: parent.width - 32
- height: 1
- color: "#30FFFFFF"
- }
-
- Column {
- spacing: 8
- width: parent.width - 32
-
- Text {
- text: "Usage:"
- font.pixelSize: 14
- font.weight: Font.Medium
- color: "#FFFFFF"
- }
-
- Column {
- spacing: 4
- leftPadding: 16
- bottomPadding: 24
-
- Text {
- text: "1. Open Launcher (Ctrl+Space or click launcher button)"
- font.pixelSize: 12
- color: "#CCFFFFFF"
- }
-
- Text {
- text: noTriggerToggle.checked ? "2. Items are always visible in the launcher" : "2. Type your trigger (default: #) to filter to this plugin"
- font.pixelSize: 12
- color: "#CCFFFFFF"
- }
-
- Text {
- text: noTriggerToggle.checked ? "3. Search works normally with plugin items included" : "3. Optionally add search terms: '# test' to find test items"
- font.pixelSize: 12
- color: "#CCFFFFFF"
- }
-
- Text {
- text: "4. Select an item and press Enter to execute its action"
- font.pixelSize: 12
- color: "#CCFFFFFF"
- }
- }
- }
- }
-
- function saveSettings(key, value) {
- if (pluginService) {
- pluginService.savePluginData("launcherExample", key, value)
- }
- }
-
- function loadSettings(key, defaultValue) {
- if (pluginService) {
- return pluginService.loadPluginData("launcherExample", key, defaultValue)
- }
- return defaultValue
- }
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/README.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/README.md
deleted file mode 100644
index db34b83..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/README.md
+++ /dev/null
@@ -1,244 +0,0 @@
-# LauncherExample Plugin
-
-A demonstration plugin that showcases the DMS launcher plugin system capabilities.
-
-## Purpose
-
-This plugin serves as a comprehensive example for developers creating launcher plugins for DMS. It demonstrates:
-
-- **Plugin Structure**: Proper manifest, launcher, and settings components
-- **Trigger System**: Customizable trigger strings for plugin activation (including empty triggers)
-- **Item Management**: Providing searchable items to the launcher
-- **Action Execution**: Handling different types of actions (toast, copy, script)
-- **Settings Integration**: Configurable plugin settings with persistence
-
-## Features
-
-### Example Items
-- **Test Items 1-3**: Demonstrate toast notifications
-- **Copy Action**: Shows clipboard integration
-- **Script Action**: Demonstrates command execution
-
-### Trigger System
-- **Default Trigger**: `#` (configurable in settings)
-- **Empty Trigger Option**: Items can always be visible without needing a trigger
-- **Usage**: Type `#` in launcher to filter to this plugin (when trigger is set)
-- **Search**: Type `# test` to search within plugin items
-
-### Action Types
-- `toast:message` - Shows toast notification
-- `copy:text` - Copies text to clipboard
-- `script:command` - Executes shell command (demo only)
-
-## File Structure
-
-```
-PLUGINS/LauncherExample/
-├── plugin.json # Plugin manifest
-├── LauncherExampleLauncher.qml # Main launcher component
-├── LauncherExampleSettings.qml # Settings interface
-└── README.md # This documentation
-```
-
-## Installation
-
-1. **Plugin Directory**: Copy to `~/.config/DankMaterialShell/plugins/LauncherExample`
-2. **Enable Plugin**: Settings → Plugins → Enable "LauncherExample"
-3. **Configure**: Set custom trigger in plugin settings if desired
-
-## Usage
-
-### With Trigger (Default)
-1. Open launcher (Ctrl+Space or launcher button)
-2. Type `#` to activate plugin trigger
-3. Browse available items or add search terms
-4. Press Enter to execute selected item
-
-### Without Trigger (Empty Trigger Mode)
-1. Enable "No trigger (always show)" in plugin settings
-2. Open launcher - plugin items are always visible
-3. Search works normally with plugin items included
-4. Press Enter to execute selected item
-
-### Search Examples
-- `#` - Show all plugin items (with trigger enabled)
-- `# test` - Show items matching "test"
-- `# copy` - Show items matching "copy"
-- `test` - Show all items matching "test" (with empty trigger enabled)
-
-## Developer Guide
-
-### Plugin Contract
-
-**Launcher Component Requirements**:
-```qml
-// Required properties
-property var pluginService: null
-property string trigger: "#"
-
-// Required signals
-signal itemsChanged()
-
-// Required functions
-function getItems(query): array
-function executeItem(item): void
-
-// Optional functions (for Shift+Enter paste support)
-function getPasteText(item): string|null
-function getPasteArgs(item): array|null
-```
-
-**Item Structure**:
-```javascript
-{
- name: "Item Name", // Display name
- icon: "icon_name", // Icon (optional, see Icon Types below)
- comment: "Description", // Subtitle text
- action: "type:data", // Action to execute
- categories: ["PluginName"] // Category array
-}
-```
-
-**Icon Types**:
-
-The `icon` field supports four formats:
-
-1. **Material Design Icons** - Use `material:` prefix:
- ```javascript
- icon: "material:lightbulb" // Material Symbols Rounded font
- ```
- Examples: `material:star`, `material:favorite`, `material:settings`
-
-2. **Unicode/Emoji Icons** - Use `unicode:` prefix:
- ```javascript
- icon: "unicode:🚀" // Unicode character or emoji
- ```
- Display any Unicode character or emoji as the icon. Examples: `unicode:😀`, `unicode:⚡`, `unicode:🎨`
-
-3. **Desktop Theme Icons** - Use icon name directly:
- ```javascript
- icon: "firefox" // Uses system icon theme
- ```
- Examples: `firefox`, `chrome`, `folder`, `text-editor`
-
-4. **No Icon** - Omit the `icon` field entirely:
- ```javascript
- {
- name: "😀 Grinning Face",
- // No icon field
- comment: "Copy emoji",
- action: "copy:😀",
- categories: ["MyPlugin"]
- }
- ```
- When icon is omitted, the launcher hides the icon area and displays only text
-
-**Action Format**: `type:data` where:
-- `type` - Action handler (toast, copy, script, etc.)
-- `data` - Action-specific data
-
-### Settings Integration
-```qml
-// Save setting
-pluginService.savePluginData("pluginId", "key", value)
-
-// Load setting
-pluginService.loadPluginData("pluginId", "key", defaultValue)
-```
-
-### Trigger Configuration
-
-The trigger can be configured in two ways:
-
-1. **Empty Trigger** (No Trigger Mode):
- - Check "No trigger (always show)" in settings
- - Saves `trigger: ""` and `noTrigger: true`
- - Items always appear in launcher alongside regular apps
-
-2. **Custom Trigger**:
- - Enter any string (e.g., `#`, `!`, `@`, `!ex`)
- - Uncheck "No trigger" checkbox
- - Items only appear when trigger is typed
-
-### Manifest Structure
-```json
-{
- "id": "launcherExample",
- "name": "LauncherExample",
- "type": "launcher",
- "capabilities": ["launcher"],
- "component": "./LauncherExampleLauncher.qml",
- "settings": "./LauncherExampleSettings.qml",
- "permissions": ["settings_read", "settings_write"]
-}
-```
-
-Note: The `trigger` field in the manifest is optional and serves as the default trigger value.
-
-## Extending This Plugin
-
-### Adding New Items
-```qml
-function getItems(query) {
- return [
- {
- name: "My Item",
- icon: "custom_icon",
- comment: "Does something cool",
- action: "custom:action_data",
- categories: ["LauncherExample"]
- }
- ]
-}
-```
-
-### Adding New Actions
-```qml
-function executeItem(item) {
- const actionParts = item.action.split(":")
- const actionType = actionParts[0]
- const actionData = actionParts.slice(1).join(":")
-
- switch (actionType) {
- case "custom":
- handleCustomAction(actionData)
- break
- }
-}
-```
-
-### Custom Trigger Logic
-```qml
-Component.onCompleted: {
- if (pluginService) {
- trigger = pluginService.loadPluginData("launcherExample", "trigger", "#")
- }
-}
-
-onTriggerChanged: {
- if (pluginService) {
- pluginService.savePluginData("launcherExample", "trigger", trigger)
- }
-}
-```
-
-## Best Practices
-
-1. **Unique Triggers**: Choose triggers that don't conflict with other plugins
-2. **Clear Descriptions**: Write helpful item comments
-3. **Error Handling**: Gracefully handle action failures
-4. **Performance**: Return results quickly in getItems()
-5. **Cleanup**: Destroy temporary objects in executeItem()
-6. **Empty Trigger Support**: Consider if your plugin should support empty trigger mode
-
-## Testing
-
-Test the plugin by:
-1. Installing and enabling in DMS
-2. Testing with trigger enabled
-3. Testing with empty trigger (no trigger mode)
-4. Trying each action type
-5. Testing search functionality
-6. Verifying settings persistence
-
-This plugin provides a solid foundation for building more sophisticated launcher plugins with custom functionality!
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/plugin.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/plugin.json
deleted file mode 100644
index c95b302..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherExample/plugin.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "id": "launcherExample",
- "name": "LauncherExample",
- "description": "Example launcher plugin demonstrating the launcher plugin system",
- "version": "1.0.0",
- "author": "DMS Team",
- "icon": "extension",
- "type": "launcher",
- "capabilities": ["clipboard", "command-execution"],
- "component": "./LauncherExampleLauncher.qml",
- "settings": "./LauncherExampleSettings.qml",
- "trigger": "#",
- "permissions": [
- "settings_read",
- "settings_write"
- ]
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherImageExample/LauncherImageExample.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherImageExample/LauncherImageExample.qml
deleted file mode 100644
index 2e85570..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherImageExample/LauncherImageExample.qml
+++ /dev/null
@@ -1,113 +0,0 @@
-import QtQuick
-import Quickshell
-import qs.Services
-
-QtObject {
- id: root
-
- property var pluginService: null
- property string trigger: "img"
-
- signal itemsChanged
-
- readonly property var images: [
- {
- name: "DankDash",
- imageUrl: "https://danklinux.com/img/dankdash.png",
- comment: "DankMaterialShell Dashboard"
- },
- {
- name: "Control Center",
- imageUrl: "https://danklinux.com/img/cc.png",
- comment: "System Control Center"
- },
- {
- name: "Desktop",
- imageUrl: "https://danklinux.com/img/desktop.png",
- comment: "Desktop Environment"
- },
- {
- name: "Search",
- imageUrl: "https://danklinux.com/img/dsearch.png",
- comment: "Application Search"
- },
- {
- name: "Theme Registry",
- imageUrl: "https://danklinux.com/img/blog/v1.2/themeregistry.png",
- comment: "Theme Registry Browser"
- },
- {
- name: "Monitor Settings",
- imageUrl: "https://danklinux.com/img/blog/v1.2/monitordark.png",
- comment: "Display Configuration"
- }
- ]
-
- function getItems(query) {
- const lowerQuery = query ? query.toLowerCase().trim() : "";
-
- if (lowerQuery.length === 0) {
- return images.map(img => ({
- name: img.name,
- icon: "material:image",
- comment: img.comment,
- action: "view:" + img.imageUrl,
- categories: ["Image Gallery"],
- imageUrl: img.imageUrl
- }));
- }
-
- return images.filter(img => img.name.toLowerCase().includes(lowerQuery) || img.comment.toLowerCase().includes(lowerQuery)).map(img => ({
- name: img.name,
- icon: "material:image",
- comment: img.comment,
- action: "view:" + img.imageUrl,
- categories: ["Image Gallery"],
- imageUrl: img.imageUrl
- }));
- }
-
- function executeItem(item) {
- if (!item?.action)
- return;
- const actionParts = item.action.split(":");
- const actionType = actionParts[0];
- const actionData = actionParts.slice(1).join(":");
-
- if (actionType === "view") {
- if (typeof ToastService !== "undefined") {
- ToastService.showInfo("Image Gallery", "Viewing: " + item.name);
- }
- }
- }
-
- function getContextMenuActions(item) {
- if (!item)
- return [];
- return [
- {
- icon: "open_in_new",
- text: "Open in Browser",
- action: () => {
- const url = item.imageUrl || "";
- if (url) {
- Qt.openUrlExternally(url);
- }
- }
- },
- {
- icon: "content_copy",
- text: "Copy URL",
- action: () => {
- const url = item.imageUrl || "";
- if (url) {
- Quickshell.execDetached(["dms", "cl", "copy", url]);
- if (typeof ToastService !== "undefined") {
- ToastService.showInfo("Copied", url);
- }
- }
- }
- }
- ];
- }
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherImageExample/README.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherImageExample/README.md
deleted file mode 100644
index 13b608d..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherImageExample/README.md
+++ /dev/null
@@ -1,43 +0,0 @@
-# LauncherImageExample
-
-Example launcher plugin demonstrating tile mode with URL-based images.
-
-## Features
-
-- **Tile Mode**: Uses `viewMode: "tile"` in plugin.json to display results as image tiles
-- **Enforced View Mode**: Uses `viewModeEnforced: true` to lock the view to tile mode (users cannot change it)
-- **URL Images**: Demonstrates using `imageUrl` property for remote images
-
-## Usage
-
-1. Open the launcher (DankLauncherV2)
-2. Type `img` to activate the plugin
-3. Browse DankMaterialShell screenshots in tile view
-
-## Plugin Configuration
-
-```json
-{
- "viewMode": "tile",
- "viewModeEnforced": true
-}
-```
-
-- `viewMode`: Sets the default view mode ("list", "grid", or "tile")
-- `viewModeEnforced`: When true, users cannot switch view modes for this plugin
-
-## Item Data Structure
-
-To display images in tile mode, set `imageUrl` directly on the item:
-
-```javascript
-{
- name: "Image Title",
- icon: "material:image",
- comment: "Image description",
- categories: ["Category"],
- imageUrl: "https://example.com/image.png"
-}
-```
-
-The `imageUrl` property supports remote URLs or local files, use `file://` prefix for local files.
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherImageExample/plugin.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherImageExample/plugin.json
deleted file mode 100644
index a3069e1..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/LauncherImageExample/plugin.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "id": "launcherImageExample",
- "name": "Image Gallery Example",
- "description": "Example launcher plugin demonstrating tile mode with images",
- "version": "1.0.0",
- "author": "DMS Team",
- "icon": "photo_library",
- "type": "launcher",
- "trigger": "img",
- "viewMode": "tile",
- "viewModeEnforced": true,
- "component": "./LauncherImageExample.qml",
- "permissions": []
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/POPOUT_SERVICE.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/POPOUT_SERVICE.md
deleted file mode 100644
index e4f556f..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/POPOUT_SERVICE.md
+++ /dev/null
@@ -1,294 +0,0 @@
-# PopoutService for Plugins
-
-## Overview
-
-The `PopoutService` singleton provides plugins with access to all DankMaterialShell popouts and modals. It's automatically injected into plugin widgets and daemons, enabling them to control shell UI elements.
-
-## Automatic Injection
-
-The `popoutService` property is automatically injected into:
-
-- Widget plugins (loaded in DankBar)
-- Daemon plugins (background services)
-- Plugin settings components
-
-**Required**: Declare the property in your plugin component:
-
-```qml
-property var popoutService: null
-```
-
-**Note**: Without this declaration, the service cannot be injected and you'll see errors like `Cannot assign to non-existent property "popoutService"`
-
-## API Reference
-
-### Popouts (DankPopout-based)
-
-| Component | Open | Close | Toggle |
-| ------------------- | -------------------------- | --------------------------- | ---------------------------- |
-| Control Center | `openControlCenter()` | `closeControlCenter()` | `toggleControlCenter()` |
-| Notification Center | `openNotificationCenter()` | `closeNotificationCenter()` | `toggleNotificationCenter()` |
-| App Drawer | `openAppDrawer()` | `closeAppDrawer()` | `toggleAppDrawer()` |
-| Process List | `openProcessList()` | `closeProcessList()` | `toggleProcessList()` |
-| DankDash | `openDankDash(tab)` | `closeDankDash()` | `toggleDankDash(tab)` |
-| Battery | `openBattery()` | `closeBattery()` | `toggleBattery()` |
-| VPN | `openVpn()` | `closeVpn()` | `toggleVpn()` |
-| System Update | `openSystemUpdate()` | `closeSystemUpdate()` | `toggleSystemUpdate()` |
-
-### Modals (DankModal-based)
-
-| Modal | Show | Hide | Notes |
-| ------------------ | ------------------------- | ------------------------- | -------------------------------------------------- |
-| Settings | `openSettings()` | `closeSettings()` | Full settings interface |
-| Clipboard History | `openClipboardHistory()` | `closeClipboardHistory()` | Clipboard integration |
-| Launcher | `openDankLauncherV2()` | `closeDankLauncherV2()` | Command launcher, also has `toggleDankLauncherV2()` |
-| Power Menu | `openPowerMenu()` | `closePowerMenu()` | Also has `togglePowerMenu()` |
-| Process List Modal | `showProcessListModal()` | `hideProcessListModal()` | Fullscreen version, has `toggleProcessListModal()` |
-| Color Picker | `showColorPicker()` | `hideColorPicker()` | Theme color selection |
-| Notification | `showNotificationModal()` | `hideNotificationModal()` | Notification details |
-| WiFi Password | `showWifiPasswordModal()` | `hideWifiPasswordModal()` | Network authentication |
-| Network Info | `showNetworkInfoModal()` | `hideNetworkInfoModal()` | Network details |
-
-### Slideouts
-
-| Component | Open | Close | Toggle |
-| --------- | --------------- | ---------------- | ----------------- |
-| Notepad | `openNotepad()` | `closeNotepad()` | `toggleNotepad()` |
-
-## Usage Examples
-
-### Simple Widget with Popout Control
-
-```qml
-import QtQuick
-import qs.Common
-import qs.Widgets
-
-Rectangle {
- id: root
-
- property var popoutService: null
-
- width: 100
- height: 30
- color: Theme.surfaceContainerHigh
- radius: Theme.cornerRadius
-
- MouseArea {
- anchors.fill: parent
- onClicked: popoutService?.toggleControlCenter()
- }
-
- StyledText {
- anchors.centerIn: parent
- text: "Settings"
- }
-}
-```
-
-### Daemon with Event-Driven Popouts
-
-```qml
-import QtQuick
-import qs.Services
-
-Item {
- id: root
-
- property var popoutService: null
-
- Connections {
- target: NotificationService
-
- function onNotificationReceived(notification) {
- if (notification.urgency === "critical") {
- popoutService?.openNotificationCenter()
- }
- }
- }
-
- Connections {
- target: BatteryService
-
- function onPercentageChanged() {
- if (BatteryService.percentage < 10 && !BatteryService.isCharging) {
- popoutService?.openBattery()
- }
- }
- }
-}
-```
-
-### Widget with Multiple Popout Options
-
-```qml
-import QtQuick
-import QtQuick.Controls
-import qs.Common
-
-Rectangle {
- property var popoutService: null
-
- MouseArea {
- anchors.fill: parent
- acceptedButtons: Qt.LeftButton | Qt.RightButton
-
- onClicked: (mouse) => {
- if (mouse.button === Qt.RightButton) {
- contextMenu.popup()
- } else {
- popoutService?.toggleControlCenter()
- }
- }
- }
-
- Menu {
- id: contextMenu
-
- MenuItem {
- text: "Settings"
- onClicked: popoutService?.openSettings()
- }
-
- MenuItem {
- text: "Notifications"
- onClicked: popoutService?.toggleNotificationCenter()
- }
-
- MenuItem {
- text: "Power Menu"
- onClicked: popoutService?.openPowerMenu()
- }
- }
-}
-```
-
-## Implementation Details
-
-### Service Architecture
-
-`PopoutService` is a singleton that holds references to popout instances:
-
-```qml
-// Services/PopoutService.qml
-Singleton {
- id: root
-
- property var controlCenterPopout: null
- property var notificationCenterPopout: null
- // ... other popout references
-
- function toggleControlCenter() {
- controlCenterPopout?.toggle()
- }
- // ... other control functions
-}
-```
-
-### Reference Assignment
-
-References are assigned in `DMSShell.qml` when popouts are loaded:
-
-```qml
-LazyLoader {
- ControlCenterPopout {
- id: controlCenterPopout
-
- Component.onCompleted: {
- PopoutService.controlCenterPopout = controlCenterPopout
- }
- }
-}
-```
-
-### Plugin Injection
-
-The service is injected in three locations:
-
-1. **DMSShell.qml** (daemon plugins):
-
-```qml
-Instantiator {
- delegate: Loader {
- onLoaded: {
- if (item) {
- item.popoutService = PopoutService
- }
- }
- }
-}
-```
-
-2. **WidgetHost.qml** (widget plugins):
-
-```qml
-onLoaded: {
- if (item.popoutService !== undefined) {
- item.popoutService = PopoutService
- }
-}
-```
-
-3. **CenterSection.qml** (center widgets):
-
-```qml
-onLoaded: {
- if (item.popoutService !== undefined) {
- item.popoutService = PopoutService
- }
-}
-```
-
-4. **PluginsTab.qml** (settings):
-
-```qml
-onLoaded: {
- if (item && typeof PopoutService !== "undefined") {
- item.popoutService = PopoutService
- }
-}
-```
-
-## Best Practices
-
-1. **Use Optional Chaining**: Always use `?.` to handle null cases
-
- ```qml
- popoutService?.toggleControlCenter()
- ```
-
-2. **Check Availability**: Some popouts may not be available
-
- ```qml
- if (popoutService && popoutService.controlCenterPopout) {
- popoutService.toggleControlCenter()
- }
- ```
-
-3. **Lazy Loading**: First access may activate lazy loaders - this is normal
-
-4. **Feature Detection**: Some popouts require specific features
-
- ```qml
- if (BatteryService.batteryAvailable) {
- popoutService?.openBattery()
- }
- ```
-
-5. **User Intent**: Only trigger popouts based on user actions or critical events
-
-## Example Plugin
-
-See `PLUGINS/PopoutControlExample/` for a complete working example that demonstrates:
-
-- Widget creation with popout controls
-- Menu-based popout selection
-- Proper service usage
-- Error handling
-
-## Limitations
-
-- Popouts are shared across all plugins - avoid conflicts
-- Some popouts may be compositor or feature-dependent
-- Lazy-loaded popouts need activation before use
-- Multi-monitor considerations apply to positioned popouts
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/PopoutControlSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/PopoutControlSettings.qml
deleted file mode 100644
index 374af30..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/PopoutControlSettings.qml
+++ /dev/null
@@ -1,98 +0,0 @@
-import QtQuick
-import qs.Common
-import qs.Widgets
-import qs.Modules.Plugins
-
-PluginSettings {
- id: root
- pluginId: "popoutControlExample"
-
- StyledText {
- width: parent.width
- text: "Popout Control Settings"
- font.pixelSize: Theme.fontSizeLarge
- font.weight: Font.Bold
- color: Theme.surfaceText
- }
-
- StyledText {
- width: parent.width
- text: "Choose which popout/modal will open when clicking the widget"
- font.pixelSize: Theme.fontSizeSmall
- color: Theme.surfaceVariantText
- wrapMode: Text.WordWrap
- }
-
- SelectionSetting {
- settingKey: "selectedPopout"
- label: "Popout to Open"
- description: "Select which popout or modal opens when you click the widget"
- options: [
- {
- label: "Control Center",
- value: "controlCenter"
- },
- {
- label: "Notification Center",
- value: "notificationCenter"
- },
- {
- label: "App Drawer",
- value: "appDrawer"
- },
- {
- label: "Process List",
- value: "processList"
- },
- {
- label: "DankDash",
- value: "dankDash"
- },
- {
- label: "Battery Info",
- value: "battery"
- },
- {
- label: "VPN",
- value: "vpn"
- },
- {
- label: "System Update",
- value: "systemUpdate"
- },
- {
- label: "Settings",
- value: "settings"
- },
- {
- label: "Clipboard History",
- value: "clipboardHistory"
- },
- {
- label: "Spotlight",
- value: "spotlight"
- },
- {
- label: "Power Menu",
- value: "powerMenu"
- },
- {
- label: "Color Picker",
- value: "colorPicker"
- },
- {
- label: "Notepad",
- value: "notepad"
- }
- ]
- defaultValue: "controlCenter"
- }
-
- StyledText {
- width: parent.width
- text: "💡 Tip: The widget displays the name of the selected popout and opens it when clicked!"
- font.pixelSize: Theme.fontSizeSmall
- color: Theme.surfaceVariantText
- wrapMode: Text.WordWrap
- }
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/PopoutControlWidget.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/PopoutControlWidget.qml
deleted file mode 100644
index fdbf89f..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/PopoutControlWidget.qml
+++ /dev/null
@@ -1,93 +0,0 @@
-import QtQuick
-import qs.Common
-import qs.Widgets
-import qs.Modules.Plugins
-
-PluginComponent {
- id: root
-
- property var popoutService: null
-
- property string selectedPopout: pluginData.selectedPopout || "controlCenter"
-
- property var popoutActions: ({
- "controlCenter": (x, y, w, s, scr) => popoutService?.toggleControlCenter(x, y, w, s, scr),
- "notificationCenter": (x, y, w, s, scr) => popoutService?.toggleNotificationCenter(x, y, w, s, scr),
- "appDrawer": (x, y, w, s, scr) => popoutService?.toggleAppDrawer(x, y, w, s, scr),
- "processList": (x, y, w, s, scr) => popoutService?.toggleProcessList(x, y, w, s, scr),
- "dankDash": (x, y, w, s, scr) => popoutService?.toggleDankDash(0, x, y, w, s, scr),
- "battery": (x, y, w, s, scr) => popoutService?.toggleBattery(x, y, w, s, scr),
- "vpn": (x, y, w, s, scr) => popoutService?.toggleVpn(x, y, w, s, scr),
- "systemUpdate": (x, y, w, s, scr) => popoutService?.toggleSystemUpdate(x, y, w, s, scr),
- "settings": () => popoutService?.openSettings(),
- "clipboardHistory": () => popoutService?.openClipboardHistory(),
- "spotlight": () => popoutService?.toggleDankLauncherV2(),
- "powerMenu": () => popoutService?.togglePowerMenu(),
- "colorPicker": () => popoutService?.showColorPicker(),
- "notepad": () => popoutService?.toggleNotepad()
- })
-
- property var popoutNames: ({
- "controlCenter": "Control Center",
- "notificationCenter": "Notification Center",
- "appDrawer": "App Drawer",
- "processList": "Process List",
- "dankDash": "DankDash",
- "battery": "Battery Info",
- "vpn": "VPN",
- "systemUpdate": "System Update",
- "settings": "Settings",
- "clipboardHistory": "Clipboard",
- "spotlight": "Spotlight",
- "powerMenu": "Power Menu",
- "colorPicker": "Color Picker",
- "notepad": "Notepad"
- })
-
- pillClickAction: (x, y, width, section, screen) => {
- if (popoutActions[selectedPopout]) {
- popoutActions[selectedPopout](x, y, width, section, screen);
- }
- }
-
- horizontalBarPill: Component {
- Row {
- spacing: Theme.spacingXS
-
- DankIcon {
- name: "widgets"
- color: Theme.primary
- font.pixelSize: Theme.iconSize - 6
- anchors.verticalCenter: parent.verticalCenter
- }
-
- StyledText {
- text: popoutNames[selectedPopout] || "Popouts"
- color: Theme.primary
- font.pixelSize: Theme.fontSizeMedium
- anchors.verticalCenter: parent.verticalCenter
- }
- }
- }
-
- verticalBarPill: Component {
- Column {
- spacing: Theme.spacingXS
-
- DankIcon {
- name: "widgets"
- color: Theme.primary
- font.pixelSize: Theme.iconSize - 6
- anchors.horizontalCenter: parent.horizontalCenter
- }
-
- StyledText {
- text: popoutNames[selectedPopout] || "Popouts"
- color: Theme.primary
- font.pixelSize: Theme.fontSizeSmall
- anchors.horizontalCenter: parent.horizontalCenter
- horizontalAlignment: Text.AlignHCenter
- }
- }
- }
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/README.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/README.md
deleted file mode 100644
index d1fb54a..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/README.md
+++ /dev/null
@@ -1,208 +0,0 @@
-# Popout Control Example Plugin
-
-This example plugin demonstrates:
-- Using `PopoutService` to trigger positioned popouts and modals
-- Using `pillClickAction` with position parameters
-- Using `PluginSettings` with dropdown selection
-- Dynamic widget text based on settings
-
-The `pillClickAction` receives position parameters `(x, y, width, section, screen)` which are passed to PopoutService functions to properly position popouts relative to the widget.
-
-## PopoutService API
-
-The `PopoutService` is automatically injected into plugin widgets and daemons as `popoutService`. It provides access to all shell popouts and modals.
-
-### Available Popouts
-
-#### Control Center
-```qml
-popoutService.openControlCenter()
-popoutService.closeControlCenter()
-popoutService.toggleControlCenter()
-```
-
-#### Notification Center
-```qml
-popoutService.openNotificationCenter()
-popoutService.closeNotificationCenter()
-popoutService.toggleNotificationCenter()
-```
-
-#### App Drawer
-```qml
-popoutService.openAppDrawer()
-popoutService.closeAppDrawer()
-popoutService.toggleAppDrawer()
-```
-
-#### Process List (Popout)
-```qml
-popoutService.openProcessList()
-popoutService.closeProcessList()
-popoutService.toggleProcessList()
-```
-
-#### DankDash
-```qml
-popoutService.openDankDash(tabIndex) // tabIndex: 0=Calendar, 1=Media, 2=Weather
-popoutService.closeDankDash()
-popoutService.toggleDankDash(tabIndex)
-```
-
-#### Battery Popout
-```qml
-popoutService.openBattery()
-popoutService.closeBattery()
-popoutService.toggleBattery()
-```
-
-#### VPN Popout
-```qml
-popoutService.openVpn()
-popoutService.closeVpn()
-popoutService.toggleVpn()
-```
-
-#### System Update Popout
-```qml
-popoutService.openSystemUpdate()
-popoutService.closeSystemUpdate()
-popoutService.toggleSystemUpdate()
-```
-
-### Available Modals
-
-#### Settings Modal
-```qml
-popoutService.openSettings()
-popoutService.closeSettings()
-```
-
-#### Clipboard History Modal
-```qml
-popoutService.openClipboardHistory()
-popoutService.closeClipboardHistory()
-```
-
-#### Launcher Modal
-```qml
-popoutService.openDankLauncherV2()
-popoutService.closeDankLauncherV2()
-popoutService.toggleDankLauncherV2()
-```
-
-#### Power Menu Modal
-```qml
-popoutService.openPowerMenu()
-popoutService.closePowerMenu()
-popoutService.togglePowerMenu()
-```
-
-#### Process List Modal (fullscreen)
-```qml
-popoutService.showProcessListModal()
-popoutService.hideProcessListModal()
-popoutService.toggleProcessListModal()
-```
-
-#### Color Picker Modal
-```qml
-popoutService.showColorPicker()
-popoutService.hideColorPicker()
-```
-
-#### Notification Modal
-```qml
-popoutService.showNotificationModal()
-popoutService.hideNotificationModal()
-```
-
-#### WiFi Password Modal
-```qml
-popoutService.showWifiPasswordModal()
-popoutService.hideWifiPasswordModal()
-```
-
-#### Network Info Modal
-```qml
-popoutService.showNetworkInfoModal()
-popoutService.hideNetworkInfoModal()
-```
-
-#### Notepad Slideout
-```qml
-popoutService.openNotepad()
-popoutService.closeNotepad()
-popoutService.toggleNotepad()
-```
-
-## Usage in Plugins
-
-### Widget Plugins
-
-```qml
-import QtQuick
-import qs.Common
-import qs.Widgets
-
-Rectangle {
- id: root
-
- property var popoutService: null // REQUIRED: Must declare for injection
-
- MouseArea {
- anchors.fill: parent
- onClicked: {
- popoutService?.toggleControlCenter()
- }
- }
-}
-```
-
-### Daemon Plugins
-
-```qml
-import QtQuick
-import qs.Services
-
-Item {
- id: root
-
- property var popoutService: null // REQUIRED: Must declare for injection
-
- Connections {
- target: NotificationService
- function onNotificationReceived() {
- popoutService?.openNotificationCenter()
- }
- }
-}
-```
-
-**Important**: The `popoutService` property **must** be declared in your plugin component. Without it, you'll get errors like:
-```
-Error: Cannot assign to non-existent property "popoutService"
-```
-
-## Example Use Cases
-
-1. **Custom Launcher**: Create a widget that opens the app drawer
-2. **Quick Settings**: Toggle control center from a custom button
-3. **Notification Manager**: Open notification center on new notifications
-4. **System Monitor**: Open process list on high CPU usage
-5. **Power Management**: Trigger power menu from a custom widget
-
-## Installation
-
-1. Copy the plugin directory to `~/.config/DankMaterialShell/plugins/`
-2. Open Settings → Plugins
-3. Click "Scan for Plugins"
-4. Enable "Popout Control Example"
-5. Add `popoutControlExample` to your DankBar widget list
-
-## Notes
-
-- The `popoutService` property is automatically injected - no manual setup required
-- Always use optional chaining (`?.`) when calling methods to handle null cases
-- Popouts are lazily loaded - first access may activate the loader
-- Some popouts require specific system features to be available
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/plugin.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/plugin.json
deleted file mode 100644
index 02042a0..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/PopoutControlExample/plugin.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "id": "popoutControlExample",
- "name": "Popout Control Example",
- "description": "Example widget demonstrating PopoutService usage with pillClickAction",
- "version": "1.0.0",
- "author": "DankMaterialShell",
- "type": "widget",
- "capabilities": ["dankbar-widget"],
- "component": "./PopoutControlWidget.qml",
- "icon": "widgets",
- "settings": "./PopoutControlSettings.qml",
- "permissions": ["settings_read", "settings_write"]
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/QuickNotesExample/QuickNotesLauncher.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/QuickNotesExample/QuickNotesLauncher.qml
deleted file mode 100644
index 42e4001..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/QuickNotesExample/QuickNotesLauncher.qml
+++ /dev/null
@@ -1,174 +0,0 @@
-import QtQuick
-import Quickshell
-import qs.Services
-
-Item {
- id: root
-
- property var pluginService: null
- property string trigger: "n"
-
- signal itemsChanged
-
- property var notes: []
- property int maxNotes: 50
-
- Component.onCompleted: {
- if (!pluginService)
- return;
- trigger = pluginService.loadPluginData("quickNotesExample", "trigger", "n");
- maxNotes = pluginService.loadPluginData("quickNotesExample", "maxNotes", 50);
-
- // Load notes from plugin STATE (persistent across sessions, separate file)
- notes = pluginService.loadPluginState("quickNotesExample", "notes", []);
- }
-
- function getItems(query) {
- const items = [];
-
- if (query && query.trim().length > 0) {
- const text = query.trim();
- items.push({
- name: "Save note: " + text,
- icon: "material:note_add",
- comment: "Save as a new note",
- action: "add:" + text,
- categories: ["Quick Notes"]
- });
-
- items.push({
- name: "Copy: " + text,
- icon: "material:content_copy",
- comment: "Copy text to clipboard",
- action: "copy:" + text,
- categories: ["Quick Notes"]
- });
- }
-
- const filteredNotes = query ? notes.filter(n => n.text.toLowerCase().includes(query.toLowerCase())) : notes;
-
- for (let i = 0; i < Math.min(20, filteredNotes.length); i++) {
- const note = filteredNotes[i];
- const age = _formatAge(note.timestamp);
- items.push({
- name: note.text,
- icon: "material:sticky_note_2",
- comment: age + " — select to copy, hold for options",
- action: "copy:" + note.text,
- categories: ["Quick Notes"]
- });
- }
-
- if (notes.length > 0 && !query) {
- items.push({
- name: "Clear all notes (" + notes.length + ")",
- icon: "material:delete_sweep",
- comment: "Remove all saved notes",
- action: "clear:",
- categories: ["Quick Notes"]
- });
- }
-
- return items;
- }
-
- function executeItem(item) {
- if (!item?.action)
- return;
-
- const colonIdx = item.action.indexOf(":");
- const actionType = item.action.substring(0, colonIdx);
- const actionData = item.action.substring(colonIdx + 1);
-
- switch (actionType) {
- case "add":
- addNote(actionData);
- break;
- case "copy":
- copyToClipboard(actionData);
- break;
- case "remove":
- removeNote(actionData);
- break;
- case "clear":
- clearAllNotes();
- break;
- default:
- showToast("Unknown action: " + actionType);
- }
- }
-
- function addNote(text) {
- if (!text)
- return;
-
- const existing = notes.findIndex(n => n.text === text);
- if (existing !== -1)
- notes.splice(existing, 1);
-
- notes.unshift({
- text: text,
- timestamp: Date.now()
- });
-
- if (notes.length > maxNotes)
- notes = notes.slice(0, maxNotes);
-
- _saveNotes();
- showToast("Note saved");
- }
-
- function removeNote(text) {
- notes = notes.filter(n => n.text !== text);
- _saveNotes();
- showToast("Note removed");
- }
-
- function clearAllNotes() {
- notes = [];
- pluginService.clearPluginState("quickNotesExample");
- showToast("All notes cleared");
- itemsChanged();
- }
-
- function _saveNotes() {
- if (!pluginService)
- return;
- // Save to plugin STATE — writes to quickNotesExample_state.json
- // This is separate from plugin SETTINGS (plugin_settings.json)
- pluginService.savePluginState("quickNotesExample", "notes", notes);
- itemsChanged();
- }
-
- function copyToClipboard(text) {
- Quickshell.execDetached(["dms", "cl", "copy", text]);
- showToast("Copied to clipboard");
- }
-
- function showToast(message) {
- if (typeof ToastService !== "undefined")
- ToastService.showInfo("Quick Notes", message);
- }
-
- function _formatAge(timestamp) {
- if (!timestamp)
- return "";
- const seconds = Math.floor((Date.now() - timestamp) / 1000);
- if (seconds < 60)
- return "just now";
- const minutes = Math.floor(seconds / 60);
- if (minutes < 60)
- return minutes + "m ago";
- const hours = Math.floor(minutes / 60);
- if (hours < 24)
- return hours + "h ago";
- const days = Math.floor(hours / 24);
- return days + "d ago";
- }
-
- onTriggerChanged: {
- if (!pluginService)
- return;
- pluginService.savePluginData("quickNotesExample", "trigger", trigger);
- }
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/QuickNotesExample/QuickNotesSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/QuickNotesExample/QuickNotesSettings.qml
deleted file mode 100644
index 9659614..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/QuickNotesExample/QuickNotesSettings.qml
+++ /dev/null
@@ -1,263 +0,0 @@
-import QtQuick
-import qs.Widgets
-
-FocusScope {
- id: root
-
- property var pluginService: null
-
- implicitHeight: settingsColumn.implicitHeight
- height: implicitHeight
-
- Column {
- id: settingsColumn
- anchors.fill: parent
- anchors.margins: 16
- spacing: 16
-
- Text {
- text: "Quick Notes Settings"
- font.pixelSize: 18
- font.weight: Font.Bold
- color: "#FFFFFF"
- }
-
- Text {
- text: "Demonstrates the plugin state API — notes are stored in a separate state file (quickNotesExample_state.json) rather than plugin_settings.json."
- font.pixelSize: 14
- color: "#CCFFFFFF"
- wrapMode: Text.WordWrap
- width: parent.width - 32
- }
-
- Rectangle {
- width: parent.width - 32
- height: 1
- color: "#30FFFFFF"
- }
-
- Column {
- spacing: 12
- width: parent.width - 32
-
- Text {
- text: "Trigger Configuration"
- font.pixelSize: 16
- font.weight: Font.Medium
- color: "#FFFFFF"
- }
-
- Row {
- spacing: 12
- anchors.left: parent.left
- anchors.right: parent.right
-
- Text {
- text: "Trigger:"
- font.pixelSize: 14
- color: "#FFFFFF"
- anchors.verticalCenter: parent.verticalCenter
- }
-
- DankTextField {
- id: triggerField
- width: 100
- height: 40
- text: loadSettings("trigger", "n")
- placeholderText: "n"
- backgroundColor: "#30FFFFFF"
- textColor: "#FFFFFF"
-
- onTextEdited: {
- saveSettings("trigger", text.trim() || "n");
- }
- }
- }
- }
-
- Rectangle {
- width: parent.width - 32
- height: 1
- color: "#30FFFFFF"
- }
-
- Column {
- spacing: 12
- width: parent.width - 32
-
- Text {
- text: "Storage"
- font.pixelSize: 16
- font.weight: Font.Medium
- color: "#FFFFFF"
- }
-
- Row {
- spacing: 12
-
- Text {
- text: "Max notes:"
- font.pixelSize: 14
- color: "#FFFFFF"
- anchors.verticalCenter: parent.verticalCenter
- }
-
- DankTextField {
- id: maxNotesField
- width: 80
- height: 40
- text: loadSettings("maxNotes", 50).toString()
- placeholderText: "50"
- backgroundColor: "#30FFFFFF"
- textColor: "#FFFFFF"
-
- onTextEdited: {
- const val = parseInt(text);
- if (!isNaN(val) && val > 0)
- saveSettings("maxNotes", val);
- }
- }
- }
-
- Text {
- text: {
- const count = loadState("notes", []).length;
- return "Currently storing " + count + " note(s)";
- }
- font.pixelSize: 12
- color: "#AAFFFFFF"
- }
-
- Rectangle {
- width: clearRow.implicitWidth + 24
- height: clearRow.implicitHeight + 16
- radius: 8
- color: clearMouseArea.containsMouse ? "#40FF5252" : "#30FF5252"
-
- Row {
- id: clearRow
- anchors.centerIn: parent
- spacing: 8
-
- Text {
- text: "🗑"
- font.pixelSize: 14
- anchors.verticalCenter: parent.verticalCenter
- }
-
- Text {
- text: "Clear all notes"
- font.pixelSize: 14
- color: "#FF5252"
- anchors.verticalCenter: parent.verticalCenter
- }
- }
-
- MouseArea {
- id: clearMouseArea
- anchors.fill: parent
- hoverEnabled: true
- cursorShape: Qt.PointingHandCursor
- onClicked: {
- if (pluginService) {
- pluginService.clearPluginState("quickNotesExample");
- }
- }
- }
- }
- }
-
- Rectangle {
- width: parent.width - 32
- height: 1
- color: "#30FFFFFF"
- }
-
- Column {
- spacing: 8
- width: parent.width - 32
-
- Text {
- text: "API Usage (for plugin developers):"
- font.pixelSize: 14
- font.weight: Font.Medium
- color: "#FFFFFF"
- }
-
- Column {
- spacing: 4
- leftPadding: 16
- bottomPadding: 24
-
- Text {
- text: "• pluginService.savePluginState(id, key, value)"
- font.pixelSize: 12
- color: "#CCFFFFFF"
- font.family: "monospace"
- }
-
- Text {
- text: " Writes to ~/.local/state/.../id_state.json"
- font.pixelSize: 11
- color: "#AAFFFFFF"
- }
-
- Text {
- text: "• pluginService.loadPluginState(id, key, default)"
- font.pixelSize: 12
- color: "#CCFFFFFF"
- font.family: "monospace"
- }
-
- Text {
- text: " Reads from the per-plugin state file"
- font.pixelSize: 11
- color: "#AAFFFFFF"
- }
-
- Text {
- text: "• pluginService.clearPluginState(id)"
- font.pixelSize: 12
- color: "#CCFFFFFF"
- font.family: "monospace"
- }
-
- Text {
- text: " Clears all state for a plugin"
- font.pixelSize: 11
- color: "#AAFFFFFF"
- }
-
- Text {
- text: "• pluginService.removePluginStateKey(id, key)"
- font.pixelSize: 12
- color: "#CCFFFFFF"
- font.family: "monospace"
- }
-
- Text {
- text: " Removes a single key from plugin state"
- font.pixelSize: 11
- color: "#AAFFFFFF"
- }
- }
- }
- }
-
- function saveSettings(key, value) {
- if (pluginService)
- pluginService.savePluginData("quickNotesExample", key, value);
- }
-
- function loadSettings(key, defaultValue) {
- if (pluginService)
- return pluginService.loadPluginData("quickNotesExample", key, defaultValue);
- return defaultValue;
- }
-
- function loadState(key, defaultValue) {
- if (pluginService)
- return pluginService.loadPluginState("quickNotesExample", key, defaultValue);
- return defaultValue;
- }
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/QuickNotesExample/plugin.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/QuickNotesExample/plugin.json
deleted file mode 100644
index fcf3458..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/QuickNotesExample/plugin.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "id": "quickNotesExample",
- "name": "Quick Notes",
- "description": "Example launcher plugin demonstrating the plugin state API for persistent data like history and notes",
- "version": "1.0.0",
- "author": "DankMaterialShell",
- "icon": "sticky_note_2",
- "type": "launcher",
- "capabilities": ["clipboard"],
- "component": "./QuickNotesLauncher.qml",
- "settings": "./QuickNotesSettings.qml",
- "trigger": "n",
- "permissions": [
- "settings_read",
- "settings_write"
- ]
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/README.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/README.md
deleted file mode 100644
index f7bed6a..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/README.md
+++ /dev/null
@@ -1,1665 +0,0 @@
-# Plugin System
-
-Create widgets for DankBar and Control Center using dynamically-loaded QML components.
-
-## Plugin Registry
-
-Browse and discover community plugins at **https://plugins.danklinux.com/**
-
-## Overview
-
-Plugins let you add custom widgets to DankBar and Control Center. They're discovered from `~/.config/DankMaterialShell/plugins/` and managed via PluginService.
-
-## Architecture
-
-### Core Components
-
-1. **PluginService** (`Services/PluginService.qml`)
- - Singleton service managing plugin lifecycle
- - Discovers plugins from `$CONFIGPATH/DankMaterialShell/plugins/`
- - Handles loading, unloading, and state management
- - Provides data persistence for plugin settings
-
-2. **PluginsTab** (`Modules/Settings/PluginsTab.qml`)
- - UI for managing available plugins
- - Access plugin settings
-
-3. **PluginsTab Settings** (`Modules/Settings/PluginsTab.qml`)
- - Accordion-style plugin configuration interface
- - Dynamically loads plugin settings components inline
- - Provides consistent settings interface with proper focus handling
-
-4. **DankBar Integration** (`Modules/DankBar/DankBar.qml`)
- - Renders plugin widgets in the bar
- - Merges plugin components with built-in widgets
- - Supports left, center, and right sections
- - Supports any dankbar position (top/left/right/bottom)
-
-## Plugin Structure
-
-Each plugin must be a directory in `$CONFIGPATH/DankMaterialShell/plugins/` containing:
-
-```
-$CONFIGPATH/DankMaterialShell/plugins/YourPlugin/
-├── plugin.json # Required: Plugin manifest
-├── YourWidget.qml # Required: Widget component
-├── YourSettings.qml # Optional: Settings UI
-└── *.js # Optional: JavaScript utilities
-```
-
-### Plugin Manifest (plugin.json)
-
-The manifest file defines plugin metadata and configuration.
-
-**JSON Schema:** See `plugin-schema.json` for the complete specification and validation schema.
-
-```json
-{
- "id": "yourPlugin",
- "name": "Your Plugin Name",
- "description": "Brief description of what your plugin does",
- "version": "1.0.0",
- "author": "Your Name",
- "type": "widget",
- "capabilities": ["thing-my-plugin-does"],
- "component": "./YourWidget.qml",
- "icon": "material_icon_name",
- "settings": "./YourSettings.qml",
- "requires_dms": ">=0.1.0",
- "requires": ["some-system-tool"],
- "permissions": [
- "settings_read",
- "settings_write"
- ]
-}
-```
-
-**Required Fields:**
-- `id`: Unique plugin identifier (camelCase, no spaces)
-- `name`: Human-readable plugin name
-- `description`: Short description of plugin functionality (displayed in UI)
-- `version`: Semantic version string (e.g., "1.0.0")
-- `author`: Plugin creator name or email
-- `type`: Plugin type - "widget", "daemon", "launcher", or "desktop"
-- `capabilities`: Array of plugin capabilities (e.g., ["dankbar-widget"], ["control-center"], ["monitoring"])
-- `component`: Relative path to main QML component file
-
-**Required for Launcher Type:**
-- `trigger`: Trigger string for launcher activation (e.g., "=", "#", "!")
-
-**Optional Fields:**
-- `icon`: Material Design icon name (displayed in UI)
-- `settings`: Path to settings component (enables settings UI)
-- `requires_dms`: Minimum DMS version requirement (e.g., ">=0.1.18", ">0.1.0")
-- `requires`: Array of required system tools/dependencies (e.g., ["curl", "jq"])
-- `permissions`: Required DMS permissions (e.g., ["settings_read", "settings_write"])
-
-**Permissions:**
-
-The plugin system enforces permissions when settings are accessed:
-- `settings_read`: Required to read plugin settings (currently not enforced)
-- `settings_write`: **Required** to use PluginSettings component and save settings
-
-If your plugin includes a settings component but doesn't declare `settings_write` permission, users will see an error message instead of the settings UI.
-
-### Widget Component
-
-The main widget component uses the **PluginComponent** wrapper which provides automatic property injection and bar integration:
-
-```qml
-import QtQuick
-import qs.Common
-import qs.Widgets
-import qs.Modules.Plugins
-
-PluginComponent {
- // Define horizontal bar pill, for top and bottom DankBar positions (optional)
- horizontalBarPill: Component {
- StyledRect {
- width: content.implicitWidth + Theme.spacingM * 2
- height: parent.widgetThickness
- radius: Theme.cornerRadius
- color: Theme.surfaceContainerHigh
-
- StyledText {
- id: content
- anchors.centerIn: parent
- text: "Hello World"
- color: Theme.surfaceText
- font.pixelSize: Theme.fontSizeMedium
- }
- }
- }
-
- // Define vertical bar pill, for left and right DankBar positions (optional)
- verticalBarPill: Component {
- // Same as horizontal but optimized for vertical layout
- }
-
- // Define popout content, opens when clicking the bar pill (optional)
- popoutContent: Component {
- PopoutComponent {
- headerText: "My Plugin"
- detailsText: "Optional description text goes here"
- showCloseButton: true
-
- // Your popout content goes here
- Column {
- width: parent.width
- spacing: Theme.spacingM
-
- StyledText {
- text: "Popout Content"
- font.pixelSize: Theme.fontSizeLarge
- color: Theme.surfaceText
- }
- }
- }
- }
-
- // Popout dimensions (required if popoutContent is set)
- popoutWidth: 400
- popoutHeight: 300
-}
-```
-
-**PluginComponent Properties (automatically injected):**
-- `axis`: Bar axis information (horizontal/vertical)
-- `section`: Bar section ("left", "center", "right")
-- `parentScreen`: Screen reference for multi-monitor support
-- `widgetThickness`: Recommended widget size perpendicular to bar
-- `barThickness`: Bar thickness parallel to edge
-
-**Component Options:**
-- `horizontalBarPill`: Component shown in horizontal bars
-- `verticalBarPill`: Component shown in vertical bars
-- `popoutContent`: Optional popout window content
-- `popoutWidth`: Popout window width
-- `popoutHeight`: Popout window height
-- `pillClickAction`: Custom click handler function (overrides popout)
-- `pillRightClickAction`: Custom right click handler function
-
-### Control Center Integration
-
-Add your plugin to Control Center by defining CC properties:
-
-```qml
-PluginComponent {
- ccWidgetIcon: "toggle_on"
- ccWidgetPrimaryText: "My Feature"
- ccWidgetSecondaryText: isEnabled ? "Active" : "Inactive"
- ccWidgetIsActive: isEnabled
-
- onCcWidgetToggled: {
- isEnabled = !isEnabled
- if (pluginService) {
- pluginService.savePluginData("myPlugin", "isEnabled", isEnabled)
- }
- }
-
- ccDetailContent: Component {
- Rectangle {
- implicitHeight: 200
- color: Theme.surfaceContainerHigh
- radius: Theme.cornerRadius
- // Your detail UI here
- }
- }
-
- horizontalBarPill: Component { /* ... */ }
-}
-```
-
-**CC Properties:**
-- `ccWidgetIcon`: Material icon name
-- `ccWidgetPrimaryText`: Main label
-- `ccWidgetSecondaryText`: Subtitle/status
-- `ccWidgetIsActive`: Active state styling
-- `ccDetailContent`: Optional dropdown panel (use for CompoundPill)
-
-**Signals:**
-- `ccWidgetToggled()`: Fired when icon clicked
-- `ccWidgetExpanded()`: Fired when expand area clicked (CompoundPill only)
-
-**Widget Sizing:**
-- 25% width → SmallToggleButton (icon only)
-- 50% width → ToggleButton (no detail) or CompoundPill (with detail)
-- Users can resize in edit mode
-
-**Custom Click Actions:**
-
-Override default popout with `pillClickAction` and `pillRightClickAction`:
-
-```qml
-pillClickAction: () => {
- Process.exec("bash", ["-c", "notify-send 'Clicked!'"])
-}
-
-// Or with position params: (x, y, width, section, screen)
-pillClickAction: (x, y, width, section, screen) => {
- popoutService?.toggleControlCenter(x, y, width, section, screen)
-}
-
-pillRightClickAction: () => {
- Process.exec("bash", ["-c", "notify-send 'Right clicked!'"])
-}
-
-pillRightClickAction: (x, y, width, section, screen) => {
- popoutService?.toggleControlCenter(x, y, width, section, screen)
-}
-```
-
-The PluginComponent automatically handles:
-- Bar orientation detection
-- Click handlers for popouts
-- Proper positioning and anchoring
-- Theme integration
-
-### PopoutComponent
-
-PopoutComponent provides a consistent header/content layout for plugin popouts:
-
-```qml
-import qs.Modules.Plugins
-
-PopoutComponent {
- headerText: "Header Title" // Main header text (bold, large)
- detailsText: "Description text" // Optional description (smaller, gray)
- showCloseButton: true // Show X button in top-right
-
- // Access to exposed properties for dynamic sizing
- readonly property int headerHeight // Height of header area
- readonly property int detailsHeight // Height of description area
-
- // Your content here - use parent.width for full width
- // Calculate available height: root.popoutHeight - headerHeight - detailsHeight - spacing
- DankGridView {
- width: parent.width
- height: parent.height
- // ...
- }
-}
-```
-
-**PopoutComponent Properties:**
-- `headerText`: Main header text (optional, hidden if empty)
-- `detailsText`: Description text below header (optional, hidden if empty)
-- `showCloseButton`: Show close button in header (default: false)
-- `closePopout`: Function to close popout (auto-injected by PluginPopout)
-- `headerHeight`: Readonly height of header (0 if not visible)
-- `detailsHeight`: Readonly height of description (0 if not visible)
-
-The component automatically handles spacing and layout. Content children are rendered below the description with proper padding.
-
-### Settings Component
-
-Optional settings UI loaded inline in the PluginsTab accordion interface. Use the simplified settings API with auto-storage components:
-
-```qml
-import QtQuick
-import qs.Common
-import qs.Widgets
-import qs.Modules.Plugins
-
-PluginSettings {
- id: root
- pluginId: "yourPlugin"
-
- StringSetting {
- settingKey: "apiKey"
- label: "API Key"
- description: "Your API key for accessing the service"
- placeholder: "Enter API key..."
- }
-
- ToggleSetting {
- settingKey: "notifications"
- label: "Enable Notifications"
- description: "Show desktop notifications for updates"
- defaultValue: true
- }
-
- SelectionSetting {
- settingKey: "updateInterval"
- label: "Update Interval"
- description: "How often to refresh data"
- options: [
- {label: "1 minute", value: "60"},
- {label: "5 minutes", value: "300"},
- {label: "15 minutes", value: "900"}
- ]
- defaultValue: "300"
- }
-
- ListSetting {
- id: itemList
- settingKey: "items"
- label: "Saved Items"
- description: "List of configured items"
- delegate: Component {
- StyledRect {
- width: parent.width
- height: 40
- radius: Theme.cornerRadius
- color: Theme.surfaceContainerHigh
-
- StyledText {
- anchors.left: parent.left
- anchors.leftMargin: Theme.spacingM
- anchors.verticalCenter: parent.verticalCenter
- text: modelData.name
- color: Theme.surfaceText
- }
-
- Rectangle {
- anchors.right: parent.right
- anchors.rightMargin: Theme.spacingM
- anchors.verticalCenter: parent.verticalCenter
- width: 60
- height: 28
- color: removeArea.containsMouse ? Theme.errorHover : Theme.error
- radius: Theme.cornerRadius
-
- StyledText {
- anchors.centerIn: parent
- text: "Remove"
- color: Theme.errorText
- font.pixelSize: Theme.fontSizeSmall
- font.weight: Font.Medium
- }
-
- MouseArea {
- id: removeArea
- anchors.fill: parent
- hoverEnabled: true
- cursorShape: Qt.PointingHandCursor
- onClicked: itemList.removeItem(index)
- }
- }
- }
- }
- }
-}
-```
-
-**Available Setting Components:**
-
-All settings automatically save on change and load on component creation.
-
-**How Default Values Work:**
-
-Each setting component has a `defaultValue` property that is used when no saved value exists. Define sensible defaults in your settings UI:
-
-```qml
-StringSetting {
- settingKey: "apiKey"
- defaultValue: "" // Empty string if no key saved
-}
-
-ToggleSetting {
- settingKey: "enabled"
- defaultValue: true // Enabled by default
-}
-
-ListSettingWithInput {
- settingKey: "locations"
- defaultValue: [] // Empty array if no locations saved
-}
-```
-
-1. **PluginSettings** - Root wrapper for all plugin settings
- - `pluginId`: Your plugin ID (required)
- - Auto-handles storage and provides saveValue/loadValue to children
- - Place all other setting components inside this wrapper
-
-2. **StringSetting** - Text input field
- - `settingKey`: Storage key (required)
- - `label`: Display label (required)
- - `description`: Help text (optional)
- - `placeholder`: Input placeholder (optional)
- - `defaultValue`: Default value (optional, default: `""`)
- - Layout: Vertical stack (label, description, input field)
-
-3. **ToggleSetting** - Boolean toggle switch
- - `settingKey`: Storage key (required)
- - `label`: Display label (required)
- - `description`: Help text (optional)
- - `defaultValue`: Default boolean (optional, default: `false`)
- - Layout: Horizontal (label/description left, toggle right)
-
-4. **SelectionSetting** - Dropdown menu
- - `settingKey`: Storage key (required)
- - `label`: Display label (required)
- - `description`: Help text (optional)
- - `options`: Array of `{label, value}` objects or simple strings (required)
- - `defaultValue`: Default value (optional, default: `""`)
- - Layout: Horizontal (label/description left, dropdown right)
- - Stores the `value` field, displays the `label` field
-
-5. **ListSetting** - Manage list of items (manual add/remove)
- - `settingKey`: Storage key (required)
- - `label`: Display label (required)
- - `description`: Help text (optional)
- - `defaultValue`: Default array (optional, default: `[]`)
- - `delegate`: Custom item delegate Component (optional)
- - `addItem(item)`: Add item to list
- - `removeItem(index)`: Remove item from list
- - Use when you need custom UI for adding items
-
-6. **ListSettingWithInput** - Complete list management with built-in form
- - `settingKey`: Storage key (required)
- - `label`: Display label (required)
- - `description`: Help text (optional)
- - `defaultValue`: Default array (optional, default: `[]`)
- - `fields`: Array of field definitions (required)
- - `id`: Field ID in saved object (required)
- - `label`: Column header text (required)
- - `placeholder`: Input placeholder (optional)
- - `width`: Column width in pixels (optional, default 200)
- - `required`: Must have value to add (optional, default false)
- - `default`: Default value if empty (optional)
- - Automatically generates:
- - Column headers from field labels
- - Input fields with placeholders
- - Add button with validation
- - List display showing all field values
- - Remove buttons for each item
- - Best for collecting structured data (servers, locations, etc.)
-
-**Complete Settings Example:**
-
-```qml
-import QtQuick
-import qs.Common
-import qs.Widgets
-import qs.Modules.Plugins
-
-PluginSettings {
- pluginId: "myPlugin"
-
- StyledText {
- width: parent.width
- text: "General Settings"
- font.pixelSize: Theme.fontSizeLarge
- font.weight: Font.Bold
- color: Theme.surfaceText
- }
-
- StringSetting {
- settingKey: "apiKey"
- label: "API Key"
- description: "Your service API key"
- placeholder: "sk-..."
- defaultValue: ""
- }
-
- ToggleSetting {
- settingKey: "enabled"
- label: "Enable Feature"
- description: "Turn this feature on or off"
- defaultValue: true
- }
-
- SelectionSetting {
- settingKey: "theme"
- label: "Theme"
- description: "Choose your preferred theme"
- options: [
- {label: "Dark", value: "dark"},
- {label: "Light", value: "light"},
- {label: "Auto", value: "auto"}
- ]
- defaultValue: "dark"
- }
-
- ListSettingWithInput {
- settingKey: "locations"
- label: "Locations"
- description: "Track multiple locations"
- defaultValue: []
- fields: [
- {id: "name", label: "Name", placeholder: "Home", width: 150, required: true},
- {id: "timezone", label: "Timezone", placeholder: "America/New_York", width: 200, required: true}
- ]
- }
-}
-```
-
-**Key Benefits:**
-- Zero boilerplate - just define your settings
-- Automatic persistence to `settings.json`
-- Clean, consistent UI across all plugins
-- No manual `pluginService` calls needed
-- Proper layout and spacing handled automatically
-
-## PluginService API
-
-### Properties
-
-```qml
-PluginService.pluginDirectory: string
-// Path to plugins directory ($CONFIGPATH/DankMaterialShell/plugins)
-
-PluginService.availablePlugins: object
-// Map of all discovered plugins {pluginId: pluginInfo}
-
-PluginService.loadedPlugins: object
-// Map of currently loaded plugins {pluginId: pluginInfo}
-
-PluginService.pluginWidgetComponents: object
-// Map of loaded widget components {pluginId: Component}
-```
-
-### Functions
-
-```qml
-// Plugin Management
-PluginService.loadPlugin(pluginId: string): bool
-PluginService.unloadPlugin(pluginId: string): bool
-PluginService.reloadPlugin(pluginId: string): bool
-PluginService.enablePlugin(pluginId: string): bool
-PluginService.disablePlugin(pluginId: string): bool
-
-// Plugin Discovery
-PluginService.scanPlugins(): void
-PluginService.getAvailablePlugins(): array
-PluginService.getLoadedPlugins(): array
-PluginService.isPluginLoaded(pluginId: string): bool
-PluginService.getWidgetComponents(): object
-
-// Data Persistence
-PluginService.savePluginData(pluginId: string, key: string, value: any): bool
-PluginService.loadPluginData(pluginId: string, key: string, defaultValue: any): any
-
-// Global Variables - Shared state across all plugin instances
-PluginService.getGlobalVar(pluginId: string, varName: string, defaultValue: any): any
-PluginService.setGlobalVar(pluginId: string, varName: string, value: any): void
-```
-
-### Signals
-
-```qml
-PluginService.pluginLoaded(pluginId: string)
-PluginService.pluginUnloaded(pluginId: string)
-PluginService.pluginLoadFailed(pluginId: string, error: string)
-PluginService.globalVarChanged(pluginId: string, varName: string)
-```
-
-## Plugin Global Variables
-
-Plugins can share state across multiple instances using global variables. This is useful when you have the same widget displayed on multiple monitors or multiple instances of the same widget on different bars.
-
-### Why Use Global Variables?
-
-Unlike regular properties which are scoped to each component instance, global variables are synchronized across all instances of your plugin. This enables:
-
-- **Multi-monitor consistency**: Same data displayed across all monitors
-- **Multi-instance widgets**: Multiple instances of the same widget sharing state
-- **Cross-component communication**: Share data between widget and settings components
-
-### Using PluginGlobalVar
-
-The `PluginGlobalVar` helper component provides reactive global variable access:
-
-```qml
-import QtQuick
-import qs.Widgets
-import qs.Modules.Plugins
-
-PluginComponent {
- PluginGlobalVar {
- id: globalCounter
- varName: "counter"
- defaultValue: 0
- }
-
- horizontalBarPill: Component {
- StyledRect {
- width: content.implicitWidth + Theme.spacingM * 2
- height: parent.widgetThickness
- radius: Theme.cornerRadius
- color: Theme.surfaceContainerHigh
-
- StyledText {
- id: content
- anchors.centerIn: parent
- text: "Count: " + globalCounter.value
- color: Theme.surfaceText
- }
-
- MouseArea {
- anchors.fill: parent
- onClicked: globalCounter.set(globalCounter.value + 1)
- }
- }
- }
-}
-```
-
-**PluginGlobalVar Properties:**
-- `varName` (required): Name of the global variable
-- `defaultValue` (optional): Default value if not set
-- `value` (readonly): Current value of the global variable
-
-**PluginGlobalVar Methods:**
-- `set(newValue)`: Update the global variable (triggers reactivity across all instances)
-
-### Using PluginService API Directly
-
-For more control, use the PluginService API directly:
-
-```qml
-import QtQuick
-import qs.Services
-import qs.Modules.Plugins
-
-PluginComponent {
- property int counter: PluginService.getGlobalVar("myPlugin", "counter", 0)
-
- Connections {
- target: PluginService
- function onGlobalVarChanged(pluginId, varName) {
- if (pluginId === "myPlugin" && varName === "counter") {
- counter = PluginService.getGlobalVar("myPlugin", "counter", 0)
- }
- }
- }
-
- horizontalBarPill: Component {
- StyledRect {
- MouseArea {
- anchors.fill: parent
- onClicked: {
- const current = PluginService.getGlobalVar("myPlugin", "counter", 0)
- PluginService.setGlobalVar("myPlugin", "counter", current + 1)
- }
- }
- }
- }
-}
-```
-
-### Global Variables vs Settings
-
-**Global Variables** (`getGlobalVar`/`setGlobalVar`):
-- Runtime state only (not persisted to disk)
-- Synchronized across all plugin instances
-- Changes trigger `globalVarChanged` signal for reactivity
-- Use for: counters, current selection, temporary UI state
-
-**Settings** (`savePluginData`/`loadPluginData`):
-- Persisted to `settings.json` across sessions
-- Loaded once per plugin instance
-- Use for: user preferences, API keys, configuration
-
-### Important Notes
-
-1. **Reactivity**: Global variables are reactive - all instances update when a value changes
-2. **Namespacing**: Variables are namespaced by plugin ID to avoid conflicts
-3. **Type Safety**: Values can be any QML/JavaScript type (numbers, strings, objects, arrays)
-4. **Not Persistent**: Global variables are cleared when the shell restarts (use settings for persistence)
-5. **Performance**: Efficient for frequent updates - changes only trigger updates for the specific variable
-
-## Creating a Plugin
-
-### Step 1: Create Plugin Directory
-
-```bash
-mkdir -p $CONFIGPATH/DankMaterialShell/plugins/MyPlugin
-cd $CONFIGPATH/DankMaterialShell/plugins/MyPlugin
-```
-
-### Step 2: Create Manifest
-
-Create `plugin.json`:
-
-```json
-{
- "id": "myPlugin",
- "name": "My Plugin",
- "description": "A sample plugin",
- "version": "1.0.0",
- "author": "Your Name",
- "type": "widget",
- "capabilities": ["my-functionality"],
- "component": "./MyWidget.qml",
- "icon": "extension",
- "settings": "./MySettings.qml",
- "requires_dms": ">=0.1.0",
- "permissions": ["settings_read", "settings_write"]
-}
-```
-
-### Step 3: Create Widget Component
-
-Create `MyWidget.qml`:
-
-```qml
-import QtQuick
-import qs.Common
-import qs.Widgets
-import qs.Modules.Plugins
-
-PluginComponent {
- horizontalBarPill: Component {
- StyledRect {
- width: textItem.implicitWidth + Theme.spacingM * 2
- height: parent.widgetThickness
- radius: Theme.cornerRadius
- color: Theme.surfaceContainerHigh
-
- StyledText {
- id: textItem
- anchors.centerIn: parent
- text: "Hello World"
- color: Theme.surfaceText
- font.pixelSize: Theme.fontSizeMedium
- }
- }
- }
-
- verticalBarPill: Component {
- StyledRect {
- width: parent.widgetThickness
- height: textItem.implicitWidth + Theme.spacingM * 2
- radius: Theme.cornerRadius
- color: Theme.surfaceContainerHigh
-
- StyledText {
- id: textItem
- anchors.centerIn: parent
- text: "Hello"
- color: Theme.surfaceText
- font.pixelSize: Theme.fontSizeSmall
- rotation: 90
- }
- }
- }
-}
-```
-
-**Note:** Use `PluginComponent` wrapper for automatic property injection and bar integration. Define separate components for horizontal and vertical orientations.
-
-### Step 4: Create Settings Component (Optional)
-
-Create `MySettings.qml`:
-
-```qml
-import QtQuick
-import qs.Common
-import qs.Widgets
-import qs.Modules.Plugins
-
-PluginSettings {
- pluginId: "myPlugin"
-
- StyledText {
- width: parent.width
- text: "Configure your plugin settings"
- font.pixelSize: Theme.fontSizeMedium
- color: Theme.surfaceVariantText
- wrapMode: Text.WordWrap
- }
-
- StringSetting {
- settingKey: "text"
- label: "Display Text"
- description: "Text shown in the bar widget"
- placeholder: "Hello World"
- defaultValue: "Hello World"
- }
-
- ToggleSetting {
- settingKey: "showIcon"
- label: "Show Icon"
- description: "Display an icon next to the text"
- defaultValue: true
- }
-}
-```
-
-### Step 5: Enable Plugin
-
-1. Run the shell: `qs -p $CONFIGPATH/quickshell/dms/shell.qml`
-2. Open Settings (Ctrl+,)
-3. Navigate to Plugins tab
-4. Click "Scan for Plugins"
-5. Enable your plugin with the toggle switch
-6. Add the plugin to your DankBar configuration
-
-## Adding Plugin to DankBar
-
-After enabling a plugin, add it to the bar:
-
-1. Open Settings → Appearance → DankBar Layout
-2. Add a new widget entry with your plugin ID
-3. Choose section (left, center, right)
-4. Save and reload
-
-Or edit `$CONFIGPATH/quickshell/dms/config.json`:
-
-```json
-{
- "dankBarLeftWidgets": [
- {"widgetId": "myPlugin", "enabled": true}
- ]
-}
-```
-
-## Best Practices
-
-1. **Use Existing Widgets**: Leverage `qs.Widgets` components (DankIcon, DankToggle, etc.) for consistency
-2. **Follow Theme**: Use `Theme` singleton for colors, spacing, and fonts
-3. **Data Persistence**: Use PluginService data APIs instead of manual file operations
-4. **Error Handling**: Gracefully handle missing dependencies and invalid data
-5. **Performance**: Keep widgets lightweight, avoid long operations that block the UI loop
-6. **Responsive Design**: Adapt to `compactMode` and different screen sizes
-7. **Documentation**: Include README.md explaining plugin usage
-8. **Versioning**: Use semantic versioning for updates
-9. **Dependencies**: Document external library requirements
-
-## Clipboard Access
-
-Plugins that need to copy text to the clipboard should use the built-in `dms cl copy` command through Quickshell's `execDetached` function.
-
-### Correct Method
-
-Import Quickshell and use `execDetached` with `dms cl copy`:
-
-```qml
-import QtQuick
-import Quickshell
-
-Item {
- function copyToClipboard(text) {
- Quickshell.execDetached(["dms", "cl", "copy", text])
- }
-}
-```
-
-### Example Usage
-
-From the ExampleEmojiPlugin (EmojiWidget.qml):
-
-```qml
-MouseArea {
- onClicked: {
- Quickshell.execDetached(["dms", "cl", "copy", modelData])
- ToastService.showInfo("Copied " + modelData + " to clipboard")
- popoutColumn.closePopout()
- }
-}
-```
-
-### Important Notes
-
-1. **Do NOT** use `globalThis.clipboard` or similar JavaScript APIs - they don't exist in the QML runtime
-2. **Always** import `Quickshell` at the top of your QML file
-3. Consider showing a toast notification to confirm the copy action to users
-
-### Dependencies
-
-This method uses the built-in DMS clipboard functionality which has native Wayland support.
-
-## Running External Commands
-
-Plugins that need to execute external commands and capture their output should use the `Proc` singleton, which provides debounced command execution with automatic cleanup.
-
-### Correct Method
-
-Import the `Proc` singleton from `qs.Common` and use `runCommand`:
-
-```qml
-import QtQuick
-import qs.Common
-
-Item {
- function fetchData() {
- Proc.runCommand(
- "myPlugin.fetchData",
- ["curl", "-s", "https://api.example.com/data"],
- (stdout, exitCode) => {
- if (exitCode === 0) {
- console.log("Success:", stdout)
- processData(stdout)
- } else {
- console.error("Command failed with exit code:", exitCode)
- }
- },
- 100
- )
- }
-}
-```
-
-### Function Signature
-
-```qml
-Proc.runCommand(id, command, callback, debounceMs)
-```
-
-**Parameters:**
-- `id` (string): Unique identifier for this command. Used for debouncing - multiple calls with the same ID within the debounce window will only execute the last one
-- `command` (array): Command and arguments as an array (e.g., `["sh", "-c", "echo hello"]`)
-- `callback` (function): Callback function receiving `(stdout, exitCode)` when the command completes
- - `stdout` (string): Captured standard output from the command
- - `exitCode` (number): Exit code of the process (0 typically means success)
-- `debounceMs` (number, optional): Debounce delay in milliseconds. Defaults to 50ms if not specified
-
-### Key Features
-
-1. **Automatic Cleanup**: Process objects are automatically destroyed after completion
-2. **Debouncing**: Rapid successive calls with the same ID are debounced, only executing the last one
-3. **Output Capture**: Automatically captures stdout for processing
-4. **Error Handling**: Exit codes are passed to the callback for error detection
-
-### Example Usage
-
-#### Simple Command Execution
-
-```qml
-import QtQuick
-import qs.Common
-
-Item {
- function checkNetwork() {
- Proc.runCommand(
- "myPlugin.ping",
- ["ping", "-c", "1", "8.8.8.8"],
- (output, exitCode) => {
- if (exitCode === 0) {
- console.log("Network is up")
- } else {
- console.log("Network is down")
- }
- }
- )
- }
-}
-```
-
-#### Parsing Command Output
-
-```qml
-import QtQuick
-import qs.Common
-
-Item {
- property var diskUsage: ({})
-
- function updateDiskUsage() {
- Proc.runCommand(
- "myPlugin.df",
- ["df", "-h", "/home"],
- (output, exitCode) => {
- if (exitCode === 0) {
- const lines = output.trim().split("\n")
- if (lines.length > 1) {
- const parts = lines[1].split(/\s+/)
- diskUsage = {
- total: parts[1],
- used: parts[2],
- available: parts[3],
- percent: parts[4]
- }
- }
- }
- }
- )
- }
-}
-```
-
-#### Shell Commands with Pipes
-
-```qml
-import QtQuick
-import qs.Common
-
-Item {
- function getTopProcess() {
- Proc.runCommand(
- "myPlugin.topProcess",
- ["sh", "-c", "ps aux | sort -nrk 3,3 | head -n 1"],
- (output, exitCode) => {
- if (exitCode === 0) {
- console.log("Top process:", output)
- }
- }
- )
- }
-}
-```
-
-#### Debouncing Rapid Updates
-
-```qml
-import QtQuick
-import qs.Common
-import qs.Widgets
-
-Item {
- DankTextField {
- id: searchField
- placeholderText: "Search files..."
-
- onTextChanged: {
- Proc.runCommand(
- "myPlugin.search",
- ["find", "/home", "-name", "*" + text + "*"],
- (output, exitCode) => {
- if (exitCode === 0) {
- updateSearchResults(output)
- }
- },
- 500
- )
- }
- }
-}
-```
-
-### Important Notes
-
-1. **Unique IDs**: Use descriptive, namespaced IDs (e.g., `"myPlugin.actionName"`) to avoid conflicts
-2. **Debouncing**: Use appropriate debounce delays for your use case:
- - Fast updates (50-100ms): System monitoring, real-time data
- - User input (300-500ms): Search fields, text input processing
- - Network requests (500-1000ms): API calls, web scraping
-3. **Error Handling**: Always check the exit code in your callback before processing output
-4. **Shell Commands**: Use `["sh", "-c", "command"]` for complex shell commands with pipes or redirects
-5. **Security**: Sanitize user input before passing to commands to prevent command injection
-6. **Performance**: Avoid running expensive commands too frequently - use debouncing wisely
-
-### Comparison with Other Methods
-
-**Proc.runCommand** vs **Quickshell.execDetached**:
-- Use `Proc.runCommand` when you need to capture output or check exit codes
-- Use `Quickshell.execDetached` for fire-and-forget operations (like clipboard copy)
-
-**Proc.runCommand** vs **Process component**:
-- Use `Proc.runCommand` for simple, one-off command executions with automatic cleanup
-- Use `Process` component for long-running processes or when you need fine-grained control
-
-## Debugging
-
-### Console Logging
-
-View plugin logs:
-
-```bash
-qs -v -p $CONFIGPATH/quickshell/dms/shell.qml
-```
-
-Look for lines prefixed with:
-- `PluginService:` - Service operations
-- `PluginsTab:` - UI interactions
-- `PluginsTab:` - Settings loading and accordion interface
-
-### Common Issues
-
-1. **Plugin Not Detected**
- - Check plugin.json syntax (use `jq` or JSON validator)
- - Verify directory is in `$CONFIGPATH/DankMaterialShell/plugins/`
- - Click "Scan for Plugins" in Settings
-
-2. **Widget Not Displaying**
- - Ensure plugin is enabled in Settings
- - Add plugin ID to DankBar widget list
- - Check widget width/height properties
-
-3. **Settings Not Loading**
- - Verify `settings` path in plugin.json
- - Check settings component for errors
- - Ensure plugin is enabled and loaded
- - Review PluginsTab console output for injection issues
-
-4. **Data Not Persisting**
- - Confirm pluginService.savePluginData() calls (with injection)
- - Check `$CONFIGPATH/DankMaterialShell/settings.json` for pluginSettings data
- - Verify plugin has settings permissions
- - Ensure PluginService was properly injected into settings component
-
-## Security Considerations
-
-Plugins run with full QML runtime access. Only install plugins from trusted sources.
-
-**Permissions System:**
-- `settings_read`: Read plugin configuration (not currently enforced)
-- `settings_write`: **Required** to use PluginSettings - write plugin configuration (enforced)
-- `process`: Execute system commands (not currently enforced)
-- `network`: Network access (not currently enforced)
-
-Currently, only `settings_write` is enforced by the PluginSettings component.
-
-## API Stability
-
-The plugin API is currently **experimental**. Breaking changes may occur in minor version updates. Pin to specific DMS versions for production use.
-
-**Roadmap:**
-- Plugin marketplace/repository
-- Sandboxed plugin execution
-- Enhanced permission system
-- Plugin update notifications
-- Inter-plugin communication
-
-## Launcher Plugins
-
-Launcher plugins extend the DMS application launcher by adding custom searchable items with trigger-based filtering.
-
-### Overview
-
-Launcher plugins enable you to:
-- Add custom items to the launcher/app drawer
-- Use trigger strings for quick filtering (e.g., `!`, `#`, `@`)
-- Execute custom actions when items are selected
-- Provide searchable, categorized content
-- Integrate seamlessly with the existing launcher
-
-### Plugin Type Configuration
-
-To create a launcher plugin, set the plugin type in `plugin.json`:
-
-```json
-{
- "id": "myLauncher",
- "name": "My Launcher Plugin",
- "description": "A custom launcher plugin for quick actions",
- "version": "1.0.0",
- "author": "Your Name",
- "type": "launcher",
- "capabilities": ["show-thing"],
- "component": "./MyLauncher.qml",
- "trigger": "#",
- "icon": "search",
- "settings": "./MySettings.qml",
- "requires_dms": ">=0.1.18",
- "permissions": ["settings_read", "settings_write"]
-}
-```
-
-### Launcher Component Contract
-
-Create `MyLauncher.qml` with the following interface:
-
-```qml
-import QtQuick
-import qs.Services
-
-Item {
- id: root
-
- // Required properties
- property var pluginService: null
- property string trigger: "#"
-
- // Required signals
- signal itemsChanged()
-
- // Required: Return array of launcher items
- function getItems(query) {
- return [
- {
- name: "Item Name",
- icon: "icon_name",
- comment: "Description",
- action: "type:data",
- categories: ["MyLauncher"]
- }
- ]
- }
-
- // Required: Execute item action
- function executeItem(item) {
- const [type, data] = item.action.split(":", 2)
- // Handle action based on type
- }
-
- Component.onCompleted: {
- if (pluginService) {
- trigger = pluginService.loadPluginData("myLauncher", "trigger", "#")
- }
- }
-}
-```
-
-### Item Structure
-
-Each item returned by `getItems()` must include:
-
-- `name` (string): Display name shown in launcher
-- `icon` (string, optional): Icon specification (see Icon Types below)
-- `comment` (string): Description/subtitle text
-- `action` (string): Action identifier in `type:data` format
-- `categories` (array): Array containing your plugin name
-
-### Icon Types
-
-The `icon` field supports four formats:
-
-**1. Material Design Icons** - Use the `material:` prefix:
-```javascript
-{
- name: "My Item",
- icon: "material:lightbulb", // Material Symbols Rounded font
- comment: "Uses Material Design icon",
- action: "toast:Hello!",
- categories: ["MyPlugin"]
-}
-```
-Available icons: Any icon from Material Symbols font (e.g., `lightbulb`, `star`, `favorite`, `settings`, `terminal`, `translate`, `sentiment_satisfied`)
-
-**2. Unicode/Emoji Icons** - Use the `unicode:` prefix:
-```javascript
-{
- name: "Grinning Face",
- icon: "unicode:😀", // Unicode character or emoji
- comment: "Copy emoji to clipboard",
- action: "copy:😀",
- categories: ["MyPlugin"]
-}
-```
-Display any Unicode character or emoji as the icon. The character is rendered at 70-80% of the icon size with proper theming. Perfect for emoji pickers, symbol selectors, or character libraries.
-
-**3. Desktop Theme Icons** - Use icon name directly:
-```javascript
-{
- name: "Firefox",
- icon: "firefox", // Uses system icon theme
- comment: "Launches Firefox browser",
- action: "exec:firefox",
- categories: ["MyPlugin"]
-}
-```
-Uses the user's installed icon theme. Common examples: `firefox`, `chrome`, `folder`, `text-editor`
-
-**4. No Icon** - Omit the `icon` field entirely:
-```javascript
-{
- name: "😀 Grinning Face",
- // No icon field - emoji/unicode in name displays without icon area
- comment: "Copy emoji to clipboard",
- action: "copy:😀",
- categories: ["MyPlugin"]
-}
-```
-When `icon` is omitted, the launcher hides the icon area and displays only the text, giving full width to the item name. Useful when you want emojis or symbols to be part of the item name itself.
-
-### Trigger System
-
-Triggers control when your plugin's items appear in the launcher:
-
-**Empty Trigger Mode** (No trigger):
-- Items always visible alongside regular apps
-- Search includes your items automatically
-- Configure by saving empty trigger: `trigger: ""`
-
-**Custom Trigger Mode**:
-- Items only appear when trigger is typed
-- Example: Type `#` to show only your plugin's items
-- Type `# query` to search within your plugin
-- Configure any string: `#`, `!`, `@`, `!custom`, etc.
-
-### Trigger Configuration in Settings
-
-Provide a settings component with trigger configuration:
-
-```qml
-import QtQuick
-import QtQuick.Controls
-import qs.Widgets
-
-FocusScope {
- id: root
-
- property var pluginService: null
-
- Column {
- spacing: 12
-
- CheckBox {
- id: noTriggerToggle
- text: "No trigger (always show)"
- checked: loadSettings("noTrigger", false)
-
- onCheckedChanged: {
- saveSettings("noTrigger", checked)
- if (checked) {
- saveSettings("trigger", "")
- } else {
- saveSettings("trigger", triggerField.text || "#")
- }
- }
- }
-
- DankTextField {
- id: triggerField
- visible: !noTriggerToggle.checked
- text: loadSettings("trigger", "#")
- placeholderText: "#"
-
- onTextEdited: {
- saveSettings("trigger", text || "#")
- }
- }
- }
-
- function saveSettings(key, value) {
- if (pluginService) {
- pluginService.savePluginData("myLauncher", key, value)
- }
- }
-
- function loadSettings(key, defaultValue) {
- if (pluginService) {
- return pluginService.loadPluginData("myLauncher", key, defaultValue)
- }
- return defaultValue
- }
-}
-```
-
-### Action Execution
-
-Handle different action types in `executeItem()`:
-
-```qml
-function executeItem(item) {
- const actionParts = item.action.split(":")
- const actionType = actionParts[0]
- const actionData = actionParts.slice(1).join(":")
-
- switch (actionType) {
- case "toast":
- if (typeof ToastService !== "undefined") {
- ToastService.showInfo("Plugin", actionData)
- }
- break
- case "copy":
- // Copy to clipboard
- break
- case "script":
- // Execute command
- break
- default:
- console.warn("Unknown action:", actionType)
- }
-}
-```
-
-### Search and Filtering
-
-The launcher automatically handles search when:
-
-**With empty trigger**:
-- Your items appear in all searches
-- No prefix needed
-
-**With custom trigger**:
-- Type trigger alone: Shows all your items
-- Type trigger + query: Filters your items by query
-- The query parameter is passed to your `getItems(query)` function
-
-Example `getItems()` implementation:
-
-```qml
-function getItems(query) {
- const allItems = [
- {name: "Item 1", ...},
- {name: "Item 2", ...},
- {name: "Test Item", ...}
- ]
-
- if (!query || query.length === 0) {
- return allItems
- }
-
- const lowerQuery = query.toLowerCase()
- return allItems.filter(item => {
- return item.name.toLowerCase().includes(lowerQuery) ||
- item.comment.toLowerCase().includes(lowerQuery)
- })
-}
-```
-
-### Integration Flow
-
-1. User opens launcher
-2. If empty trigger: Your items appear alongside apps
-3. If custom trigger: User types trigger (e.g., `#`)
-4. Launcher calls `getItems(query)` on your plugin
-5. Your items displayed with your plugin's category
-6. User selects item and presses Enter
-7. Launcher calls `executeItem(item)` on your plugin
-
-### Best Practices
-
-1. **Unique Triggers**: Choose non-conflicting trigger strings
-2. **Fast Response**: Return results quickly from `getItems()`
-3. **Clear Names**: Use descriptive item names and comments
-4. **Error Handling**: Gracefully handle failures in `executeItem()`
-5. **Cleanup**: Destroy temporary objects after use
-6. **Empty Trigger Support**: Consider if your plugin benefits from always being visible
-
-### Example Plugin
-
-See `PLUGINS/LauncherExample/` for a complete working example demonstrating:
-- Trigger configuration (including empty trigger mode)
-- Multiple action types (toast, copy, script)
-- Search/filtering implementation
-- Settings integration
-- Proper error handling
-
-## Desktop Plugins
-
-Desktop plugins are widgets that appear directly on the desktop background layer. They can be dragged, resized, and positioned freely by the user.
-
-### Overview
-
-Desktop plugins enable you to:
-- Display widgets on the desktop background
-- Support drag-and-drop positioning
-- Support resize via corner handles
-- Persist position and size across sessions
-- Provide settings for customization
-
-### Plugin Type Configuration
-
-To create a desktop plugin, set the plugin type in `plugin.json`:
-
-```json
-{
- "id": "myDesktopWidget",
- "name": "My Desktop Widget",
- "description": "A custom desktop widget",
- "version": "1.0.0",
- "author": "Your Name",
- "type": "desktop",
- "capabilities": ["desktop-widget"],
- "component": "./MyWidget.qml",
- "icon": "widgets",
- "settings": "./MySettings.qml",
- "permissions": ["settings_read", "settings_write"]
-}
-```
-
-### Desktop Widget Component Contract
-
-Create your widget component (`MyWidget.qml`) with the following interface:
-
-```qml
-import QtQuick
-import qs.Common
-
-Item {
- id: root
-
- // Injected properties (provided by DesktopPluginWrapper)
- property var pluginService: null
- property string pluginId: ""
- property bool editMode: false
- property real widgetWidth: 200
- property real widgetHeight: 200
-
- // Optional: Define minimum size constraints
- property real minWidth: 100
- property real minHeight: 100
-
- // Your widget content
- Rectangle {
- anchors.fill: parent
- radius: Theme.cornerRadius
- color: Theme.surfaceContainer
- opacity: 0.85
-
- // Widget content here
- Text {
- anchors.centerIn: parent
- text: "Hello Desktop!"
- color: Theme.surfaceText
- }
- }
-}
-```
-
-### Injected Properties
-
-Desktop widgets receive these properties automatically:
-
-- `pluginService`: Reference to PluginService for data persistence
-- `pluginId`: The plugin's unique identifier
-- `editMode`: Boolean indicating if the user is in edit mode (dragging/resizing)
-- `widgetWidth`: Current width of the widget container
-- `widgetHeight`: Current height of the widget container
-
-### Optional Properties
-
-Define these properties on your widget to customize behavior:
-
-- `minWidth`: Minimum allowed width (default: 100)
-- `minHeight`: Minimum allowed height (default: 100)
-
-### Loading and Saving Data
-
-Use the injected `pluginService` to persist widget-specific data:
-
-```qml
-property string myValue: pluginService ? pluginService.loadPluginData(pluginId, "myValue", "default") : "default"
-
-Connections {
- target: pluginService
- function onPluginDataChanged(changedPluginId) {
- if (changedPluginId !== pluginId) return;
- root.myValue = pluginService.loadPluginData(pluginId, "myValue", "default");
- }
-}
-
-function saveMyValue(value) {
- if (pluginService) {
- pluginService.savePluginData(pluginId, "myValue", value);
- }
-}
-```
-
-### Position and Size Persistence
-
-Position (`desktopX`, `desktopY`) and size (`desktopWidth`, `desktopHeight`) are automatically persisted by the `DesktopPluginWrapper`. You don't need to handle this in your widget.
-
-### Edit Mode
-
-When `editMode` is true, the user is repositioning or resizing the widget. You can use this to:
-- Show visual indicators
-- Disable interactive elements
-- Display additional controls
-
-```qml
-Rectangle {
- anchors.fill: parent
- border.color: root.editMode ? Theme.primary : "transparent"
- border.width: root.editMode ? 2 : 0
-
- // Content that should be disabled during edit mode
- MouseArea {
- anchors.fill: parent
- enabled: !root.editMode
- onClicked: doSomething()
- }
-}
-```
-
-### Settings Component
-
-Create a settings component using `PluginSettings`:
-
-```qml
-import QtQuick
-import qs.Common
-import qs.Widgets
-import qs.Modules.Plugins
-
-PluginSettings {
- pluginId: "myDesktopWidget"
-
- ToggleSetting {
- settingKey: "showBorder"
- label: "Show Border"
- description: "Display a border around the widget"
- defaultValue: true
- }
-
- SelectionSetting {
- settingKey: "theme"
- label: "Theme"
- options: [
- {label: "Light", value: "light"},
- {label: "Dark", value: "dark"}
- ]
- defaultValue: "dark"
- }
-}
-```
-
-### User Interaction
-
-Desktop widgets support:
-
-1. **Drag**: Click and drag anywhere on the widget (when in edit mode)
-2. **Resize**: Drag the bottom-right corner handle (when in edit mode)
-3. **Edit Mode Toggle**: Click the edit button in the bottom-right corner of the screen
-
-### Example Plugin
-
-See `PLUGINS/ExampleDesktopClock/` for a complete working example demonstrating:
-- Analog and digital clock styles
-- Settings integration
-- Responsive sizing
-- Edit mode handling
-
-## Resources
-
-- **Plugin Schema**: `plugin-schema.json` - JSON Schema for validation
-- **Example Plugins**:
- - [Emoji Picker](./ExampleEmojiPlugin/)
- - [WorldClock](https://github.com/rochacbruno/WorldClock)
- - [LauncherExample](./LauncherExample/)
- - [Calculator](https://github.com/rochacbruno/DankCalculator)
- - [Desktop Clock](./ExampleDesktopClock/)
-- **PluginService**: `Services/PluginService.qml`
-- **Settings UI**: `Modules/Settings/PluginsTab.qml`
-- **DankBar Integration**: `Modules/DankBar/DankBar.qml`
-- **Launcher Integration**: `Modules/AppDrawer/AppLauncher.qml`
-- **Desktop Widget Integration**: `Modules/DesktopWidgetLayer.qml`
-- **Theme Reference**: `Common/Theme.qml`
-- **Widget Library**: `Widgets/`
-
-## Contributing
-
-Share your plugins with the community:
-
-1. Create a public repository with your plugin
-2. Validate your `plugin.json` against `plugin-schema.json`
-3. Include comprehensive README.md
-4. Add example screenshots
-5. Document dependencies and permissions
-
-For plugin system improvements, submit issues or PRs to the main DMS repository.
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/THEME_REFERENCE.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/THEME_REFERENCE.md
deleted file mode 100644
index be1373a..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/THEME_REFERENCE.md
+++ /dev/null
@@ -1,132 +0,0 @@
-# Theme Property Reference for Plugins
-
-Quick reference for commonly used Theme properties in plugin development.
-
-## Font Sizes
-
-```qml
-Theme.fontSizeSmall // 12px (scaled)
-Theme.fontSizeMedium // 14px (scaled)
-Theme.fontSizeLarge // 16px (scaled)
-Theme.fontSizeXLarge // 20px (scaled)
-```
-
-**Note**: These are scaled by `SettingsData.fontScale`
-
-## Icon Sizes
-
-```qml
-Theme.iconSizeSmall // 16px
-Theme.iconSize // 24px (default)
-Theme.iconSizeLarge // 32px
-```
-
-## Spacing
-
-```qml
-Theme.spacingXS // Extra small
-Theme.spacingS // Small
-Theme.spacingM // Medium
-Theme.spacingL // Large
-Theme.spacingXL // Extra large
-```
-
-## Border Radius
-
-```qml
-Theme.cornerRadius // Standard corner radius
-Theme.cornerRadiusSmall // Smaller radius
-Theme.cornerRadiusLarge // Larger radius
-```
-
-## Colors
-
-### Surface Colors
-```qml
-Theme.surface
-Theme.surfaceContainerLow
-Theme.surfaceContainer
-Theme.surfaceContainerHigh
-Theme.surfaceContainerHighest
-```
-
-### Text Colors
-```qml
-Theme.onSurface // Primary text on surface
-Theme.onSurfaceVariant // Secondary text on surface
-Theme.outline // Border/divider color
-```
-
-### Semantic Colors
-```qml
-Theme.primary
-Theme.onPrimary
-Theme.secondary
-Theme.onSecondary
-Theme.error
-Theme.warning
-Theme.success
-```
-
-### Special Functions
-```qml
-Theme.popupBackground() // Popup background with opacity
-```
-
-## Common Patterns
-
-### Icon with Text
-```qml
-DankIcon {
- name: "icon_name"
- color: Theme.onSurface
- font.pixelSize: Theme.iconSize
-}
-
-StyledText {
- text: "Label"
- color: Theme.onSurface
- font.pixelSize: Theme.fontSizeMedium
-}
-```
-
-### Container with Border
-```qml
-Rectangle {
- color: Theme.surfaceContainerHigh
- radius: Theme.cornerRadius
- border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
- border.width: 1
-}
-```
-
-### Hover Effect
-```qml
-MouseArea {
- hoverEnabled: true
- onEntered: parent.color = Qt.lighter(Theme.surfaceContainerHigh, 1.1)
- onExited: parent.color = Theme.surfaceContainerHigh
-}
-```
-
-## Common Mistakes
-
-❌ **Wrong**:
-```qml
-font.pixelSize: Theme.fontSizeS // Property doesn't exist
-font.pixelSize: Theme.iconSizeS // Property doesn't exist
-```
-
-✅ **Correct**:
-```qml
-font.pixelSize: Theme.fontSizeSmall // Use full name
-font.pixelSize: Theme.iconSizeSmall // Use full name
-```
-
-## Checking Available Properties
-
-To see all available Theme properties, check `Common/Theme.qml` or use:
-
-```bash
-grep "property" Common/Theme.qml
-```
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/README.md b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/README.md
deleted file mode 100644
index 159b58d..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/README.md
+++ /dev/null
@@ -1,37 +0,0 @@
-# Wallpaper Watcher Daemon
-
-Run a script whenever your wallpaper changes.
-
-## What it does
-
-This daemon monitors wallpaper changes and executes a script you specify. The new wallpaper path gets passed as the first argument to your script.
-
-## Setup
-
-1. Enable the plugin in Settings → Plugins
-2. Configure the script path in the plugin settings
-3. Make sure your script is executable (`chmod +x /path/to/script.sh`)
-
-## Example script
-
-```bash
-#!/bin/bash
-echo "New wallpaper: $1"
-# Do something with the wallpaper path
-```
-
-Save this to a file, make it executable, and point the plugin to it.
-
-## Use cases
-
-- Generate color schemes from the new wallpaper
-- Update theme files based on wallpaper colors
-- Send notifications when wallpaper changes
-- Sync wallpaper info to other devices
-- Log wallpaper history
-
-## Notes
-
-- Script errors show up as toast notifications
-- Script output goes to console logs
-- The daemon runs invisibly in the background
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/WallpaperWatcherDaemon.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/WallpaperWatcherDaemon.qml
deleted file mode 100644
index ffed6c1..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/WallpaperWatcherDaemon.qml
+++ /dev/null
@@ -1,66 +0,0 @@
-import QtQuick
-import Quickshell
-import Quickshell.Io
-import qs.Common
-import qs.Services
-import qs.Modules.Plugins
-
-PluginComponent {
- id: root
-
- property string scriptPath: pluginData.scriptPath || ""
- property var popoutService: null
-
- Connections {
- target: SessionData
- function onWallpaperPathChanged() {
- if (scriptPath) {
- var scriptProcess = scriptProcessComponent.createObject(root, {
- wallpaperPath: SessionData.wallpaperPath
- })
- scriptProcess.running = true
- }
- }
- }
-
- Component {
- id: scriptProcessComponent
-
- Process {
- property string wallpaperPath: ""
-
- command: [scriptPath, wallpaperPath]
-
- stdout: StdioCollector {
- onStreamFinished: {
- if (text.trim()) {
- console.log("WallpaperWatcherDaemon script output:", text.trim())
- }
- }
- }
-
- stderr: StdioCollector {
- onStreamFinished: {
- if (text.trim()) {
- ToastService.showError("Wallpaper Change Script Error", text.trim())
- }
- }
- }
-
- onExited: (exitCode) => {
- if (exitCode !== 0) {
- ToastService.showError("Wallpaper Change Script Error", "Script exited with code: " + exitCode)
- }
- destroy()
- }
- }
- }
-
- Component.onCompleted: {
- console.info("WallpaperWatcherDaemon: Started monitoring wallpaper changes")
- }
-
- Component.onDestruction: {
- console.info("WallpaperWatcherDaemon: Stopped monitoring wallpaper changes")
- }
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/WallpaperWatcherSettings.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/WallpaperWatcherSettings.qml
deleted file mode 100644
index 5f8c2c0..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/WallpaperWatcherSettings.qml
+++ /dev/null
@@ -1,24 +0,0 @@
-import QtQuick
-import qs.Common
-import qs.Widgets
-import qs.Modules.Plugins
-
-PluginSettings {
- id: root
- pluginId: "wallpaperWatcherDaemon"
-
- StyledText {
- text: "Wallpaper Change Hook"
- font.pixelSize: Theme.fontSizeLarge
- font.weight: Font.Bold
- color: Theme.surfaceText
- }
-
- StringSetting {
- settingKey: "scriptPath"
- label: "Script Path"
- description: "Path to a script that will be executed when the wallpaper changes. The new wallpaper path will be passed as the first argument."
- placeholder: "/path/to/your/script.sh"
- defaultValue: ""
- }
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/plugin.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/plugin.json
deleted file mode 100644
index 6e08395..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/WallpaperWatcherDaemon/plugin.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "id": "wallpaperWatcherDaemon",
- "name": "Wallpaper Watcher Daemon",
- "description": "Background daemon that monitors wallpaper changes and logs them",
- "version": "1.0.0",
- "author": "DankMaterialShell",
- "type": "daemon",
- "capabilities": ["wallpaper", "monitoring"],
- "component": "./WallpaperWatcherDaemon.qml",
- "icon": "wallpaper",
- "settings": "./WallpaperWatcherSettings.qml",
- "permissions": [
- "settings_read",
- "settings_write"
- ]
-}
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/plugin-schema.json b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/plugin-schema.json
deleted file mode 100644
index 2f7e172..0000000
--- a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/PLUGINS/plugin-schema.json
+++ /dev/null
@@ -1,115 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "$id": "https://danklinux.com/schemas/plugin.json",
- "title": "DankMaterialShell Plugin Manifest",
- "description": "Schema for DankMaterialShell plugin.json manifest files",
- "type": "object",
- "required": [
- "id",
- "name",
- "description",
- "version",
- "author",
- "type",
- "capabilities",
- "component"
- ],
- "properties": {
- "id": {
- "type": "string",
- "description": "Unique plugin identifier (camelCase, no spaces)",
- "pattern": "^[a-zA-Z][a-zA-Z0-9]*$"
- },
- "name": {
- "type": "string",
- "description": "Human-readable plugin name",
- "minLength": 1
- },
- "description": {
- "type": "string",
- "description": "Short description of plugin functionality",
- "minLength": 1
- },
- "version": {
- "type": "string",
- "description": "Semantic version string (e.g., '1.0.0')",
- "pattern": "^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?(\\+[a-zA-Z0-9.-]+)?$"
- },
- "author": {
- "type": "string",
- "description": "Plugin creator name or email",
- "minLength": 1
- },
- "type": {
- "type": "string",
- "description": "Plugin type",
- "enum": ["widget", "daemon", "launcher", "desktop"]
- },
- "capabilities": {
- "type": "array",
- "description": "Array of plugin capabilities",
- "items": {
- "type": "string"
- },
- "minItems": 1
- },
- "component": {
- "type": "string",
- "description": "Relative path to main QML component file",
- "pattern": "^\\./.*\\.qml$"
- },
- "trigger": {
- "type": "string",
- "description": "Trigger string for launcher activation (required for launcher type)"
- },
- "icon": {
- "type": "string",
- "description": "Material Design icon name"
- },
- "settings": {
- "type": "string",
- "description": "Path to settings component QML file",
- "pattern": "^\\./.*\\.qml$"
- },
- "requires_dms": {
- "type": "string",
- "description": "Minimum DMS version requirement (e.g., '>=0.1.18', '>0.1.0')",
- "pattern": "^(>=?|<=?|=|>|<)\\d+\\.\\d+\\.\\d+$"
- },
- "requires": {
- "type": "array",
- "description": "Array of required system tools/dependencies",
- "items": {
- "type": "string"
- }
- },
- "permissions": {
- "type": "array",
- "description": "Required capabilities",
- "items": {
- "type": "string",
- "enum": [
- "settings_read",
- "settings_write",
- "process",
- "network"
- ]
- }
- }
- },
- "allOf": [
- {
- "if": {
- "properties": {
- "type": {
- "const": "launcher"
- }
- }
- },
- "then": {
- "required": ["trigger"]
- }
- }
- ],
- "additionalProperties": true
-}