From dcf6f0059eaaf640576af87b6371721bdaf65e4a Mon Sep 17 00:00:00 2001 From: Radu Macocian Date: Tue, 9 Jun 2026 11:01:37 +0200 Subject: [PATCH] Added theme engine support and aur publish pipeline --- .gitea/workflows/aur-publish.yml | 79 ++++++++++++++++++++++++++++++++ .gitea/workflows/tag-on-bump.yml | 66 ++++++++++++++++++++++++++ PKGBUILD | 2 +- README.md | 18 ++++++-- qml/Config.qml | 22 +++++++++ qml/Theme.qml | 34 ++++++++------ 6 files changed, 204 insertions(+), 17 deletions(-) create mode 100644 .gitea/workflows/aur-publish.yml create mode 100644 .gitea/workflows/tag-on-bump.yml diff --git a/.gitea/workflows/aur-publish.yml b/.gitea/workflows/aur-publish.yml new file mode 100644 index 0000000..c29cc73 --- /dev/null +++ b/.gitea/workflows/aur-publish.yml @@ -0,0 +1,79 @@ +name: Publish to AUR + +on: + push: + tags: ['v*'] + +jobs: + publish: + runs-on: ubuntu-latest + container: + image: archlinux:latest + defaults: + run: + shell: bash + steps: + - name: Install dependencies + run: | + pacman -Syu --noconfirm --needed git openssh pacman-contrib base-devel sudo curl coreutils + useradd -m builder + echo "builder ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers + + - name: Checkout source at tag + run: | + git clone --depth 1 --branch ${{ gitea.ref_name }} \ + http://gitea-actions:${{ gitea.token }}@gitea:3030/${{ gitea.repository }}.git . + + - name: Recompute sha256sums for tagged archive + run: | + set -euo pipefail + PKGVER=$(awk -F= '/^pkgver=/{print $2}' PKGBUILD) + URL=$(awk -F\" '/^url=/{print $2}' PKGBUILD) + SRC_URL="${URL}/archive/v${PKGVER}.tar.gz" + echo "Fetching ${SRC_URL}" + curl -fsSL "${SRC_URL}" -o /tmp/src.tar.gz + NEW_SHA=$(sha256sum /tmp/src.tar.gz | awk '{print $1}') + sed -i "s/^sha256sums=.*/sha256sums=('${NEW_SHA}')/" PKGBUILD + + - name: Configure SSH for AUR + env: + AUR_SSH_KEY: ${{ secrets.AUR_SSH_KEY }} + run: | + install -dm700 ~/.ssh + printf '%s\n' "$AUR_SSH_KEY" > ~/.ssh/aur + chmod 600 ~/.ssh/aur + ssh-keyscan aur.archlinux.org >> ~/.ssh/known_hosts 2>/dev/null + cat > ~/.ssh/config < .SRCINFO' + cd /tmp/aur + git config user.name "${{ vars.AUR_GIT_NAME || 'Radu Macocian' }}" + git config user.email "${{ vars.AUR_GIT_EMAIL || 'radu@macocian.com' }}" + git add PKGBUILD .SRCINFO + if git diff --cached --quiet; then + echo "No changes to publish." + exit 0 + fi + PKGVER=$(awk -F= '/^pkgver=/{print $2}' PKGBUILD) + PKGREL=$(awk -F= '/^pkgrel=/{print $2}' PKGBUILD) + git commit -m "Update to ${PKGVER}-${PKGREL}" + git push origin master diff --git a/.gitea/workflows/tag-on-bump.yml b/.gitea/workflows/tag-on-bump.yml new file mode 100644 index 0000000..96a9e17 --- /dev/null +++ b/.gitea/workflows/tag-on-bump.yml @@ -0,0 +1,66 @@ +name: Tag on version bump + +on: + push: + branches: [master] + +jobs: + tag: + runs-on: ubuntu-latest + container: + image: archlinux:latest + defaults: + run: + shell: bash + steps: + - name: Install dependencies + run: pacman -Syu --noconfirm --needed git curl coreutils + + - name: Checkout source + run: | + git clone --branch ${{ gitea.ref_name }} \ + http://gitea-actions:${{ gitea.token }}@gitea:3030/${{ gitea.repository }}.git . + + - name: Tag if pkgver bumped + id: tag + run: | + set -euo pipefail + PKGVER=$(awk -F= '/^pkgver=/{print $2}' PKGBUILD) + TAG="v${PKGVER}" + git config --global --add safe.directory "$(pwd)" + git fetch --tags origin + if git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null; then + echo "Tag ${TAG} already exists, nothing to do." + echo "created=0" >> "$GITHUB_OUTPUT" + exit 0 + fi + git config user.name "${{ vars.AUR_GIT_NAME || 'Radu Macocian' }}" + git config user.email "${{ vars.AUR_GIT_EMAIL || 'radu@macocian.com' }}" + git tag -a "${TAG}" -m "Release ${TAG}" + git push \ + http://gitea-actions:${{ gitea.token }}@gitea:3030/${{ gitea.repository }}.git \ + "${TAG}" + echo "created=1" >> "$GITHUB_OUTPUT" + echo "pkgver=${PKGVER}" >> "$GITHUB_OUTPUT" + + - name: Update sha256sums on master + if: steps.tag.outputs.created == '1' + run: | + set -euo pipefail + PKGVER="${{ steps.tag.outputs.pkgver }}" + URL=$(awk -F\" '/^url=/{print $2}' PKGBUILD) + SRC_URL="${URL}/archive/v${PKGVER}.tar.gz" + echo "Fetching ${SRC_URL}" + curl -fsSL "${SRC_URL}" -o /tmp/src.tar.gz + NEW_SHA=$(sha256sum /tmp/src.tar.gz | awk '{print $1}') + CUR_SHA=$(awk -F\' "/^sha256sums=/{print \$2}" PKGBUILD) + if [ "${NEW_SHA}" = "${CUR_SHA}" ]; then + echo "sha256sums already up to date." + exit 0 + fi + sed -i "s/^sha256sums=.*/sha256sums=('${NEW_SHA}')/" PKGBUILD + git add PKGBUILD + git commit -m "Update sha256sums for v${PKGVER} [skip ci]" + git push \ + http://gitea-actions:${{ gitea.token }}@gitea:3030/${{ gitea.repository }}.git \ + HEAD:${{ gitea.ref_name }} diff --git a/PKGBUILD b/PKGBUILD index a7df90b..5889457 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -1,6 +1,6 @@ # Maintainer: Radu Macocian pkgname=omni-launcher -pkgver=0.0.1 +pkgver=0.0.2 pkgrel=1 pkgdesc="Application launcher overlay built on Quickshell, with calculator, unit/currency conversion, unicode search and Giphy search" arch=('any') diff --git a/README.md b/README.md index 7a4eedc..922ffa9 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ bind = SUPER, SPACE, exec, omni-launcher-toggle ## Configuration -`~/.config/omni-launcher/config.json` — any missing key falls back to a built-in default: +`~/.config/omni-launcher/config.json` — any missing key falls back to a built-in default, so the file can be omitted entirely: ```json { @@ -52,7 +52,19 @@ bind = SUPER, SPACE, exec, omni-launcher-toggle "fontSize": 16, "giphyApiKey": "", "panelWidth": 720, - "panelHeight": 520 + "panelHeight": 520, + "padding": 5, + "spacing": 5, + "radius": 10, + "colors": { + "background": "#101010", + "foreground": "#e6e6e6", + "idle": "#a0a0a0", + "accent": "#5e9eff", + "overlayStrong": "#2b5f96", + "overlayWeak": "#202020", + "border": "#3a3a3a" + } } ``` @@ -60,7 +72,7 @@ Changes take effect on restart (`omni-launcher`). ### Theming -The launcher reads `org.freedesktop.appearance` from `xdg-desktop-portal` for color-scheme and accent, and falls back to Qt's `SystemPalette` (qt6ct / KDE / qgnomeplatform) for everything else. No app-side config is required for theming. +The launcher reads `org.freedesktop.appearance` from `xdg-desktop-portal` for color-scheme and accent, and falls back to Qt's `SystemPalette` (qt6ct / KDE / qgnomeplatform) for everything else. Values under `colors` are optional overrides for users or theme managers that want a fixed palette. ## Dependencies diff --git a/qml/Config.qml b/qml/Config.qml index 2c0765b..429b665 100644 --- a/qml/Config.qml +++ b/qml/Config.qml @@ -13,6 +13,16 @@ QtObject { property string giphyApiKey: "" property int panelWidth: 720 property int panelHeight: 520 + property int padding: 5 + property int spacing: 5 + property int radius: 10 + property string backgroundColor: "" + property string foregroundColor: "" + property string idleColor: "" + property string accentColor: "" + property string overlayStrongColor: "" + property string overlayWeakColor: "" + property string borderColor: "" property bool loaded: false @@ -22,6 +32,18 @@ QtObject { if (typeof obj.giphyApiKey === "string") giphyApiKey = obj.giphyApiKey; if (typeof obj.panelWidth === "number" && obj.panelWidth > 0) panelWidth = obj.panelWidth; if (typeof obj.panelHeight === "number" && obj.panelHeight > 0) panelHeight = obj.panelHeight; + if (typeof obj.padding === "number" && obj.padding > 0) padding = obj.padding; + if (typeof obj.spacing === "number" && obj.spacing > 0) spacing = obj.spacing; + if (typeof obj.radius === "number" && obj.radius >= 0) radius = obj.radius; + + const colors = obj.colors || {}; + if (typeof colors.background === "string" && colors.background.length > 0) backgroundColor = colors.background; + if (typeof colors.foreground === "string" && colors.foreground.length > 0) foregroundColor = colors.foreground; + if (typeof colors.idle === "string" && colors.idle.length > 0) idleColor = colors.idle; + if (typeof colors.accent === "string" && colors.accent.length > 0) accentColor = colors.accent; + if (typeof colors.overlayStrong === "string" && colors.overlayStrong.length > 0) overlayStrongColor = colors.overlayStrong; + if (typeof colors.overlayWeak === "string" && colors.overlayWeak.length > 0) overlayWeakColor = colors.overlayWeak; + if (typeof colors.border === "string" && colors.border.length > 0) borderColor = colors.border; } property Process _loader: Process { diff --git a/qml/Theme.qml b/qml/Theme.qml index 3e17f7b..055985d 100644 --- a/qml/Theme.qml +++ b/qml/Theme.qml @@ -13,7 +13,7 @@ QtObject { // Portal-reported state. Defaults match "prefer dark, neutral accent". // 0 = no preference, 1 = dark, 2 = light (per xdg-desktop-portal spec). property int colorScheme: 1 - property color accent: "#5e9eff" + property color portalAccent: "#5e9eff" property bool _portalLoaded: false readonly property bool dark: colorScheme !== 2 @@ -22,22 +22,30 @@ QtObject { // background — mixing portal color-scheme with SystemPalette text led to // unreadable combinations (dark bg + dark text) when the Qt platform // theme disagrees with the portal. - readonly property color foreground: dark ? "#e6e6e6" : "#1a1a1a" - readonly property color idle: dark ? Qt.rgba(1, 1, 1, 0.55) - : Qt.rgba(0, 0, 0, 0.55) - readonly property color opaque_background: dark + readonly property color accent: Config.accentColor.length > 0 + ? Config.accentColor : portalAccent + readonly property color foreground: Config.foregroundColor.length > 0 + ? Config.foregroundColor : (dark ? "#e6e6e6" : "#1a1a1a") + readonly property color idle: Config.idleColor.length > 0 + ? Config.idleColor : (dark ? Qt.rgba(1, 1, 1, 0.55) + : Qt.rgba(0, 0, 0, 0.55)) + readonly property color opaque_background: Config.backgroundColor.length > 0 + ? Config.backgroundColor : (dark ? Qt.rgba(0, 0, 0, 0.8) - : Qt.rgba(1, 1, 1, 0.9) - readonly property color overlay_strong: dark ? Qt.rgba(1, 1, 1, 0.14) : Qt.rgba(0, 0, 0, 0.10) - readonly property color overlay_weak: dark ? Qt.rgba(1, 1, 1, 0.06) : Qt.rgba(0, 0, 0, 0.04) - readonly property color border_subtle: dark ? Qt.rgba(1, 1, 1, 0.10) : Qt.rgba(0, 0, 0, 0.10) + : Qt.rgba(1, 1, 1, 0.9)) + readonly property color overlay_strong: Config.overlayStrongColor.length > 0 + ? Config.overlayStrongColor : (dark ? Qt.rgba(1, 1, 1, 0.14) : Qt.rgba(0, 0, 0, 0.10)) + readonly property color overlay_weak: Config.overlayWeakColor.length > 0 + ? Config.overlayWeakColor : (dark ? Qt.rgba(1, 1, 1, 0.06) : Qt.rgba(0, 0, 0, 0.04)) + readonly property color border_subtle: Config.borderColor.length > 0 + ? Config.borderColor : (dark ? Qt.rgba(1, 1, 1, 0.10) : Qt.rgba(0, 0, 0, 0.10)) readonly property string fontFamily: Config.fontFamily readonly property int fontSize: Config.fontSize - readonly property int padding: 5 - readonly property int spacing: 5 - readonly property int radius: 10 + readonly property int padding: Config.padding + readonly property int spacing: Config.spacing + readonly property int radius: Config.radius // Read the portal once at startup. The portal also emits a SettingChanged // signal we could subscribe to, but a one-shot read keeps us out of a @@ -60,7 +68,7 @@ QtObject { const ac = text.match(/'accent-color':\s*<\(([-\d.eE+]+),\s*([-\d.eE+]+),\s*([-\d.eE+]+)\)>/); if (ac) { const r = parseFloat(ac[1]), g = parseFloat(ac[2]), b = parseFloat(ac[3]); - if (r >= 0 && g >= 0 && b >= 0) root.accent = Qt.rgba(r, g, b, 1); + if (r >= 0 && g >= 0 && b >= 0) root.portalAccent = Qt.rgba(r, g, b, 1); } root._portalLoaded = true; }