diff --git a/.config/quickshell/modules/common/functions/string_utils.js b/.config/quickshell/modules/common/functions/string_utils.js index 3251b457..13635500 100644 --- a/.config/quickshell/modules/common/functions/string_utils.js +++ b/.config/quickshell/modules/common/functions/string_utils.js @@ -91,4 +91,21 @@ function splitMarkdownBlocks(markdown) { function escapeBackslashes(str) { return str.replace(/\\/g, '\\\\'); +} + +function wordWrap(str, maxLen) { + if (!str) return ""; + let words = str.split(" "); + let lines = []; + let current = ""; + for (let i = 0; i < words.length; ++i) { + if ((current + (current.length > 0 ? " " : "") + words[i]).length > maxLen) { + if (current.length > 0) lines.push(current); + current = words[i]; + } else { + current += (current.length > 0 ? " " : "") + words[i]; + } + } + if (current.length > 0) lines.push(current); + return lines.join("\n"); } \ No newline at end of file diff --git a/.config/quickshell/modules/sidebarLeft/anime/BooruImage.qml b/.config/quickshell/modules/sidebarLeft/anime/BooruImage.qml index 1efe1010..673fc7b9 100644 --- a/.config/quickshell/modules/sidebarLeft/anime/BooruImage.qml +++ b/.config/quickshell/modules/sidebarLeft/anime/BooruImage.qml @@ -7,6 +7,7 @@ import Qt.labs.platform import QtQuick import QtQuick.Controls import QtQuick.Layouts +import Quickshell import Quickshell.Io import Quickshell.Hyprland import Qt5Compat.GraphicalEffects @@ -21,9 +22,9 @@ Button { property string nsfwPath property string fileName: decodeURIComponent((imageData.file_url).substring((imageData.file_url).lastIndexOf('/') + 1)) property string filePath: `${root.previewDownloadPath}/${root.fileName}` + property int maxTagStringLineLength: 50 property bool showActions: false - Process { id: downloadProcess running: false @@ -95,6 +96,10 @@ Button { PointingHandInteraction {} + StyledToolTip { + content: StringUtils.wordWrap(root.imageData.tags, root.maxTagStringLineLength) + } + background: Rectangle { color: menuButton.down ? Appearance.transparentize(Appearance.mix(Appearance.m3colors.m3surface, Appearance.m3colors.m3onSurface, 0.6), 0.1) : menuButton.hovered ? Appearance.transparentize(Appearance.mix(Appearance.m3colors.m3surface, Appearance.m3colors.m3onSurface, 0.8), 0.2) : @@ -114,83 +119,92 @@ Button { } } - Rectangle { - id: contextMenu - opacity: root.showActions ? 1 : 0 - visible: opacity > 0 - radius: Appearance.rounding.small - color: Appearance.m3colors.m3surfaceContainer + Loader { + id: contextMenuLoader + active: root.showActions anchors.top: menuButton.bottom anchors.right: parent.right anchors.margins: 8 - implicitHeight: contextMenuColumnLayout.implicitHeight + radius * 2 - implicitWidth: contextMenuColumnLayout.implicitWidth - Behavior on opacity { - NumberAnimation { - duration: Appearance.animation.elementMoveFast.duration - easing.type: Appearance.animation.elementMoveFast.type - easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve - } - } + sourceComponent: Item { + width: contextMenu.width + height: contextMenu.height - ColumnLayout { - id: contextMenuColumnLayout - anchors.centerIn: parent - spacing: 0 + Rectangle { + id: contextMenu + anchors.centerIn: parent + opacity: root.showActions ? 1 : 0 + visible: opacity > 0 + radius: Appearance.rounding.small + color: Appearance.m3colors.m3surfaceContainer + implicitHeight: contextMenuColumnLayout.implicitHeight + radius * 2 + implicitWidth: contextMenuColumnLayout.implicitWidth - MenuButton { - id: openFileLinkButton - Layout.fillWidth: true - buttonText: qsTr("Open file link") - onClicked: { - root.showActions = false - Qt.openUrlExternally(root.imageData.file_url) + Behavior on opacity { + NumberAnimation { + duration: Appearance.animation.elementMoveFast.duration + easing.type: Appearance.animation.elementMoveFast.type + easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve + } + } + + ColumnLayout { + id: contextMenuColumnLayout + anchors.centerIn: parent + spacing: 0 + + MenuButton { + id: openFileLinkButton + Layout.fillWidth: true + buttonText: qsTr("Open file link") + onClicked: { + root.showActions = false + Qt.openUrlExternally(root.imageData.file_url) + } + } + MenuButton { + id: sourceButton + visible: root.imageData.source && root.imageData.source.length > 0 + Layout.fillWidth: true + buttonText: StringUtils.format(qsTr("Go to source ({0})"), StringUtils.getDomain(root.imageData.source)) + enabled: root.imageData.source && root.imageData.source.length > 0 + onClicked: { + root.showActions = false + Qt.openUrlExternally(root.imageData.source) + } + } + MenuButton { + id: downloadButton + Layout.fillWidth: true + buttonText: "Download" + onClicked: { + root.showActions = false + Hyprland.dispatch(`exec curl '${root.imageData.file_url}' -o '${root.imageData.is_nsfw ? root.nsfwPath : root.downloadPath}/${root.fileName}' && notify-send '${qsTr("Download complete")}' '${root.downloadPath}/${root.fileName}'`) + } + } } } - MenuButton { - id: sourceButton - visible: root.imageData.source && root.imageData.source.length > 0 - Layout.fillWidth: true - buttonText: StringUtils.format(qsTr("Go to source ({0})"), StringUtils.getDomain(root.imageData.source)) - enabled: root.imageData.source && root.imageData.source.length > 0 - onClicked: { - root.showActions = false - Hyprland.dispatch("global quickshell:sidebarLeftClose") - Qt.openUrlExternally(root.imageData.source) - } - } - MenuButton { - id: downloadButton - Layout.fillWidth: true - buttonText: "Download" - onClicked: { - root.showActions = false - Hyprland.dispatch(`exec curl '${root.imageData.file_url}' -o '${root.imageData.is_nsfw ? root.nsfwPath : root.downloadPath}/${root.fileName}' && notify-send '${qsTr("Download complete")}' '${root.downloadPath}/${root.fileName}'`) + + DropShadow { + opacity: root.showActions ? 1 : 0 + visible: opacity > 0 + anchors.fill: contextMenu + source: contextMenu + radius: Appearance.sizes.elevationMargin + samples: radius * 2 + 1 + color: Appearance.colors.colShadow + verticalOffset: 2 + horizontalOffset: 0 + + Behavior on opacity { + NumberAnimation { + duration: Appearance.animation.elementMoveFast.duration + easing.type: Appearance.animation.elementMoveFast.type + easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve + } } } } } - - DropShadow { - opacity: root.showActions ? 1 : 0 - visible: opacity > 0 - anchors.fill: contextMenu - source: contextMenu - radius: Appearance.sizes.elevationMargin - samples: radius * 2 + 1 - color: Appearance.colors.colShadow - verticalOffset: 2 - horizontalOffset: 0 - - Behavior on opacity { - NumberAnimation { - duration: Appearance.animation.elementMoveFast.duration - easing.type: Appearance.animation.elementMoveFast.type - easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve - } - } - } - } } \ No newline at end of file