Keeps the Takemi geometry — the lean, the chamfer, the slabs — and swaps the palette wholesale. Mocha carries the ground; blue is the accent for anything live (focus, selection, borders, hover) and pink is the alarm for anything destructive or failed, so one hue no longer has to mean both 'active' and 'wrong'. Destructive controls rest as a pink keyline and fill solid only when hovered or selected: Mocha's pink is a pastel, and a resting slab of it reads as washed-out red rather than as a warning. The load ramp climbs text -> blue -> pink for the same reason, instead of fading straight through a muddy mid-tone. Surfaces covered: quickshell, Hyprland borders, alacritty, fish, dunst, and nvim (via the catppuccin plugin, submodule branch catppuccin-mocha). GTK 3/4, Qt and xsettingsd move to catppuccin-mocha-blue and are now tracked, since nothing else makes non-shell apps match the rice; the previous Takemi copies are in theme-repair-backups/. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
112 lines
3.2 KiB
QML
112 lines
3.2 KiB
QML
pragma Singleton
|
|
|
|
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Services.Notifications
|
|
import "root:/config"
|
|
|
|
// Notification server. Replaces dunst: the shell owns the org.freedesktop
|
|
// .Notifications name and renders popups and the history list itself.
|
|
Singleton {
|
|
id: root
|
|
|
|
property bool dnd: false
|
|
|
|
// Newest first. Popups read the head of this list.
|
|
property list<Notification> history: []
|
|
property int maxHistory: 60
|
|
|
|
readonly property int count: history.length
|
|
readonly property bool hasUnread: unread > 0
|
|
property int unread: 0
|
|
|
|
NotificationServer {
|
|
id: server
|
|
|
|
keepOnReload: true
|
|
bodySupported: true
|
|
bodyMarkupSupported: true
|
|
bodyImagesSupported: true
|
|
actionsSupported: true
|
|
actionIconsSupported: true
|
|
imageSupported: true
|
|
inlineReplySupported: true
|
|
persistenceSupported: true
|
|
|
|
onNotification: notif => {
|
|
// Hold the notification open until we drop it ourselves.
|
|
notif.tracked = true;
|
|
|
|
root.history = [notif, ...root.history].slice(0, root.maxHistory);
|
|
root.unread++;
|
|
|
|
if (!root.dnd) root.popupRequested(notif);
|
|
}
|
|
}
|
|
|
|
signal popupRequested(Notification notif)
|
|
|
|
function dismiss(notif: Notification) {
|
|
if (!notif) return;
|
|
const idx = root.history.indexOf(notif);
|
|
if (idx !== -1) {
|
|
const next = root.history.slice();
|
|
next.splice(idx, 1);
|
|
root.history = next;
|
|
}
|
|
notif.dismiss();
|
|
}
|
|
|
|
function clearAll() {
|
|
const all = root.history.slice();
|
|
root.history = [];
|
|
root.unread = 0;
|
|
for (const n of all) n.dismiss();
|
|
}
|
|
|
|
function markRead() {
|
|
root.unread = 0;
|
|
}
|
|
|
|
function toggleDnd() {
|
|
root.dnd = !root.dnd;
|
|
}
|
|
|
|
readonly property string icon: {
|
|
if (root.dnd) return "";
|
|
if (root.hasUnread) return "";
|
|
return "";
|
|
}
|
|
|
|
// Urgency-driven accents for the popup chrome.
|
|
function urgencyColor(u: int): color {
|
|
switch (u) {
|
|
case NotificationUrgency.Critical: return Theme.alarm;
|
|
case NotificationUrgency.Low: return Theme.muted;
|
|
default: return Theme.primary;
|
|
}
|
|
}
|
|
|
|
function appIconFor(notif: Notification): string {
|
|
if (!notif) return "";
|
|
const app = (notif.appName || "").toLowerCase();
|
|
if (app.includes("spotify")) return "";
|
|
if (app.includes("discord")) return "";
|
|
if (app.includes("slack")) return "";
|
|
if (app.includes("thunderbird") || app.includes("mail")) return "";
|
|
if (app.includes("firefox")) return "";
|
|
if (app.includes("volume") || app.includes("audio")) return "";
|
|
if (app.includes("screenshot") || app.includes("grim")) return "";
|
|
return "";
|
|
}
|
|
|
|
// How long a popup stays up, in ms.
|
|
function timeoutFor(notif: Notification): int {
|
|
if (!notif) return 5000;
|
|
if (notif.urgency === NotificationUrgency.Critical) return 0; // sticky
|
|
if (notif.expireTimeout > 0) return notif.expireTimeout;
|
|
if (notif.urgency === NotificationUrgency.Low) return 3500;
|
|
return 6000;
|
|
}
|
|
}
|