Compare commits
17 Commits
2317eee72a
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
| 29b4c54370 | |||
| 9eaaa01663 | |||
| e94b841b2a | |||
| 51b725e1f7 | |||
| da22b6446d | |||
|
|
932b174c36 | ||
|
|
7e9d12e640 | ||
| 7d4d54c5b8 | |||
|
|
f0adb2a291 | ||
|
|
01133b78f0 | ||
|
|
50f84afb66 | ||
|
|
59c39260d1 | ||
|
|
0ba6bbd181 | ||
|
|
1690ec5eb4 | ||
|
|
2f3fc71ab7 | ||
|
|
40850161a5 | ||
|
|
8ee25d7853 |
34
INSTALL/configs/ags/config.js
Normal file
34
INSTALL/configs/ags/config.js
Normal file
@@ -0,0 +1,34 @@
|
||||
// ── violet-chaton v2 — AGS config ───────────────────────────────────────────
|
||||
// Barre + OSD + Launcher + Notifications
|
||||
// Modulaire : Hyprland = full, COSMIC = bar + OSD + launcher + notifs
|
||||
|
||||
import { Bar } from "./widgets/Bar.js";
|
||||
import { OSD } from "./widgets/OSD.js";
|
||||
import { Launcher } from "./widgets/Launcher.js";
|
||||
import { Notifications } from "./widgets/Notifications.js";
|
||||
|
||||
// ── Compositor detection ────────────────────────────────────────────────────
|
||||
const compositor = (() => {
|
||||
const session = Utils.exec("echo $XDG_CURRENT_DESKTOP").trim();
|
||||
if (session.includes("Hyprland")) return "hyprland";
|
||||
if (session.includes("COSMIC")) return "cosmic";
|
||||
return "unknown";
|
||||
})();
|
||||
|
||||
print(`[violet-chaton] compositor: ${compositor}`);
|
||||
|
||||
// ── Windows ─────────────────────────────────────────────────────────────────
|
||||
const windows = (monitor) => {
|
||||
const wins = [
|
||||
Bar(monitor, compositor),
|
||||
OSD(monitor),
|
||||
Launcher(monitor),
|
||||
Notifications(monitor),
|
||||
];
|
||||
return wins;
|
||||
};
|
||||
|
||||
export default {
|
||||
style: `${App.configDir}/css/style.css`,
|
||||
windows: windows(0).flat(),
|
||||
};
|
||||
385
INSTALL/configs/ags/css/style.css
Normal file
385
INSTALL/configs/ags/css/style.css
Normal file
@@ -0,0 +1,385 @@
|
||||
/* ── violet-chaton v2 — AGS stylesheet ────────────────────────────────────────
|
||||
*
|
||||
* Palette :
|
||||
* crust #1a0e27
|
||||
* base #261537
|
||||
* mantle #341c4a
|
||||
* surface0 #3d2454
|
||||
* surface1 #493161
|
||||
* surface2 #5a3875
|
||||
* magenta #ff4da6 accent primaire
|
||||
* lilac #c9a0ff accent secondaire
|
||||
* mitsuri #9adba8 vert pastel
|
||||
* lavande #a4b4ff bleu-violet
|
||||
* champagne #e8c87a or chaud
|
||||
* danger #f25c7a
|
||||
* text #f0eaf8
|
||||
* subtext1 #c4b8d4
|
||||
* subtext0 #9a8fad
|
||||
* muted #716686
|
||||
*
|
||||
* ─────────────────────────────────────────────────────────────────────────── */
|
||||
|
||||
/* ── Reset ───────────────────────────────────────────────────────────────── */
|
||||
|
||||
* {
|
||||
font-family: "Maple Mono NF", "MapleMono Nerd Font", monospace;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* ══════════════════════════════════════════════════════════════════════════
|
||||
* BAR — 3 pills glassmorphism (island floating)
|
||||
* ══════════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
.bar {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.bar .modules-left,
|
||||
.bar .modules-center,
|
||||
.bar .modules-right {
|
||||
background: alpha(#261537, 0.88);
|
||||
border-radius: 14px;
|
||||
border: 3px solid alpha(#ff4da6, 0.60);
|
||||
margin: 8px 4px;
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.bar .modules-left:hover,
|
||||
.bar .modules-center:hover,
|
||||
.bar .modules-right:hover {
|
||||
border-color: #ff4da6;
|
||||
box-shadow: 0 4px 28px alpha(#c9a0ff, 0.18);
|
||||
}
|
||||
|
||||
/* ── Launcher button ─────────────────────────────────────────────────────── */
|
||||
|
||||
.bar .launcher-btn {
|
||||
color: #ff4da6;
|
||||
font-size: 19px;
|
||||
padding: 0 14px 0 18px;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.bar .launcher-btn:hover {
|
||||
color: #c9a0ff;
|
||||
}
|
||||
|
||||
/* ── Separator ───────────────────────────────────────────────────────────── */
|
||||
|
||||
.bar .separator {
|
||||
color: alpha(#f0eaf8, 0.12);
|
||||
font-size: 11px;
|
||||
padding: 0 4px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
/* ── Clock ───────────────────────────────────────────────────────────────── */
|
||||
|
||||
.bar .clock {
|
||||
color: #ff4da6;
|
||||
font-weight: 900;
|
||||
font-size: 14px;
|
||||
letter-spacing: 0.04em;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.bar .clock:hover {
|
||||
color: #c9a0ff;
|
||||
}
|
||||
|
||||
/* ── Date ────────────────────────────────────────────────────────────────── */
|
||||
|
||||
.bar .date {
|
||||
color: #a4b4ff;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
padding: 0 10px 0 2px;
|
||||
}
|
||||
|
||||
/* ── System modules ──────────────────────────────────────────────────────── */
|
||||
|
||||
.bar .cpu { color: #a4b4ff; }
|
||||
.bar .cpu.warning { color: #e8c87a; }
|
||||
.bar .cpu.critical { color: #f25c7a; }
|
||||
|
||||
.bar .ram { color: #ff4da6; }
|
||||
.bar .ram.warning { color: #e8c87a; }
|
||||
.bar .ram.critical { color: #f25c7a; }
|
||||
|
||||
.bar .temp {
|
||||
color: alpha(#a4b4ff, 0.60);
|
||||
font-size: 11px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.bar .temp.warning { color: #e8c87a; }
|
||||
.bar .temp.critical { color: #f25c7a; }
|
||||
|
||||
/* ── Network ─────────────────────────────────────────────────────────────── */
|
||||
|
||||
.bar .network {
|
||||
color: #a4b4ff;
|
||||
font-size: 11px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.bar .network.disconnected { color: #f25c7a; }
|
||||
.bar .network.wifi { color: alpha(#a4b4ff, 0.80); }
|
||||
|
||||
/* ── Volume ──────────────────────────────────────────────────────────────── */
|
||||
|
||||
.bar .volume { color: #ff4da6; }
|
||||
.bar .volume.muted { color: alpha(#ff4da6, 0.30); }
|
||||
|
||||
/* ── Battery ─────────────────────────────────────────────────────────────── */
|
||||
|
||||
.bar .battery { color: #ff4da6; }
|
||||
.bar .battery.charging { color: #9adba8; }
|
||||
.bar .battery.low { color: #f25c7a; }
|
||||
.bar .battery.warning { color: #e8c87a; }
|
||||
|
||||
/* ── Media (MPRIS) ───────────────────────────────────────────────────────── */
|
||||
|
||||
.bar .media {
|
||||
color: #c9a0ff;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.bar .media.paused {
|
||||
color: alpha(#c9a0ff, 0.50);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* ── Systray ─────────────────────────────────────────────────────────────── */
|
||||
|
||||
.bar .systray { padding: 0 8px; }
|
||||
.bar .systray .passive { opacity: 0.5; }
|
||||
|
||||
/* ── Workspaces (Hyprland only) ──────────────────────────────────────────── */
|
||||
|
||||
.bar .workspaces button {
|
||||
background: transparent;
|
||||
color: #716686;
|
||||
min-width: 24px;
|
||||
min-height: 24px;
|
||||
border-radius: 8px;
|
||||
margin: 2px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.bar .workspaces button.active {
|
||||
background: alpha(#ff4da6, 0.20);
|
||||
color: #ff4da6;
|
||||
border: 1px solid alpha(#ff4da6, 0.40);
|
||||
}
|
||||
|
||||
.bar .workspaces button.occupied {
|
||||
color: #c9a0ff;
|
||||
}
|
||||
|
||||
.bar .workspaces button:hover {
|
||||
background: alpha(#c9a0ff, 0.12);
|
||||
color: #c9a0ff;
|
||||
}
|
||||
|
||||
/* ── Power button ────────────────────────────────────────────────────────── */
|
||||
|
||||
.bar .power-btn {
|
||||
color: #f25c7a;
|
||||
font-size: 15px;
|
||||
padding: 0 14px 0 8px;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.bar .power-btn:hover { color: #ff4da6; }
|
||||
|
||||
/* ── Hover global modules ────────────────────────────────────────────────── */
|
||||
|
||||
.bar .cpu:hover,
|
||||
.bar .ram:hover,
|
||||
.bar .temp:hover,
|
||||
.bar .network:hover,
|
||||
.bar .volume:hover,
|
||||
.bar .battery:hover {
|
||||
color: #c9a0ff;
|
||||
}
|
||||
|
||||
/* ══════════════════════════════════════════════════════════════════════════
|
||||
* OSD — volume / brightness overlay
|
||||
* ══════════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
.osd {
|
||||
background: alpha(#261537, 0.92);
|
||||
border-radius: 14px;
|
||||
border: 2px solid alpha(#ff4da6, 0.40);
|
||||
padding: 12px 20px;
|
||||
margin: 0 0 40px 0;
|
||||
}
|
||||
|
||||
.osd .icon {
|
||||
color: #ff4da6;
|
||||
font-size: 24px;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.osd progressbar trough {
|
||||
background: #3d2454;
|
||||
border-radius: 8px;
|
||||
min-height: 8px;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.osd progressbar progress {
|
||||
border-radius: 8px;
|
||||
min-height: 8px;
|
||||
background: linear-gradient(to right, #ff4da6, #c9a0ff, #a4b4ff, #9adba8);
|
||||
}
|
||||
|
||||
.osd .label {
|
||||
color: #f0eaf8;
|
||||
font-size: 12px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
/* ══════════════════════════════════════════════════════════════════════════
|
||||
* LAUNCHER — app search
|
||||
* ══════════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
.launcher {
|
||||
background: alpha(#1a0e27, 0.94);
|
||||
border-radius: 14px;
|
||||
border: 2px solid alpha(#ff4da6, 0.38);
|
||||
padding: 10px;
|
||||
min-width: 500px;
|
||||
}
|
||||
|
||||
.launcher .search {
|
||||
background: alpha(#261537, 0.75);
|
||||
border-radius: 12px;
|
||||
border: 1px solid alpha(#5a3875, 0.50);
|
||||
padding: 9px 14px;
|
||||
color: #f0eaf8;
|
||||
caret-color: #ff4da6;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.launcher .search:focus {
|
||||
border-color: alpha(#ff4da6, 0.60);
|
||||
}
|
||||
|
||||
.launcher .app-item {
|
||||
background: transparent;
|
||||
border-radius: 8px;
|
||||
padding: 7px 10px;
|
||||
color: #f0eaf8;
|
||||
}
|
||||
|
||||
.launcher .app-item:hover,
|
||||
.launcher .app-item:focus {
|
||||
background: alpha(#ff4da6, 0.16);
|
||||
border: 1px solid alpha(#ff4da6, 0.32);
|
||||
}
|
||||
|
||||
.launcher .app-item:hover label,
|
||||
.launcher .app-item:focus label {
|
||||
color: #ff4da6;
|
||||
}
|
||||
|
||||
.launcher .app-item image {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.launcher .no-results {
|
||||
color: #716686;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/* ══════════════════════════════════════════════════════════════════════════
|
||||
* NOTIFICATIONS
|
||||
* ══════════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
.notification {
|
||||
background: alpha(#261537, 0.94);
|
||||
border-radius: 14px;
|
||||
border: 2px solid alpha(#c9a0ff, 0.30);
|
||||
padding: 12px;
|
||||
margin: 8px;
|
||||
min-width: 350px;
|
||||
}
|
||||
|
||||
.notification .title {
|
||||
color: #ff4da6;
|
||||
font-weight: bold;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.notification .body {
|
||||
color: #c4b8d4;
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.notification .app-name {
|
||||
color: #716686;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.notification .time {
|
||||
color: #716686;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.notification .close-btn {
|
||||
color: #716686;
|
||||
font-size: 14px;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
padding: 2px 6px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.notification .close-btn:hover {
|
||||
color: #f25c7a;
|
||||
background: alpha(#f25c7a, 0.12);
|
||||
}
|
||||
|
||||
.notification .actions button {
|
||||
background: alpha(#5a3875, 0.50);
|
||||
color: #c9a0ff;
|
||||
border-radius: 8px;
|
||||
padding: 4px 12px;
|
||||
margin: 4px 4px 0 0;
|
||||
}
|
||||
|
||||
.notification .actions button:hover {
|
||||
background: alpha(#ff4da6, 0.20);
|
||||
color: #ff4da6;
|
||||
}
|
||||
|
||||
/* ── Urgency levels ──────────────────────────────────────────────────────── */
|
||||
|
||||
.notification.critical {
|
||||
border-color: alpha(#f25c7a, 0.60);
|
||||
}
|
||||
|
||||
.notification.critical .title {
|
||||
color: #f25c7a;
|
||||
}
|
||||
|
||||
/* ══════════════════════════════════════════════════════════════════════════
|
||||
* TOOLTIP — shared
|
||||
* ══════════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
tooltip {
|
||||
background: alpha(#1a0e27, 0.96);
|
||||
border: 1px solid alpha(#ff4da6, 0.30);
|
||||
border-radius: 10px;
|
||||
color: #f0eaf8;
|
||||
padding: 6px 10px;
|
||||
}
|
||||
228
INSTALL/configs/ags/widgets/Bar.js
Normal file
228
INSTALL/configs/ags/widgets/Bar.js
Normal file
@@ -0,0 +1,228 @@
|
||||
// ── violet-chaton v2 — Bar widget ───────────────────────────────────────────
|
||||
// 3 pills glassmorphism — modulaire selon compositor
|
||||
|
||||
const audio = await Service.import("audio");
|
||||
const battery = await Service.import("battery");
|
||||
const network = await Service.import("network");
|
||||
const systemtray = await Service.import("systemtray");
|
||||
const mpris = await Service.import("mpris");
|
||||
|
||||
// ── Helpers ─────────────────────────────────────────────────────────────────
|
||||
|
||||
const Separator = () => Widget.Label({ className: "separator", label: "│" });
|
||||
|
||||
const Clock = () => Widget.Label({
|
||||
className: "clock",
|
||||
connections: [[1000, (self) => {
|
||||
self.label = Utils.exec("date +%H:%M");
|
||||
}]],
|
||||
});
|
||||
|
||||
const DateWidget = () => Widget.Label({
|
||||
className: "date",
|
||||
connections: [[60000, (self) => {
|
||||
self.label = Utils.exec("date '+%a %d %b'");
|
||||
}]],
|
||||
});
|
||||
|
||||
// ── System ──────────────────────────────────────────────────────────────────
|
||||
|
||||
const CPU = () => Widget.Label({
|
||||
className: "cpu",
|
||||
connections: [[2000, (self) => {
|
||||
const usage = Math.round(
|
||||
Number(Utils.exec(`bash -c "top -bn1 | awk '/^%Cpu/ {print 100-$8}'"`)
|
||||
));
|
||||
self.label = ` ${usage}%`;
|
||||
self.toggleClassName("warning", usage > 70);
|
||||
self.toggleClassName("critical", usage > 90);
|
||||
}]],
|
||||
});
|
||||
|
||||
const RAM = () => Widget.Label({
|
||||
className: "ram",
|
||||
connections: [[2000, (self) => {
|
||||
const used = Utils.exec(`bash -c "free -m | awk '/^Mem:/ {printf \"%.1f\", $3/1024}'"`)
|
||||
const total = Utils.exec(`bash -c "free -m | awk '/^Mem:/ {printf \"%.1f\", $2/1024}'"`)
|
||||
const pct = Math.round((parseFloat(used) / parseFloat(total)) * 100);
|
||||
self.label = ` ${used}G`;
|
||||
self.toggleClassName("warning", pct > 70);
|
||||
self.toggleClassName("critical", pct > 90);
|
||||
}]],
|
||||
});
|
||||
|
||||
// ── Network ─────────────────────────────────────────────────────────────────
|
||||
|
||||
const Network = () => Widget.Label({
|
||||
className: "network",
|
||||
connections: [[network, (self) => {
|
||||
if (network.primary === "wifi") {
|
||||
const wifi = network.wifi;
|
||||
self.label = ` ${wifi?.ssid || ""}`;
|
||||
self.toggleClassName("wifi", true);
|
||||
self.toggleClassName("disconnected", false);
|
||||
} else if (network.primary === "wired") {
|
||||
self.label = " Eth";
|
||||
self.toggleClassName("wifi", false);
|
||||
self.toggleClassName("disconnected", false);
|
||||
} else {
|
||||
self.label = " ";
|
||||
self.toggleClassName("disconnected", true);
|
||||
}
|
||||
}]],
|
||||
});
|
||||
|
||||
// ── Volume ──────────────────────────────────────────────────────────────────
|
||||
|
||||
const Volume = () => Widget.Button({
|
||||
className: "volume",
|
||||
onClicked: () => { audio.speaker.isMuted = !audio.speaker.isMuted; },
|
||||
child: Widget.Label({
|
||||
connections: [[audio, (self) => {
|
||||
const vol = Math.round((audio.speaker?.volume || 0) * 100);
|
||||
const muted = audio.speaker?.isMuted;
|
||||
const icon = muted ? "" : vol > 66 ? "" : vol > 33 ? "" : "";
|
||||
self.label = `${icon} ${vol}%`;
|
||||
self.parent?.toggleClassName("muted", muted);
|
||||
}, "speaker-changed"]],
|
||||
}),
|
||||
});
|
||||
|
||||
// ── Battery ─────────────────────────────────────────────────────────────────
|
||||
|
||||
const Battery = () => Widget.Label({
|
||||
className: "battery",
|
||||
visible: battery.bind("available"),
|
||||
connections: [[battery, (self) => {
|
||||
const pct = battery.percent;
|
||||
const charging = battery.charging;
|
||||
const icon = charging ? "" : pct > 80 ? "" : pct > 60 ? "" :
|
||||
pct > 40 ? "" : pct > 20 ? "" : "";
|
||||
self.label = `${icon} ${pct}%`;
|
||||
self.toggleClassName("charging", charging);
|
||||
self.toggleClassName("low", pct <= 20 && !charging);
|
||||
self.toggleClassName("warning", pct <= 30 && !charging);
|
||||
}]],
|
||||
});
|
||||
|
||||
// ── Media ───────────────────────────────────────────────────────────────────
|
||||
|
||||
const Media = () => Widget.Label({
|
||||
className: "media",
|
||||
connections: [[mpris, (self) => {
|
||||
const player = mpris.players[0];
|
||||
if (!player) {
|
||||
self.visible = false;
|
||||
return;
|
||||
}
|
||||
self.visible = true;
|
||||
const artist = player.trackArtists?.join(", ") || "";
|
||||
const title = player.trackTitle || "";
|
||||
const icon = player.playBackStatus === "Playing" ? " " : " ";
|
||||
self.label = `${icon}${artist ? artist + " — " : ""}${title}`.slice(0, 50);
|
||||
self.toggleClassName("paused", player.playBackStatus !== "Playing");
|
||||
}]],
|
||||
});
|
||||
|
||||
// ── Systray ─────────────────────────────────────────────────────────────────
|
||||
|
||||
const SysTray = () => Widget.Box({
|
||||
className: "systray",
|
||||
children: systemtray.bind("items").transform((items) =>
|
||||
items.map((item) =>
|
||||
Widget.Button({
|
||||
child: Widget.Icon({ icon: item.bind("icon"), size: 16 }),
|
||||
tooltipMarkup: item.bind("tooltip-markup"),
|
||||
onPrimaryClick: (_, event) => item.activate(event),
|
||||
onSecondaryClick: (_, event) => item.openMenu(event),
|
||||
})
|
||||
)
|
||||
),
|
||||
});
|
||||
|
||||
// ── Launcher button ─────────────────────────────────────────────────────────
|
||||
|
||||
const LauncherBtn = () => Widget.Button({
|
||||
className: "launcher-btn",
|
||||
label: "",
|
||||
onClicked: () => App.toggleWindow("launcher"),
|
||||
});
|
||||
|
||||
// ── Power button ────────────────────────────────────────────────────────────
|
||||
|
||||
const PowerBtn = () => Widget.Button({
|
||||
className: "power-btn",
|
||||
label: "⏻",
|
||||
onClicked: () => Utils.exec("bash -c 'systemctl poweroff'"),
|
||||
});
|
||||
|
||||
// ── Workspaces (Hyprland only) ──────────────────────────────────────────────
|
||||
|
||||
const Workspaces = (compositor) => {
|
||||
if (compositor !== "hyprland") return Widget.Box({});
|
||||
|
||||
const hyprland = await Service.import("hyprland");
|
||||
return Widget.Box({
|
||||
className: "workspaces",
|
||||
children: hyprland.bind("workspaces").transform((ws) =>
|
||||
ws.sort((a, b) => a.id - b.id)
|
||||
.filter((w) => w.id > 0)
|
||||
.map((w) =>
|
||||
Widget.Button({
|
||||
onClicked: () => hyprland.messageAsync(`dispatch workspace ${w.id}`),
|
||||
child: Widget.Label({ label: `${w.id}` }),
|
||||
className: hyprland.active.workspace.bind("id").transform(
|
||||
(id) => id === w.id ? "active" : w.windows > 0 ? "occupied" : ""
|
||||
),
|
||||
})
|
||||
)
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
// ── Bar assembly ────────────────────────────────────────────────────────────
|
||||
|
||||
export const Bar = (monitor, compositor) => Widget.Window({
|
||||
name: `bar-${monitor}`,
|
||||
monitor,
|
||||
anchor: ["top", "left", "right"],
|
||||
exclusivity: "exclusive",
|
||||
className: "bar",
|
||||
child: Widget.CenterBox({
|
||||
startWidget: Widget.Box({
|
||||
className: "modules-left",
|
||||
children: [
|
||||
LauncherBtn(),
|
||||
Separator(),
|
||||
Workspaces(compositor),
|
||||
Separator(),
|
||||
CPU(),
|
||||
RAM(),
|
||||
],
|
||||
}),
|
||||
centerWidget: Widget.Box({
|
||||
className: "modules-center",
|
||||
children: [
|
||||
Media(),
|
||||
],
|
||||
}),
|
||||
endWidget: Widget.Box({
|
||||
className: "modules-right",
|
||||
hpack: "end",
|
||||
children: [
|
||||
Network(),
|
||||
Separator(),
|
||||
Volume(),
|
||||
Separator(),
|
||||
Battery(),
|
||||
Separator(),
|
||||
DateWidget(),
|
||||
Clock(),
|
||||
Separator(),
|
||||
SysTray(),
|
||||
Separator(),
|
||||
PowerBtn(),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
});
|
||||
99
INSTALL/configs/ags/widgets/Launcher.js
Normal file
99
INSTALL/configs/ags/widgets/Launcher.js
Normal file
@@ -0,0 +1,99 @@
|
||||
// ── violet-chaton v2 — Launcher widget ──────────────────────────────────────
|
||||
// App launcher avec recherche fuzzy
|
||||
|
||||
const applications = await Service.import("applications");
|
||||
|
||||
const AppItem = (app) => Widget.Button({
|
||||
className: "app-item",
|
||||
onClicked: () => {
|
||||
app.launch();
|
||||
App.closeWindow("launcher");
|
||||
},
|
||||
child: Widget.Box({
|
||||
children: [
|
||||
Widget.Icon({ icon: app.iconName || "application-x-executable", size: 24 }),
|
||||
Widget.Box({
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Label({
|
||||
label: app.name,
|
||||
xalign: 0,
|
||||
truncate: "end",
|
||||
}),
|
||||
Widget.Label({
|
||||
label: app.description || "",
|
||||
xalign: 0,
|
||||
truncate: "end",
|
||||
className: "description",
|
||||
css: "color: #716686; font-size: 11px; font-weight: normal;",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
export const Launcher = (monitor) => {
|
||||
let apps = applications.list;
|
||||
|
||||
const list = Widget.Box({
|
||||
vertical: true,
|
||||
spacing: 2,
|
||||
});
|
||||
|
||||
const entry = Widget.Entry({
|
||||
className: "search",
|
||||
placeholderText: "Rechercher...",
|
||||
onAccept: () => {
|
||||
const first = apps[0];
|
||||
if (first) {
|
||||
first.launch();
|
||||
App.closeWindow("launcher");
|
||||
}
|
||||
},
|
||||
onChange: ({ text }) => {
|
||||
apps = applications.query(text || "");
|
||||
list.children = apps.slice(0, 12).map(AppItem);
|
||||
|
||||
if (apps.length === 0) {
|
||||
list.children = [Widget.Label({
|
||||
className: "no-results",
|
||||
label: "Aucun resultat",
|
||||
})];
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return Widget.Window({
|
||||
name: "launcher",
|
||||
monitor,
|
||||
anchor: ["top"],
|
||||
layer: "overlay",
|
||||
visible: false,
|
||||
keymode: "exclusive",
|
||||
setup: (self) => {
|
||||
self.keybind("Escape", () => App.closeWindow("launcher"));
|
||||
self.hook(App, (_, name, visible) => {
|
||||
if (name === "launcher" && visible) {
|
||||
entry.text = "";
|
||||
apps = applications.list;
|
||||
list.children = apps.slice(0, 12).map(AppItem);
|
||||
entry.grab_focus();
|
||||
}
|
||||
});
|
||||
},
|
||||
child: Widget.Box({
|
||||
className: "launcher",
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Scrollable({
|
||||
hscroll: "never",
|
||||
vscroll: "automatic",
|
||||
css: "min-height: 400px;",
|
||||
child: list,
|
||||
}),
|
||||
entry,
|
||||
],
|
||||
}),
|
||||
});
|
||||
};
|
||||
105
INSTALL/configs/ags/widgets/Notifications.js
Normal file
105
INSTALL/configs/ags/widgets/Notifications.js
Normal file
@@ -0,0 +1,105 @@
|
||||
// ── violet-chaton v2 — Notifications widget ─────────────────────────────────
|
||||
// Popup notifications stylees — urgency-aware
|
||||
|
||||
const notifications = await Service.import("notifications");
|
||||
|
||||
// Ne pas déranger
|
||||
notifications.popupTimeout = 5000;
|
||||
notifications.cacheActions = true;
|
||||
|
||||
const NotificationIcon = (notif) => {
|
||||
if (notif.image) {
|
||||
return Widget.Box({
|
||||
css: `
|
||||
min-width: 48px; min-height: 48px;
|
||||
background-image: url("${notif.image}");
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
border-radius: 8px;
|
||||
margin-right: 10px;
|
||||
`,
|
||||
});
|
||||
}
|
||||
return Widget.Icon({
|
||||
icon: notif.appIcon || notif.appEntry || "dialog-information",
|
||||
size: 36,
|
||||
css: "margin-right: 10px;",
|
||||
});
|
||||
};
|
||||
|
||||
const Notification = (notif) => Widget.Box({
|
||||
className: `notification ${notif.urgency}`,
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
children: [
|
||||
NotificationIcon(notif),
|
||||
Widget.Box({
|
||||
vertical: true,
|
||||
hexpand: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
children: [
|
||||
Widget.Label({
|
||||
className: "title",
|
||||
label: notif.summary,
|
||||
xalign: 0,
|
||||
hexpand: true,
|
||||
truncate: "end",
|
||||
}),
|
||||
Widget.Label({
|
||||
className: "time",
|
||||
label: new Date(notif.time * 1000)
|
||||
.toLocaleTimeString("fr-FR", {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
}),
|
||||
}),
|
||||
Widget.Button({
|
||||
className: "close-btn",
|
||||
label: "✕",
|
||||
onClicked: () => notif.close(),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Widget.Label({
|
||||
className: "app-name",
|
||||
label: notif.appName || "",
|
||||
xalign: 0,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
...(notif.body ? [Widget.Label({
|
||||
className: "body",
|
||||
label: notif.body,
|
||||
xalign: 0,
|
||||
wrap: true,
|
||||
useMarkup: true,
|
||||
})] : []),
|
||||
...(notif.actions.length > 0 ? [Widget.Box({
|
||||
className: "actions",
|
||||
children: notif.actions.map((action) =>
|
||||
Widget.Button({
|
||||
label: action.label,
|
||||
onClicked: () => notif.invoke(action.id),
|
||||
})
|
||||
),
|
||||
})] : []),
|
||||
],
|
||||
});
|
||||
|
||||
export const Notifications = (monitor) => Widget.Window({
|
||||
name: `notifications-${monitor}`,
|
||||
monitor,
|
||||
anchor: ["top", "right"],
|
||||
layer: "overlay",
|
||||
child: Widget.Box({
|
||||
vertical: true,
|
||||
css: "min-width: 350px;",
|
||||
children: notifications.bind("popups").transform((popups) =>
|
||||
popups.map(Notification)
|
||||
),
|
||||
}),
|
||||
});
|
||||
95
INSTALL/configs/ags/widgets/OSD.js
Normal file
95
INSTALL/configs/ags/widgets/OSD.js
Normal file
@@ -0,0 +1,95 @@
|
||||
// ── violet-chaton v2 — OSD widget ───────────────────────────────────────────
|
||||
// Overlay volume / brightness avec gradient Mitsuri
|
||||
|
||||
const audio = await Service.import("audio");
|
||||
|
||||
// ── OSD reveal timer ────────────────────────────────────────────────────────
|
||||
|
||||
let osdTimeout = null;
|
||||
|
||||
const showOSD = (window) => {
|
||||
window.visible = true;
|
||||
if (osdTimeout) clearTimeout(osdTimeout);
|
||||
osdTimeout = setTimeout(() => {
|
||||
window.visible = false;
|
||||
}, 1500);
|
||||
};
|
||||
|
||||
// ── Volume OSD ──────────────────────────────────────────────────────────────
|
||||
|
||||
const VolumeOSD = () => {
|
||||
const icon = Widget.Label({ className: "icon" });
|
||||
const progress = Widget.ProgressBar();
|
||||
const label = Widget.Label({ className: "label" });
|
||||
|
||||
const box = Widget.Box({
|
||||
className: "osd",
|
||||
children: [icon, progress, label],
|
||||
connections: [[audio, (self) => {
|
||||
const vol = audio.speaker?.volume || 0;
|
||||
const muted = audio.speaker?.isMuted;
|
||||
icon.label = muted ? "" : vol > 0.66 ? "" : vol > 0.33 ? "" : "";
|
||||
progress.value = vol;
|
||||
label.label = `${Math.round(vol * 100)}%`;
|
||||
}, "speaker-changed"]],
|
||||
});
|
||||
|
||||
return box;
|
||||
};
|
||||
|
||||
// ── Brightness OSD ──────────────────────────────────────────────────────────
|
||||
|
||||
const BrightnessOSD = () => {
|
||||
const icon = Widget.Label({ className: "icon", label: "" });
|
||||
const progress = Widget.ProgressBar();
|
||||
const label = Widget.Label({ className: "label" });
|
||||
|
||||
const getBrightness = () => {
|
||||
try {
|
||||
const max = Number(Utils.exec("brightnessctl max"));
|
||||
const cur = Number(Utils.exec("brightnessctl get"));
|
||||
return max > 0 ? cur / max : 0;
|
||||
} catch {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
const box = Widget.Box({
|
||||
className: "osd",
|
||||
children: [icon, progress, label],
|
||||
connections: [[500, (self) => {
|
||||
const val = getBrightness();
|
||||
progress.value = val;
|
||||
label.label = `${Math.round(val * 100)}%`;
|
||||
}]],
|
||||
});
|
||||
|
||||
return box;
|
||||
};
|
||||
|
||||
// ── OSD windows ─────────────────────────────────────────────────────────────
|
||||
|
||||
export const OSD = (monitor) => {
|
||||
const volumeWin = Widget.Window({
|
||||
name: `osd-volume-${monitor}`,
|
||||
monitor,
|
||||
anchor: ["bottom"],
|
||||
layer: "overlay",
|
||||
visible: false,
|
||||
child: VolumeOSD(),
|
||||
});
|
||||
|
||||
const brightnessWin = Widget.Window({
|
||||
name: `osd-brightness-${monitor}`,
|
||||
monitor,
|
||||
anchor: ["bottom"],
|
||||
layer: "overlay",
|
||||
visible: false,
|
||||
child: BrightnessOSD(),
|
||||
});
|
||||
|
||||
// Auto-show on volume change
|
||||
Utils.merge([audio.speaker?.bind("volume")], () => showOSD(volumeWin));
|
||||
|
||||
return [volumeWin, brightnessWin];
|
||||
};
|
||||
@@ -1,376 +1,19 @@
|
||||
## ── violet-chaton config ──────────────────────────────────────────────────────
|
||||
dialect = "uk" # format de date européen
|
||||
## ── violet-chaton v2 — atuin config ──────────────────────────────────────────
|
||||
dialect = "uk"
|
||||
timezone = "local"
|
||||
search_mode = "fuzzy" # recherche floue comme fzf
|
||||
filter_mode = "global" # cherche dans tout l'historique
|
||||
style = "full" # interface complète
|
||||
inline_height = 40 # occupe 40% du terminal
|
||||
invert = true # barre de recherche en haut
|
||||
show_preview = true # aperçu de la commande sélectionnée
|
||||
enter_accept = true # Entrée accepte directement
|
||||
search_mode = "fuzzy"
|
||||
filter_mode = "global"
|
||||
style = "full"
|
||||
inline_height = 40
|
||||
invert = true
|
||||
show_preview = true
|
||||
enter_accept = true
|
||||
|
||||
[theme]
|
||||
name = "violet-chaton"
|
||||
|
||||
## ── fin config violet-chaton ──────────────────────────────────────────────────
|
||||
|
||||
## Base directory for Atuin data files (databases, keys, session, etc.)
|
||||
## All data file paths default to being relative to this directory.
|
||||
## linux/mac: ~/.local/share/atuin (or XDG_DATA_HOME/atuin)
|
||||
## windows: %USERPROFILE%/.local/share/atuin
|
||||
# data_dir = "~/.local/share/atuin"
|
||||
|
||||
## where to store your database, default is your system data directory
|
||||
## linux/mac: ~/.local/share/atuin/history.db
|
||||
## windows: %USERPROFILE%/.local/share/atuin/history.db
|
||||
# db_path = "~/.history.db"
|
||||
|
||||
## where to store your encryption key, default is your system data directory
|
||||
## linux/mac: ~/.local/share/atuin/key
|
||||
## windows: %USERPROFILE%/.local/share/atuin/key
|
||||
# key_path = "~/.key"
|
||||
|
||||
## where to store your auth session token, default is your system data directory
|
||||
## linux/mac: ~/.local/share/atuin/session
|
||||
## windows: %USERPROFILE%/.local/share/atuin/session
|
||||
# session_path = "~/.session"
|
||||
|
||||
## date format used, either "us" or "uk"
|
||||
# dialect = "us"
|
||||
|
||||
## default timezone to use when displaying time
|
||||
## either "l", "local" to use the system's current local timezone, or an offset
|
||||
## from UTC in the format of "<+|->H[H][:M[M][:S[S]]]"
|
||||
## for example: "+9", "-05", "+03:30", "-01:23:45", etc.
|
||||
# timezone = "local"
|
||||
|
||||
## enable or disable automatic sync
|
||||
# auto_sync = true
|
||||
|
||||
## enable or disable automatic update checks
|
||||
# update_check = true
|
||||
|
||||
## address of the sync server
|
||||
# sync_address = "https://api.atuin.sh"
|
||||
|
||||
## how often to sync history. note that this is only triggered when a command
|
||||
## is ran, so sync intervals may well be longer
|
||||
## set it to 0 to sync after every command
|
||||
# sync_frequency = "10m"
|
||||
|
||||
## which search mode to use
|
||||
## possible values: prefix, fulltext, fuzzy, skim
|
||||
# search_mode = "fuzzy"
|
||||
|
||||
## which filter mode to use by default
|
||||
## possible values: "global", "host", "session", "session-preload", "directory", "workspace"
|
||||
## consider using search.filters to customize the enablement and order of filter modes
|
||||
# filter_mode = "global"
|
||||
|
||||
## With workspace filtering enabled, Atuin will filter for commands executed
|
||||
## in any directory within a git repository tree (default: false).
|
||||
##
|
||||
## To use workspace mode by default when available, set this to true and
|
||||
## set filter_mode to "workspace" or leave it unspecified and
|
||||
## set search.filters to include "workspace" before other filter modes.
|
||||
# workspaces = false
|
||||
|
||||
## which filter mode to use when atuin is invoked from a shell up-key binding
|
||||
## the accepted values are identical to those of "filter_mode"
|
||||
## leave unspecified to use same mode set in "filter_mode"
|
||||
# filter_mode_shell_up_key_binding = "global"
|
||||
|
||||
## which search mode to use when atuin is invoked from a shell up-key binding
|
||||
## the accepted values are identical to those of "search_mode"
|
||||
## leave unspecified to use same mode set in "search_mode"
|
||||
# search_mode_shell_up_key_binding = "fuzzy"
|
||||
|
||||
## which style to use
|
||||
## possible values: auto, full, compact
|
||||
# style = "auto"
|
||||
|
||||
## the maximum number of lines the interface should take up
|
||||
## set it to 0 to always go full screen
|
||||
# inline_height = 0
|
||||
|
||||
## the maximum number of lines the interface should take up
|
||||
## when atuin is invoked from a shell up-key binding
|
||||
## the accepted values are identical to those of "inline_height"
|
||||
# inline_height_shell_up_key_binding = 0
|
||||
|
||||
## Invert the UI - put the search bar at the top , Default to `false`
|
||||
# invert = false
|
||||
|
||||
## enable or disable showing a preview of the selected command
|
||||
## useful when the command is longer than the terminal width and is cut off
|
||||
# show_preview = true
|
||||
|
||||
## what to do when the escape key is pressed when searching
|
||||
## possible values: return-original, return-query
|
||||
# exit_mode = "return-original"
|
||||
|
||||
## possible values: emacs, subl
|
||||
# word_jump_mode = "emacs"
|
||||
|
||||
## characters that count as a part of a word
|
||||
# word_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
|
||||
## number of context lines to show when scrolling by pages
|
||||
# scroll_context_lines = 1
|
||||
|
||||
## use ctrl instead of alt as the shortcut modifier key for numerical UI shortcuts
|
||||
## alt-0 .. alt-9
|
||||
# ctrl_n_shortcuts = false
|
||||
|
||||
## Show numeric shortcuts (1..9) beside list items in the TUI
|
||||
## set to false to hide the moving numbers if you find them distracting
|
||||
# show_numeric_shortcuts = true
|
||||
|
||||
## default history list format - can also be specified with the --format arg
|
||||
# history_format = "{time}\t{command}\t{duration}"
|
||||
|
||||
## prevent commands matching any of these regexes from being written to history.
|
||||
## Note that these regular expressions are unanchored, i.e. if they don't start
|
||||
## with ^ or end with $, they'll match anywhere in the command.
|
||||
## For details on the supported regular expression syntax, see
|
||||
## https://docs.rs/regex/latest/regex/#syntax
|
||||
# history_filter = [
|
||||
# "^secret-cmd",
|
||||
# "^innocuous-cmd .*--secret=.+",
|
||||
# ]
|
||||
|
||||
## prevent commands run with cwd matching any of these regexes from being written
|
||||
## to history. Note that these regular expressions are unanchored, i.e. if they don't
|
||||
## start with ^ or end with $, they'll match anywhere in CWD.
|
||||
## For details on the supported regular expression syntax, see
|
||||
## https://docs.rs/regex/latest/regex/#syntax
|
||||
# cwd_filter = [
|
||||
# "^/very/secret/area",
|
||||
# ]
|
||||
|
||||
## Configure the maximum height of the preview to show.
|
||||
## Useful when you have long scripts in your history that you want to distinguish
|
||||
## by more than the first few lines.
|
||||
# max_preview_height = 4
|
||||
|
||||
## Configure whether or not to show the help row, which includes the current Atuin
|
||||
## version (and whether an update is available), a keymap hint, and the total
|
||||
## amount of commands in your history.
|
||||
# show_help = true
|
||||
|
||||
## Configure whether or not to show tabs for search and inspect
|
||||
# show_tabs = true
|
||||
|
||||
## Configure whether or not the tabs row may be auto-hidden, which includes the current Atuin
|
||||
## tab, such as Search or Inspector, and other tabs you may wish to see. This will
|
||||
## only be hidden if there are fewer than this count of lines available, and does not affect the use
|
||||
## of keyboard shortcuts to switch tab. 0 to never auto-hide, default is 8 (lines).
|
||||
## This is ignored except in `compact` mode.
|
||||
# auto_hide_height = 8
|
||||
|
||||
## Defaults to true. This matches history against a set of default regex, and will not save it if we get a match. Defaults include
|
||||
## 1. AWS key id
|
||||
## 2. Github pat (old and new)
|
||||
## 3. Slack oauth tokens (bot, user)
|
||||
## 4. Slack webhooks
|
||||
## 5. Stripe live/test keys
|
||||
# secrets_filter = true
|
||||
|
||||
## Defaults to true. If enabled, upon hitting enter Atuin will immediately execute the command,
|
||||
## whereas tab will put the command in the prompt for editing.
|
||||
## If set to false, both enter and tab will place the command in the prompt for editing.
|
||||
## This applies for new installs. Old installs will keep the old behaviour unless configured otherwise.
|
||||
enter_accept = true
|
||||
|
||||
## Defaults to false. If enabled, when triggered after &&, || or |, Atuin will complete commands to chain rather than replace the current line.
|
||||
# command_chaining = false
|
||||
|
||||
## Defaults to "emacs". This specifies the keymap on the startup of `atuin
|
||||
## search`. If this is set to "auto", the startup keymap mode in the Atuin
|
||||
## search is automatically selected based on the shell's keymap where the
|
||||
## keybinding is defined. If this is set to "emacs", "vim-insert", or
|
||||
## "vim-normal", the startup keymap mode in the Atuin search is forced to be
|
||||
## the specified one.
|
||||
# keymap_mode = "auto"
|
||||
|
||||
## Cursor style in each keymap mode. If specified, the cursor style is changed
|
||||
## in entering the cursor shape. Available values are "default" and
|
||||
## "{blink,steady}-{block,underline,bar}".
|
||||
# keymap_cursor = { emacs = "blink-block", vim_insert = "blink-block", vim_normal = "steady-block" }
|
||||
|
||||
# network_connect_timeout = 5
|
||||
# network_timeout = 5
|
||||
|
||||
## Timeout (in seconds) for acquiring a local database connection (sqlite)
|
||||
# local_timeout = 5
|
||||
|
||||
## Set this to true and Atuin will minimize motion in the UI - timers will not update live, etc.
|
||||
## Alternatively, set env NO_MOTION=true
|
||||
# prefers_reduced_motion = false
|
||||
|
||||
[stats]
|
||||
## Set commands where we should consider the subcommand for statistics. Eg, kubectl get vs just kubectl
|
||||
# common_subcommands = [
|
||||
# "apt",
|
||||
# "cargo",
|
||||
# "composer",
|
||||
# "dnf",
|
||||
# "docker",
|
||||
# "dotnet",
|
||||
# "git",
|
||||
# "go",
|
||||
# "ip",
|
||||
# "jj",
|
||||
# "kubectl",
|
||||
# "nix",
|
||||
# "nmcli",
|
||||
# "npm",
|
||||
# "pecl",
|
||||
# "pnpm",
|
||||
# "podman",
|
||||
# "port",
|
||||
# "systemctl",
|
||||
# "tmux",
|
||||
# "yarn",
|
||||
# ]
|
||||
|
||||
## Set commands that should be totally stripped and ignored from stats
|
||||
# common_prefix = ["sudo"]
|
||||
|
||||
## Set commands that will be completely ignored from stats
|
||||
# ignored_commands = [
|
||||
# "cd",
|
||||
# "ls",
|
||||
# "vi"
|
||||
# ]
|
||||
|
||||
[keys]
|
||||
# Defaults to true. If disabled, using the up/down key won't exit the TUI when scrolled past the first/last entry.
|
||||
# scroll_exits = true
|
||||
|
||||
# Defaults to true. The left arrow key will exit the TUI when scrolling before the first character
|
||||
# exit_past_line_start = true
|
||||
|
||||
# Defaults to true. The right arrow key performs the same functionality as Tab and copies the selected line to the command line to be modified.
|
||||
# accept_past_line_end = true
|
||||
|
||||
# Defaults to false. The left arrow key performs the same functionality as Tab and copies the selected line to the command line to be modified.
|
||||
# accept_past_line_start = false
|
||||
|
||||
# Defaults to false. The backspace key performs the same functionality as Tab and copies the selected line to the command line to be modified when at the start of the line.
|
||||
# accept_with_backspace = false
|
||||
|
||||
[sync]
|
||||
# Enable sync v2 by default
|
||||
# This ensures that sync v2 is enabled for new installs only
|
||||
# In a later release it will become the default across the board
|
||||
records = true
|
||||
|
||||
[preview]
|
||||
## which preview strategy to use to calculate the preview height (respects max_preview_height).
|
||||
## possible values: auto, static
|
||||
## auto: length of the selected command.
|
||||
## static: length of the longest command stored in the history.
|
||||
## fixed: use max_preview_height as fixed height.
|
||||
# strategy = "auto"
|
||||
|
||||
[daemon]
|
||||
## Enables using the daemon to sync. Requires the daemon to be running in the background. Start it with `atuin daemon`
|
||||
# enabled = false
|
||||
|
||||
## How often the daemon should sync in seconds
|
||||
# sync_frequency = 300
|
||||
|
||||
## The path to the unix socket used by the daemon (on unix systems)
|
||||
## linux/mac: ~/.local/share/atuin/atuin.sock
|
||||
## windows: Not Supported
|
||||
# socket_path = "~/.local/share/atuin/atuin.sock"
|
||||
|
||||
## Use systemd socket activation rather than opening the given path (the path must still be correct for the client)
|
||||
## linux: false
|
||||
## mac/windows: Not Supported
|
||||
# systemd_socket = false
|
||||
|
||||
## The port that should be used for TCP on non unix systems
|
||||
# tcp_port = 8889
|
||||
|
||||
# [theme]
|
||||
## Color theme to use for rendering in the terminal.
|
||||
## There are some built-in themes, including the base theme ("default"),
|
||||
## "autumn" and "marine". You can add your own themes to the "./themes" subdirectory of your
|
||||
## Atuin config (or ATUIN_THEME_DIR, if provided) as TOML files whose keys should be one or
|
||||
## more of AlertInfo, AlertWarn, AlertError, Annotation, Base, Guidance, Important, and
|
||||
## the string values as lowercase entries from this list:
|
||||
## https://ogeon.github.io/docs/palette/master/palette/named/index.html
|
||||
## If you provide a custom theme file, it should be called "NAME.toml" and the theme below
|
||||
## should be the stem, i.e. `theme = "NAME"` for your chosen NAME.
|
||||
# name = "autumn"
|
||||
|
||||
## Whether the theme manager should output normal or extra information to help fix themes.
|
||||
## Boolean, true or false. If unset, left up to the theme manager.
|
||||
# debug = true
|
||||
|
||||
[search]
|
||||
## The list of enabled filter modes, in order of priority.
|
||||
## The "workspace" mode is skipped when not in a workspace or workspaces = false.
|
||||
## Default filter mode can be overridden with the filter_mode setting.
|
||||
# filters = [ "global", "host", "session", "session-preload", "workspace", "directory" ]
|
||||
|
||||
[tmux]
|
||||
## Enable using atuin with tmux popup (requires tmux >= 3.2)
|
||||
## When enabled and running inside tmux, Atuin will use a popup window for interactive search.
|
||||
## Set to false to disable the popup.
|
||||
## This can also be controlled with the ATUIN_TMUX_POPUP environment variable.
|
||||
## Note: The tmux popup is currently supported in zsh, bash, and fish shells. This currently doesn't work with iTerm native tmux integration.
|
||||
# enabled = false
|
||||
|
||||
## Width of the tmux popup window
|
||||
## Can be a percentage, or integer (e.g. "100" means 100 characters wide)
|
||||
# width = "80%"
|
||||
|
||||
## Height of the tmux popup window
|
||||
## Can be a percentage, or integer (e.g. "100" means 100 lines tall)
|
||||
# height = "60%"
|
||||
|
||||
[ui]
|
||||
columns = ["exit", "duration", "time", "command"]
|
||||
|
||||
## Columns to display in the interactive search, from left to right.
|
||||
## The selection indicator (" > ") is always shown first implicitly.
|
||||
##
|
||||
## Each column can be specified as a simple string (uses default width)
|
||||
## or as an object with type, width, and expand:
|
||||
## { type = "directory", width = 30, expand = true }
|
||||
##
|
||||
## Available column types (with default widths):
|
||||
## duration (5) - Command execution duration (e.g., "123ms")
|
||||
## time (8) - Relative time since execution (e.g., "59m ago")
|
||||
## datetime (16) - Absolute timestamp (e.g., "2025-01-22 14:35")
|
||||
## directory (20) - Working directory (truncated if too long)
|
||||
## host (15) - Hostname where command was run
|
||||
## user (10) - Username
|
||||
## exit (3) - Exit code (colored by success/failure)
|
||||
## command (*) - The command itself (expands by default)
|
||||
##
|
||||
## The "expand" option (default: true for command, false for others) makes a
|
||||
## column fill remaining space. Only one column should have expand = true.
|
||||
##
|
||||
## Default:
|
||||
# columns = ["duration", "time", "command"]
|
||||
##
|
||||
## Examples:
|
||||
##
|
||||
## Minimal - more space for commands:
|
||||
# columns = ["duration", "command"]
|
||||
##
|
||||
## With wider directory column:
|
||||
# columns = ["duration", { type = "directory", width = 30 }, "command"]
|
||||
##
|
||||
## Show host for multi-machine sync users:
|
||||
# columns = ["duration", "time", "host", "command"]
|
||||
##
|
||||
## Show exit codes prominently:
|
||||
# columns = ["exit", "duration", "command"]
|
||||
##
|
||||
## Make directory expand instead of command:
|
||||
# columns = ["duration", "time", { type = "directory", expand = true }, { type = "command", expand = false }]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Name=Waybar
|
||||
Comment=violet-chaton status bar
|
||||
Type=Application
|
||||
Exec=waybar
|
||||
Exec=bash -c "exec 9>/tmp/waybar-start.lock; flock -n 9 || exit 0; exec waybar"
|
||||
Hidden=false
|
||||
NoDisplay=false
|
||||
X-GNOME-Autostart-enabled=true
|
||||
|
||||
@@ -4,58 +4,74 @@
|
||||
"type": "none"
|
||||
},
|
||||
"display": {
|
||||
"separator": " ➜ ",
|
||||
"separator": " ",
|
||||
"color": {
|
||||
"keys": "magenta",
|
||||
"title": "cyan"
|
||||
"keys": "#ff4da6",
|
||||
"title": "#c9a0ff",
|
||||
"separator": "#5a3875"
|
||||
}
|
||||
},
|
||||
"modules": [
|
||||
"title",
|
||||
"separator",
|
||||
|
||||
{"type": "os", "key": " Système ", "keyColor": "magenta"},
|
||||
{"type": "kernel", "key": " Kernel ", "keyColor": "magenta"},
|
||||
{"type": "shell", "key": " Shell ", "keyColor": "magenta"},
|
||||
{"type": "terminal", "key": " Terminal ", "keyColor": "magenta"},
|
||||
{"type": "wm", "key": " Bureau ", "keyColor": "magenta"},
|
||||
{"type": "packages", "key": " Paquets ", "keyColor": "magenta"},
|
||||
{
|
||||
"type": "title",
|
||||
"format": "{user-name}@{host-name}",
|
||||
"keyColor": "#ff4da6"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "───────────────────────────────────",
|
||||
"outputColor": "#3d2454"
|
||||
},
|
||||
|
||||
"break",
|
||||
|
||||
{"type": "cpu", "key": " CPU ", "keyColor": "magenta"},
|
||||
{"type": "os", "key": " sys", "keyColor": "#ff4da6"},
|
||||
{"type": "kernel", "key": " ker", "keyColor": "#c9a0ff"},
|
||||
{"type": "shell", "key": " sh ", "keyColor": "#a4b4ff"},
|
||||
{"type": "terminal", "key": " trm", "keyColor": "#9adba8"},
|
||||
{"type": "wm", "key": " wm ", "keyColor": "#c9a0ff"},
|
||||
{"type": "packages", "key": " pkg", "keyColor": "#e8c87a"},
|
||||
|
||||
"break",
|
||||
|
||||
{"type": "cpu", "key": " cpu", "keyColor": "#ff4da6"},
|
||||
{
|
||||
"type": "gpu",
|
||||
"key": " GPU ",
|
||||
"keyColor": "magenta",
|
||||
"key": " gpu",
|
||||
"keyColor": "#c9a0ff",
|
||||
"hideTypes": ["Integrated"]
|
||||
},
|
||||
{
|
||||
"type": "display",
|
||||
"key": " Écran ",
|
||||
"keyColor": "magenta",
|
||||
"key": " dsp",
|
||||
"keyColor": "#a4b4ff",
|
||||
"format": "{width}x{height} @ {refresh-rate}Hz"
|
||||
},
|
||||
{"type": "memory", "key": " Mémoire ", "keyColor": "magenta"},
|
||||
{"type": "memory", "key": " mem", "keyColor": "#ff4da6"},
|
||||
{
|
||||
"type": "disk",
|
||||
"key": " Disque ",
|
||||
"keyColor": "magenta",
|
||||
"key": " dsk",
|
||||
"keyColor": "#e8c87a",
|
||||
"folders": "/"
|
||||
},
|
||||
{"type": "processes", "key": " Processus", "keyColor": "magenta"},
|
||||
{"type": "uptime", "key": " Uptime ", "keyColor": "magenta"},
|
||||
{"type": "uptime", "key": " up ", "keyColor": "#716686"},
|
||||
|
||||
"break",
|
||||
|
||||
{
|
||||
"type": "media",
|
||||
"key": " Musique ",
|
||||
"keyColor": "magenta",
|
||||
"key": " now",
|
||||
"keyColor": "#ff4da6",
|
||||
"format": "{artist} — {title}"
|
||||
},
|
||||
|
||||
"break",
|
||||
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "───────────────────────────────────",
|
||||
"outputColor": "#3d2454"
|
||||
},
|
||||
"colors"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -18,38 +18,38 @@
|
||||
navigate = true
|
||||
hyperlinks = true
|
||||
|
||||
# Lignes supprimées : fond rose sombre
|
||||
minus-style = syntax "#3d1a2e"
|
||||
minus-emph-style = syntax "#5a1a38"
|
||||
# Lignes supprimees : fond magenta sombre
|
||||
minus-style = syntax "#3a1230"
|
||||
minus-emph-style = syntax "#5a1848"
|
||||
|
||||
# Lignes ajoutées : fond cyan sombre
|
||||
plus-style = syntax "#0d2a35"
|
||||
plus-emph-style = syntax "#0d3a48"
|
||||
# Lignes ajoutees : fond mitsuri sombre
|
||||
plus-style = syntax "#1a3025"
|
||||
plus-emph-style = syntax "#1a4530"
|
||||
|
||||
# Numéros de ligne
|
||||
line-numbers-minus-style = "#ff79c6"
|
||||
line-numbers-plus-style = "#8be9fd"
|
||||
line-numbers-zero-style = "#6c7086"
|
||||
# Numeros de ligne
|
||||
line-numbers-minus-style = "#ff4da6"
|
||||
line-numbers-plus-style = "#9adba8"
|
||||
line-numbers-zero-style = "#716686"
|
||||
line-numbers-left-format = " {nm} │"
|
||||
line-numbers-right-format = " {np} │"
|
||||
|
||||
# En-tête de fichier
|
||||
file-style = "bold #e79cfe"
|
||||
# En-tete de fichier
|
||||
file-style = "bold #c9a0ff"
|
||||
file-decoration-style = "#3d2454 box"
|
||||
file-added-label = "[+]"
|
||||
file-removed-label = "[-]"
|
||||
file-modified-label = "[~]"
|
||||
file-renamed-label = "[»]"
|
||||
|
||||
# En-tête de hunk
|
||||
# En-tete de hunk
|
||||
hunk-header-style = "syntax #261537"
|
||||
hunk-header-decoration-style = "#6c7086 box"
|
||||
hunk-header-file-style = "bold #e79cfe"
|
||||
hunk-header-line-number-style = "#7f849c"
|
||||
hunk-header-decoration-style = "#716686 box"
|
||||
hunk-header-file-style = "bold #c9a0ff"
|
||||
hunk-header-line-number-style = "#9a8fad"
|
||||
|
||||
# Commit
|
||||
commit-decoration-style = "bold #ff79c6 box"
|
||||
commit-style = "bold #f8f8f2"
|
||||
commit-decoration-style = "bold #ff4da6 box"
|
||||
commit-style = "bold #f0eaf8"
|
||||
|
||||
[merge]
|
||||
conflictstyle = diff3
|
||||
|
||||
182
INSTALL/configs/kitty.conf
Normal file
182
INSTALL/configs/kitty.conf
Normal file
@@ -0,0 +1,182 @@
|
||||
# ── violet-chaton v2 — kitty terminal ────────────────────────────────────────
|
||||
# Font : Maple Mono NF — cursive italics + ligatures
|
||||
# Palette : violet-chaton v2 (source : themes/palette.sh)
|
||||
|
||||
# ── Font ─────────────────────────────────────────────────────────────────────
|
||||
font_family Maple Mono NF
|
||||
bold_font Maple Mono NF Bold
|
||||
italic_font Maple Mono NF Italic
|
||||
bold_italic_font Maple Mono NF Bold Italic
|
||||
font_size 13.0
|
||||
|
||||
# Ligatures et font features (cursive italics pour commentaires)
|
||||
disable_ligatures never
|
||||
font_features MapleMono-NF-Regular +cv01 +ss01 +ss02 +ss03 +ss05
|
||||
font_features MapleMono-NF-Italic +cv01 +ss01 +ss02 +ss03 +ss05
|
||||
font_features MapleMono-NF-Bold +cv01 +ss01 +ss02 +ss03 +ss05
|
||||
font_features MapleMono-NF-BoldItalic +cv01 +ss01 +ss02 +ss03 +ss05
|
||||
|
||||
# ── Cursor + trail effect ────────────────────────────────────────────────────
|
||||
cursor #ff4da6
|
||||
cursor_text_color #1a0e27
|
||||
cursor_shape beam
|
||||
cursor_beam_thickness 1.8
|
||||
cursor_blink_interval 0.4
|
||||
|
||||
# Undercurl style — vagues violettes pour les erreurs/warnings
|
||||
undercurl_style thin-sparse
|
||||
# Couleurs undercurl (utilisees par les apps qui supportent les colored underlines)
|
||||
# Les terminaux modernes + neovim/bat utilisent ces couleurs automatiquement
|
||||
|
||||
# Trail — trainee lumineuse magenta derriere le curseur
|
||||
cursor_trail 15
|
||||
cursor_trail_decay 0.05 0.3
|
||||
cursor_trail_start_threshold 0
|
||||
|
||||
# ── Scrollback ───────────────────────────────────────────────────────────────
|
||||
scrollback_lines 10000
|
||||
wheel_scroll_multiplier 3
|
||||
|
||||
# ── Mouse ────────────────────────────────────────────────────────────────────
|
||||
mouse_hide_wait 2.0
|
||||
url_color #a4b4ff
|
||||
url_style curly
|
||||
open_url_with default
|
||||
detect_urls yes
|
||||
|
||||
# ── Bell ─────────────────────────────────────────────────────────────────────
|
||||
enable_audio_bell no
|
||||
visual_bell_duration 0.0
|
||||
|
||||
# ── Window ───────────────────────────────────────────────────────────────────
|
||||
window_padding_width 8 12
|
||||
background_opacity 0.92
|
||||
dynamic_background_opacity yes
|
||||
dim_opacity 0.75
|
||||
|
||||
# Blur (compositor dependent — works on KWin, Hyprland, COSMIC)
|
||||
# background_blur 24
|
||||
|
||||
confirm_os_window_close 0
|
||||
initial_window_width 120c
|
||||
initial_window_height 35c
|
||||
|
||||
# ── Tab bar ──────────────────────────────────────────────────────────────────
|
||||
tab_bar_edge top
|
||||
tab_bar_style powerline
|
||||
tab_powerline_style slanted
|
||||
tab_bar_min_tabs 2
|
||||
|
||||
active_tab_foreground #1a0e27
|
||||
active_tab_background #ff4da6
|
||||
active_tab_font_style bold
|
||||
inactive_tab_foreground #c4b8d4
|
||||
inactive_tab_background #3d2454
|
||||
inactive_tab_font_style normal
|
||||
tab_bar_background #1a0e27
|
||||
|
||||
# ── Palette violet-chaton v2 ─────────────────────────────────────────────────
|
||||
|
||||
# Fond
|
||||
foreground #f0eaf8
|
||||
background #261537
|
||||
selection_foreground #1a0e27
|
||||
selection_background #c9a0ff
|
||||
|
||||
# Noir (fonds)
|
||||
color0 #261537
|
||||
color8 #5a3875
|
||||
|
||||
# Rouge (danger)
|
||||
color1 #f25c7a
|
||||
color9 #ff7a96
|
||||
|
||||
# Vert (mitsuri)
|
||||
color2 #9adba8
|
||||
color10 #b5e8c0
|
||||
|
||||
# Jaune (champagne)
|
||||
color3 #e8c87a
|
||||
color11 #f0d99a
|
||||
|
||||
# Bleu (lavande)
|
||||
color4 #a4b4ff
|
||||
color12 #bcc8ff
|
||||
|
||||
# Magenta
|
||||
color5 #ff4da6
|
||||
color13 #c9a0ff
|
||||
|
||||
# Cyan (lilac — pas de vrai cyan, on reste violet)
|
||||
color6 #c9a0ff
|
||||
color14 #dfc0ff
|
||||
|
||||
# Blanc (texte)
|
||||
color7 #c4b8d4
|
||||
color15 #f0eaf8
|
||||
|
||||
# ── Marks ────────────────────────────────────────────────────────────────────
|
||||
mark1_foreground #1a0e27
|
||||
mark1_background #ff4da6
|
||||
mark2_foreground #1a0e27
|
||||
mark2_background #c9a0ff
|
||||
mark3_foreground #1a0e27
|
||||
mark3_background #a4b4ff
|
||||
|
||||
# ── Keyboard shortcuts ──────────────────────────────────────────────────────
|
||||
|
||||
# Clipboard
|
||||
map ctrl+v paste_from_clipboard
|
||||
map ctrl+c copy_or_interrupt
|
||||
|
||||
# Tabs
|
||||
map ctrl+shift+t new_tab_with_cwd
|
||||
map ctrl+shift+l next_tab
|
||||
map ctrl+shift+h previous_tab
|
||||
map ctrl+shift+w close_tab
|
||||
map ctrl+shift+, set_tab_title
|
||||
|
||||
# Splits / Windows — tiling dans le terminal
|
||||
map ctrl+shift+enter new_window_with_cwd
|
||||
map ctrl+shift+\ launch --cwd=current --location=vsplit
|
||||
map ctrl+shift+- launch --cwd=current --location=hsplit
|
||||
map ctrl+shift+z toggle_layout stack
|
||||
map ctrl+shift+r start_resizing_window
|
||||
|
||||
# Navigation entre splits
|
||||
map ctrl+shift+left neighboring_window left
|
||||
map ctrl+shift+right neighboring_window right
|
||||
map ctrl+shift+up neighboring_window up
|
||||
map ctrl+shift+down neighboring_window down
|
||||
|
||||
# Swap splits
|
||||
map ctrl+shift+f move_window_forward
|
||||
map ctrl+shift+b move_window_backward
|
||||
|
||||
# Zoom
|
||||
map ctrl+shift+equal change_font_size all +1.0
|
||||
map ctrl+shift+minus change_font_size all -1.0
|
||||
map ctrl+shift+0 change_font_size all 0
|
||||
|
||||
# Reload
|
||||
map ctrl+shift+f5 load_config_file
|
||||
|
||||
# Quick layouts
|
||||
map ctrl+shift+1 goto_layout tall
|
||||
map ctrl+shift+2 goto_layout fat
|
||||
map ctrl+shift+3 goto_layout grid
|
||||
map ctrl+shift+4 goto_layout horizontal
|
||||
map ctrl+shift+5 goto_layout vertical
|
||||
|
||||
# ── Layouts ──────────────────────────────────────────────────────────────────
|
||||
enabled_layouts tall,fat,grid,horizontal,vertical,stack
|
||||
|
||||
# ── Splits styling ──────────────────────────────────────────────────────────
|
||||
active_border_color #ff4da6
|
||||
inactive_border_color #3d2454
|
||||
bell_border_color #f25c7a
|
||||
window_border_width 1.5pt
|
||||
window_margin_width 2
|
||||
single_window_margin_width 0
|
||||
draw_minimal_borders yes
|
||||
inactive_text_alpha 0.7
|
||||
37
INSTALL/configs/kitty/violet-chaton-glow.glsl
Normal file
37
INSTALL/configs/kitty/violet-chaton-glow.glsl
Normal file
@@ -0,0 +1,37 @@
|
||||
// violet-chaton v2 — subtle glow shader for kitty
|
||||
// Adds a soft bloom/glow around bright text characters
|
||||
// Usage: kitty --override 'background_shader=~/.config/kitty/violet-chaton-glow.glsl'
|
||||
|
||||
void main() {
|
||||
// Sample the original pixel
|
||||
vec4 color = texture(image, texCoord);
|
||||
|
||||
// Only glow on non-background pixels (bright enough)
|
||||
float brightness = dot(color.rgb, vec3(0.299, 0.587, 0.114));
|
||||
|
||||
if (brightness > 0.15) {
|
||||
// Sample surrounding pixels for bloom
|
||||
vec2 pixel = 1.0 / textureSize(image, 0);
|
||||
vec4 glow = vec4(0.0);
|
||||
float total = 0.0;
|
||||
|
||||
for (int x = -2; x <= 2; x++) {
|
||||
for (int y = -2; y <= 2; y++) {
|
||||
float weight = 1.0 / (1.0 + float(x*x + y*y));
|
||||
glow += texture(image, texCoord + vec2(float(x), float(y)) * pixel) * weight;
|
||||
total += weight;
|
||||
}
|
||||
}
|
||||
glow /= total;
|
||||
|
||||
// Blend glow with original — subtle violet tint
|
||||
float glowBrightness = dot(glow.rgb, vec3(0.299, 0.587, 0.114));
|
||||
vec3 violetTint = vec3(0.85, 0.55, 1.0); // lilac-ish
|
||||
vec3 glowColor = glow.rgb * violetTint;
|
||||
|
||||
// Mix: 85% original + 15% glow, only where text is
|
||||
color.rgb = mix(color.rgb, color.rgb + glowColor * 0.12, smoothstep(0.1, 0.4, glowBrightness));
|
||||
}
|
||||
|
||||
gl_FragColor = color;
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
gui:
|
||||
theme:
|
||||
activeBorderColor: ['#ff79c6', 'bold'] # pink — fenêtre active
|
||||
inactiveBorderColor: ['#6c7086'] # muted — fenêtre inactive
|
||||
optionsTextColor: ['#e79cfe'] # purple
|
||||
selectedLineBgColor: ['#3d2454'] # bg-high
|
||||
selectedRangeBgColor: ['#3d2454']
|
||||
activeBorderColor: ['#ff4da6', 'bold']
|
||||
inactiveBorderColor: ['#716686']
|
||||
optionsTextColor: ['#c9a0ff']
|
||||
selectedLineBgColor: ['#5a3875']
|
||||
selectedRangeBgColor: ['#5a3875']
|
||||
cherryPickedCommitBgColor: ['#3d2454']
|
||||
cherryPickedCommitFgColor: ['#8be9fd'] # cyan
|
||||
unstagedChangesColor: ['#f38ba8'] # danger
|
||||
defaultFgColor: ['#f8f8f2'] # text
|
||||
searchingActiveBorderColor: ['#8be9fd', 'bold'] # cyan
|
||||
cherryPickedCommitFgColor: ['#a4b4ff']
|
||||
unstagedChangesColor: ['#f25c7a']
|
||||
defaultFgColor: ['#f0eaf8']
|
||||
searchingActiveBorderColor: ['#a4b4ff', 'bold']
|
||||
nerdFontsVersion: '3'
|
||||
border: rounded
|
||||
git:
|
||||
|
||||
@@ -2,21 +2,53 @@
|
||||
command_timeout = 1000
|
||||
add_newline = true
|
||||
|
||||
# ── Format ────────────────────────────────────────────────────────────────────
|
||||
# Ligne 1 : infos → durée | mémoire | heure
|
||||
# Ligne 2 : ❯
|
||||
format = """
|
||||
$os $username$hostname$directory$git_branch$git_status$git_state$git_commit\
|
||||
$python$nodejs$rust$golang$java$docker_context$package\
|
||||
$fill\
|
||||
$cmd_duration$memory_usage$time
|
||||
$status$character"""
|
||||
# ── violet-chaton v2 — palette reference ─────────────────────────────────────
|
||||
# magenta #ff4da6 accent primaire
|
||||
# lilac #c9a0ff accent secondaire
|
||||
# mitsuri #9adba8 vert pastel (success, fresh)
|
||||
# lavande #a4b4ff bleu-violet (info, fonctions)
|
||||
# champagne #e8c87a or chaud (warning, langages)
|
||||
# danger #f25c7a rouge vif
|
||||
# text #f0eaf8 texte principal
|
||||
# subtext1 #c4b8d4 texte secondaire
|
||||
# subtext0 #9a8fad labels
|
||||
# muted #716686 desactive
|
||||
# surface2 #5a3875 selection
|
||||
|
||||
# ── Système ───────────────────────────────────────────────────────────────────
|
||||
# ── Format — 3 lignes ───────────────────────────────────────────────────────
|
||||
# Ligne 1 : separateur
|
||||
# Ligne 2 : os | dir | git | langages | ... fill ... | duree | batterie | heure
|
||||
# Ligne 3 : prompt caractere
|
||||
format = """
|
||||
[┌──](bold #5a3875) $os$sudo$username$hostname\
|
||||
$directory$git_branch$git_status$git_state$git_commit\
|
||||
$python$nodejs$rust$golang$java$docker_context$package$env_var\
|
||||
$fill\
|
||||
$cmd_duration$battery$time
|
||||
[└─](bold #5a3875) $status$character"""
|
||||
|
||||
# ── Palette Starship ─────────────────────────────────────────────────────────
|
||||
palette = "violet-chaton"
|
||||
|
||||
[palettes.violet-chaton]
|
||||
magenta = "#ff4da6"
|
||||
lilac = "#c9a0ff"
|
||||
mitsuri = "#9adba8"
|
||||
lavande = "#a4b4ff"
|
||||
champagne = "#e8c87a"
|
||||
danger = "#f25c7a"
|
||||
text = "#f0eaf8"
|
||||
subtext1 = "#c4b8d4"
|
||||
subtext0 = "#9a8fad"
|
||||
muted = "#716686"
|
||||
surface2 = "#5a3875"
|
||||
crust = "#1a0e27"
|
||||
|
||||
# ── Systeme ──────────────────────────────────────────────────────────────────
|
||||
|
||||
[os]
|
||||
disabled = false
|
||||
style = "bold #ff79c6"
|
||||
style = "bold magenta"
|
||||
format = "[$symbol]($style)"
|
||||
|
||||
[os.symbols]
|
||||
@@ -43,38 +75,44 @@ Macos = " "
|
||||
Windows = " "
|
||||
Unknown = " "
|
||||
|
||||
[sudo]
|
||||
disabled = false
|
||||
style = "bold danger"
|
||||
symbol = " "
|
||||
format = "[$symbol]($style)"
|
||||
|
||||
[username]
|
||||
style_user = "#9399b2"
|
||||
style_root = "bold #f38ba8"
|
||||
style_user = "subtext0"
|
||||
style_root = "bold danger"
|
||||
format = "[$user]($style)"
|
||||
show_always = true
|
||||
show_always = false
|
||||
|
||||
[hostname]
|
||||
style = "#7f849c"
|
||||
style = "muted"
|
||||
format = "[@$hostname ]($style)"
|
||||
ssh_only = false
|
||||
ssh_only = true
|
||||
ssh_symbol = " "
|
||||
|
||||
# ── Navigation ────────────────────────────────────────────────────────────────
|
||||
# ── Navigation ───────────────────────────────────────────────────────────────
|
||||
|
||||
[directory]
|
||||
style = "bold #e79cfe"
|
||||
style = "bold lilac"
|
||||
read_only = " "
|
||||
read_only_style = "#f38ba8"
|
||||
read_only_style = "danger"
|
||||
truncate_to_repo = false
|
||||
truncation_length = 4
|
||||
truncation_symbol = "…/"
|
||||
format = "[ $path]($style)[$read_only]($read_only_style) "
|
||||
|
||||
# ── Git ───────────────────────────────────────────────────────────────────────
|
||||
# ── Git ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
[git_branch]
|
||||
symbol = " "
|
||||
style = "bold #ff79c6"
|
||||
style = "bold magenta"
|
||||
format = "[$symbol$branch]($style) "
|
||||
|
||||
[git_status]
|
||||
style = "#8be9fd"
|
||||
style = "mitsuri"
|
||||
format = "([$all_status$ahead_behind]($style) )"
|
||||
ahead = "⇡$count"
|
||||
behind = "⇣$count"
|
||||
@@ -88,85 +126,98 @@ deleted = "✘$count"
|
||||
conflicted = "=$count"
|
||||
|
||||
[git_state]
|
||||
style = "#f9e2af"
|
||||
style = "champagne"
|
||||
format = '\([$state( $progress_current/$progress_total)]($style)\) '
|
||||
|
||||
[git_commit]
|
||||
style = "#6c7086"
|
||||
style = "muted"
|
||||
format = '[\($hash$tag\)]($style) '
|
||||
tag_symbol = " "
|
||||
only_detached = true
|
||||
|
||||
# ── Langages ──────────────────────────────────────────────────────────────────
|
||||
# ── Langages ─────────────────────────────────────────────────────────────────
|
||||
|
||||
[python]
|
||||
symbol = " "
|
||||
style = "#f9e2af"
|
||||
style = "champagne"
|
||||
format = "[$symbol$version]($style) "
|
||||
|
||||
[nodejs]
|
||||
symbol = " "
|
||||
style = "#a6e3a1"
|
||||
style = "mitsuri"
|
||||
format = "[$symbol$version]($style) "
|
||||
|
||||
[rust]
|
||||
symbol = " "
|
||||
style = "#ff79c6"
|
||||
style = "magenta"
|
||||
format = "[$symbol$version]($style) "
|
||||
|
||||
[golang]
|
||||
symbol = " "
|
||||
style = "#8be9fd"
|
||||
style = "lavande"
|
||||
format = "[$symbol$version]($style) "
|
||||
|
||||
[java]
|
||||
symbol = " "
|
||||
style = "#f38ba8"
|
||||
style = "danger"
|
||||
format = "[$symbol$version]($style) "
|
||||
|
||||
[docker_context]
|
||||
symbol = " "
|
||||
style = "#8be9fd"
|
||||
style = "lavande"
|
||||
format = "[$symbol$context]($style) "
|
||||
only_with_files = true
|
||||
|
||||
[package]
|
||||
symbol = " "
|
||||
style = "#e79cfe"
|
||||
style = "lilac"
|
||||
format = "[$symbol$version]($style) "
|
||||
display_private = false
|
||||
|
||||
# ── Droite (après $fill) ─────────────────────────────────────────────────────
|
||||
# ── Env var custom — brain_name ──────────────────────────────────────────────
|
||||
[env_var.brain_name]
|
||||
variable = "brain_name"
|
||||
style = "italic muted"
|
||||
symbol = " "
|
||||
format = "[$symbol$env_value]($style) "
|
||||
|
||||
# ── Droite (apres $fill) ────────────────────────────────────────────────────
|
||||
|
||||
[fill]
|
||||
symbol = " "
|
||||
symbol = "─"
|
||||
style = "#3d2454"
|
||||
|
||||
[cmd_duration]
|
||||
format = "[ $duration]($style) "
|
||||
style = "#7f849c"
|
||||
style = "subtext0"
|
||||
min_time = 2000
|
||||
|
||||
[memory_usage]
|
||||
[battery]
|
||||
disabled = false
|
||||
threshold = 0
|
||||
symbol = " "
|
||||
style = "#9399b2"
|
||||
format = "[$symbol$ram]($style) "
|
||||
format = "[$symbol$percentage]($style) "
|
||||
|
||||
[[battery.display]]
|
||||
threshold = 30
|
||||
style = "bold danger"
|
||||
|
||||
[[battery.display]]
|
||||
threshold = 70
|
||||
style = "champagne"
|
||||
|
||||
[time]
|
||||
disabled = false
|
||||
style = "bold #6c7086"
|
||||
style = "bold muted"
|
||||
format = "[ $time]($style)"
|
||||
time_format = "%H:%M"
|
||||
|
||||
# ── Ligne 2 ───────────────────────────────────────────────────────────────────
|
||||
# ── Ligne 3 — le prompt ─────────────────────────────────────────────────────
|
||||
|
||||
[status]
|
||||
disabled = false
|
||||
style = "#ff79c6"
|
||||
style = "danger"
|
||||
format = "[$symbol$status ]($style)"
|
||||
symbol = "✘ "
|
||||
|
||||
[character]
|
||||
success_symbol = "[❯](bold #8be9fd)"
|
||||
error_symbol = "[❯](bold #ff79c6)"
|
||||
success_symbol = "[❯](bold mitsuri)"
|
||||
error_symbol = "[❯](bold magenta)"
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
"custom/launcher",
|
||||
"custom/sep",
|
||||
"cpu",
|
||||
"temperature",
|
||||
"custom/cpu-temp",
|
||||
"custom/gpu",
|
||||
"memory",
|
||||
"disk",
|
||||
"custom/disks",
|
||||
"custom/sep",
|
||||
"custom/network"
|
||||
],
|
||||
@@ -77,15 +77,13 @@
|
||||
"interval": 2
|
||||
},
|
||||
|
||||
// ── Température ─────────────────────────────────────────────────────────
|
||||
// ── Température CPU (auto-détection) ────────────────────────────────────
|
||||
|
||||
"temperature": {
|
||||
"thermal-zone": 9,
|
||||
"format": " {temperatureC}°",
|
||||
"format-critical": " {temperatureC}°",
|
||||
"critical-threshold": 80,
|
||||
"tooltip": false,
|
||||
"interval": 2
|
||||
"custom/cpu-temp": {
|
||||
"exec": "~/.config/waybar/scripts/cpu-temp.sh",
|
||||
"return-type": "json",
|
||||
"interval": 2,
|
||||
"format": "{}"
|
||||
},
|
||||
|
||||
// ── GPU ─────────────────────────────────────────────────────────────────
|
||||
@@ -109,12 +107,13 @@
|
||||
"interval": 2
|
||||
},
|
||||
|
||||
// ── Disque ──────────────────────────────────────────────────────────────
|
||||
// ── Disques (auto-détection) ─────────────────────────────────────────────
|
||||
|
||||
"disk": {
|
||||
"format": " {used}",
|
||||
"tooltip-format": " Disque /\n{used} / {total}\n{percentage_used}% utilisé",
|
||||
"interval": 30
|
||||
"custom/disks": {
|
||||
"exec": "~/.config/waybar/scripts/disks.sh",
|
||||
"return-type": "json",
|
||||
"interval": 30,
|
||||
"format": "{}"
|
||||
},
|
||||
|
||||
// ── Réseau ──────────────────────────────────────────────────────────────
|
||||
|
||||
43
INSTALL/configs/waybar/scripts/cpu-temp.sh
Executable file
43
INSTALL/configs/waybar/scripts/cpu-temp.sh
Executable file
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env bash
|
||||
# cpu-temp.sh — température CPU auto-détection → JSON waybar
|
||||
# Priorité 1 : thermal zone x86_pkg_temp (Intel) ou k10temp (AMD)
|
||||
# Priorité 2 : hwmon coretemp / k10temp / zenpower
|
||||
# Retourne vide si aucune source trouvée
|
||||
|
||||
emit() {
|
||||
local temp=$1
|
||||
local cls="normal"
|
||||
(( temp >= 80 )) && cls="critical"
|
||||
(( temp >= 65 && temp < 80 )) && cls="warning"
|
||||
printf '{"text":" %d°","tooltip":"CPU %d°C","class":"%s","percentage":%d}\n' \
|
||||
"$temp" "$temp" "$cls" "$temp"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Priorité 1 — thermal_zone x86_pkg_temp (Intel) / TCPU / k10temp (AMD)
|
||||
for zone in /sys/class/thermal/thermal_zone*/; do
|
||||
zone_type=$(cat "${zone}type" 2>/dev/null) || continue
|
||||
case "$zone_type" in
|
||||
x86_pkg_temp|k10temp|TCPU|cpu_thermal)
|
||||
temp_raw=$(cat "${zone}temp" 2>/dev/null) || continue
|
||||
emit $(( temp_raw / 1000 ))
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Priorité 2 — hwmon coretemp (Intel desktop) ou k10temp (AMD)
|
||||
for hw in /sys/class/hwmon/hwmon*/; do
|
||||
hw_name=$(cat "${hw}name" 2>/dev/null) || continue
|
||||
case "$hw_name" in
|
||||
coretemp|k10temp|zenpower|amd_energy)
|
||||
for f in "${hw}temp1_input" "${hw}temp2_input"; do
|
||||
[[ -r "$f" ]] || continue
|
||||
temp_raw=$(cat "$f" 2>/dev/null) || continue
|
||||
emit $(( temp_raw / 1000 ))
|
||||
done
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Aucune source — module masqué
|
||||
printf '{"text":"","class":"unavailable"}\n'
|
||||
58
INSTALL/configs/waybar/scripts/disks.sh
Executable file
58
INSTALL/configs/waybar/scripts/disks.sh
Executable file
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env bash
|
||||
# disks.sh — liste les vrais systèmes de fichiers montés → JSON waybar
|
||||
# Exclut tmpfs, devtmpfs, squashfs (snap), overlay, efi, etc.
|
||||
|
||||
TEXT=""
|
||||
TOOLTIP=" Disques\n"
|
||||
|
||||
while IFS= read -r line; do
|
||||
fs=$(awk '{print $1}' <<< "$line")
|
||||
size=$(awk '{print $2}' <<< "$line")
|
||||
used=$(awk '{print $3}' <<< "$line")
|
||||
avail=$(awk '{print $4}' <<< "$line")
|
||||
pct=$(awk '{print $5}' <<< "$line")
|
||||
mnt=$(awk '{print $6}' <<< "$line")
|
||||
|
||||
# Exclure mounts sans intérêt
|
||||
[[ "$mnt" == /snap/* ]] && continue
|
||||
[[ "$mnt" == /boot/efi ]] && continue
|
||||
[[ "$mnt" == /boot ]] && continue
|
||||
[[ "$mnt" == /recovery ]] && continue
|
||||
[[ "$mnt" == /run* ]] && continue
|
||||
[[ "$mnt" == /sys* ]] && continue
|
||||
[[ "$mnt" == /proc* ]] && continue
|
||||
[[ "$mnt" == /dev* ]] && continue
|
||||
|
||||
# Icône selon le point de montage
|
||||
case "$mnt" in
|
||||
/) icon="" ;;
|
||||
/home) icon="" ;;
|
||||
/data*) icon="" ;;
|
||||
/media*) icon="" ;;
|
||||
/mnt*) icon="" ;;
|
||||
*) icon="" ;;
|
||||
esac
|
||||
|
||||
# Texte compact : icône + montage court + espace utilisé
|
||||
label=$(basename "$mnt")
|
||||
[[ "$mnt" == "/" ]] && label="/"
|
||||
[[ -n "$TEXT" ]] && TEXT+=" "
|
||||
TEXT+="${icon} ${label}: ${used}"
|
||||
|
||||
TOOLTIP+="${icon} ${mnt}\n Utilisé : ${used} / ${size} (${pct})\n Libre : ${avail}\n"
|
||||
|
||||
done < <(df -hP --exclude-type=tmpfs \
|
||||
--exclude-type=devtmpfs \
|
||||
--exclude-type=squashfs \
|
||||
--exclude-type=overlay \
|
||||
--exclude-type=fuse.portal \
|
||||
--exclude-type=efivarfs \
|
||||
2>/dev/null | tail -n +2 | sort -k6)
|
||||
|
||||
if [[ -z "$TEXT" ]]; then
|
||||
printf '{"text":" N/A","tooltip":"Aucun disque détecté","class":"unavailable"}\n'
|
||||
else
|
||||
# Échapper uniquement les guillemets pour JSON (\n reste tel quel = saut de ligne)
|
||||
TOOLTIP_JSON=$(printf '%s' "$TOOLTIP" | sed 's/"/\\"/g')
|
||||
printf '{"text":"%s","tooltip":"%s"}\n' "$TEXT" "$TOOLTIP_JSON"
|
||||
fi
|
||||
@@ -3,19 +3,17 @@
|
||||
|
||||
STATE_FILE="/tmp/waybar_net_state"
|
||||
|
||||
# Détecter l'interface active
|
||||
IFACE=""
|
||||
for candidate in enp7s0 enp6s0 eth0; do
|
||||
if [[ -d "/sys/class/net/$candidate" && "$(cat /sys/class/net/$candidate/operstate 2>/dev/null)" == "up" ]]; then
|
||||
IFACE="$candidate"; TYPE="eth"; break
|
||||
# Détecter l'interface active via la route par défaut (portable sur tous les PC)
|
||||
IFACE=$(ip route get 1.1.1.1 2>/dev/null \
|
||||
| awk '/dev/{for(i=1;i<=NF;i++) if($i=="dev") print $(i+1)}' \
|
||||
| head -1)
|
||||
|
||||
if [[ -n "$IFACE" ]]; then
|
||||
if [[ -d "/sys/class/net/$IFACE/wireless" || -d "/sys/class/net/$IFACE/phy80211" ]]; then
|
||||
TYPE="wifi"
|
||||
else
|
||||
TYPE="eth"
|
||||
fi
|
||||
done
|
||||
if [[ -z "$IFACE" ]]; then
|
||||
for candidate in wlp8s0 wlp0s20f3 wlan0; do
|
||||
if [[ -d "/sys/class/net/$candidate" && "$(cat /sys/class/net/$candidate/operstate 2>/dev/null)" == "up" ]]; then
|
||||
IFACE="$candidate"; TYPE="wifi"; break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [[ -z "$IFACE" ]]; then
|
||||
|
||||
@@ -40,6 +40,12 @@ fi
|
||||
|
||||
# ── Affichage JSON ────────────────────────────────────────────────────────────
|
||||
|
||||
# PC fixe ou VM sans gestion de profil → module masqué
|
||||
if [[ ! -f /sys/firmware/acpi/platform_profile ]]; then
|
||||
printf '{"text":"","class":"unavailable"}\n'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
PROFILE=$(cat /sys/firmware/acpi/platform_profile 2>/dev/null || echo "unknown")
|
||||
|
||||
case "$PROFILE" in
|
||||
|
||||
@@ -1,245 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# vc-brightness-popup.py — Popup luminosité violet-chaton
|
||||
# Lancé par le clic sur le module backlight de waybar
|
||||
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
gi.require_version('GtkLayerShell', '0.1')
|
||||
from gi.repository import Gtk, Gdk, GtkLayerShell, GLib
|
||||
import subprocess
|
||||
import os
|
||||
import re
|
||||
|
||||
# ── CSS ───────────────────────────────────────────────────────────────────────
|
||||
|
||||
CSS = b"""
|
||||
window {
|
||||
background-color: rgba(52, 28, 74, 0.93);
|
||||
border: 3px solid rgba(255, 121, 198, 0.78);
|
||||
border-radius: 14px;
|
||||
}
|
||||
|
||||
#container {
|
||||
padding: 14px 20px 16px 20px;
|
||||
}
|
||||
|
||||
#bright-icon {
|
||||
color: #8be9fd;
|
||||
font-family: "JetBrainsMono Nerd Font";
|
||||
font-size: 18px;
|
||||
min-width: 24px;
|
||||
}
|
||||
|
||||
#bright-title {
|
||||
color: rgba(248, 248, 242, 0.55);
|
||||
font-family: "JetBrainsMono Nerd Font";
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
#device-name {
|
||||
color: #8be9fd;
|
||||
font-family: "JetBrainsMono Nerd Font";
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#bright-pct {
|
||||
color: #f8f8f2;
|
||||
font-family: "JetBrainsMono Nerd Font";
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
min-width: 44px;
|
||||
}
|
||||
|
||||
#separator {
|
||||
color: rgba(92, 73, 108, 0.60);
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
scale trough {
|
||||
background-color: rgba(92, 73, 108, 0.55);
|
||||
border-radius: 3px;
|
||||
min-height: 6px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
scale highlight {
|
||||
background-color: #8be9fd;
|
||||
border-radius: 3px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
scale slider {
|
||||
background-color: #f8f8f2;
|
||||
border-radius: 50%;
|
||||
min-width: 18px;
|
||||
min-height: 18px;
|
||||
border: 2px solid rgba(139, 233, 253, 0.80);
|
||||
box-shadow: none;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
scale slider:hover {
|
||||
background-color: #8be9fd;
|
||||
border-color: #8be9fd;
|
||||
}
|
||||
"""
|
||||
|
||||
POPUP_WIDTH = 300
|
||||
|
||||
# ── Brightness helpers ────────────────────────────────────────────────────────
|
||||
|
||||
def get_brightness():
|
||||
"""Retourne (valeur 0-100, nom du device)."""
|
||||
try:
|
||||
r = subprocess.run(
|
||||
['brightnessctl', 'info'],
|
||||
capture_output=True, text=True, timeout=2
|
||||
)
|
||||
pct_match = re.search(r'\((\d+)%\)', r.stdout)
|
||||
dev_match = re.search(r"Device '([^']+)'", r.stdout)
|
||||
pct = int(pct_match.group(1)) if pct_match else 50
|
||||
dev = dev_match.group(1) if dev_match else 'Écran'
|
||||
# Rendre le nom plus lisible
|
||||
dev = dev.replace('_', ' ').replace('backlight', '').strip().title()
|
||||
return pct, dev
|
||||
except Exception:
|
||||
return 50, 'Écran'
|
||||
|
||||
def set_brightness(pct):
|
||||
pct = max(1, min(100, pct)) # minimum 1% pour ne pas éteindre l'écran
|
||||
subprocess.run(
|
||||
['brightnessctl', 'set', f'{pct}%', '-q'],
|
||||
capture_output=True
|
||||
)
|
||||
# Feedback wob
|
||||
fifo = '/tmp/wob.fifo'
|
||||
if os.path.exists(fifo):
|
||||
try:
|
||||
fd = os.open(fifo, os.O_WRONLY | os.O_NONBLOCK)
|
||||
os.write(fd, f'{pct}\n'.encode())
|
||||
os.close(fd)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def bright_icon(pct):
|
||||
if pct < 34:
|
||||
return ''
|
||||
if pct < 67:
|
||||
return ''
|
||||
return ''
|
||||
|
||||
# ── Popup ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
class BrightnessPopup(Gtk.Window):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._blocked = False
|
||||
|
||||
# ── Position : centré sous le module backlight ────────────────────────
|
||||
display = Gdk.Display.get_default()
|
||||
monitor = display.get_primary_monitor() if display else None
|
||||
screen_w = monitor.get_geometry().width if monitor else 1920
|
||||
|
||||
# Backlight est le 2e module de la pill droite (~250px depuis le bord)
|
||||
module_center = screen_w - 16 - 250
|
||||
margin_left = max(0, module_center - POPUP_WIDTH // 2)
|
||||
|
||||
GtkLayerShell.init_for_window(self)
|
||||
GtkLayerShell.set_layer(self, GtkLayerShell.Layer.OVERLAY)
|
||||
GtkLayerShell.set_anchor(self, GtkLayerShell.Edge.TOP, True)
|
||||
GtkLayerShell.set_anchor(self, GtkLayerShell.Edge.LEFT, True)
|
||||
GtkLayerShell.set_margin(self, GtkLayerShell.Edge.TOP, 66)
|
||||
GtkLayerShell.set_margin(self, GtkLayerShell.Edge.LEFT, margin_left)
|
||||
GtkLayerShell.set_keyboard_mode(self, GtkLayerShell.KeyboardMode.ON_DEMAND)
|
||||
GtkLayerShell.set_exclusive_zone(self, -1)
|
||||
|
||||
self.set_decorated(False)
|
||||
self.set_resizable(False)
|
||||
self.set_default_size(POPUP_WIDTH, -1)
|
||||
|
||||
# ── CSS ───────────────────────────────────────────────────────────────
|
||||
provider = Gtk.CssProvider()
|
||||
provider.load_from_data(CSS)
|
||||
Gtk.StyleContext.add_provider_for_screen(
|
||||
Gdk.Screen.get_default(),
|
||||
provider,
|
||||
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
|
||||
)
|
||||
|
||||
# ── État initial ──────────────────────────────────────────────────────
|
||||
pct, dev = get_brightness()
|
||||
|
||||
# ── Layout ────────────────────────────────────────────────────────────
|
||||
container = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
|
||||
container.set_name('container')
|
||||
self.add(container)
|
||||
|
||||
# Ligne device
|
||||
dev_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
|
||||
dev_icon = Gtk.Label(label='')
|
||||
dev_icon.set_name('bright-title')
|
||||
dev_row.pack_start(dev_icon, False, False, 0)
|
||||
dev_label = Gtk.Label(label=dev)
|
||||
dev_label.set_name('device-name')
|
||||
dev_label.set_halign(Gtk.Align.START)
|
||||
dev_label.set_ellipsize(3)
|
||||
dev_row.pack_start(dev_label, True, True, 0)
|
||||
container.pack_start(dev_row, False, False, 0)
|
||||
|
||||
# Séparateur
|
||||
sep = Gtk.Label(label='─' * 30)
|
||||
sep.set_name('separator')
|
||||
container.pack_start(sep, False, False, 4)
|
||||
|
||||
# En-tête : icône + "Luminosité" + %
|
||||
header = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=8)
|
||||
self.icon = Gtk.Label(label=bright_icon(pct))
|
||||
self.icon.set_name('bright-icon')
|
||||
header.pack_start(self.icon, False, False, 0)
|
||||
|
||||
title = Gtk.Label(label='Luminosité')
|
||||
title.set_name('bright-title')
|
||||
title.set_halign(Gtk.Align.START)
|
||||
header.pack_start(title, True, True, 0)
|
||||
|
||||
self.pct = Gtk.Label(label=f'{pct}%')
|
||||
self.pct.set_name('bright-pct')
|
||||
self.pct.set_halign(Gtk.Align.END)
|
||||
header.pack_end(self.pct, False, False, 0)
|
||||
container.pack_start(header, False, False, 0)
|
||||
|
||||
# Slider (min 1% pour ne pas éteindre l'écran)
|
||||
self.scale = Gtk.Scale.new_with_range(
|
||||
Gtk.Orientation.HORIZONTAL, 1, 100, 5
|
||||
)
|
||||
self.scale.set_value(pct)
|
||||
self.scale.set_draw_value(False)
|
||||
self.scale.set_hexpand(True)
|
||||
self.scale.connect('value-changed', self._on_changed)
|
||||
container.pack_start(self.scale, False, False, 0)
|
||||
|
||||
# ── Fermeture ─────────────────────────────────────────────────────────
|
||||
self.connect('key-press-event', self._on_key)
|
||||
self.connect('focus-out-event', lambda *_: self.destroy())
|
||||
|
||||
self.show_all()
|
||||
self.grab_focus()
|
||||
|
||||
def _on_changed(self, scale):
|
||||
if self._blocked:
|
||||
return
|
||||
pct = int(scale.get_value())
|
||||
self.pct.set_label(f'{pct}%')
|
||||
self.icon.set_label(bright_icon(pct))
|
||||
set_brightness(pct)
|
||||
|
||||
def _on_key(self, _widget, event):
|
||||
if event.keyval == Gdk.KEY_Escape:
|
||||
self.destroy()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
win = BrightnessPopup()
|
||||
win.connect('destroy', Gtk.main_quit)
|
||||
Gtk.main()
|
||||
@@ -3,9 +3,16 @@
|
||||
# Lancé depuis le clic sur wireplumber OU backlight
|
||||
|
||||
import gi
|
||||
import math
|
||||
import threading
|
||||
import urllib.request
|
||||
|
||||
gi.require_version('Gtk', '3.0')
|
||||
gi.require_version('GtkLayerShell', '0.1')
|
||||
from gi.repository import Gtk, Gdk, GtkLayerShell, GLib
|
||||
gi.require_version('GdkPixbuf', '2.0')
|
||||
gi.require_version('Pango', '1.0')
|
||||
gi.require_version('PangoCairo', '1.0')
|
||||
from gi.repository import Gtk, Gdk, GtkLayerShell, GLib, GdkPixbuf, Pango, PangoCairo
|
||||
import subprocess
|
||||
import os
|
||||
import re
|
||||
@@ -135,6 +142,31 @@ scale.audio.muted slider {
|
||||
border-color: rgba(108, 112, 134, 0.60);
|
||||
}
|
||||
|
||||
/* ── Sélecteur de périphérique de sortie ────────────────────────────────────── */
|
||||
|
||||
#device-btn {
|
||||
background-color: transparent;
|
||||
color: rgba(248, 248, 242, 0.65);
|
||||
font-family: "JetBrainsMono Nerd Font";
|
||||
font-size: 11px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 8px;
|
||||
padding: 5px 10px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
#device-btn:hover {
|
||||
background-color: rgba(91, 70, 113, 0.55);
|
||||
color: #f8f8f2;
|
||||
border-color: rgba(92, 73, 108, 0.60);
|
||||
}
|
||||
|
||||
#device-btn.active {
|
||||
background-color: rgba(255, 121, 198, 0.14);
|
||||
color: #ff79c6;
|
||||
border-color: rgba(255, 121, 198, 0.55);
|
||||
}
|
||||
|
||||
/* ── Slider luminosité (cyan) ───────────────────────────────────────────────── */
|
||||
|
||||
scale.bright {
|
||||
@@ -176,14 +208,55 @@ scale.bright slider:hover {
|
||||
font-size: 17px;
|
||||
min-width: 28px;
|
||||
}
|
||||
|
||||
/* ── Section MPRIS ────────────────────────────────────────────────────────── */
|
||||
|
||||
#mpris-title {
|
||||
color: #f8f8f2;
|
||||
font-family: "JetBrainsMono Nerd Font";
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#mpris-artist {
|
||||
color: rgba(248, 248, 242, 0.55);
|
||||
font-family: "JetBrainsMono Nerd Font";
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
#mpris-btn {
|
||||
background-color: transparent;
|
||||
color: #e79cfe;
|
||||
font-family: "JetBrainsMono Nerd Font";
|
||||
font-size: 16px;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
padding: 4px 8px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
#mpris-btn:hover {
|
||||
background-color: rgba(231, 156, 254, 0.15);
|
||||
}
|
||||
|
||||
#mpris-btn.play {
|
||||
font-size: 20px;
|
||||
color: #ff79c6;
|
||||
padding: 4px 12px;
|
||||
}
|
||||
|
||||
#mpris-btn.play:hover {
|
||||
background-color: rgba(255, 121, 198, 0.15);
|
||||
}
|
||||
"""
|
||||
|
||||
POPUP_WIDTH = 310
|
||||
|
||||
# ── Helpers ───────────────────────────────────────────────────────────────────
|
||||
|
||||
def run(cmd, **kw):
|
||||
return subprocess.run(cmd, capture_output=True, text=True, timeout=2, **kw)
|
||||
def run(cmd, env=None, **kw):
|
||||
return subprocess.run(cmd, capture_output=True, text=True, timeout=2,
|
||||
env=env, **kw)
|
||||
|
||||
def get_sink_volume():
|
||||
r = run(['wpctl', 'get-volume', '@DEFAULT_AUDIO_SINK@'])
|
||||
@@ -239,6 +312,93 @@ def _wob(msg):
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def get_sinks():
|
||||
"""Retourne [(sink_name, description, is_default)] — exclut SUSPENDED."""
|
||||
env = {**os.environ, 'LANG': 'C', 'LC_ALL': 'C'}
|
||||
r_default = run(['pactl', 'get-default-sink'], env=env)
|
||||
default_name = r_default.stdout.strip()
|
||||
|
||||
r_full = run(['pactl', 'list', 'sinks'], env=env)
|
||||
sinks, state, name, desc = [], None, None, None
|
||||
for line in r_full.stdout.splitlines():
|
||||
st = re.search(r'^\s+State:\s+(\S+)', line)
|
||||
nm = re.search(r'^\s+Name:\s+(.+)$', line)
|
||||
ds = re.search(r'^\s+Description:\s+(.+)$', line)
|
||||
if st: state = st.group(1)
|
||||
elif nm: name = nm.group(1).strip()
|
||||
elif ds and name:
|
||||
desc = ds.group(1).strip()
|
||||
if state != 'SUSPENDED':
|
||||
sinks.append((name, desc, name == default_name))
|
||||
state, name, desc = None, None, None
|
||||
return sinks
|
||||
|
||||
def set_default_sink(name):
|
||||
run(['pactl', 'set-default-sink', name])
|
||||
|
||||
def get_sources():
|
||||
"""Retourne [(source_name, description, is_default)] — exclut les .monitor."""
|
||||
env = {**os.environ, 'LANG': 'C', 'LC_ALL': 'C'}
|
||||
r_default = run(['pactl', 'get-default-source'], env=env)
|
||||
default_name = r_default.stdout.strip()
|
||||
|
||||
r_full = run(['pactl', 'list', 'sources'], env=env)
|
||||
sources, name, desc = [], None, None
|
||||
for line in r_full.stdout.splitlines():
|
||||
nm = re.search(r'^\s+Name:\s+(.+)$', line)
|
||||
ds = re.search(r'^\s+Description:\s+(.+)$', line)
|
||||
if nm:
|
||||
name = nm.group(1).strip()
|
||||
elif ds and name:
|
||||
desc = ds.group(1).strip()
|
||||
if '.monitor' not in name:
|
||||
sources.append((name, desc, name == default_name))
|
||||
name, desc = None, None
|
||||
return sources
|
||||
|
||||
def set_default_source(name):
|
||||
run(['pactl', 'set-default-source', name])
|
||||
|
||||
def get_mpris_info():
|
||||
"""Retourne dict ou None si pas de lecteur actif."""
|
||||
try:
|
||||
r = run(['playerctl', 'metadata', '--format',
|
||||
'{{title}}||{{artist}}||{{mpris:artUrl}}||{{status}}'])
|
||||
except (FileNotFoundError, subprocess.TimeoutExpired):
|
||||
return None
|
||||
if r.returncode != 0 or not r.stdout.strip():
|
||||
return None
|
||||
parts = r.stdout.strip().split('||', 3)
|
||||
if len(parts) < 4:
|
||||
return None
|
||||
title, artist, art_url, status = [p.strip() for p in parts]
|
||||
if not title:
|
||||
return None
|
||||
return {
|
||||
'title': title,
|
||||
'artist': artist,
|
||||
'art_url': art_url,
|
||||
'status': status.lower(), # 'playing' | 'paused' | 'stopped'
|
||||
}
|
||||
|
||||
def source_icon(name, desc):
|
||||
s = (name + desc).lower()
|
||||
if 'bluetooth' in s or 'bluez' in s: return ''
|
||||
if 'usb' in s: return ''
|
||||
if 'headset' in s or 'headphone' in s: return ''
|
||||
return ''
|
||||
|
||||
def sink_icon(name, desc):
|
||||
s = (name + desc).lower()
|
||||
if 'hdmi' in s or 'dp-' in s or 'displayport' in s: return ''
|
||||
if 'bluetooth' in s or 'bluez' in s: return ''
|
||||
if 'usb' in s: return ''
|
||||
if 'headphone' in s or 'headset' in s: return ''
|
||||
return ''
|
||||
|
||||
def short_desc(desc, maxlen=16):
|
||||
return desc if len(desc) <= maxlen else desc[:maxlen - 1] + '…'
|
||||
|
||||
def vol_icon(muted):
|
||||
return '' if muted else ''
|
||||
|
||||
@@ -250,26 +410,109 @@ def bright_icon(pct):
|
||||
if pct < 67: return ''
|
||||
return ''
|
||||
|
||||
# ── Art widget (album art / miniature YouTube) ────────────────────────────────
|
||||
|
||||
class ArtWidget(Gtk.DrawingArea):
|
||||
SIZE = 72
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._pixbuf = None
|
||||
self._url = None
|
||||
self.set_size_request(self.SIZE, self.SIZE)
|
||||
self.connect('draw', self._on_draw)
|
||||
|
||||
def load_url(self, url):
|
||||
if url == self._url:
|
||||
return
|
||||
self._url = url
|
||||
self._pixbuf = None
|
||||
self.queue_draw()
|
||||
if not url:
|
||||
return
|
||||
threading.Thread(target=self._fetch, args=(url,), daemon=True).start()
|
||||
|
||||
def _fetch(self, url):
|
||||
try:
|
||||
if url.startswith('file://'):
|
||||
raw = GdkPixbuf.Pixbuf.new_from_file(url[7:])
|
||||
else:
|
||||
req = urllib.request.Request(
|
||||
url, headers={'User-Agent': 'Mozilla/5.0'})
|
||||
with urllib.request.urlopen(req, timeout=5) as resp:
|
||||
data = resp.read()
|
||||
loader = GdkPixbuf.PixbufLoader()
|
||||
loader.write(data)
|
||||
loader.close()
|
||||
raw = loader.get_pixbuf()
|
||||
|
||||
if raw:
|
||||
s = self.SIZE
|
||||
ow, oh = raw.get_width(), raw.get_height()
|
||||
scale = min(s / ow, s / oh)
|
||||
nw = max(1, int(ow * scale))
|
||||
nh = max(1, int(oh * scale))
|
||||
pixbuf = raw.scale_simple(nw, nh, GdkPixbuf.InterpType.BILINEAR)
|
||||
else:
|
||||
pixbuf = None
|
||||
except Exception:
|
||||
pixbuf = None
|
||||
GLib.idle_add(self._set_pixbuf, pixbuf, url)
|
||||
|
||||
def _set_pixbuf(self, pixbuf, url):
|
||||
if url == self._url:
|
||||
self._pixbuf = pixbuf
|
||||
self.queue_draw()
|
||||
return False
|
||||
|
||||
def _on_draw(self, _widget, cr):
|
||||
s, r = self.SIZE, 10
|
||||
|
||||
# Coins arrondis (clip)
|
||||
cr.new_sub_path()
|
||||
cr.arc(r, r, r, math.pi, 3 * math.pi / 2)
|
||||
cr.arc(s - r, r, r, -math.pi / 2, 0)
|
||||
cr.arc(s - r, s - r, r, 0, math.pi / 2)
|
||||
cr.arc(r, s - r, r, math.pi / 2, math.pi)
|
||||
cr.close_path()
|
||||
cr.clip()
|
||||
|
||||
# Fond violet
|
||||
cr.set_source_rgba(73/255, 49/255, 97/255, 0.85)
|
||||
cr.paint()
|
||||
|
||||
if self._pixbuf:
|
||||
pw = self._pixbuf.get_width()
|
||||
ph = self._pixbuf.get_height()
|
||||
Gdk.cairo_set_source_pixbuf(cr, self._pixbuf,
|
||||
(s - pw) / 2, (s - ph) / 2)
|
||||
cr.paint()
|
||||
else:
|
||||
# Icône note de musique (placeholder)
|
||||
layout = PangoCairo.create_layout(cr)
|
||||
layout.set_markup('<span font="JetBrainsMono Nerd Font 24"></span>')
|
||||
lw, lh = layout.get_size()
|
||||
cr.set_source_rgba(231/255, 156/255, 254/255, 0.45)
|
||||
cr.move_to((s - lw / Pango.SCALE) / 2,
|
||||
(s - lh / Pango.SCALE) / 2)
|
||||
PangoCairo.show_layout(cr, layout)
|
||||
|
||||
|
||||
# ── Popup ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
class MediaPopup(Gtk.Window):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._blk = False
|
||||
self._has_mpris = False
|
||||
|
||||
# ── Position ─────────────────────────────────────────────────────────
|
||||
display = Gdk.Display.get_default()
|
||||
monitor = display.get_primary_monitor() if display else None
|
||||
screen_w = monitor.get_geometry().width if monitor else 1920
|
||||
module_center = screen_w - 16 - 210
|
||||
margin_left = max(0, module_center - POPUP_WIDTH // 2)
|
||||
|
||||
# ── Position — ancré à droite, toujours dans l'écran ─────────────────
|
||||
GtkLayerShell.init_for_window(self)
|
||||
GtkLayerShell.set_layer(self, GtkLayerShell.Layer.OVERLAY)
|
||||
GtkLayerShell.set_anchor(self, GtkLayerShell.Edge.TOP, True)
|
||||
GtkLayerShell.set_anchor(self, GtkLayerShell.Edge.LEFT, True)
|
||||
GtkLayerShell.set_anchor(self, GtkLayerShell.Edge.RIGHT, True)
|
||||
GtkLayerShell.set_margin(self, GtkLayerShell.Edge.TOP, 66)
|
||||
GtkLayerShell.set_margin(self, GtkLayerShell.Edge.LEFT, margin_left)
|
||||
GtkLayerShell.set_margin(self, GtkLayerShell.Edge.RIGHT, 12)
|
||||
GtkLayerShell.set_keyboard_mode(self, GtkLayerShell.KeyboardMode.ON_DEMAND)
|
||||
GtkLayerShell.set_exclusive_zone(self, -1)
|
||||
self.set_decorated(False)
|
||||
@@ -295,10 +538,22 @@ class MediaPopup(Gtk.Window):
|
||||
box.set_name('container')
|
||||
self.add(box)
|
||||
|
||||
# ╔═══ LECTURE (MPRIS) — affiché seulement si lecteur actif ════════════╗
|
||||
mpris_info = get_mpris_info()
|
||||
if mpris_info:
|
||||
self._build_mpris_section(box, mpris_info)
|
||||
sep0 = Gtk.Label(label='─' * 34)
|
||||
sep0.set_name('separator')
|
||||
box.pack_start(sep0, False, False, 0)
|
||||
|
||||
# ╔═══ SORTIE ══════════════════════════════════════════════════════════╗
|
||||
sinks = get_sinks()
|
||||
box.pack_start(self._section_header('SORTIE', ''), False, False, 0)
|
||||
box.pack_start(self._device_label(
|
||||
get_node_name('@DEFAULT_AUDIO_SINK@')), False, False, 2)
|
||||
self.sink_device_lbl = self._device_label(
|
||||
get_node_name('@DEFAULT_AUDIO_SINK@'))
|
||||
box.pack_start(self.sink_device_lbl, False, False, 2)
|
||||
if len(sinks) > 1:
|
||||
box.pack_start(self._sink_selector(sinks), False, False, 4)
|
||||
sink_row, self.sink_scale, self.sink_pct, self.sink_icon = \
|
||||
self._slider_row(sink_vol, sink_muted, 'audio', vol_icon(sink_muted),
|
||||
self._toggle_sink_mute, '@DEFAULT_AUDIO_SINK@')
|
||||
@@ -309,9 +564,13 @@ class MediaPopup(Gtk.Window):
|
||||
sep1.set_name('separator')
|
||||
box.pack_start(sep1, False, False, 0)
|
||||
|
||||
sources = get_sources()
|
||||
box.pack_start(self._section_header('ENTRÉE', ''), False, False, 0)
|
||||
box.pack_start(self._device_label(
|
||||
get_node_name('@DEFAULT_AUDIO_SOURCE@')), False, False, 2)
|
||||
self.src_device_lbl = self._device_label(
|
||||
get_node_name('@DEFAULT_AUDIO_SOURCE@'))
|
||||
box.pack_start(self.src_device_lbl, False, False, 2)
|
||||
if len(sources) > 1:
|
||||
box.pack_start(self._source_selector(sources), False, False, 4)
|
||||
src_row, self.src_scale, self.src_pct, self.src_icon = \
|
||||
self._slider_row(src_vol, src_muted, 'audio', mic_icon(src_muted),
|
||||
self._toggle_src_mute, '@DEFAULT_AUDIO_SOURCE@')
|
||||
@@ -333,23 +592,167 @@ class MediaPopup(Gtk.Window):
|
||||
self.connect('focus-out-event', lambda *_: self.destroy())
|
||||
self.show_all()
|
||||
# GTK3 bug : set_value() avant réalisation → highlight width=0 à max
|
||||
# Forcer un re-calcul après que les widgets sont visibles
|
||||
GLib.idle_add(self._redraw_scales)
|
||||
self.grab_focus()
|
||||
|
||||
def _redraw_scales(self):
|
||||
"""Force GTK3 à recalculer les highlights.
|
||||
set_value(même_valeur) est un no-op — on oscille ±1 pour déclencher
|
||||
un vrai recalcul de la position du highlight dans le trough."""
|
||||
# ── MPRIS section builder ─────────────────────────────────────────────────
|
||||
|
||||
def _build_mpris_section(self, box, info):
|
||||
box.pack_start(self._section_header('LECTURE', ''), False, False, 0)
|
||||
|
||||
content = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=12)
|
||||
content.set_margin_top(4)
|
||||
content.set_margin_bottom(4)
|
||||
|
||||
# Album art
|
||||
self.mpris_art = ArtWidget()
|
||||
content.pack_start(self.mpris_art, False, False, 0)
|
||||
|
||||
# Infos + contrôles
|
||||
info_col = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
|
||||
info_col.set_valign(Gtk.Align.CENTER)
|
||||
|
||||
self.mpris_title = Gtk.Label(label=info['title'])
|
||||
self.mpris_title.set_name('mpris-title')
|
||||
self.mpris_title.set_halign(Gtk.Align.START)
|
||||
self.mpris_title.set_ellipsize(3)
|
||||
self.mpris_title.set_max_width_chars(20)
|
||||
info_col.pack_start(self.mpris_title, False, False, 0)
|
||||
|
||||
self.mpris_artist = Gtk.Label(label=info['artist'] or '—')
|
||||
self.mpris_artist.set_name('mpris-artist')
|
||||
self.mpris_artist.set_halign(Gtk.Align.START)
|
||||
self.mpris_artist.set_ellipsize(3)
|
||||
self.mpris_artist.set_max_width_chars(20)
|
||||
info_col.pack_start(self.mpris_artist, False, False, 0)
|
||||
|
||||
# Contrôles prev / play-pause / next
|
||||
ctrl = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
|
||||
ctrl.set_margin_top(4)
|
||||
|
||||
btn_prev = Gtk.Button(label='')
|
||||
btn_prev.set_name('mpris-btn')
|
||||
btn_prev.connect('clicked', lambda _: run(['playerctl', 'previous']))
|
||||
|
||||
self.btn_play = Gtk.Button(
|
||||
label='' if info['status'] == 'playing' else '')
|
||||
self.btn_play.set_name('mpris-btn')
|
||||
self.btn_play.get_style_context().add_class('play')
|
||||
self.btn_play.connect('clicked', self._on_play_pause)
|
||||
|
||||
btn_next = Gtk.Button(label='')
|
||||
btn_next.set_name('mpris-btn')
|
||||
btn_next.connect('clicked', lambda _: run(['playerctl', 'next']))
|
||||
|
||||
ctrl.pack_start(btn_prev, False, False, 0)
|
||||
ctrl.pack_start(self.btn_play, False, False, 0)
|
||||
ctrl.pack_start(btn_next, False, False, 0)
|
||||
info_col.pack_start(ctrl, False, False, 0)
|
||||
|
||||
content.pack_start(info_col, True, True, 0)
|
||||
box.pack_start(content, False, False, 4)
|
||||
|
||||
# Charger l'artwork en arrière-plan
|
||||
if info.get('art_url'):
|
||||
self.mpris_art.load_url(info['art_url'])
|
||||
|
||||
self._has_mpris = True
|
||||
self._mpris_status = info['status']
|
||||
|
||||
def _on_play_pause(self, _btn):
|
||||
run(['playerctl', 'play-pause'])
|
||||
info = get_mpris_info()
|
||||
if info and self._has_mpris:
|
||||
self._mpris_status = info['status']
|
||||
self.btn_play.set_label(
|
||||
'' if info['status'] == 'playing' else '')
|
||||
|
||||
# ── Sélecteur de sortie ────────────────────────────────────────────────────
|
||||
|
||||
def _sink_selector(self, sinks):
|
||||
self._sink_btns = {}
|
||||
self._sink_descs = {}
|
||||
col = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=2)
|
||||
for name, desc, is_default in sinks:
|
||||
self._sink_descs[name] = desc
|
||||
btn = Gtk.Button()
|
||||
btn.set_name('device-btn')
|
||||
btn.set_hexpand(True)
|
||||
lbl = Gtk.Label(label=self._sink_label(name, desc, is_default))
|
||||
lbl.set_halign(Gtk.Align.START)
|
||||
btn.add(lbl)
|
||||
if is_default:
|
||||
btn.get_style_context().add_class('active')
|
||||
btn.connect('clicked', self._on_sink_selected, name)
|
||||
col.pack_start(btn, False, True, 0)
|
||||
self._sink_btns[name] = btn
|
||||
return col
|
||||
|
||||
def _sink_label(self, name, desc, active):
|
||||
check = ' ' if active else ''
|
||||
return f'{sink_icon(name, desc)} {desc}{check}'
|
||||
|
||||
def _source_selector(self, sources):
|
||||
self._src_btns = {}
|
||||
self._src_descs = {}
|
||||
col = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=2)
|
||||
for name, desc, is_default in sources:
|
||||
self._src_descs[name] = desc
|
||||
btn = Gtk.Button()
|
||||
btn.set_name('device-btn')
|
||||
btn.set_hexpand(True)
|
||||
lbl = Gtk.Label(label=self._src_label(name, desc, is_default))
|
||||
lbl.set_halign(Gtk.Align.START)
|
||||
btn.add(lbl)
|
||||
if is_default:
|
||||
btn.get_style_context().add_class('active')
|
||||
btn.connect('clicked', self._on_source_selected, name)
|
||||
col.pack_start(btn, False, True, 0)
|
||||
self._src_btns[name] = btn
|
||||
return col
|
||||
|
||||
def _src_label(self, name, desc, active):
|
||||
check = ' ' if active else ''
|
||||
return f'{source_icon(name, desc)} {desc}{check}'
|
||||
|
||||
def _on_source_selected(self, _btn, name):
|
||||
for n, b in self._src_btns.items():
|
||||
b.get_style_context().remove_class('active')
|
||||
b.get_child().set_label(self._src_label(n, self._src_descs[n], False))
|
||||
self._src_btns[name].get_style_context().add_class('active')
|
||||
self._src_btns[name].get_child().set_label(
|
||||
self._src_label(name, self._src_descs[name], True))
|
||||
set_default_source(name)
|
||||
self.src_device_lbl.set_label(self._src_descs[name])
|
||||
vol, muted = get_source_volume()
|
||||
self._blk = True
|
||||
for scale in [self.sink_scale, self.src_scale, self.bright_scale]:
|
||||
v = scale.get_value()
|
||||
adj = scale.get_adjustment()
|
||||
lo = adj.get_lower()
|
||||
scale.set_value(max(lo, v - 1)) # valeur différente → GTK recalcule
|
||||
scale.set_value(v) # retour à la valeur réelle
|
||||
self.src_scale.set_value(vol)
|
||||
self.src_pct.set_label(f'{vol}%')
|
||||
self._blk = False
|
||||
return False
|
||||
self._src_muted = muted
|
||||
self._apply_mute(self.src_scale, self.src_icon, muted, mic_icon)
|
||||
subprocess.Popen(['pkill', '-RTMIN+1', 'waybar'],
|
||||
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
|
||||
def _on_sink_selected(self, _btn, name):
|
||||
for n, b in self._sink_btns.items():
|
||||
b.get_style_context().remove_class('active')
|
||||
b.get_child().set_label(
|
||||
self._sink_label(n, self._sink_descs[n], False))
|
||||
self._sink_btns[name].get_style_context().add_class('active')
|
||||
self._sink_btns[name].get_child().set_label(
|
||||
self._sink_label(name, self._sink_descs[name], True))
|
||||
set_default_sink(name)
|
||||
self.sink_device_lbl.set_label(self._sink_descs[name])
|
||||
vol, muted = get_sink_volume()
|
||||
self._blk = True
|
||||
self.sink_scale.set_value(vol)
|
||||
self.sink_pct.set_label(f'{vol}%')
|
||||
self._blk = False
|
||||
self._sink_muted = muted
|
||||
self._apply_mute(self.sink_scale, self.sink_icon, muted, vol_icon)
|
||||
subprocess.Popen(['pkill', '-RTMIN+1', 'waybar'],
|
||||
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
|
||||
# ── Builders UI ───────────────────────────────────────────────────────────
|
||||
|
||||
@@ -376,7 +779,6 @@ class MediaPopup(Gtk.Window):
|
||||
"""Retourne (row, scale, pct_label, icon_btn)"""
|
||||
row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
|
||||
|
||||
# Icône = bouton mute
|
||||
icon_btn = Gtk.Button(label=icon_char)
|
||||
icon_btn.set_name('mute-icon' if target == '@DEFAULT_AUDIO_SINK@' else 'mic-icon')
|
||||
if muted:
|
||||
@@ -384,7 +786,6 @@ class MediaPopup(Gtk.Window):
|
||||
icon_btn.connect('clicked', mute_cb)
|
||||
row.pack_start(icon_btn, False, False, 0)
|
||||
|
||||
# Slider
|
||||
scale = Gtk.Scale.new_with_range(Gtk.Orientation.HORIZONTAL, 0, 100, 5)
|
||||
scale.set_value(val)
|
||||
scale.set_draw_value(False)
|
||||
@@ -396,7 +797,6 @@ class MediaPopup(Gtk.Window):
|
||||
self._on_audio_changed(s, pct_lbl, t))
|
||||
row.pack_start(scale, True, True, 0)
|
||||
|
||||
# %
|
||||
pct_lbl = Gtk.Label(label=f'{val}%')
|
||||
pct_lbl.set_name('pct-label')
|
||||
pct_lbl.set_halign(Gtk.Align.END)
|
||||
@@ -469,7 +869,20 @@ class MediaPopup(Gtk.Window):
|
||||
self._apply_mute(self.src_scale, self.src_icon,
|
||||
self._src_muted, mic_icon)
|
||||
|
||||
def _redraw_scales(self):
|
||||
"""Force GTK3 à recalculer les highlights."""
|
||||
self._blk = True
|
||||
for scale in [self.sink_scale, self.src_scale, self.bright_scale]:
|
||||
v = scale.get_value()
|
||||
adj = scale.get_adjustment()
|
||||
lo = adj.get_lower()
|
||||
scale.set_value(max(lo, v - 1))
|
||||
scale.set_value(v)
|
||||
self._blk = False
|
||||
return False
|
||||
|
||||
def _refresh(self):
|
||||
# ── Audio ──────────────────────────────────────────────────────────────
|
||||
sink_vol, sink_muted = get_sink_volume()
|
||||
src_vol, src_muted = get_source_volume()
|
||||
|
||||
@@ -489,6 +902,20 @@ class MediaPopup(Gtk.Window):
|
||||
self.src_pct.set_label(f'{src_vol}%')
|
||||
self._blk = False
|
||||
|
||||
# ── MPRIS ──────────────────────────────────────────────────────────────
|
||||
if self._has_mpris:
|
||||
info = get_mpris_info()
|
||||
if info:
|
||||
self.mpris_title.set_label(info['title'])
|
||||
self.mpris_artist.set_label(info['artist'] or '—')
|
||||
if info['status'] != self._mpris_status:
|
||||
self._mpris_status = info['status']
|
||||
self.btn_play.set_label(
|
||||
'' if info['status'] == 'playing' else '')
|
||||
cur_url = info.get('art_url', '')
|
||||
if cur_url != self.mpris_art._url:
|
||||
self.mpris_art.load_url(cur_url)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
||||
@@ -1,422 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# vc-volume-popup.py — Popup volume slider violet-chaton
|
||||
# Lancé par le clic sur le module wireplumber de waybar
|
||||
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
gi.require_version('GtkLayerShell', '0.1')
|
||||
from gi.repository import Gtk, Gdk, GtkLayerShell, GLib
|
||||
import subprocess
|
||||
import os
|
||||
import re
|
||||
|
||||
# ── CSS ───────────────────────────────────────────────────────────────────────
|
||||
|
||||
CSS = b"""
|
||||
window {
|
||||
background-color: rgba(52, 28, 74, 0.93);
|
||||
border: 3px solid rgba(255, 121, 198, 0.78);
|
||||
border-radius: 14px;
|
||||
}
|
||||
|
||||
#container {
|
||||
padding: 14px 20px 16px 20px;
|
||||
}
|
||||
|
||||
#vol-icon {
|
||||
color: #ff79c6;
|
||||
font-family: "JetBrainsMono Nerd Font";
|
||||
font-size: 18px;
|
||||
min-width: 24px;
|
||||
}
|
||||
|
||||
#vol-title {
|
||||
color: rgba(248, 248, 242, 0.55);
|
||||
font-family: "JetBrainsMono Nerd Font";
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
#sink-name {
|
||||
color: #8be9fd;
|
||||
font-family: "JetBrainsMono Nerd Font";
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#vol-pct {
|
||||
color: #f8f8f2;
|
||||
font-family: "JetBrainsMono Nerd Font";
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
min-width: 44px;
|
||||
}
|
||||
|
||||
#separator {
|
||||
color: rgba(92, 73, 108, 0.60);
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
scale trough {
|
||||
background-color: rgba(92, 73, 108, 0.55);
|
||||
border-radius: 3px;
|
||||
min-height: 6px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
scale highlight {
|
||||
background-color: #ff79c6;
|
||||
border-radius: 3px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
scale slider {
|
||||
background-color: #f8f8f2;
|
||||
border-radius: 50%;
|
||||
min-width: 18px;
|
||||
min-height: 18px;
|
||||
border: 2px solid rgba(255, 121, 198, 0.80);
|
||||
box-shadow: none;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
scale slider:hover {
|
||||
background-color: #e79cfe;
|
||||
border-color: #ff79c6;
|
||||
}
|
||||
|
||||
#mute-btn {
|
||||
background: rgba(73, 49, 97, 0.50);
|
||||
border: 1px solid rgba(92, 73, 108, 0.60);
|
||||
border-radius: 8px;
|
||||
color: rgba(248, 248, 242, 0.65);
|
||||
font-family: "JetBrainsMono Nerd Font";
|
||||
font-size: 12px;
|
||||
padding: 5px 16px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
#mute-btn:hover {
|
||||
background: rgba(255, 121, 198, 0.18);
|
||||
border-color: rgba(255, 121, 198, 0.45);
|
||||
color: #ff79c6;
|
||||
}
|
||||
|
||||
#mute-btn.muted {
|
||||
color: #f38ba8;
|
||||
border-color: rgba(243, 139, 168, 0.45);
|
||||
background: rgba(243, 139, 168, 0.10);
|
||||
}
|
||||
|
||||
#mic-btn {
|
||||
background: rgba(73, 49, 97, 0.50);
|
||||
border: 1px solid rgba(139, 233, 253, 0.35);
|
||||
border-radius: 8px;
|
||||
color: #8be9fd;
|
||||
font-family: "JetBrainsMono Nerd Font";
|
||||
font-size: 12px;
|
||||
padding: 5px 16px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
#mic-btn:hover {
|
||||
background: rgba(139, 233, 253, 0.12);
|
||||
border-color: rgba(139, 233, 253, 0.60);
|
||||
color: #8be9fd;
|
||||
}
|
||||
|
||||
#mic-btn.muted {
|
||||
color: #f38ba8;
|
||||
border-color: rgba(243, 139, 168, 0.45);
|
||||
background: rgba(243, 139, 168, 0.10);
|
||||
}
|
||||
"""
|
||||
|
||||
POPUP_WIDTH = 300
|
||||
|
||||
# ── Audio helpers ─────────────────────────────────────────────────────────────
|
||||
|
||||
def get_volume():
|
||||
"""Retourne (volume 0-100, is_muted)"""
|
||||
try:
|
||||
r = subprocess.run(
|
||||
['wpctl', 'get-volume', '@DEFAULT_AUDIO_SINK@'],
|
||||
capture_output=True, text=True, timeout=2
|
||||
)
|
||||
parts = r.stdout.strip().split()
|
||||
vol = int(float(parts[1]) * 100)
|
||||
muted = '[MUTED]' in r.stdout
|
||||
return min(max(vol, 0), 100), muted
|
||||
except Exception:
|
||||
return 50, False
|
||||
|
||||
def get_sink_name():
|
||||
"""Retourne le nom humain de la sortie audio active."""
|
||||
try:
|
||||
r = subprocess.run(
|
||||
['wpctl', 'inspect', '@DEFAULT_AUDIO_SINK@'],
|
||||
capture_output=True, text=True, timeout=2
|
||||
)
|
||||
# Chercher node.description en priorité, sinon node.nick
|
||||
for field in ('node.description', 'node.nick'):
|
||||
m = re.search(rf'{field}\s*=\s*"([^"]+)"', r.stdout)
|
||||
if m:
|
||||
return m.group(1)
|
||||
except Exception:
|
||||
pass
|
||||
return 'Sortie audio'
|
||||
|
||||
def set_volume(vol):
|
||||
subprocess.run(
|
||||
['wpctl', 'set-volume', '-l', '1.0', '@DEFAULT_AUDIO_SINK@', f'{vol}%'],
|
||||
capture_output=True
|
||||
)
|
||||
# Feedback wob (non-bloquant)
|
||||
fifo = '/tmp/wob.fifo'
|
||||
if os.path.exists(fifo):
|
||||
try:
|
||||
fd = os.open(fifo, os.O_WRONLY | os.O_NONBLOCK)
|
||||
os.write(fd, f'{vol}\n'.encode())
|
||||
os.close(fd)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def toggle_mute():
|
||||
subprocess.run(
|
||||
['wpctl', 'set-mute', '@DEFAULT_AUDIO_SINK@', 'toggle'],
|
||||
capture_output=True
|
||||
)
|
||||
|
||||
def get_mic_muted():
|
||||
"""Retourne True si le micro actif est muté."""
|
||||
try:
|
||||
r = subprocess.run(
|
||||
['wpctl', 'get-volume', '@DEFAULT_AUDIO_SOURCE@'],
|
||||
capture_output=True, text=True, timeout=2
|
||||
)
|
||||
return '[MUTED]' in r.stdout
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def toggle_mic_mute():
|
||||
subprocess.run(
|
||||
['wpctl', 'set-mute', '@DEFAULT_AUDIO_SOURCE@', 'toggle'],
|
||||
capture_output=True
|
||||
)
|
||||
|
||||
def vol_icon(vol, muted):
|
||||
if muted or vol == 0:
|
||||
return ''
|
||||
if vol < 50:
|
||||
return ''
|
||||
return ''
|
||||
|
||||
# ── Popup ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
class VolumePopup(Gtk.Window):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._blocked = False
|
||||
|
||||
# ── Position : centré sous le module wireplumber ──────────────────────
|
||||
# Wireplumber = 1er module de la pill droite (côté droit de l'écran).
|
||||
# On centre le popup horizontalement sous ce module.
|
||||
display = Gdk.Display.get_default()
|
||||
monitor = display.get_primary_monitor() if display else None
|
||||
if monitor:
|
||||
screen_w = monitor.get_geometry().width
|
||||
else:
|
||||
screen_w = 1920 # fallback
|
||||
|
||||
# La pill droite a ~16px de marge depuis le bord droit.
|
||||
# Le module wireplumber est le 1er élément : ~180px depuis le bord droit.
|
||||
module_center = screen_w - 16 - 180
|
||||
margin_left = max(0, module_center - POPUP_WIDTH // 2)
|
||||
|
||||
GtkLayerShell.init_for_window(self)
|
||||
GtkLayerShell.set_layer(self, GtkLayerShell.Layer.OVERLAY)
|
||||
GtkLayerShell.set_anchor(self, GtkLayerShell.Edge.TOP, True)
|
||||
GtkLayerShell.set_anchor(self, GtkLayerShell.Edge.LEFT, True)
|
||||
GtkLayerShell.set_margin(self, GtkLayerShell.Edge.TOP, 66)
|
||||
GtkLayerShell.set_margin(self, GtkLayerShell.Edge.LEFT, margin_left)
|
||||
GtkLayerShell.set_keyboard_mode(self, GtkLayerShell.KeyboardMode.ON_DEMAND)
|
||||
GtkLayerShell.set_exclusive_zone(self, -1)
|
||||
|
||||
self.set_decorated(False)
|
||||
self.set_resizable(False)
|
||||
self.set_default_size(POPUP_WIDTH, -1)
|
||||
|
||||
# ── CSS ───────────────────────────────────────────────────────────────
|
||||
provider = Gtk.CssProvider()
|
||||
provider.load_from_data(CSS)
|
||||
Gtk.StyleContext.add_provider_for_screen(
|
||||
Gdk.Screen.get_default(),
|
||||
provider,
|
||||
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
|
||||
)
|
||||
|
||||
# ── État initial ──────────────────────────────────────────────────────
|
||||
vol, muted = get_volume()
|
||||
self._muted = muted
|
||||
self._mic_muted = get_mic_muted()
|
||||
sink = get_sink_name()
|
||||
|
||||
# ── Layout ────────────────────────────────────────────────────────────
|
||||
container = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
|
||||
container.set_name('container')
|
||||
self.add(container)
|
||||
|
||||
# Ligne sink (sortie active)
|
||||
sink_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
|
||||
sink_icon = Gtk.Label(label='')
|
||||
sink_icon.set_name('vol-title')
|
||||
sink_row.pack_start(sink_icon, False, False, 0)
|
||||
self.sink_label = Gtk.Label(label=sink)
|
||||
self.sink_label.set_name('sink-name')
|
||||
self.sink_label.set_halign(Gtk.Align.START)
|
||||
self.sink_label.set_ellipsize(3) # PANGO_ELLIPSIZE_END
|
||||
sink_row.pack_start(self.sink_label, True, True, 0)
|
||||
container.pack_start(sink_row, False, False, 0)
|
||||
|
||||
# Séparateur
|
||||
sep = Gtk.Label(label='─' * 30)
|
||||
sep.set_name('separator')
|
||||
container.pack_start(sep, False, False, 4)
|
||||
|
||||
# En-tête volume : icône + "Volume" + %
|
||||
header = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=8)
|
||||
self.icon = Gtk.Label(label=vol_icon(vol, muted))
|
||||
self.icon.set_name('vol-icon')
|
||||
header.pack_start(self.icon, False, False, 0)
|
||||
|
||||
title = Gtk.Label(label='Volume')
|
||||
title.set_name('vol-title')
|
||||
title.set_halign(Gtk.Align.START)
|
||||
header.pack_start(title, True, True, 0)
|
||||
|
||||
self.pct = Gtk.Label(label=f'{vol}%')
|
||||
self.pct.set_name('vol-pct')
|
||||
self.pct.set_halign(Gtk.Align.END)
|
||||
header.pack_end(self.pct, False, False, 0)
|
||||
container.pack_start(header, False, False, 0)
|
||||
|
||||
# Slider
|
||||
self.scale = Gtk.Scale.new_with_range(
|
||||
Gtk.Orientation.HORIZONTAL, 0, 100, 5
|
||||
)
|
||||
self.scale.set_value(vol)
|
||||
self.scale.set_draw_value(False)
|
||||
self.scale.set_hexpand(True)
|
||||
self.scale.connect('value-changed', self._on_changed)
|
||||
container.pack_start(self.scale, False, False, 0)
|
||||
|
||||
# Bouton mute
|
||||
self.mute_btn = Gtk.Button(label=f' {"Remettre le son" if muted else "Muet"}')
|
||||
self.mute_btn.set_name('mute-btn')
|
||||
self.mute_btn.set_halign(Gtk.Align.CENTER)
|
||||
if muted:
|
||||
self.mute_btn.get_style_context().add_class('muted')
|
||||
self.mute_btn.connect('clicked', self._on_mute)
|
||||
container.pack_start(self.mute_btn, False, False, 0)
|
||||
|
||||
# ── Section micro ─────────────────────────────────────────────────────
|
||||
sep2 = Gtk.Label(label='─' * 30)
|
||||
sep2.set_name('separator')
|
||||
container.pack_start(sep2, False, False, 4)
|
||||
|
||||
mic_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=8)
|
||||
mic_icon = Gtk.Label(label='')
|
||||
mic_icon.set_name('vol-title')
|
||||
mic_icon.set_markup('<span font_family="JetBrainsMono Nerd Font" size="large"></span>')
|
||||
mic_row.pack_start(mic_icon, False, False, 0)
|
||||
|
||||
mic_title = Gtk.Label(label='Micro')
|
||||
mic_title.set_name('vol-title')
|
||||
mic_title.set_halign(Gtk.Align.START)
|
||||
mic_row.pack_start(mic_title, True, True, 0)
|
||||
|
||||
mic_label = ' Coupé' if self._mic_muted else ' Actif'
|
||||
self.mic_btn = Gtk.Button(label=mic_label)
|
||||
self.mic_btn.set_name('mic-btn')
|
||||
if self._mic_muted:
|
||||
self.mic_btn.get_style_context().add_class('muted')
|
||||
self.mic_btn.connect('clicked', self._on_mic_mute)
|
||||
mic_row.pack_end(self.mic_btn, False, False, 0)
|
||||
|
||||
container.pack_start(mic_row, False, False, 0)
|
||||
|
||||
# ── Refresh périodique (détecte changement de sink/micro) ─────────────
|
||||
GLib.timeout_add(2000, self._refresh_sink)
|
||||
|
||||
# ── Fermeture ─────────────────────────────────────────────────────────
|
||||
self.connect('key-press-event', self._on_key)
|
||||
self.connect('focus-out-event', lambda *_: self.destroy())
|
||||
|
||||
self.show_all()
|
||||
self.grab_focus()
|
||||
|
||||
def _on_changed(self, scale):
|
||||
if self._blocked:
|
||||
return
|
||||
vol = int(scale.get_value())
|
||||
self.pct.set_label(f'{vol}%')
|
||||
self.icon.set_label(vol_icon(vol, self._muted))
|
||||
set_volume(vol)
|
||||
|
||||
def _on_mute(self, btn):
|
||||
toggle_mute()
|
||||
_, self._muted = get_volume()
|
||||
vol = int(self.scale.get_value())
|
||||
self.icon.set_label(vol_icon(vol, self._muted))
|
||||
if self._muted:
|
||||
btn.get_style_context().add_class('muted')
|
||||
btn.set_label(' Remettre le son')
|
||||
else:
|
||||
btn.get_style_context().remove_class('muted')
|
||||
btn.set_label(' Muet')
|
||||
|
||||
def _refresh_sink(self):
|
||||
"""Met à jour la sortie et l'état du micro si changement détecté."""
|
||||
# Sortie audio
|
||||
sink = get_sink_name()
|
||||
if self.sink_label.get_label() != sink:
|
||||
self.sink_label.set_label(sink)
|
||||
vol, muted = get_volume()
|
||||
self._blocked = True
|
||||
self.scale.set_value(vol)
|
||||
self._blocked = False
|
||||
self.pct.set_label(f'{vol}%')
|
||||
self._muted = muted
|
||||
self.icon.set_label(vol_icon(vol, muted))
|
||||
|
||||
# Micro
|
||||
mic_muted = get_mic_muted()
|
||||
if mic_muted != self._mic_muted:
|
||||
self._mic_muted = mic_muted
|
||||
if mic_muted:
|
||||
self.mic_btn.get_style_context().add_class('muted')
|
||||
self.mic_btn.set_label(' Coupé')
|
||||
else:
|
||||
self.mic_btn.get_style_context().remove_class('muted')
|
||||
self.mic_btn.set_label(' Actif')
|
||||
|
||||
return True # continuer le timer
|
||||
|
||||
def _on_mic_mute(self, btn):
|
||||
toggle_mic_mute()
|
||||
self._mic_muted = get_mic_muted()
|
||||
if self._mic_muted:
|
||||
btn.get_style_context().add_class('muted')
|
||||
btn.set_label(' Coupé')
|
||||
else:
|
||||
btn.get_style_context().remove_class('muted')
|
||||
btn.set_label(' Actif')
|
||||
|
||||
def _on_key(self, _widget, event):
|
||||
if event.keyval == Gdk.KEY_Escape:
|
||||
self.destroy()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
win = VolumePopup()
|
||||
win.connect('destroy', Gtk.main_quit)
|
||||
Gtk.main()
|
||||
@@ -12,10 +12,35 @@ max_width = 600
|
||||
max_height = 900
|
||||
|
||||
[opener]
|
||||
edit = [{ run = 'nano "$@"', block = true }]
|
||||
edit = [
|
||||
{ run = '${EDITOR:-nano} "$@"', block = true },
|
||||
]
|
||||
open = [
|
||||
{ run = 'xdg-open "$@"', orphan = true },
|
||||
]
|
||||
reveal = [
|
||||
{ run = 'xdg-open "$(dirname "$1")"', orphan = true },
|
||||
]
|
||||
|
||||
[open]
|
||||
rules = [
|
||||
{ mime = "text/*", use = "edit" },
|
||||
{ mime = "image/*", use = "open" },
|
||||
{ mime = "video/*", use = "open" },
|
||||
{ mime = "audio/*", use = "open" },
|
||||
{ mime = "application/pdf", use = "open" },
|
||||
{ mime = "application/json", use = "edit" },
|
||||
{ mime = "*/xml", use = "edit" },
|
||||
{ name = "*.md", use = "edit" },
|
||||
{ name = "*.yml", use = "edit" },
|
||||
{ name = "*.yaml", use = "edit" },
|
||||
{ name = "*.toml", use = "edit" },
|
||||
{ name = "*.conf", use = "edit" },
|
||||
{ name = "*.sh", use = "edit" },
|
||||
]
|
||||
|
||||
[plugin]
|
||||
prepend_previewers = [
|
||||
# Image preview via kitty protocol (native dans kitty)
|
||||
{ mime = "image/*", run = "image" },
|
||||
]
|
||||
|
||||
@@ -17,19 +17,22 @@ zinit light zsh-users/zsh-completions
|
||||
export PATH="/usr/local/bin:$HOME/.local/bin:/usr/bin:$HOME/.atuin/bin:$PATH"
|
||||
|
||||
# ── Historique ────────────────────────────────────────────────────────────────
|
||||
HISTSIZE=10000
|
||||
HISTFILESIZE=20000
|
||||
HISTSIZE=50000
|
||||
HISTFILESIZE=100000
|
||||
HISTFILE=~/.zsh_history
|
||||
setopt HIST_IGNORE_DUPS
|
||||
setopt HIST_IGNORE_SPACE
|
||||
setopt HIST_FIND_NO_DUPS
|
||||
setopt SHARE_HISTORY
|
||||
setopt APPEND_HISTORY
|
||||
setopt EXTENDED_HISTORY
|
||||
|
||||
# ── Options zsh ───────────────────────────────────────────────────────────────
|
||||
setopt AUTO_CD # cd en tapant juste le nom du dossier
|
||||
setopt CORRECT # correction de typos
|
||||
setopt GLOB_DOTS # inclure fichiers cachés dans les globs
|
||||
setopt GLOB_DOTS # inclure fichiers caches dans les globs
|
||||
setopt NO_BEEP # silence
|
||||
setopt INTERACTIVE_COMMENTS # commentaires en mode interactif
|
||||
|
||||
# ── Completion ────────────────────────────────────────────────────────────────
|
||||
autoload -Uz compinit && compinit
|
||||
@@ -37,44 +40,46 @@ zstyle ':completion:*' menu select
|
||||
zstyle ':completion:*' list-colors "${(s.:.)LS_COLORS}"
|
||||
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Za-z}'
|
||||
zstyle ':completion:*' group-name ''
|
||||
zstyle ':completion:*:descriptions' format '%F{#e79cfe}── %d ──%f'
|
||||
zstyle ':completion:*:descriptions' format '%F{#c9a0ff}── %d ──%f'
|
||||
|
||||
# ── Couleurs grep ─────────────────────────────────────────────────────────────
|
||||
alias grep='grep --color=auto'
|
||||
alias fgrep='fgrep --color=auto'
|
||||
alias egrep='egrep --color=auto'
|
||||
|
||||
# ── eza (remplace ls) ─────────────────────────────────────────────────────────
|
||||
# ── eza (remplace ls) ────────────────────────────────────────────────────────
|
||||
alias ls='eza --icons --color=always --group-directories-first'
|
||||
alias ll='eza -l --icons --git --group-directories-first'
|
||||
alias lt='eza --tree --icons'
|
||||
alias la='eza -la --icons --git --group-directories-first'
|
||||
alias lt='eza --tree --icons --level=3'
|
||||
export LS_COLORS="$(bash ~/.local/share/violet-chaton/violet-chaton-ls-colors.sh)"
|
||||
|
||||
# ── bat (remplace cat) ────────────────────────────────────────────────────────
|
||||
# ── bat (remplace cat) ───────────────────────────────────────────────────────
|
||||
alias bat='batcat'
|
||||
alias cat='batcat --paging=never'
|
||||
export MANPAGER="sh -c 'col -bx | batcat -l man -p'"
|
||||
|
||||
# ── fd (remplace find) ────────────────────────────────────────────────────────
|
||||
# ── fd (remplace find) ───────────────────────────────────────────────────────
|
||||
alias fd='fdfind'
|
||||
|
||||
# ── Nouveaux outils ───────────────────────────────────────────────────────────
|
||||
alias lg='lazygit' # git TUI
|
||||
alias rg='rg --color=always' # ripgrep avec couleurs
|
||||
alias disk='ncdu' # analyse disque
|
||||
alias man='tldr' # man pages simplifiées
|
||||
alias pipes='pipes.sh' # animation pipes
|
||||
fuck() { eval "$(thefuck --alias 2>/dev/null)"; fuck "$@"; } # init paresseux
|
||||
# ── Outils modernes ──────────────────────────────────────────────────────────
|
||||
alias lg='lazygit'
|
||||
alias rg='rg --color=always'
|
||||
alias disk='dust' # analyse disque (remplace ncdu)
|
||||
alias tl='tldr' # man pages simplifiees (man reste intact)
|
||||
alias pipes='pipes.sh'
|
||||
alias top='btop'
|
||||
fuck() { eval "$(thefuck --alias 2>/dev/null)"; fuck "$@"; }
|
||||
|
||||
# ── fzf ───────────────────────────────────────────────────────────────────────
|
||||
# ── fzf ──────────────────────────────────────────────────────────────────────
|
||||
[ -f /usr/share/doc/fzf/examples/key-bindings.zsh ] && source /usr/share/doc/fzf/examples/key-bindings.zsh
|
||||
[ -f /usr/share/doc/fzf/examples/completion.zsh ] && source /usr/share/doc/fzf/examples/completion.zsh
|
||||
|
||||
# Raccourcis fzf personnalisés
|
||||
bindkey -r '^T' # libère Ctrl+T
|
||||
bindkey -r '\ec' # libère Alt+C
|
||||
bindkey '^G' fzf-file-widget # Ctrl+G → chercher un fichier
|
||||
bindkey '^F' fzf-cd-widget # Ctrl+F → chercher un dossier
|
||||
# Raccourcis fzf
|
||||
bindkey -r '^T'
|
||||
bindkey -r '\ec'
|
||||
bindkey '^G' fzf-file-widget
|
||||
bindkey '^F' fzf-cd-widget
|
||||
export FZF_DEFAULT_COMMAND='fdfind --type f --hidden --follow --exclude .git --exclude .cache --search-path $HOME'
|
||||
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"
|
||||
export FZF_ALT_C_COMMAND='fdfind --type d --hidden --follow --exclude .git --exclude .cache --search-path $HOME'
|
||||
@@ -82,39 +87,188 @@ export FZF_DEFAULT_OPTS="
|
||||
--height 40% --layout=reverse --border rounded --info=hidden
|
||||
--preview 'batcat --color=always --style=plain --line-range=:80 {}'
|
||||
--preview-window 'right:50%:wrap'
|
||||
--color=bg+:#3d2454,bg:#341c4a,spinner:#ff79c6,hl:#8be9fd
|
||||
--color=fg:#f8f8f2,header:#ff79c6,info:#e79cfe,pointer:#ff79c6
|
||||
--color=marker:#a6e3a1,fg+:#f8f8f2,prompt:#e79cfe,hl+:#8be9fd"
|
||||
--color=bg+:#5a3875,bg:#261537,spinner:#ff4da6,hl:#a4b4ff
|
||||
--color=fg:#f0eaf8,header:#ff4da6,info:#c9a0ff,pointer:#ff4da6
|
||||
--color=marker:#9adba8,fg+:#f0eaf8,prompt:#c9a0ff,hl+:#a4b4ff"
|
||||
|
||||
# ── zoxide (remplace cd) ──────────────────────────────────────────────────────
|
||||
# ── zoxide (remplace cd) ────────────────────────────────────────────────────
|
||||
eval "$(zoxide init zsh --cmd cd)"
|
||||
|
||||
# ── Fastfetch ─────────────────────────────────────────────────────────────────
|
||||
alias fetch='fastfetch --config ~/.config/fastfetch/config.jsonc --raw <(chafa --size 44x22 --symbols vhalf --color-space rgb "$HOME/.config/fastfetch/violet-chaton-logo.png") --logo-width 52'
|
||||
fetch
|
||||
# ── direnv (charge .envrc automatiquement) ───────────────────────────────────
|
||||
command -v direnv &>/dev/null && eval "$(direnv hook zsh)"
|
||||
|
||||
# ── zsh-autosuggestions ───────────────────────────────────────────────────────
|
||||
ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="fg=#6c7086"
|
||||
# ── fnm (Node.js version manager — lazy load) ───────────────────────────────
|
||||
if [ -d "$HOME/.local/share/fnm" ]; then
|
||||
export PATH="$HOME/.local/share/fnm:$PATH"
|
||||
eval "$(fnm env --use-on-cd --shell zsh)"
|
||||
fi
|
||||
|
||||
# ── Fastfetch ────────────────────────────────────────────────────────────────
|
||||
alias fetch='fastfetch --config ~/.config/fastfetch/config.jsonc --raw <(chafa --size 44x22 --symbols vhalf --color-space rgb "$HOME/.config/fastfetch/violet-chaton-logo.png") --logo-width 52'
|
||||
[[ -z "$TMUX" && -z "$INSIDE_EMACS" && -z "$VSCODE_INJECTION" ]] && fetch
|
||||
|
||||
# ── zsh-autosuggestions ──────────────────────────────────────────────────────
|
||||
ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="fg=#716686"
|
||||
ZSH_AUTOSUGGEST_STRATEGY=(history completion)
|
||||
ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=20
|
||||
bindkey '^ ' autosuggest-accept # Ctrl+Space pour accepter la suggestion
|
||||
bindkey '^ ' autosuggest-accept
|
||||
|
||||
# ── zsh-syntax-highlighting (couleurs violet-chaton) ─────────────────────────
|
||||
ZSH_HIGHLIGHT_STYLES[command]='fg=#8be9fd'
|
||||
ZSH_HIGHLIGHT_STYLES[builtin]='fg=#ff79c6'
|
||||
ZSH_HIGHLIGHT_STYLES[alias]='fg=#e79cfe'
|
||||
ZSH_HIGHLIGHT_STYLES[function]='fg=#8be9fd'
|
||||
ZSH_HIGHLIGHT_STYLES[string]='fg=#e79cfe'
|
||||
ZSH_HIGHLIGHT_STYLES[path]='fg=#f8f8f2,underline'
|
||||
ZSH_HIGHLIGHT_STYLES[unknown-token]='fg=#f38ba8,bold'
|
||||
ZSH_HIGHLIGHT_STYLES[reserved-word]='fg=#ff79c6'
|
||||
ZSH_HIGHLIGHT_STYLES[comment]='fg=#6c7086,italic'
|
||||
ZSH_HIGHLIGHT_STYLES[globbing]='fg=#f9e2af'
|
||||
ZSH_HIGHLIGHT_STYLES[history-expansion]='fg=#f9e2af'
|
||||
# ── zsh-syntax-highlighting (couleurs violet-chaton v2) ──────────────────────
|
||||
ZSH_HIGHLIGHT_STYLES[command]='fg=#a4b4ff'
|
||||
ZSH_HIGHLIGHT_STYLES[builtin]='fg=#ff4da6'
|
||||
ZSH_HIGHLIGHT_STYLES[alias]='fg=#c9a0ff'
|
||||
ZSH_HIGHLIGHT_STYLES[function]='fg=#a4b4ff'
|
||||
ZSH_HIGHLIGHT_STYLES[string]='fg=#9adba8'
|
||||
ZSH_HIGHLIGHT_STYLES[path]='fg=#f0eaf8,underline'
|
||||
ZSH_HIGHLIGHT_STYLES[unknown-token]='fg=#f25c7a,bold,standout'
|
||||
ZSH_HIGHLIGHT_STYLES[reserved-word]='fg=#ff4da6'
|
||||
ZSH_HIGHLIGHT_STYLES[single-hyphen-option]='fg=#e8c87a'
|
||||
ZSH_HIGHLIGHT_STYLES[double-hyphen-option]='fg=#e8c87a'
|
||||
ZSH_HIGHLIGHT_STYLES[back-quoted-argument]='fg=#c9a0ff'
|
||||
ZSH_HIGHLIGHT_STYLES[dollar-quoted-argument]='fg=#9adba8'
|
||||
ZSH_HIGHLIGHT_STYLES[assign]='fg=#f0eaf8'
|
||||
ZSH_HIGHLIGHT_STYLES[redirection]='fg=#ff4da6,bold'
|
||||
ZSH_HIGHLIGHT_STYLES[commandseparator]='fg=#ff4da6'
|
||||
|
||||
# ── atuin (remplace Ctrl+R) ───────────────────────────────────────────────────
|
||||
# ── Vi-mode — cursor shape adaptatif ────────────────────────────────────────
|
||||
bindkey -v
|
||||
export KEYTIMEOUT=1
|
||||
|
||||
# Beam en insert, block en normal
|
||||
zle-keymap-select() {
|
||||
case $KEYMAP in
|
||||
vicmd) echo -ne '\e[1 q' ;; # block clignotant
|
||||
viins|main) echo -ne '\e[5 q' ;; # beam clignotant
|
||||
esac
|
||||
}
|
||||
zle -N zle-keymap-select
|
||||
|
||||
# Reset beam au demarrage de chaque prompt
|
||||
zle-line-init() { echo -ne '\e[5 q' }
|
||||
zle -N zle-line-init
|
||||
|
||||
# Garder les keybindings essentiels en mode insert
|
||||
bindkey '^A' beginning-of-line
|
||||
bindkey '^E' end-of-line
|
||||
bindkey '^K' kill-line
|
||||
bindkey '^U' backward-kill-line
|
||||
bindkey '^W' backward-kill-word
|
||||
bindkey '^Y' yank
|
||||
bindkey '^R' history-incremental-search-backward
|
||||
bindkey '^P' up-line-or-history
|
||||
bindkey '^N' down-line-or-history
|
||||
bindkey '^?' backward-delete-char
|
||||
bindkey '^H' backward-delete-char
|
||||
ZSH_HIGHLIGHT_STYLES[comment]='fg=#716686,italic'
|
||||
ZSH_HIGHLIGHT_STYLES[globbing]='fg=#e8c87a'
|
||||
ZSH_HIGHLIGHT_STYLES[history-expansion]='fg=#e8c87a'
|
||||
|
||||
# ── fzf pimped — git log picker, process killer ─────────────────────────────
|
||||
|
||||
# Git log browser — Ctrl+L en mode normal
|
||||
fzf-git-log() {
|
||||
git log --oneline --color=always --decorate --graph 2>/dev/null |
|
||||
fzf --ansi --no-sort --reverse --preview \
|
||||
'git show --color=always $(echo {} | grep -oP "[a-f0-9]{7,}" | head -1)' \
|
||||
--preview-window='right:60%:wrap' \
|
||||
--bind='enter:execute(echo {} | grep -oP "[a-f0-9]{7,}" | head -1 | tr -d "\n" | xclip -selection clipboard)+abort'
|
||||
}
|
||||
alias glog='fzf-git-log'
|
||||
|
||||
# Process killer — fzf powered
|
||||
fkill() {
|
||||
local pid
|
||||
pid=$(procs --color=always 2>/dev/null || ps aux) |
|
||||
fzf --ansi --header="Select process to kill" \
|
||||
--preview-window='hidden' |
|
||||
awk '{print $1}'
|
||||
[ -n "$pid" ] && kill -9 "$pid" && echo "Killed $pid"
|
||||
}
|
||||
|
||||
# ── Shell functions — violet-chaton toolkit ──────────────────────────────────
|
||||
|
||||
# mkcd — creer un dossier et y aller
|
||||
mkcd() { mkdir -p "$1" && cd "$1" }
|
||||
|
||||
# Project switcher — fzf dans ~/Dev
|
||||
proj() {
|
||||
local dir
|
||||
dir=$(find ~/Dev -maxdepth 3 -name ".git" -type d 2>/dev/null | sed 's|/.git$||' |
|
||||
fzf --preview 'eza -la --icons --color=always --group-directories-first {}' \
|
||||
--preview-window='right:50%')
|
||||
[ -n "$dir" ] && cd "$dir"
|
||||
}
|
||||
|
||||
# Palette preview — affiche violet-chaton v2 dans le terminal
|
||||
colors() {
|
||||
echo ""
|
||||
echo -e " \033[1mviolet-chaton v2\033[0m"
|
||||
echo ""
|
||||
echo -e " \033[38;2;255;77;166m████\033[0m magenta #ff4da6"
|
||||
echo -e " \033[38;2;201;160;255m████\033[0m lilac #c9a0ff"
|
||||
echo -e " \033[38;2;154;219;168m████\033[0m mitsuri #9adba8"
|
||||
echo -e " \033[38;2;164;180;255m████\033[0m lavande #a4b4ff"
|
||||
echo -e " \033[38;2;232;200;122m████\033[0m champagne #e8c87a"
|
||||
echo ""
|
||||
echo -e " \033[38;2;242;92;122m████\033[0m danger #f25c7a"
|
||||
echo -e " \033[38;2;232;200;122m████\033[0m warning #e8c87a"
|
||||
echo -e " \033[38;2;154;219;168m████\033[0m success #9adba8"
|
||||
echo -e " \033[38;2;164;180;255m████\033[0m info #a4b4ff"
|
||||
echo ""
|
||||
echo -e " \033[38;2;240;234;248m████\033[0m text #f0eaf8"
|
||||
echo -e " \033[38;2;196;184;212m████\033[0m subtext1 #c4b8d4"
|
||||
echo -e " \033[38;2;154;143;173m████\033[0m subtext0 #9a8fad"
|
||||
echo -e " \033[38;2;113;102;134m████\033[0m muted #716686"
|
||||
echo ""
|
||||
echo -e " Gradient: \033[38;2;255;77;166m██\033[38;2;226;118;212m██\033[38;2;201;160;255m██\033[38;2;182;168;255m██\033[38;2;164;180;255m██\033[38;2;159;200;212m██\033[38;2;154;219;168m██\033[38;2;130;232;160m██\033[0m"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Yazi — wrapper qui cd dans le dernier dossier visite
|
||||
y() {
|
||||
local tmp="$(mktemp -t "yazi-cwd.XXXXXX")"
|
||||
yazi "$@" --cwd-file="$tmp"
|
||||
if cwd="$(cat -- "$tmp")" && [ -n "$cwd" ] && [ "$cwd" != "$PWD" ]; then
|
||||
cd "$cwd"
|
||||
fi
|
||||
rm -f "$tmp"
|
||||
}
|
||||
|
||||
# Weather — meteo rapide
|
||||
weather() { curl -s "wttr.in/${1:-Paris}?format=3" }
|
||||
|
||||
# Cheatsheet — raccourcis violet-chaton
|
||||
hotkeys() {
|
||||
echo ""
|
||||
echo -e " \033[38;2;255;77;166m\033[1m── kitty ──\033[0m"
|
||||
echo -e " \033[38;2;201;160;255mCtrl+Shift+\\\033[0m split vertical"
|
||||
echo -e " \033[38;2;201;160;255mCtrl+Shift+-\033[0m split horizontal"
|
||||
echo -e " \033[38;2;201;160;255mCtrl+Shift+Z\033[0m zoom (stack toggle)"
|
||||
echo -e " \033[38;2;201;160;255mCtrl+Shift+←→↑↓\033[0m naviguer splits"
|
||||
echo -e " \033[38;2;201;160;255mCtrl+Shift+1-5\033[0m layouts (tall/fat/grid/h/v)"
|
||||
echo -e " \033[38;2;201;160;255mCtrl+Shift+T\033[0m nouvel onglet"
|
||||
echo ""
|
||||
echo -e " \033[38;2;255;77;166m\033[1m── zsh ──\033[0m"
|
||||
echo -e " \033[38;2;154;219;168mEsc\033[0m vi normal mode (hjkl, w, b)"
|
||||
echo -e " \033[38;2;154;219;168mi\033[0m retour insert"
|
||||
echo -e " \033[38;2;154;219;168mCtrl+G\033[0m fzf fichier"
|
||||
echo -e " \033[38;2;154;219;168mCtrl+F\033[0m fzf dossier"
|
||||
echo -e " \033[38;2;154;219;168mCtrl+Space\033[0m accepter suggestion"
|
||||
echo ""
|
||||
echo -e " \033[38;2;255;77;166m\033[1m── commandes ──\033[0m"
|
||||
echo -e " \033[38;2;164;180;255mproj\033[0m project switcher fzf"
|
||||
echo -e " \033[38;2;164;180;255mglog\033[0m git log fzf"
|
||||
echo -e " \033[38;2;164;180;255mfkill\033[0m process killer fzf"
|
||||
echo -e " \033[38;2;164;180;255my\033[0m yazi (cd au dossier visite)"
|
||||
echo -e " \033[38;2;164;180;255mcolors\033[0m palette violet-chaton v2"
|
||||
echo -e " \033[38;2;164;180;255mweather [ville]\033[0m meteo rapide"
|
||||
echo -e " \033[38;2;164;180;255mhotkeys\033[0m cette aide"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# ── atuin (remplace Ctrl+R) ──────────────────────────────────────────────────
|
||||
[[ -f ~/.atuin/bin/env ]] && source ~/.atuin/bin/env
|
||||
command -v atuin &>/dev/null && eval "$(atuin init zsh --disable-up-arrow)"
|
||||
|
||||
# ── starship ──────────────────────────────────────────────────────────────────
|
||||
# ── starship ─────────────────────────────────────────────────────────────────
|
||||
command -v starship &>/dev/null && eval "$(starship init zsh)"
|
||||
|
||||
@@ -12,6 +12,14 @@ export INSTALL_LOG="$HOME/violet-chaton-install-$(date +%Y%m%d-%H%M%S).log"
|
||||
|
||||
source "$SCRIPT_DIR/scripts/lib.sh"
|
||||
|
||||
# ── Refus root ────────────────────────────────────────────────────────────────
|
||||
if [ "$EUID" -eq 0 ]; then
|
||||
echo -e "${RED}${BOLD} ERREUR : Ne pas lancer ce script en tant que root !${RESET}"
|
||||
echo -e " Lance-le en tant qu'utilisateur normal : ${CYAN}bash install.sh${RESET}"
|
||||
echo -e " ${MUTED}(sudo sera demandé automatiquement quand nécessaire)${RESET}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ── Vérifications préalables ──────────────────────────────────────────────────
|
||||
check_requirements() {
|
||||
local ok=true
|
||||
|
||||
@@ -19,6 +19,7 @@ PACKAGES=(
|
||||
chafa
|
||||
jq
|
||||
libgtk-3-bin
|
||||
adw-gtk3
|
||||
nemo
|
||||
nemo-fileroller
|
||||
# fastfetch → installé via .deb GitHub (voir 02-packages-manual.sh)
|
||||
@@ -26,16 +27,19 @@ PACKAGES=(
|
||||
btop
|
||||
# atuin → installé via son propre script (voir 02-packages-manual.sh)
|
||||
# starship → installé via son propre script (voir 02-packages-manual.sh)
|
||||
# ── Waybar + launcher + dépendances ──────────────────────────────────────
|
||||
waybar
|
||||
wob
|
||||
wofi
|
||||
# ── AGS + deps (remplace waybar/wob/wofi) ─────────────────────────────────
|
||||
brightnessctl
|
||||
playerctl
|
||||
wireplumber
|
||||
python3-gi
|
||||
gir1.2-gtk-3.0
|
||||
gir1.2-gtklayershell-0.1
|
||||
gir1.2-gdkpixbuf-2.0
|
||||
gir1.2-pango-1.0
|
||||
libgtk-layer-shell-dev
|
||||
libpulse-dev
|
||||
libdbusmenu-gtk3-dev
|
||||
# Rofi reste en backup launcher (AGS launcher = principal)
|
||||
rofi
|
||||
# ── Fun & utils ──────────────────────────────────────────────────────────
|
||||
cmatrix
|
||||
toilet
|
||||
|
||||
@@ -131,6 +131,135 @@ else
|
||||
chmod +x "$BIN/pipes.sh" && ok "pipes.sh" || fail "pipes.sh"
|
||||
fi
|
||||
|
||||
# dust (remplace ncdu/du)
|
||||
if has_cmd dust; then
|
||||
ok "dust (déjà installé)"
|
||||
else
|
||||
DUST_VER=$(github_latest_tag "bootandy/dust")
|
||||
if [ -z "$DUST_VER" ]; then
|
||||
fail "dust — version introuvable"
|
||||
else
|
||||
install_binary "dust" \
|
||||
"https://github.com/bootandy/dust/releases/download/${DUST_VER}/dust-${DUST_VER}-x86_64-unknown-linux-musl.tar.gz" \
|
||||
"tar:dust"
|
||||
fi
|
||||
fi
|
||||
|
||||
# procs (remplace ps)
|
||||
if has_cmd procs; then
|
||||
ok "procs (déjà installé)"
|
||||
else
|
||||
PROCS_VER=$(github_latest_tag "dalance/procs")
|
||||
if [ -z "$PROCS_VER" ]; then
|
||||
fail "procs — version introuvable"
|
||||
else
|
||||
install_binary "procs" \
|
||||
"https://github.com/dalance/procs/releases/download/${PROCS_VER}/procs-${PROCS_VER}-x86_64-linux.zip" \
|
||||
"zip:procs"
|
||||
fi
|
||||
fi
|
||||
|
||||
# tokei (stats code par langage) — v12 car v13+ n'a plus de binaires pre-compiles
|
||||
if has_cmd tokei; then
|
||||
ok "tokei (déjà installé)"
|
||||
else
|
||||
install_binary "tokei" \
|
||||
"https://github.com/XAMPPRocky/tokei/releases/download/v12.1.2/tokei-x86_64-unknown-linux-musl.tar.gz" \
|
||||
"tar:tokei"
|
||||
fi
|
||||
|
||||
# sd (remplace sed simplifié)
|
||||
if has_cmd sd; then
|
||||
ok "sd (déjà installé)"
|
||||
else
|
||||
SD_VER=$(github_latest_tag "chmln/sd")
|
||||
if [ -z "$SD_VER" ]; then
|
||||
fail "sd — version introuvable"
|
||||
else
|
||||
install_binary "sd" \
|
||||
"https://github.com/chmln/sd/releases/download/${SD_VER}/sd-${SD_VER}-x86_64-unknown-linux-musl.tar.gz" \
|
||||
"tar:sd"
|
||||
fi
|
||||
fi
|
||||
|
||||
# hyperfine (benchmarks CLI)
|
||||
if has_cmd hyperfine; then
|
||||
ok "hyperfine (déjà installé)"
|
||||
else
|
||||
HF_VER=$(github_latest_tag "sharkdp/hyperfine")
|
||||
if [ -z "$HF_VER" ]; then
|
||||
fail "hyperfine — version introuvable"
|
||||
else
|
||||
install_binary "hyperfine" \
|
||||
"https://github.com/sharkdp/hyperfine/releases/download/${HF_VER}/hyperfine-${HF_VER}-x86_64-unknown-linux-musl.tar.gz" \
|
||||
"tar:hyperfine"
|
||||
fi
|
||||
fi
|
||||
|
||||
# gping (ping avec graphe)
|
||||
if has_cmd gping; then
|
||||
ok "gping (déjà installé)"
|
||||
else
|
||||
GPING_VER=$(github_latest_tag "orf/gping")
|
||||
if [ -z "$GPING_VER" ]; then
|
||||
fail "gping — version introuvable"
|
||||
else
|
||||
install_binary "gping" \
|
||||
"https://github.com/orf/gping/releases/download/${GPING_VER}/gping-Linux-musl-x86_64.tar.gz" \
|
||||
"tar:gping"
|
||||
fi
|
||||
fi
|
||||
|
||||
section "AGS (Aylur's GTK Shell — barre + OSD + launcher + notifs)"
|
||||
if has_cmd ags; then
|
||||
ok "ags (deja installe)"
|
||||
else
|
||||
step "Installation de AGS depuis source..."
|
||||
tmp=$(mktemp -d)
|
||||
AGS_VER=$(github_latest_tag "Aylur/ags")
|
||||
if [ -z "$AGS_VER" ]; then
|
||||
warn "ags — version introuvable — a installer manuellement"
|
||||
else
|
||||
if git clone --depth 1 --branch "$AGS_VER" https://github.com/Aylur/ags.git "$tmp/ags" &>/dev/null; then
|
||||
if cd "$tmp/ags" && npm install &>/dev/null && npm run build &>/dev/null; then
|
||||
cp "$tmp/ags/ags" "$BIN/ags" 2>/dev/null && chmod +x "$BIN/ags" 2>/dev/null
|
||||
if [ -x "$BIN/ags" ]; then
|
||||
ok "ags"
|
||||
else
|
||||
warn "ags — build OK mais binaire non trouve. Install manuelle recommandee :"
|
||||
info " git clone https://github.com/Aylur/ags && cd ags && npm i && npm run build"
|
||||
fi
|
||||
else
|
||||
warn "ags — build echoue. Install manuelle recommandee :"
|
||||
info " git clone https://github.com/Aylur/ags && cd ags && npm i && npm run build"
|
||||
fi
|
||||
cd - &>/dev/null
|
||||
else
|
||||
warn "ags — clone echoue"
|
||||
fi
|
||||
fi
|
||||
rm -rf "$tmp"
|
||||
fi
|
||||
|
||||
section "kitty (terminal GPU-accelerated)"
|
||||
if has_cmd kitty; then
|
||||
ok "kitty (deja installe)"
|
||||
else
|
||||
step "Installation de kitty..."
|
||||
if curl -L https://sw.kovidgoyal.net/kitty/installer.sh | sh /dev/stdin launch=n &>/dev/null; then
|
||||
ln -sf "$HOME/.local/kitty.app/bin/kitty" "$HOME/.local/bin/kitty"
|
||||
ln -sf "$HOME/.local/kitty.app/bin/kitten" "$HOME/.local/bin/kitten"
|
||||
# Desktop file pour le launcher
|
||||
cp "$HOME/.local/kitty.app/share/applications/kitty.desktop" \
|
||||
"$HOME/.local/share/applications/" 2>/dev/null
|
||||
sed -i "s|Icon=kitty|Icon=$HOME/.local/kitty.app/share/icons/hicolor/256x256/apps/kitty.png|g" \
|
||||
"$HOME/.local/share/applications/kitty.desktop" 2>/dev/null
|
||||
ok "kitty"
|
||||
else
|
||||
fail "kitty"
|
||||
fi
|
||||
fi
|
||||
|
||||
section "starship (prompt)"
|
||||
if has_cmd starship; then
|
||||
ok "starship (déjà installé)"
|
||||
@@ -188,7 +317,7 @@ else
|
||||
fi
|
||||
|
||||
# ── Nerd Fonts ─────────────────────────────────────────────────────────────────
|
||||
section "Nerd Fonts (JetBrainsMono NL + 0xProto)"
|
||||
section "Nerd Fonts (Maple Mono NF + JetBrainsMono NL + 0xProto)"
|
||||
FONTS_DIR="$HOME/.local/share/fonts/NerdFonts"
|
||||
ensure_dir "$FONTS_DIR"
|
||||
|
||||
@@ -213,6 +342,9 @@ install_font() {
|
||||
rm -rf "$tmp"
|
||||
}
|
||||
|
||||
install_font "Maple Mono NF" \
|
||||
"https://github.com/subframe7536/maple-font/releases/latest/download/MapleMono-NF.zip" \
|
||||
"MapleMono-NF-Regular.ttf"
|
||||
install_font "JetBrainsMono NL" \
|
||||
"https://github.com/ryanoasis/nerd-fonts/releases/latest/download/JetBrainsMono.zip" \
|
||||
"JetBrainsMonoNLNerdFont-Regular.ttf"
|
||||
|
||||
@@ -11,7 +11,14 @@ deploy_file() {
|
||||
local src="$1"
|
||||
local dst="$2"
|
||||
ensure_dir "$(dirname "$dst")"
|
||||
if [ -f "$dst" ]; then
|
||||
if [ -L "$dst" ]; then
|
||||
# Symlink géré par COSMIC : sauvegarder la cible réelle puis supprimer le lien
|
||||
local real; real=$(readlink -f "$dst")
|
||||
local rel="${dst#"$HOME/"}"
|
||||
ensure_dir "$BACKUP_DIR/$(dirname "$rel")"
|
||||
cp "$real" "$BACKUP_DIR/$rel" 2>/dev/null
|
||||
rm "$dst"
|
||||
elif [ -f "$dst" ]; then
|
||||
local rel="${dst#"$HOME/"}"
|
||||
ensure_dir "$BACKUP_DIR/$(dirname "$rel")"
|
||||
cp "$dst" "$BACKUP_DIR/$rel" 2>/dev/null
|
||||
@@ -44,6 +51,10 @@ fi
|
||||
# ── Configs outils ─────────────────────────────────────────────────────────────
|
||||
section "Configs outils"
|
||||
deploy_file "$CONFIGS/starship.toml" "$HOME/.config/starship.toml"
|
||||
deploy_file "$CONFIGS/kitty.conf" "$HOME/.config/kitty/kitty.conf"
|
||||
if [ -f "$CONFIGS/kitty/violet-chaton-glow.glsl" ]; then
|
||||
deploy_file "$CONFIGS/kitty/violet-chaton-glow.glsl" "$HOME/.config/kitty/violet-chaton-glow.glsl"
|
||||
fi
|
||||
deploy_file "$CONFIGS/bat.conf" "$HOME/.config/bat/config"
|
||||
deploy_file "$CONFIGS/btop.conf" "$HOME/.config/btop/btop.conf"
|
||||
deploy_file "$CONFIGS/fastfetch.jsonc" "$HOME/.config/fastfetch/config.jsonc"
|
||||
@@ -118,11 +129,33 @@ else
|
||||
fail "CosmicTerm"
|
||||
fi
|
||||
|
||||
# ── GTK3 — thème violet-chaton ─────────────────────────────────────────────
|
||||
section "GTK3 — thème violet-chaton"
|
||||
# ── GTK3 / GTK4 — thème violet-chaton ─────────────────────────────────────
|
||||
section "GTK — thème violet-chaton"
|
||||
|
||||
step "Thème GTK3 dark (adw-gtk3-dark + couleurs violet-chaton)..."
|
||||
ensure_dir "$HOME/.config/gtk-3.0"
|
||||
deploy_file "$THEMES/violet-chaton-gtk.css" "$HOME/.config/gtk-3.0/gtk.css"
|
||||
|
||||
step "Thème GTK3 light..."
|
||||
deploy_file "$THEMES/violet-chaton-gtk-light.css" "$HOME/.config/gtk-3.0/gtk-light.css"
|
||||
|
||||
step "Thème GTK4 / libadwaita dark..."
|
||||
ensure_dir "$HOME/.config/gtk-4.0"
|
||||
deploy_file "$THEMES/violet-chaton-gtk.css" "$HOME/.config/gtk-4.0/gtk.css"
|
||||
|
||||
step "Thème GTK4 / libadwaita light..."
|
||||
deploy_file "$THEMES/violet-chaton-gtk-light.css" "$HOME/.config/gtk-4.0/gtk-light.css"
|
||||
|
||||
step "Activation adw-gtk3-dark + dark mode (gsettings)..."
|
||||
if has_cmd gsettings; then
|
||||
gsettings set org.gnome.desktop.interface gtk-theme 'adw-gtk3-dark' 2>/dev/null && \
|
||||
gsettings set org.gnome.desktop.interface color-scheme 'prefer-dark' 2>/dev/null && \
|
||||
ok "gtk-theme=adw-gtk3-dark, color-scheme=prefer-dark" || \
|
||||
warn "gsettings GTK échoué — thème à appliquer manuellement"
|
||||
else
|
||||
warn "gsettings non disponible — thème GTK à appliquer manuellement"
|
||||
fi
|
||||
|
||||
# ── Nemo — gestionnaire de fichiers ────────────────────────────────────────
|
||||
section "Nemo — configuration et thème"
|
||||
|
||||
@@ -223,105 +256,59 @@ PYEOF
|
||||
fi
|
||||
fi
|
||||
|
||||
# ── Waybar ─────────────────────────────────────────────────────────────────────
|
||||
section "Waybar — island floating 3 pills"
|
||||
deploy_file "$CONFIGS/waybar/config" "$HOME/.config/waybar/config"
|
||||
deploy_file "$THEMES/violet-chaton-waybar.css" "$HOME/.config/waybar/style.css"
|
||||
deploy_file "$CONFIGS/waybar/cava-waybar.cfg" "$HOME/.config/waybar/cava-waybar.cfg"
|
||||
# ── AGS (remplace waybar + wob + wofi) ─────────────────────────────────────────
|
||||
section "AGS — violet-chaton shell"
|
||||
ensure_dir "$HOME/.config/ags/css"
|
||||
ensure_dir "$HOME/.config/ags/widgets"
|
||||
deploy_file "$CONFIGS/ags/config.js" "$HOME/.config/ags/config.js"
|
||||
deploy_file "$CONFIGS/ags/css/style.css" "$HOME/.config/ags/css/style.css"
|
||||
deploy_file "$CONFIGS/ags/widgets/Bar.js" "$HOME/.config/ags/widgets/Bar.js"
|
||||
deploy_file "$CONFIGS/ags/widgets/OSD.js" "$HOME/.config/ags/widgets/OSD.js"
|
||||
deploy_file "$CONFIGS/ags/widgets/Launcher.js" "$HOME/.config/ags/widgets/Launcher.js"
|
||||
deploy_file "$CONFIGS/ags/widgets/Notifications.js" "$HOME/.config/ags/widgets/Notifications.js"
|
||||
|
||||
step "Scripts waybar..."
|
||||
ensure_dir "$HOME/.config/waybar/scripts"
|
||||
for script in "$CONFIGS/waybar/scripts/"*.sh; do
|
||||
dst="$HOME/.config/waybar/scripts/$(basename "$script")"
|
||||
cp "$script" "$dst" && chmod +x "$dst"
|
||||
done
|
||||
for script in "$CONFIGS/waybar/scripts/"*.py; do
|
||||
dst="$HOME/.config/waybar/scripts/$(basename "$script")"
|
||||
cp "$script" "$dst" && chmod +x "$dst"
|
||||
done
|
||||
ok "Scripts waybar"
|
||||
|
||||
# ── Autostart ───────────────────────────────────────────────────────────────────
|
||||
section "Autostart — waybar + wob"
|
||||
# ── Autostart — AGS ────────────────────────────────────────────────────────────
|
||||
section "Autostart — AGS"
|
||||
ensure_dir "$HOME/.config/autostart"
|
||||
deploy_file "$CONFIGS/autostart/waybar.desktop" "$HOME/.config/autostart/waybar.desktop"
|
||||
deploy_file "$CONFIGS/autostart/wob.desktop" "$HOME/.config/autostart/wob.desktop"
|
||||
|
||||
cat > /tmp/ags-vc.desktop << 'DESKTOP'
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=AGS violet-chaton
|
||||
Exec=ags
|
||||
X-GNOME-Autostart-enabled=true
|
||||
DESKTOP
|
||||
deploy_file "/tmp/ags-vc.desktop" "$HOME/.config/autostart/ags.desktop"
|
||||
rm -f /tmp/ags-vc.desktop
|
||||
|
||||
# Cleanup ancien waybar/wob autostart si present
|
||||
[ -f "$HOME/.config/autostart/waybar.desktop" ] && rm -f "$HOME/.config/autostart/waybar.desktop" && ok "waybar autostart retire"
|
||||
[ -f "$HOME/.config/autostart/wob.desktop" ] && rm -f "$HOME/.config/autostart/wob.desktop" && ok "wob autostart retire"
|
||||
|
||||
# ── Règle sudoers — profil énergie ──────────────────────────────────────────────
|
||||
section "Sudoers — profil énergie ACPI"
|
||||
SUDOERS_FILE="/etc/sudoers.d/waybar-power-profile"
|
||||
SUDOERS_FILE="/etc/sudoers.d/vc-power-profile"
|
||||
SUDOERS_RULE="$USER ALL=(ALL) NOPASSWD: /usr/bin/tee /sys/firmware/acpi/platform_profile"
|
||||
if [ -f "$SUDOERS_FILE" ]; then
|
||||
if [ -f "$SUDOERS_FILE" ] || [ -f "/etc/sudoers.d/waybar-power-profile" ]; then
|
||||
ok "Règle sudoers déjà présente"
|
||||
else
|
||||
step "Création de la règle sudoers (mot de passe sudo requis)..."
|
||||
echo "$SUDOERS_RULE" > /tmp/waybar-pp-sudoers
|
||||
if sudo cp /tmp/waybar-pp-sudoers "$SUDOERS_FILE" && sudo chmod 440 "$SUDOERS_FILE"; then
|
||||
rm -f /tmp/waybar-pp-sudoers
|
||||
echo "$SUDOERS_RULE" > /tmp/vc-pp-sudoers
|
||||
if sudo cp /tmp/vc-pp-sudoers "$SUDOERS_FILE" && sudo chmod 440 "$SUDOERS_FILE"; then
|
||||
rm -f /tmp/vc-pp-sudoers
|
||||
ok "Règle sudoers créée"
|
||||
else
|
||||
rm -f /tmp/waybar-pp-sudoers
|
||||
rm -f /tmp/vc-pp-sudoers
|
||||
warn "Échec sudoers — changement de profil énergie nécessitera sudo"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ── Règle udev — permissions platform_profile ────────────────────────────────
|
||||
section "udev — platform_profile accessible au groupe video"
|
||||
UDEV_FILE="/etc/udev/rules.d/90-platform-profile.rules"
|
||||
if [ -f "$UDEV_FILE" ]; then
|
||||
ok "Règle udev déjà présente"
|
||||
else
|
||||
step "Création de la règle udev (mot de passe sudo requis)..."
|
||||
echo 'ACTION=="add|change", KERNEL=="platform_profile", SUBSYSTEM=="acpi", RUN+="/bin/chmod g+w /sys/firmware/acpi/platform_profile", RUN+="/bin/chgrp video /sys/firmware/acpi/platform_profile"' \
|
||||
> /tmp/90-platform-profile.rules
|
||||
if sudo cp /tmp/90-platform-profile.rules "$UDEV_FILE" && sudo chmod 644 "$UDEV_FILE"; then
|
||||
rm -f /tmp/90-platform-profile.rules
|
||||
sudo chmod g+w /sys/firmware/acpi/platform_profile 2>/dev/null
|
||||
sudo chgrp video /sys/firmware/acpi/platform_profile 2>/dev/null
|
||||
ok "Règle udev créée"
|
||||
else
|
||||
rm -f /tmp/90-platform-profile.rules
|
||||
warn "Échec udev — redémarrage requis pour les permissions platform_profile"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ── Wofi — launcher + power menu ────────────────────────────────────────────────
|
||||
section "Wofi — launcher violet-chaton"
|
||||
ensure_dir "$HOME/.config/wofi"
|
||||
deploy_file "$CONFIGS/wofi/config" "$HOME/.config/wofi/config"
|
||||
deploy_file "$THEMES/violet-chaton-wofi.css" "$HOME/.config/wofi/style.css"
|
||||
deploy_file "$THEMES/violet-chaton-wofi-power.css" "$HOME/.config/wofi/power-style.css"
|
||||
|
||||
# ── Rofi ────────────────────────────────────────────────────────────────────────
|
||||
section "Rofi — thème violet-chaton"
|
||||
# ── Rofi — backup launcher (AGS launcher = principal) ──────────────────────────
|
||||
section "Rofi — thème violet-chaton (backup launcher)"
|
||||
ensure_dir "$HOME/.config/rofi"
|
||||
deploy_file "$CONFIGS/rofi/config.rasi" "$HOME/.config/rofi/config.rasi"
|
||||
deploy_file "$THEMES/violet-chaton-rofi.rasi" "$HOME/.config/rofi/violet-chaton.rasi"
|
||||
|
||||
# ── wob ─────────────────────────────────────────────────────────────────────────
|
||||
section "wob — overlay volume/luminosité"
|
||||
deploy_file "$CONFIGS/wob/wob.ini" "$HOME/.config/wob.ini"
|
||||
|
||||
# ── Désactiver cosmic-osd (remplacé par wob) ─────────────────────────────────
|
||||
section "cosmic-osd — désactivation (wob le remplace)"
|
||||
if [ -f /usr/bin/cosmic-osd.real ]; then
|
||||
ok "cosmic-osd déjà désactivé via dpkg-divert"
|
||||
elif [ -f /usr/bin/cosmic-osd ]; then
|
||||
step "Divert de cosmic-osd (mot de passe sudo requis)..."
|
||||
if sudo dpkg-divert --add --rename --divert /usr/bin/cosmic-osd.real /usr/bin/cosmic-osd; then
|
||||
printf '#!/usr/bin/env bash\nexec sleep infinity\n' > /tmp/cosmic-osd-fake
|
||||
chmod +x /tmp/cosmic-osd-fake
|
||||
sudo cp /tmp/cosmic-osd-fake /usr/bin/cosmic-osd
|
||||
rm -f /tmp/cosmic-osd-fake
|
||||
pkill -x cosmic-osd 2>/dev/null
|
||||
ok "cosmic-osd désactivé — wob gère les overlays"
|
||||
else
|
||||
warn "dpkg-divert échoué — cosmic-osd reste actif"
|
||||
fi
|
||||
else
|
||||
warn "cosmic-osd introuvable — rien à faire"
|
||||
fi
|
||||
|
||||
# ── Logo fastfetch ─────────────────────────────────────────────────────────────
|
||||
section "Logo fastfetch"
|
||||
if [ -f "$SCRIPT_DIR/assets/violet-chaton-logo.png" ]; then
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
#!/bin/bash
|
||||
# ── violet-chaton : fonctions partagées ───────────────────────────────────────
|
||||
|
||||
PINK='\033[38;2;255;121;198m'
|
||||
PURPLE='\033[38;2;231;156;254m'
|
||||
CYAN='\033[38;2;139;233;253m'
|
||||
GREEN='\033[38;2;166;227;161m'
|
||||
YELLOW='\033[38;2;249;226;175m'
|
||||
RED='\033[38;2;243;139;168m'
|
||||
MUTED='\033[38;2;108;112;134m'
|
||||
TEXT='\033[38;2;248;248;242m'
|
||||
BOLD='\033[1m'
|
||||
RESET='\033[0m'
|
||||
# ── Palette violet-chaton v2 (source de verite : themes/palette.sh) ──────────
|
||||
_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
_PALETTE="$_LIB_DIR/../themes/palette.sh"
|
||||
if [ -f "$_PALETTE" ]; then
|
||||
source "$_PALETTE"
|
||||
fi
|
||||
|
||||
PINK="${VC_ANSI_MAGENTA:-\033[38;2;255;77;166m}"
|
||||
PURPLE="${VC_ANSI_LILAC:-\033[38;2;201;160;255m}"
|
||||
CYAN="${VC_ANSI_LAVANDE:-\033[38;2;164;180;255m}"
|
||||
GREEN="${VC_ANSI_MITSURI:-\033[38;2;154;219;168m}"
|
||||
YELLOW="${VC_ANSI_CHAMPAGNE:-\033[38;2;232;200;122m}"
|
||||
RED="${VC_ANSI_DANGER:-\033[38;2;242;92;122m}"
|
||||
MUTED="${VC_ANSI_MUTED:-\033[38;2;113;102;134m}"
|
||||
TEXT="${VC_ANSI_TEXT:-\033[38;2;240;234;248m}"
|
||||
BOLD="${VC_ANSI_BOLD:-\033[1m}"
|
||||
RESET="${VC_ANSI_RESET:-\033[0m}"
|
||||
|
||||
# ── Log ────────────────────────────────────────────────────────────────────────
|
||||
# INSTALL_LOG peut être pré-exporté par install.sh pour que tous les sous-scripts
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
{
|
||||
0: (
|
||||
name: "violet-chaton",
|
||||
foreground: "#F8F8F2",
|
||||
foreground: "#F0EAF8",
|
||||
background: "#261537",
|
||||
cursor: "#FF79C6",
|
||||
bright_foreground: "#F8F8F2",
|
||||
dim_foreground: "#6C7086",
|
||||
cursor: "#FF4DA6",
|
||||
bright_foreground: "#F0EAF8",
|
||||
dim_foreground: "#716686",
|
||||
normal: (
|
||||
black: "#261537",
|
||||
red: "#F38BA8",
|
||||
green: "#A6E3A1",
|
||||
yellow: "#F9E2AF",
|
||||
blue: "#3D2454",
|
||||
magenta: "#FF79C6",
|
||||
cyan: "#8BE9FD",
|
||||
white: "#F8F8F2",
|
||||
red: "#F25C7A",
|
||||
green: "#9ADBA8",
|
||||
yellow: "#E8C87A",
|
||||
blue: "#A4B4FF",
|
||||
magenta: "#FF4DA6",
|
||||
cyan: "#C9A0FF",
|
||||
white: "#C4B8D4",
|
||||
),
|
||||
bright: (
|
||||
black: "#6C7086",
|
||||
red: "#FF79C6",
|
||||
green: "#8BE9FD",
|
||||
yellow: "#E79CFE",
|
||||
blue: "#E79CFE",
|
||||
magenta: "#E79CFE",
|
||||
cyan: "#8BE9FD",
|
||||
white: "#F8F8F2",
|
||||
black: "#5A3875",
|
||||
red: "#FF7A96",
|
||||
green: "#B5E8C0",
|
||||
yellow: "#F0D99A",
|
||||
blue: "#BCC8FF",
|
||||
magenta: "#C9A0FF",
|
||||
cyan: "#DFC0FF",
|
||||
white: "#F0EAF8",
|
||||
),
|
||||
dim: (
|
||||
black: "#261537",
|
||||
red: "#F38BA8",
|
||||
green: "#A6E3A1",
|
||||
yellow: "#F9E2AF",
|
||||
blue: "#3D2454",
|
||||
magenta: "#FF79C6",
|
||||
cyan: "#8BE9FD",
|
||||
white: "#6C7086",
|
||||
black: "#1A0E27",
|
||||
red: "#C93A5A",
|
||||
green: "#6EBE80",
|
||||
yellow: "#B89840",
|
||||
blue: "#7A8ACC",
|
||||
magenta: "#D4348A",
|
||||
cyan: "#8A5CB8",
|
||||
white: "#716686",
|
||||
),
|
||||
),
|
||||
}
|
||||
@@ -1,40 +1,40 @@
|
||||
{
|
||||
0: (
|
||||
name: "violet-chaton",
|
||||
foreground: "#F8F8F2",
|
||||
background: "#261537",
|
||||
cursor: "#FF79C6",
|
||||
bright_foreground: "#F8F8F2",
|
||||
dim_foreground: "#6C7086",
|
||||
name: "violet-chaton-light",
|
||||
foreground: "#261537",
|
||||
background: "#F3EDF8",
|
||||
cursor: "#D4348A",
|
||||
bright_foreground: "#261537",
|
||||
dim_foreground: "#8A7BA0",
|
||||
normal: (
|
||||
black: "#261537",
|
||||
red: "#F38BA8",
|
||||
green: "#A6E3A1",
|
||||
yellow: "#F9E2AF",
|
||||
blue: "#3D2454",
|
||||
magenta: "#FF79C6",
|
||||
cyan: "#8BE9FD",
|
||||
white: "#F8F8F2",
|
||||
black: "#F3EDF8",
|
||||
red: "#C93A5A",
|
||||
green: "#3D9E68",
|
||||
yellow: "#B89840",
|
||||
blue: "#5A6AD0",
|
||||
magenta: "#D4348A",
|
||||
cyan: "#8A5CB8",
|
||||
white: "#3D2454",
|
||||
),
|
||||
bright: (
|
||||
black: "#6C7086",
|
||||
red: "#FF79C6",
|
||||
green: "#8BE9FD",
|
||||
yellow: "#E79CFE",
|
||||
blue: "#E79CFE",
|
||||
magenta: "#E79CFE",
|
||||
cyan: "#8BE9FD",
|
||||
white: "#F8F8F2",
|
||||
black: "#C4B8D4",
|
||||
red: "#E04A6A",
|
||||
green: "#4DAE78",
|
||||
yellow: "#C8A850",
|
||||
blue: "#6A7AE0",
|
||||
magenta: "#8A5CB8",
|
||||
cyan: "#A070D0",
|
||||
white: "#261537",
|
||||
),
|
||||
dim: (
|
||||
black: "#261537",
|
||||
red: "#F38BA8",
|
||||
green: "#A6E3A1",
|
||||
yellow: "#F9E2AF",
|
||||
blue: "#3D2454",
|
||||
magenta: "#FF79C6",
|
||||
cyan: "#8BE9FD",
|
||||
white: "#6C7086",
|
||||
black: "#EBE4F2",
|
||||
red: "#A02840",
|
||||
green: "#2D7E50",
|
||||
yellow: "#987830",
|
||||
blue: "#4A5AB0",
|
||||
magenta: "#B42870",
|
||||
cyan: "#704898",
|
||||
white: "#5A3875",
|
||||
),
|
||||
),
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
"JetBrains Mono NL"
|
||||
"Maple Mono NF"
|
||||
@@ -1 +1 @@
|
||||
14
|
||||
13
|
||||
@@ -1,74 +1,74 @@
|
||||
(
|
||||
base: (
|
||||
red: 0.90588236,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.788,
|
||||
green: 0.627,
|
||||
blue: 1.0,
|
||||
alpha: 1.0,
|
||||
),
|
||||
hover: (
|
||||
red: 0.8103273,
|
||||
green: 0.558776,
|
||||
blue: 0.90052974,
|
||||
red: 0.708,
|
||||
green: 0.564,
|
||||
blue: 0.900,
|
||||
alpha: 1.0,
|
||||
),
|
||||
pressed: (
|
||||
red: 0.51201665,
|
||||
green: 0.32542938,
|
||||
blue: 0.59074855,
|
||||
red: 0.469,
|
||||
green: 0.355,
|
||||
blue: 0.608,
|
||||
alpha: 1.0,
|
||||
),
|
||||
selected: (
|
||||
red: 0.8103273,
|
||||
green: 0.558776,
|
||||
blue: 0.90052974,
|
||||
red: 0.708,
|
||||
green: 0.564,
|
||||
blue: 0.900,
|
||||
alpha: 1.0,
|
||||
),
|
||||
selected_text: (
|
||||
red: 0.90588236,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.788,
|
||||
green: 0.627,
|
||||
blue: 1.0,
|
||||
alpha: 1.0,
|
||||
),
|
||||
focus: (
|
||||
red: 0.90588236,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.788,
|
||||
green: 0.627,
|
||||
blue: 1.0,
|
||||
alpha: 1.0,
|
||||
),
|
||||
divider: (
|
||||
red: 0.0,
|
||||
green: 0.0,
|
||||
blue: 0.000000000000000000000000000000000000000000055,
|
||||
red: 0.102,
|
||||
green: 0.055,
|
||||
blue: 0.153,
|
||||
alpha: 1.0,
|
||||
),
|
||||
on: (
|
||||
red: 0.0,
|
||||
green: 0.0,
|
||||
blue: 0.000000000000000000000000000000000000000000055,
|
||||
red: 0.102,
|
||||
green: 0.055,
|
||||
blue: 0.153,
|
||||
alpha: 1.0,
|
||||
),
|
||||
disabled: (
|
||||
red: 0.90588236,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
alpha: 1.0,
|
||||
red: 0.788,
|
||||
green: 0.627,
|
||||
blue: 1.0,
|
||||
alpha: 0.5,
|
||||
),
|
||||
on_disabled: (
|
||||
red: 0.45294118,
|
||||
green: 0.30588236,
|
||||
blue: 0.49803922,
|
||||
red: 0.445,
|
||||
green: 0.341,
|
||||
blue: 0.577,
|
||||
alpha: 1.0,
|
||||
),
|
||||
border: (
|
||||
red: 0.90588236,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.788,
|
||||
green: 0.627,
|
||||
blue: 1.0,
|
||||
alpha: 1.0,
|
||||
),
|
||||
disabled_border: (
|
||||
red: 0.90588236,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.788,
|
||||
green: 0.627,
|
||||
blue: 1.0,
|
||||
alpha: 0.5,
|
||||
),
|
||||
)
|
||||
@@ -1,100 +1,100 @@
|
||||
(
|
||||
base: (
|
||||
red: 0.20392156,
|
||||
green: 0.109803915,
|
||||
blue: 0.2901961,
|
||||
red: 0.149,
|
||||
green: 0.082,
|
||||
blue: 0.216,
|
||||
alpha: 1.0,
|
||||
),
|
||||
component: (
|
||||
base: (
|
||||
red: 0.28618598,
|
||||
green: 0.19189146,
|
||||
blue: 0.3797182,
|
||||
red: 0.239,
|
||||
green: 0.141,
|
||||
blue: 0.329,
|
||||
alpha: 1.0,
|
||||
),
|
||||
hover: (
|
||||
red: 0.35756737,
|
||||
green: 0.27269349,
|
||||
blue: 0.44174638,
|
||||
red: 0.286,
|
||||
green: 0.192,
|
||||
blue: 0.380,
|
||||
alpha: 1.0,
|
||||
),
|
||||
pressed: (
|
||||
red: 0.4289488,
|
||||
green: 0.35349554,
|
||||
blue: 0.5037746,
|
||||
red: 0.353,
|
||||
green: 0.220,
|
||||
blue: 0.459,
|
||||
alpha: 1.0,
|
||||
),
|
||||
selected: (
|
||||
red: 0.35756737,
|
||||
green: 0.27269349,
|
||||
blue: 0.44174638,
|
||||
red: 0.286,
|
||||
green: 0.192,
|
||||
blue: 0.380,
|
||||
alpha: 1.0,
|
||||
),
|
||||
selected_text: (
|
||||
red: 0.90588236,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.788,
|
||||
green: 0.627,
|
||||
blue: 1.0,
|
||||
alpha: 1.0,
|
||||
),
|
||||
focus: (
|
||||
red: 0.90588236,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.788,
|
||||
green: 0.627,
|
||||
blue: 1.0,
|
||||
alpha: 1.0,
|
||||
),
|
||||
divider: (
|
||||
red: 0.8318802,
|
||||
green: 0.8318715,
|
||||
blue: 0.8090188,
|
||||
red: 0.769,
|
||||
green: 0.722,
|
||||
blue: 0.831,
|
||||
alpha: 0.2,
|
||||
),
|
||||
on: (
|
||||
red: 0.8318802,
|
||||
green: 0.8318715,
|
||||
blue: 0.8090188,
|
||||
red: 0.941,
|
||||
green: 0.918,
|
||||
blue: 0.973,
|
||||
alpha: 1.0,
|
||||
),
|
||||
disabled: (
|
||||
red: 0.28618598,
|
||||
green: 0.19189146,
|
||||
blue: 0.3797182,
|
||||
red: 0.239,
|
||||
green: 0.141,
|
||||
blue: 0.329,
|
||||
alpha: 0.5,
|
||||
),
|
||||
on_disabled: (
|
||||
red: 0.8318802,
|
||||
green: 0.8318715,
|
||||
blue: 0.8090188,
|
||||
red: 0.941,
|
||||
green: 0.918,
|
||||
blue: 0.973,
|
||||
alpha: 0.65,
|
||||
),
|
||||
border: (
|
||||
red: 0.7874787,
|
||||
green: 0.6994349,
|
||||
blue: 0.8914889,
|
||||
red: 0.353,
|
||||
green: 0.220,
|
||||
blue: 0.459,
|
||||
alpha: 1.0,
|
||||
),
|
||||
disabled_border: (
|
||||
red: 0.7874787,
|
||||
green: 0.6994349,
|
||||
blue: 0.8914889,
|
||||
red: 0.353,
|
||||
green: 0.220,
|
||||
blue: 0.459,
|
||||
alpha: 0.5,
|
||||
),
|
||||
),
|
||||
divider: (
|
||||
red: 0.36091125,
|
||||
green: 0.28561735,
|
||||
blue: 0.42521048,
|
||||
red: 0.204,
|
||||
green: 0.110,
|
||||
blue: 0.290,
|
||||
alpha: 1.0,
|
||||
),
|
||||
on: (
|
||||
red: 0.9888701,
|
||||
green: 0.98887116,
|
||||
blue: 0.9652681,
|
||||
red: 0.941,
|
||||
green: 0.918,
|
||||
blue: 0.973,
|
||||
alpha: 1.0,
|
||||
),
|
||||
small_widget: (
|
||||
red: 0.21216959,
|
||||
green: 0.20068932,
|
||||
blue: 0.22159976,
|
||||
red: 0.443,
|
||||
green: 0.400,
|
||||
blue: 0.525,
|
||||
alpha: 0.25,
|
||||
),
|
||||
)
|
||||
@@ -1,74 +1,74 @@
|
||||
(
|
||||
base: (
|
||||
red: 0.9529412,
|
||||
green: 0.54509807,
|
||||
blue: 0.65882355,
|
||||
red: 0.949,
|
||||
green: 0.361,
|
||||
blue: 0.478,
|
||||
alpha: 1.0,
|
||||
),
|
||||
hover: (
|
||||
red: 0.84797436,
|
||||
green: 0.5054427,
|
||||
blue: 0.6307258,
|
||||
red: 0.854,
|
||||
green: 0.325,
|
||||
blue: 0.430,
|
||||
alpha: 1.0,
|
||||
),
|
||||
pressed: (
|
||||
red: 0.53554606,
|
||||
green: 0.29209605,
|
||||
blue: 0.42212114,
|
||||
red: 0.526,
|
||||
green: 0.208,
|
||||
blue: 0.347,
|
||||
alpha: 1.0,
|
||||
),
|
||||
selected: (
|
||||
red: 0.84797436,
|
||||
green: 0.5054427,
|
||||
blue: 0.6307258,
|
||||
red: 0.854,
|
||||
green: 0.325,
|
||||
blue: 0.430,
|
||||
alpha: 1.0,
|
||||
),
|
||||
selected_text: (
|
||||
red: 0.90588236,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.949,
|
||||
green: 0.361,
|
||||
blue: 0.478,
|
||||
alpha: 1.0,
|
||||
),
|
||||
focus: (
|
||||
red: 0.90588236,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.949,
|
||||
green: 0.361,
|
||||
blue: 0.478,
|
||||
alpha: 1.0,
|
||||
),
|
||||
divider: (
|
||||
red: 0.0,
|
||||
green: 0.0,
|
||||
blue: 0.000000000000000000000000000000000000000000055,
|
||||
red: 0.102,
|
||||
green: 0.055,
|
||||
blue: 0.153,
|
||||
alpha: 1.0,
|
||||
),
|
||||
on: (
|
||||
red: 0.0,
|
||||
green: 0.0,
|
||||
blue: 0.000000000000000000000000000000000000000000055,
|
||||
red: 0.102,
|
||||
green: 0.055,
|
||||
blue: 0.153,
|
||||
alpha: 1.0,
|
||||
),
|
||||
disabled: (
|
||||
red: 0.9529412,
|
||||
green: 0.54509807,
|
||||
blue: 0.65882355,
|
||||
alpha: 1.0,
|
||||
red: 0.949,
|
||||
green: 0.361,
|
||||
blue: 0.478,
|
||||
alpha: 0.5,
|
||||
),
|
||||
on_disabled: (
|
||||
red: 0.4764706,
|
||||
green: 0.27254903,
|
||||
blue: 0.32941177,
|
||||
red: 0.526,
|
||||
green: 0.208,
|
||||
blue: 0.316,
|
||||
alpha: 1.0,
|
||||
),
|
||||
border: (
|
||||
red: 0.9529412,
|
||||
green: 0.54509807,
|
||||
blue: 0.65882355,
|
||||
red: 0.949,
|
||||
green: 0.361,
|
||||
blue: 0.478,
|
||||
alpha: 1.0,
|
||||
),
|
||||
disabled_border: (
|
||||
red: 0.9529412,
|
||||
green: 0.54509807,
|
||||
blue: 0.65882355,
|
||||
red: 0.949,
|
||||
green: 0.361,
|
||||
blue: 0.478,
|
||||
alpha: 0.5,
|
||||
),
|
||||
)
|
||||
@@ -1 +1 @@
|
||||
"Violet-chaton"
|
||||
"Violet-Chaton Dark"
|
||||
@@ -1,100 +1,100 @@
|
||||
(
|
||||
base: (
|
||||
red: 0.21960787,
|
||||
green: 0.13725492,
|
||||
blue: 0.29411766,
|
||||
red: 0.204,
|
||||
green: 0.110,
|
||||
blue: 0.290,
|
||||
alpha: 1.0,
|
||||
),
|
||||
component: (
|
||||
base: (
|
||||
red: 0.28282174,
|
||||
green: 0.19933021,
|
||||
blue: 0.36183798,
|
||||
red: 0.239,
|
||||
green: 0.141,
|
||||
blue: 0.329,
|
||||
alpha: 1.0,
|
||||
),
|
||||
hover: (
|
||||
red: 0.35453954,
|
||||
green: 0.27938837,
|
||||
blue: 0.42565417,
|
||||
red: 0.286,
|
||||
green: 0.192,
|
||||
blue: 0.380,
|
||||
alpha: 1.0,
|
||||
),
|
||||
pressed: (
|
||||
red: 0.4262574,
|
||||
green: 0.35944653,
|
||||
blue: 0.48947042,
|
||||
red: 0.353,
|
||||
green: 0.220,
|
||||
blue: 0.459,
|
||||
alpha: 1.0,
|
||||
),
|
||||
selected: (
|
||||
red: 0.35453954,
|
||||
green: 0.27938837,
|
||||
blue: 0.42565417,
|
||||
red: 0.286,
|
||||
green: 0.192,
|
||||
blue: 0.380,
|
||||
alpha: 1.0,
|
||||
),
|
||||
selected_text: (
|
||||
red: 0.90588236,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.788,
|
||||
green: 0.627,
|
||||
blue: 1.0,
|
||||
alpha: 1.0,
|
||||
),
|
||||
focus: (
|
||||
red: 0.90588236,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.788,
|
||||
green: 0.627,
|
||||
blue: 1.0,
|
||||
alpha: 1.0,
|
||||
),
|
||||
divider: (
|
||||
red: 0.8318802,
|
||||
green: 0.8318715,
|
||||
blue: 0.8090188,
|
||||
red: 0.769,
|
||||
green: 0.722,
|
||||
blue: 0.831,
|
||||
alpha: 0.2,
|
||||
),
|
||||
on: (
|
||||
red: 0.8318802,
|
||||
green: 0.8318715,
|
||||
blue: 0.8090188,
|
||||
red: 0.941,
|
||||
green: 0.918,
|
||||
blue: 0.973,
|
||||
alpha: 1.0,
|
||||
),
|
||||
disabled: (
|
||||
red: 0.28282174,
|
||||
green: 0.19933021,
|
||||
blue: 0.36183798,
|
||||
red: 0.239,
|
||||
green: 0.141,
|
||||
blue: 0.329,
|
||||
alpha: 0.5,
|
||||
),
|
||||
on_disabled: (
|
||||
red: 0.8318802,
|
||||
green: 0.8318715,
|
||||
blue: 0.8090188,
|
||||
red: 0.941,
|
||||
green: 0.918,
|
||||
blue: 0.973,
|
||||
alpha: 0.65,
|
||||
),
|
||||
border: (
|
||||
red: 0.7874787,
|
||||
green: 0.6994349,
|
||||
blue: 0.8914889,
|
||||
red: 0.353,
|
||||
green: 0.220,
|
||||
blue: 0.459,
|
||||
alpha: 1.0,
|
||||
),
|
||||
disabled_border: (
|
||||
red: 0.7874787,
|
||||
green: 0.6994349,
|
||||
blue: 0.8914889,
|
||||
red: 0.353,
|
||||
green: 0.220,
|
||||
blue: 0.459,
|
||||
alpha: 0.5,
|
||||
),
|
||||
),
|
||||
divider: (
|
||||
red: 0.32676017,
|
||||
green: 0.2608749,
|
||||
blue: 0.38187551,
|
||||
red: 0.149,
|
||||
green: 0.082,
|
||||
blue: 0.216,
|
||||
alpha: 1.0,
|
||||
),
|
||||
on: (
|
||||
red: 0.75536937,
|
||||
green: 0.7553548,
|
||||
blue: 0.73290694,
|
||||
red: 0.941,
|
||||
green: 0.918,
|
||||
blue: 0.973,
|
||||
alpha: 1.0,
|
||||
),
|
||||
small_widget: (
|
||||
red: 0.23257035,
|
||||
green: 0.22102591,
|
||||
blue: 0.24228081,
|
||||
red: 0.443,
|
||||
green: 0.400,
|
||||
blue: 0.525,
|
||||
alpha: 0.25,
|
||||
),
|
||||
)
|
||||
@@ -1,74 +1,74 @@
|
||||
(
|
||||
base: (
|
||||
red: 0.6509804,
|
||||
green: 0.8901961,
|
||||
blue: 0.6313726,
|
||||
red: 0.604,
|
||||
green: 0.859,
|
||||
blue: 0.659,
|
||||
alpha: 1.0,
|
||||
),
|
||||
hover: (
|
||||
red: 0.60640574,
|
||||
green: 0.7815211,
|
||||
blue: 0.608765,
|
||||
red: 0.544,
|
||||
green: 0.773,
|
||||
blue: 0.593,
|
||||
alpha: 1.0,
|
||||
),
|
||||
pressed: (
|
||||
red: 0.38456568,
|
||||
green: 0.46464506,
|
||||
blue: 0.40839565,
|
||||
red: 0.353,
|
||||
green: 0.457,
|
||||
blue: 0.406,
|
||||
alpha: 1.0,
|
||||
),
|
||||
selected: (
|
||||
red: 0.60640574,
|
||||
green: 0.7815211,
|
||||
blue: 0.608765,
|
||||
red: 0.544,
|
||||
green: 0.773,
|
||||
blue: 0.593,
|
||||
alpha: 1.0,
|
||||
),
|
||||
selected_text: (
|
||||
red: 0.90588236,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.604,
|
||||
green: 0.859,
|
||||
blue: 0.659,
|
||||
alpha: 1.0,
|
||||
),
|
||||
focus: (
|
||||
red: 0.90588236,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.604,
|
||||
green: 0.859,
|
||||
blue: 0.659,
|
||||
alpha: 1.0,
|
||||
),
|
||||
divider: (
|
||||
red: 0.0,
|
||||
green: 0.0,
|
||||
blue: 0.000000000000000000000000000000000000000000055,
|
||||
red: 0.102,
|
||||
green: 0.055,
|
||||
blue: 0.153,
|
||||
alpha: 1.0,
|
||||
),
|
||||
on: (
|
||||
red: 0.0,
|
||||
green: 0.0,
|
||||
blue: 0.000000000000000000000000000000000000000000055,
|
||||
red: 0.102,
|
||||
green: 0.055,
|
||||
blue: 0.153,
|
||||
alpha: 1.0,
|
||||
),
|
||||
disabled: (
|
||||
red: 0.6509804,
|
||||
green: 0.8901961,
|
||||
blue: 0.6313726,
|
||||
alpha: 1.0,
|
||||
red: 0.604,
|
||||
green: 0.859,
|
||||
blue: 0.659,
|
||||
alpha: 0.5,
|
||||
),
|
||||
on_disabled: (
|
||||
red: 0.3254902,
|
||||
green: 0.44509804,
|
||||
blue: 0.3156863,
|
||||
red: 0.353,
|
||||
green: 0.457,
|
||||
blue: 0.406,
|
||||
alpha: 1.0,
|
||||
),
|
||||
border: (
|
||||
red: 0.6509804,
|
||||
green: 0.8901961,
|
||||
blue: 0.6313726,
|
||||
red: 0.604,
|
||||
green: 0.859,
|
||||
blue: 0.659,
|
||||
alpha: 1.0,
|
||||
),
|
||||
disabled_border: (
|
||||
red: 0.6509804,
|
||||
green: 0.8901961,
|
||||
blue: 0.6313726,
|
||||
red: 0.604,
|
||||
green: 0.859,
|
||||
blue: 0.659,
|
||||
alpha: 0.5,
|
||||
),
|
||||
)
|
||||
@@ -1,74 +1,74 @@
|
||||
(
|
||||
base: (
|
||||
red: 0.9764706,
|
||||
green: 0.8862745,
|
||||
blue: 0.6862745,
|
||||
red: 0.910,
|
||||
green: 0.784,
|
||||
blue: 0.478,
|
||||
alpha: 1.0,
|
||||
),
|
||||
hover: (
|
||||
red: 0.8667979,
|
||||
green: 0.7783838,
|
||||
blue: 0.6526866,
|
||||
red: 0.819,
|
||||
green: 0.706,
|
||||
blue: 0.430,
|
||||
alpha: 1.0,
|
||||
),
|
||||
pressed: (
|
||||
red: 0.54731077,
|
||||
green: 0.46268427,
|
||||
blue: 0.43584663,
|
||||
red: 0.506,
|
||||
green: 0.420,
|
||||
blue: 0.316,
|
||||
alpha: 1.0,
|
||||
),
|
||||
selected: (
|
||||
red: 0.8667979,
|
||||
green: 0.7783838,
|
||||
blue: 0.6526866,
|
||||
red: 0.819,
|
||||
green: 0.706,
|
||||
blue: 0.430,
|
||||
alpha: 1.0,
|
||||
),
|
||||
selected_text: (
|
||||
red: 0.90588236,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.910,
|
||||
green: 0.784,
|
||||
blue: 0.478,
|
||||
alpha: 1.0,
|
||||
),
|
||||
focus: (
|
||||
red: 0.90588236,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.910,
|
||||
green: 0.784,
|
||||
blue: 0.478,
|
||||
alpha: 1.0,
|
||||
),
|
||||
divider: (
|
||||
red: 0.0,
|
||||
green: 0.0,
|
||||
blue: 0.000000000000000000000000000000000000000000055,
|
||||
red: 0.102,
|
||||
green: 0.055,
|
||||
blue: 0.153,
|
||||
alpha: 1.0,
|
||||
),
|
||||
on: (
|
||||
red: 0.0,
|
||||
green: 0.0,
|
||||
blue: 0.000000000000000000000000000000000000000000055,
|
||||
red: 0.102,
|
||||
green: 0.055,
|
||||
blue: 0.153,
|
||||
alpha: 1.0,
|
||||
),
|
||||
disabled: (
|
||||
red: 0.9764706,
|
||||
green: 0.8862745,
|
||||
blue: 0.6862745,
|
||||
alpha: 1.0,
|
||||
red: 0.910,
|
||||
green: 0.784,
|
||||
blue: 0.478,
|
||||
alpha: 0.5,
|
||||
),
|
||||
on_disabled: (
|
||||
red: 0.4882353,
|
||||
green: 0.44313726,
|
||||
blue: 0.34313726,
|
||||
red: 0.506,
|
||||
green: 0.420,
|
||||
blue: 0.316,
|
||||
alpha: 1.0,
|
||||
),
|
||||
border: (
|
||||
red: 0.9764706,
|
||||
green: 0.8862745,
|
||||
blue: 0.6862745,
|
||||
red: 0.910,
|
||||
green: 0.784,
|
||||
blue: 0.478,
|
||||
alpha: 1.0,
|
||||
),
|
||||
disabled_border: (
|
||||
red: 0.9764706,
|
||||
green: 0.8862745,
|
||||
blue: 0.6862745,
|
||||
red: 0.910,
|
||||
green: 0.784,
|
||||
blue: 0.478,
|
||||
alpha: 0.5,
|
||||
),
|
||||
)
|
||||
@@ -1,74 +1,74 @@
|
||||
(
|
||||
base: (
|
||||
red: 0.9058823,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.541,
|
||||
green: 0.361,
|
||||
blue: 0.722,
|
||||
alpha: 1.0,
|
||||
),
|
||||
hover: (
|
||||
red: 0.7988549,
|
||||
green: 0.5659659,
|
||||
blue: 0.8900906,
|
||||
red: 0.461,
|
||||
green: 0.301,
|
||||
blue: 0.642,
|
||||
alpha: 1.0,
|
||||
),
|
||||
pressed: (
|
||||
red: 0.81436175,
|
||||
green: 0.6745583,
|
||||
blue: 0.91372323,
|
||||
red: 0.381,
|
||||
green: 0.241,
|
||||
blue: 0.562,
|
||||
alpha: 1.0,
|
||||
),
|
||||
selected: (
|
||||
red: 0.7988549,
|
||||
green: 0.5659659,
|
||||
blue: 0.8900906,
|
||||
red: 0.461,
|
||||
green: 0.301,
|
||||
blue: 0.642,
|
||||
alpha: 1.0,
|
||||
),
|
||||
selected_text: (
|
||||
red: 0.9058823,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.541,
|
||||
green: 0.361,
|
||||
blue: 0.722,
|
||||
alpha: 1.0,
|
||||
),
|
||||
focus: (
|
||||
red: 0.9058823,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.541,
|
||||
green: 0.361,
|
||||
blue: 0.722,
|
||||
alpha: 1.0,
|
||||
),
|
||||
divider: (
|
||||
red: 0.9999203,
|
||||
green: 0.99998146,
|
||||
blue: 1.0,
|
||||
red: 0.953,
|
||||
green: 0.929,
|
||||
blue: 0.973,
|
||||
alpha: 1.0,
|
||||
),
|
||||
on: (
|
||||
red: 0.9999203,
|
||||
green: 0.99998146,
|
||||
blue: 1.0,
|
||||
red: 0.953,
|
||||
green: 0.929,
|
||||
blue: 0.973,
|
||||
alpha: 1.0,
|
||||
),
|
||||
disabled: (
|
||||
red: 0.9058823,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.541,
|
||||
green: 0.361,
|
||||
blue: 0.722,
|
||||
alpha: 1.0,
|
||||
),
|
||||
on_disabled: (
|
||||
red: 0.9529013,
|
||||
green: 0.8058731,
|
||||
blue: 0.99803925,
|
||||
red: 0.271,
|
||||
green: 0.181,
|
||||
blue: 0.361,
|
||||
alpha: 1.0,
|
||||
),
|
||||
border: (
|
||||
red: 0.9058823,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.541,
|
||||
green: 0.361,
|
||||
blue: 0.722,
|
||||
alpha: 1.0,
|
||||
),
|
||||
disabled_border: (
|
||||
red: 0.9058823,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.541,
|
||||
green: 0.361,
|
||||
blue: 0.722,
|
||||
alpha: 0.5,
|
||||
),
|
||||
)
|
||||
@@ -1,100 +1,100 @@
|
||||
(
|
||||
base: (
|
||||
red: 0.20392156,
|
||||
green: 0.109803915,
|
||||
blue: 0.2901961,
|
||||
red: 0.953,
|
||||
green: 0.929,
|
||||
blue: 0.973,
|
||||
alpha: 1.0,
|
||||
),
|
||||
component: (
|
||||
base: (
|
||||
red: 0.28618598,
|
||||
green: 0.19189146,
|
||||
blue: 0.3797182,
|
||||
red: 0.867,
|
||||
green: 0.831,
|
||||
blue: 0.910,
|
||||
alpha: 1.0,
|
||||
),
|
||||
hover: (
|
||||
red: 0.25756738,
|
||||
green: 0.17270231,
|
||||
blue: 0.3417464,
|
||||
red: 0.816,
|
||||
green: 0.776,
|
||||
blue: 0.871,
|
||||
alpha: 1.0,
|
||||
),
|
||||
pressed: (
|
||||
red: 0.22894879,
|
||||
green: 0.15351318,
|
||||
blue: 0.30377457,
|
||||
red: 0.769,
|
||||
green: 0.722,
|
||||
blue: 0.831,
|
||||
alpha: 1.0,
|
||||
),
|
||||
selected: (
|
||||
red: 0.25756738,
|
||||
green: 0.17270231,
|
||||
blue: 0.3417464,
|
||||
red: 0.816,
|
||||
green: 0.776,
|
||||
blue: 0.871,
|
||||
alpha: 1.0,
|
||||
),
|
||||
selected_text: (
|
||||
red: 0.9058823,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.541,
|
||||
green: 0.361,
|
||||
blue: 0.722,
|
||||
alpha: 1.0,
|
||||
),
|
||||
focus: (
|
||||
red: 0.9058823,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.541,
|
||||
green: 0.361,
|
||||
blue: 0.722,
|
||||
alpha: 1.0,
|
||||
),
|
||||
divider: (
|
||||
red: 0.8318751,
|
||||
green: 0.8318648,
|
||||
blue: 0.80908096,
|
||||
red: 0.149,
|
||||
green: 0.082,
|
||||
blue: 0.216,
|
||||
alpha: 0.2,
|
||||
),
|
||||
on: (
|
||||
red: 0.8318751,
|
||||
green: 0.8318648,
|
||||
blue: 0.80908096,
|
||||
red: 0.149,
|
||||
green: 0.082,
|
||||
blue: 0.216,
|
||||
alpha: 1.0,
|
||||
),
|
||||
disabled: (
|
||||
red: 0.28618598,
|
||||
green: 0.19189146,
|
||||
blue: 0.3797182,
|
||||
red: 0.867,
|
||||
green: 0.831,
|
||||
blue: 0.910,
|
||||
alpha: 0.5,
|
||||
),
|
||||
on_disabled: (
|
||||
red: 0.8318751,
|
||||
green: 0.8318648,
|
||||
blue: 0.80908096,
|
||||
red: 0.149,
|
||||
green: 0.082,
|
||||
blue: 0.216,
|
||||
alpha: 0.65,
|
||||
),
|
||||
border: (
|
||||
red: 0.072988935,
|
||||
green: 0.079405405,
|
||||
blue: 0.14595589,
|
||||
red: 0.541,
|
||||
green: 0.482,
|
||||
blue: 0.627,
|
||||
alpha: 1.0,
|
||||
),
|
||||
disabled_border: (
|
||||
red: 0.072988935,
|
||||
green: 0.079405405,
|
||||
blue: 0.14595589,
|
||||
red: 0.541,
|
||||
green: 0.482,
|
||||
blue: 0.627,
|
||||
alpha: 0.5,
|
||||
),
|
||||
),
|
||||
divider: (
|
||||
red: 0.3609102,
|
||||
green: 0.285616,
|
||||
blue: 0.42522332,
|
||||
red: 0.769,
|
||||
green: 0.722,
|
||||
blue: 0.831,
|
||||
alpha: 1.0,
|
||||
),
|
||||
on: (
|
||||
red: 0.98886484,
|
||||
green: 0.98886436,
|
||||
blue: 0.9653322,
|
||||
red: 0.149,
|
||||
green: 0.082,
|
||||
blue: 0.216,
|
||||
alpha: 1.0,
|
||||
),
|
||||
small_widget: (
|
||||
red: 0.20783836,
|
||||
green: 0.20930338,
|
||||
blue: 0.23179808,
|
||||
red: 0.541,
|
||||
green: 0.482,
|
||||
blue: 0.627,
|
||||
alpha: 0.25,
|
||||
),
|
||||
)
|
||||
@@ -1,74 +1,74 @@
|
||||
(
|
||||
base: (
|
||||
red: 0.47058824,
|
||||
green: 0.16078432,
|
||||
blue: 0.18039216,
|
||||
red: 0.788,
|
||||
green: 0.227,
|
||||
blue: 0.353,
|
||||
alpha: 1.0,
|
||||
),
|
||||
hover: (
|
||||
red: 0.45061958,
|
||||
green: 0.20518154,
|
||||
blue: 0.23754153,
|
||||
red: 0.698,
|
||||
green: 0.187,
|
||||
blue: 0.303,
|
||||
alpha: 1.0,
|
||||
),
|
||||
pressed: (
|
||||
red: 0.59671474,
|
||||
green: 0.44906804,
|
||||
blue: 0.5058801,
|
||||
red: 0.588,
|
||||
green: 0.147,
|
||||
blue: 0.253,
|
||||
alpha: 1.0,
|
||||
),
|
||||
selected: (
|
||||
red: 0.45061958,
|
||||
green: 0.20518154,
|
||||
blue: 0.23754153,
|
||||
red: 0.698,
|
||||
green: 0.187,
|
||||
blue: 0.303,
|
||||
alpha: 1.0,
|
||||
),
|
||||
selected_text: (
|
||||
red: 0.9058823,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.541,
|
||||
green: 0.361,
|
||||
blue: 0.722,
|
||||
alpha: 1.0,
|
||||
),
|
||||
focus: (
|
||||
red: 0.9058823,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.541,
|
||||
green: 0.361,
|
||||
blue: 0.722,
|
||||
alpha: 1.0,
|
||||
),
|
||||
divider: (
|
||||
red: 0.9999203,
|
||||
green: 0.99998146,
|
||||
blue: 1.0,
|
||||
red: 0.953,
|
||||
green: 0.929,
|
||||
blue: 0.973,
|
||||
alpha: 1.0,
|
||||
),
|
||||
on: (
|
||||
red: 0.9999203,
|
||||
green: 0.99998146,
|
||||
blue: 1.0,
|
||||
red: 0.953,
|
||||
green: 0.929,
|
||||
blue: 0.973,
|
||||
alpha: 1.0,
|
||||
),
|
||||
disabled: (
|
||||
red: 0.47058824,
|
||||
green: 0.16078432,
|
||||
blue: 0.18039216,
|
||||
red: 0.788,
|
||||
green: 0.227,
|
||||
blue: 0.353,
|
||||
alpha: 1.0,
|
||||
),
|
||||
on_disabled: (
|
||||
red: 0.7352543,
|
||||
green: 0.5803829,
|
||||
blue: 0.5901961,
|
||||
red: 0.394,
|
||||
green: 0.114,
|
||||
blue: 0.177,
|
||||
alpha: 1.0,
|
||||
),
|
||||
border: (
|
||||
red: 0.47058824,
|
||||
green: 0.16078432,
|
||||
blue: 0.18039216,
|
||||
red: 0.788,
|
||||
green: 0.227,
|
||||
blue: 0.353,
|
||||
alpha: 1.0,
|
||||
),
|
||||
disabled_border: (
|
||||
red: 0.47058824,
|
||||
green: 0.16078432,
|
||||
blue: 0.18039216,
|
||||
red: 0.788,
|
||||
green: 0.227,
|
||||
blue: 0.353,
|
||||
alpha: 0.5,
|
||||
),
|
||||
)
|
||||
@@ -1 +1 @@
|
||||
"cosmic-light"
|
||||
"Violet-Chaton Light"
|
||||
@@ -1,100 +1,100 @@
|
||||
(
|
||||
base: (
|
||||
red: 0.21960787,
|
||||
green: 0.13725492,
|
||||
blue: 0.29411766,
|
||||
red: 0.922,
|
||||
green: 0.894,
|
||||
blue: 0.949,
|
||||
alpha: 1.0,
|
||||
),
|
||||
component: (
|
||||
base: (
|
||||
red: 0.28282174,
|
||||
green: 0.19933021,
|
||||
blue: 0.36183798,
|
||||
red: 0.867,
|
||||
green: 0.831,
|
||||
blue: 0.910,
|
||||
alpha: 1.0,
|
||||
),
|
||||
hover: (
|
||||
red: 0.25453955,
|
||||
green: 0.17939718,
|
||||
blue: 0.32565418,
|
||||
red: 0.816,
|
||||
green: 0.776,
|
||||
blue: 0.871,
|
||||
alpha: 1.0,
|
||||
),
|
||||
pressed: (
|
||||
red: 0.2262574,
|
||||
green: 0.15946417,
|
||||
blue: 0.2894704,
|
||||
red: 0.769,
|
||||
green: 0.722,
|
||||
blue: 0.831,
|
||||
alpha: 1.0,
|
||||
),
|
||||
selected: (
|
||||
red: 0.25453955,
|
||||
green: 0.17939718,
|
||||
blue: 0.32565418,
|
||||
red: 0.816,
|
||||
green: 0.776,
|
||||
blue: 0.871,
|
||||
alpha: 1.0,
|
||||
),
|
||||
selected_text: (
|
||||
red: 0.9058823,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.541,
|
||||
green: 0.361,
|
||||
blue: 0.722,
|
||||
alpha: 1.0,
|
||||
),
|
||||
focus: (
|
||||
red: 0.9058823,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.541,
|
||||
green: 0.361,
|
||||
blue: 0.722,
|
||||
alpha: 1.0,
|
||||
),
|
||||
divider: (
|
||||
red: 0.8318751,
|
||||
green: 0.8318648,
|
||||
blue: 0.80908096,
|
||||
red: 0.149,
|
||||
green: 0.082,
|
||||
blue: 0.216,
|
||||
alpha: 0.2,
|
||||
),
|
||||
on: (
|
||||
red: 0.8318751,
|
||||
green: 0.8318648,
|
||||
blue: 0.80908096,
|
||||
red: 0.149,
|
||||
green: 0.082,
|
||||
blue: 0.216,
|
||||
alpha: 1.0,
|
||||
),
|
||||
disabled: (
|
||||
red: 0.28282174,
|
||||
green: 0.19933021,
|
||||
blue: 0.36183798,
|
||||
red: 0.867,
|
||||
green: 0.831,
|
||||
blue: 0.910,
|
||||
alpha: 0.5,
|
||||
),
|
||||
on_disabled: (
|
||||
red: 0.8318751,
|
||||
green: 0.8318648,
|
||||
blue: 0.80908096,
|
||||
red: 0.149,
|
||||
green: 0.082,
|
||||
blue: 0.216,
|
||||
alpha: 0.65,
|
||||
),
|
||||
border: (
|
||||
red: 0.072988935,
|
||||
green: 0.079405405,
|
||||
blue: 0.14595589,
|
||||
red: 0.541,
|
||||
green: 0.482,
|
||||
blue: 0.627,
|
||||
alpha: 1.0,
|
||||
),
|
||||
disabled_border: (
|
||||
red: 0.072988935,
|
||||
green: 0.079405405,
|
||||
blue: 0.14595589,
|
||||
red: 0.541,
|
||||
green: 0.482,
|
||||
blue: 0.627,
|
||||
alpha: 0.5,
|
||||
),
|
||||
),
|
||||
divider: (
|
||||
red: 0.32675916,
|
||||
green: 0.26087362,
|
||||
blue: 0.38188773,
|
||||
red: 0.769,
|
||||
green: 0.722,
|
||||
blue: 0.831,
|
||||
alpha: 1.0,
|
||||
),
|
||||
on: (
|
||||
red: 0.7553642,
|
||||
green: 0.7553483,
|
||||
blue: 0.732968,
|
||||
red: 0.239,
|
||||
green: 0.141,
|
||||
blue: 0.329,
|
||||
alpha: 1.0,
|
||||
),
|
||||
small_widget: (
|
||||
red: 0.22808892,
|
||||
green: 0.22971416,
|
||||
blue: 0.25254303,
|
||||
red: 0.541,
|
||||
green: 0.482,
|
||||
blue: 0.627,
|
||||
alpha: 0.25,
|
||||
),
|
||||
)
|
||||
@@ -1,74 +1,74 @@
|
||||
(
|
||||
base: (
|
||||
red: 0.09411765,
|
||||
green: 0.33333334,
|
||||
blue: 0.16078432,
|
||||
red: 0.239,
|
||||
green: 0.620,
|
||||
blue: 0.408,
|
||||
alpha: 1.0,
|
||||
),
|
||||
hover: (
|
||||
red: 0.14944312,
|
||||
green: 0.34322074,
|
||||
blue: 0.22185525,
|
||||
red: 0.199,
|
||||
green: 0.540,
|
||||
blue: 0.348,
|
||||
alpha: 1.0,
|
||||
),
|
||||
pressed: (
|
||||
red: 0.40847942,
|
||||
green: 0.5353426,
|
||||
blue: 0.4960762,
|
||||
red: 0.159,
|
||||
green: 0.440,
|
||||
blue: 0.288,
|
||||
alpha: 1.0,
|
||||
),
|
||||
selected: (
|
||||
red: 0.14944312,
|
||||
green: 0.34322074,
|
||||
blue: 0.22185525,
|
||||
red: 0.199,
|
||||
green: 0.540,
|
||||
blue: 0.348,
|
||||
alpha: 1.0,
|
||||
),
|
||||
selected_text: (
|
||||
red: 0.9058823,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.541,
|
||||
green: 0.361,
|
||||
blue: 0.722,
|
||||
alpha: 1.0,
|
||||
),
|
||||
focus: (
|
||||
red: 0.9058823,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.541,
|
||||
green: 0.361,
|
||||
blue: 0.722,
|
||||
alpha: 1.0,
|
||||
),
|
||||
divider: (
|
||||
red: 0.9999203,
|
||||
green: 0.99998146,
|
||||
blue: 1.0,
|
||||
red: 0.953,
|
||||
green: 0.929,
|
||||
blue: 0.973,
|
||||
alpha: 1.0,
|
||||
),
|
||||
on: (
|
||||
red: 0.9999203,
|
||||
green: 0.99998146,
|
||||
blue: 1.0,
|
||||
red: 0.953,
|
||||
green: 0.929,
|
||||
blue: 0.973,
|
||||
alpha: 1.0,
|
||||
),
|
||||
disabled: (
|
||||
red: 0.09411765,
|
||||
green: 0.33333334,
|
||||
blue: 0.16078432,
|
||||
red: 0.239,
|
||||
green: 0.620,
|
||||
blue: 0.408,
|
||||
alpha: 1.0,
|
||||
),
|
||||
on_disabled: (
|
||||
red: 0.547019,
|
||||
green: 0.6666574,
|
||||
blue: 0.5803922,
|
||||
red: 0.120,
|
||||
green: 0.310,
|
||||
blue: 0.204,
|
||||
alpha: 1.0,
|
||||
),
|
||||
border: (
|
||||
red: 0.09411765,
|
||||
green: 0.33333334,
|
||||
blue: 0.16078432,
|
||||
red: 0.239,
|
||||
green: 0.620,
|
||||
blue: 0.408,
|
||||
alpha: 1.0,
|
||||
),
|
||||
disabled_border: (
|
||||
red: 0.09411765,
|
||||
green: 0.33333334,
|
||||
blue: 0.16078432,
|
||||
red: 0.239,
|
||||
green: 0.620,
|
||||
blue: 0.408,
|
||||
alpha: 0.5,
|
||||
),
|
||||
)
|
||||
@@ -1,74 +1,74 @@
|
||||
(
|
||||
base: (
|
||||
red: 0.3254902,
|
||||
green: 0.28235295,
|
||||
blue: 0.0,
|
||||
red: 0.722,
|
||||
green: 0.596,
|
||||
blue: 0.251,
|
||||
alpha: 1.0,
|
||||
),
|
||||
hover: (
|
||||
red: 0.33454114,
|
||||
green: 0.30243644,
|
||||
blue: 0.093227796,
|
||||
red: 0.642,
|
||||
green: 0.526,
|
||||
blue: 0.211,
|
||||
alpha: 1.0,
|
||||
),
|
||||
pressed: (
|
||||
red: 0.5241657,
|
||||
green: 0.50985235,
|
||||
blue: 0.41568404,
|
||||
red: 0.542,
|
||||
green: 0.436,
|
||||
blue: 0.171,
|
||||
alpha: 1.0,
|
||||
),
|
||||
selected: (
|
||||
red: 0.33454114,
|
||||
green: 0.30243644,
|
||||
blue: 0.093227796,
|
||||
red: 0.642,
|
||||
green: 0.526,
|
||||
blue: 0.211,
|
||||
alpha: 1.0,
|
||||
),
|
||||
selected_text: (
|
||||
red: 0.9058823,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.541,
|
||||
green: 0.361,
|
||||
blue: 0.722,
|
||||
alpha: 1.0,
|
||||
),
|
||||
focus: (
|
||||
red: 0.9058823,
|
||||
green: 0.6117647,
|
||||
blue: 0.99607843,
|
||||
red: 0.541,
|
||||
green: 0.361,
|
||||
blue: 0.722,
|
||||
alpha: 1.0,
|
||||
),
|
||||
divider: (
|
||||
red: 0.9999203,
|
||||
green: 0.99998146,
|
||||
blue: 1.0,
|
||||
red: 0.149,
|
||||
green: 0.082,
|
||||
blue: 0.216,
|
||||
alpha: 1.0,
|
||||
),
|
||||
on: (
|
||||
red: 0.9999203,
|
||||
green: 0.99998146,
|
||||
blue: 1.0,
|
||||
red: 0.149,
|
||||
green: 0.082,
|
||||
blue: 0.216,
|
||||
alpha: 1.0,
|
||||
),
|
||||
disabled: (
|
||||
red: 0.3254902,
|
||||
green: 0.28235295,
|
||||
blue: 0.0,
|
||||
red: 0.722,
|
||||
green: 0.596,
|
||||
blue: 0.251,
|
||||
alpha: 1.0,
|
||||
),
|
||||
on_disabled: (
|
||||
red: 0.66270524,
|
||||
green: 0.6411672,
|
||||
blue: 0.5,
|
||||
red: 0.361,
|
||||
green: 0.298,
|
||||
blue: 0.126,
|
||||
alpha: 1.0,
|
||||
),
|
||||
border: (
|
||||
red: 0.3254902,
|
||||
green: 0.28235295,
|
||||
blue: 0.0,
|
||||
red: 0.722,
|
||||
green: 0.596,
|
||||
blue: 0.251,
|
||||
alpha: 1.0,
|
||||
),
|
||||
disabled_border: (
|
||||
red: 0.3254902,
|
||||
green: 0.28235295,
|
||||
blue: 0.0,
|
||||
red: 0.722,
|
||||
green: 0.596,
|
||||
blue: 0.251,
|
||||
alpha: 0.5,
|
||||
),
|
||||
)
|
||||
137
INSTALL/themes/palette.sh
Normal file
137
INSTALL/themes/palette.sh
Normal file
@@ -0,0 +1,137 @@
|
||||
#!/usr/bin/env bash
|
||||
# ══════════════════════════════════════════════════════════════════════════════
|
||||
# violet-chaton v2 — palette source de verite
|
||||
#
|
||||
# Inspiration : Mitsuri Kanroji — gradient rose → vert pastel
|
||||
# Identite : univers violet profond, accents chauds/frais, zero emprunt
|
||||
#
|
||||
# Usage :
|
||||
# source palette.sh
|
||||
# echo "$VC_MAGENTA" → #ff4da6
|
||||
# echo "${VC_RGB_MAGENTA}" → 255;77;166
|
||||
# echo "${VC_ANSI_MAGENTA}" → \033[38;2;255;77;166m
|
||||
# ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
# ── Fond (signature violet-chaton) ───────────────────────────────────────────
|
||||
VC_CRUST="#1a0e27" # le plus profond — borders, shadows
|
||||
VC_BASE="#261537" # fond principal
|
||||
VC_MANTLE="#341c4a" # fond secondaire
|
||||
VC_SURFACE0="#3d2454" # elements poses
|
||||
VC_SURFACE1="#493161" # elements hover
|
||||
VC_SURFACE2="#5a3875" # selection, highlight
|
||||
|
||||
# ── Texte (teinte violet — pas du blanc pur) ─────────────────────────────────
|
||||
VC_TEXT="#f0eaf8" # texte principal
|
||||
VC_SUBTEXT1="#c4b8d4" # texte secondaire
|
||||
VC_SUBTEXT0="#9a8fad" # labels, placeholders
|
||||
VC_MUTED="#716686" # desactive, commentaires
|
||||
|
||||
# ── Accents ──────────────────────────────────────────────────────────────────
|
||||
VC_MAGENTA="#ff4da6" # accent primaire — chaud, vif
|
||||
VC_LILAC="#c9a0ff" # accent secondaire — doux, aerien
|
||||
VC_MITSURI="#9adba8" # vert pastel — frais, unique
|
||||
VC_LAVANDE="#a4b4ff" # bleu-violet — info, fonctions
|
||||
VC_CHAMPAGNE="#e8c87a" # or chaud — casse le bicolore
|
||||
|
||||
# ── Semantiques (derivees des accents) ───────────────────────────────────────
|
||||
VC_DANGER="#f25c7a" # rouge vif, teinte violet
|
||||
VC_WARNING="#e8c87a" # = champagne
|
||||
VC_SUCCESS="#9adba8" # = mitsuri green
|
||||
VC_INFO="#a4b4ff" # = lavande
|
||||
|
||||
# ── Gradient signature (cava, barres, transitions) ───────────────────────────
|
||||
# magenta → lilac → lavande → mitsuri
|
||||
VC_GRADIENT_1="$VC_MAGENTA"
|
||||
VC_GRADIENT_2="#e276d4" # magenta → lilac mid
|
||||
VC_GRADIENT_3="$VC_LILAC"
|
||||
VC_GRADIENT_4="#b6a8ff" # lilac → lavande mid
|
||||
VC_GRADIENT_5="$VC_LAVANDE"
|
||||
VC_GRADIENT_6="#9fc8d4" # lavande → mitsuri mid
|
||||
VC_GRADIENT_7="#9adba8" # = mitsuri
|
||||
VC_GRADIENT_8="#82e8a0" # mitsuri bright tip
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════════════
|
||||
# LIGHT — meme univers violet, fonds lavande clairs
|
||||
# Les accents sont legerement assombris pour le contraste sur fond clair
|
||||
# ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
# ── Fond light (lavande — identite violet conservee) ────────────────────────
|
||||
VCL_CRUST="#f8f4fc" # le plus clair — presque blanc violet
|
||||
VCL_BASE="#f3edf8" # fond principal
|
||||
VCL_MANTLE="#ebe4f2" # fond secondaire
|
||||
VCL_SURFACE0="#ddd4e8" # elements poses
|
||||
VCL_SURFACE1="#d0c6de" # elements hover
|
||||
VCL_SURFACE2="#c4b8d4" # selection, highlight
|
||||
|
||||
# ── Texte light (violet fonce — inversion du dark) ──────────────────────────
|
||||
VCL_TEXT="#261537" # texte principal (= base dark)
|
||||
VCL_SUBTEXT1="#3d2454" # texte secondaire
|
||||
VCL_SUBTEXT0="#5a3875" # labels
|
||||
VCL_MUTED="#8a7ba0" # desactive, commentaires
|
||||
|
||||
# ── Accents light (assombris pour contraste WCAG AA sur fond clair) ─────────
|
||||
VCL_MAGENTA="#d4348a" # accent primaire
|
||||
VCL_LILAC="#8a5cb8" # accent secondaire
|
||||
VCL_MITSURI="#3d9e68" # vert mitsuri assombri
|
||||
VCL_LAVANDE="#5a6ad0" # bleu-violet assombri
|
||||
VCL_CHAMPAGNE="#b89840" # or chaud assombri
|
||||
|
||||
# ── Semantiques light ──────────────────────────────────────────────────────
|
||||
VCL_DANGER="#c93a5a"
|
||||
VCL_WARNING="#b89840"
|
||||
VCL_SUCCESS="#3d9e68"
|
||||
VCL_INFO="#5a6ad0"
|
||||
|
||||
# ── Font ─────────────────────────────────────────────────────────────────────
|
||||
VC_FONT="Maple Mono NF"
|
||||
VC_FONT_FALLBACK="MapleMono Nerd Font"
|
||||
VC_FONT_SIZE=13
|
||||
|
||||
# ── RGB (pour les contextes qui n'acceptent pas le hex) ──────────────────────
|
||||
_hex2rgb() { printf '%d;%d;%d' "0x${1:1:2}" "0x${1:3:2}" "0x${1:5:2}"; }
|
||||
|
||||
VC_RGB_CRUST=$(_hex2rgb "$VC_CRUST")
|
||||
VC_RGB_BASE=$(_hex2rgb "$VC_BASE")
|
||||
VC_RGB_MANTLE=$(_hex2rgb "$VC_MANTLE")
|
||||
VC_RGB_SURFACE0=$(_hex2rgb "$VC_SURFACE0")
|
||||
VC_RGB_SURFACE1=$(_hex2rgb "$VC_SURFACE1")
|
||||
VC_RGB_SURFACE2=$(_hex2rgb "$VC_SURFACE2")
|
||||
VC_RGB_TEXT=$(_hex2rgb "$VC_TEXT")
|
||||
VC_RGB_SUBTEXT1=$(_hex2rgb "$VC_SUBTEXT1")
|
||||
VC_RGB_SUBTEXT0=$(_hex2rgb "$VC_SUBTEXT0")
|
||||
VC_RGB_MUTED=$(_hex2rgb "$VC_MUTED")
|
||||
VC_RGB_MAGENTA=$(_hex2rgb "$VC_MAGENTA")
|
||||
VC_RGB_LILAC=$(_hex2rgb "$VC_LILAC")
|
||||
VC_RGB_MITSURI=$(_hex2rgb "$VC_MITSURI")
|
||||
VC_RGB_LAVANDE=$(_hex2rgb "$VC_LAVANDE")
|
||||
VC_RGB_CHAMPAGNE=$(_hex2rgb "$VC_CHAMPAGNE")
|
||||
VC_RGB_DANGER=$(_hex2rgb "$VC_DANGER")
|
||||
VC_RGB_WARNING=$(_hex2rgb "$VC_WARNING")
|
||||
VC_RGB_SUCCESS=$(_hex2rgb "$VC_SUCCESS")
|
||||
VC_RGB_INFO=$(_hex2rgb "$VC_INFO")
|
||||
|
||||
# ── ANSI (pour echo -e dans les scripts) ─────────────────────────────────────
|
||||
_hex2ansi() { echo "\033[38;2;$(_hex2rgb "$1")m"; }
|
||||
|
||||
VC_ANSI_CRUST=$(_hex2ansi "$VC_CRUST")
|
||||
VC_ANSI_BASE=$(_hex2ansi "$VC_BASE")
|
||||
VC_ANSI_MANTLE=$(_hex2ansi "$VC_MANTLE")
|
||||
VC_ANSI_SURFACE0=$(_hex2ansi "$VC_SURFACE0")
|
||||
VC_ANSI_SURFACE1=$(_hex2ansi "$VC_SURFACE1")
|
||||
VC_ANSI_SURFACE2=$(_hex2ansi "$VC_SURFACE2")
|
||||
VC_ANSI_TEXT=$(_hex2ansi "$VC_TEXT")
|
||||
VC_ANSI_SUBTEXT1=$(_hex2ansi "$VC_SUBTEXT1")
|
||||
VC_ANSI_SUBTEXT0=$(_hex2ansi "$VC_SUBTEXT0")
|
||||
VC_ANSI_MUTED=$(_hex2ansi "$VC_MUTED")
|
||||
VC_ANSI_MAGENTA=$(_hex2ansi "$VC_MAGENTA")
|
||||
VC_ANSI_LILAC=$(_hex2ansi "$VC_LILAC")
|
||||
VC_ANSI_MITSURI=$(_hex2ansi "$VC_MITSURI")
|
||||
VC_ANSI_LAVANDE=$(_hex2ansi "$VC_LAVANDE")
|
||||
VC_ANSI_CHAMPAGNE=$(_hex2ansi "$VC_CHAMPAGNE")
|
||||
VC_ANSI_DANGER=$(_hex2ansi "$VC_DANGER")
|
||||
VC_ANSI_WARNING=$(_hex2ansi "$VC_WARNING")
|
||||
VC_ANSI_SUCCESS=$(_hex2ansi "$VC_SUCCESS")
|
||||
VC_ANSI_INFO=$(_hex2ansi "$VC_INFO")
|
||||
VC_ANSI_RESET='\033[0m'
|
||||
VC_ANSI_BOLD='\033[1m'
|
||||
VC_ANSI_ITALIC='\033[3m'
|
||||
@@ -1,10 +1,10 @@
|
||||
# violet-chaton — thème atuin
|
||||
# violet-chaton v2 — theme atuin
|
||||
# Les valeurs sont des noms de couleurs CSS (palette crate)
|
||||
|
||||
Base = "white" # texte principal #f8f8f2
|
||||
Important = "hot_pink" # éléments importants #ff79c6
|
||||
Guidance = "slate_gray" # texte d'aide/muted #7f849c
|
||||
Annotation = "orchid" # labels/annotations #e79cfe
|
||||
AlertInfo = "light_cyan" # info #8be9fd
|
||||
AlertWarn = "pale_goldenrod" # avertissement #f9e2af
|
||||
AlertError = "light_pink" # erreur #f38ba8
|
||||
Base = "lavender_blush" # texte principal #f0eaf8
|
||||
Important = "hot_pink" # accent primaire #ff4da6
|
||||
Guidance = "medium_purple" # texte aide/muted #716686
|
||||
Annotation = "plum" # labels/annotations #c9a0ff
|
||||
AlertInfo = "light_steel_blue" # info #a4b4ff
|
||||
AlertWarn = "goldenrod" # warning #e8c87a
|
||||
AlertError = "pale_violet_red" # danger #f25c7a
|
||||
|
||||
@@ -11,12 +11,12 @@
|
||||
<dict>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key> <string>#341c4a</string>
|
||||
<key>foreground</key> <string>#f8f8f2</string>
|
||||
<key>caret</key> <string>#ff79c6</string>
|
||||
<key>background</key> <string>#261537</string>
|
||||
<key>foreground</key> <string>#f0eaf8</string>
|
||||
<key>caret</key> <string>#ff4da6</string>
|
||||
<key>lineHighlight</key><string>#3d2454</string>
|
||||
<key>selection</key> <string>#3d245480</string>
|
||||
<key>invisibles</key> <string>#6c7086</string>
|
||||
<key>selection</key> <string>#5a387580</string>
|
||||
<key>invisibles</key> <string>#716686</string>
|
||||
</dict>
|
||||
</dict>
|
||||
|
||||
@@ -26,17 +26,17 @@
|
||||
<key>scope</key><string>comment, punctuation.definition.comment</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key><string>#7f849c</string>
|
||||
<key>foreground</key><string>#9a8fad</string>
|
||||
<key>fontStyle</key><string>italic</string>
|
||||
</dict>
|
||||
</dict>
|
||||
|
||||
<!-- Chaînes -->
|
||||
<!-- Chaines -->
|
||||
<dict>
|
||||
<key>name</key><string>String</string>
|
||||
<key>scope</key><string>string, string.quoted, string.template</string>
|
||||
<key>settings</key>
|
||||
<dict><key>foreground</key><string>#e79cfe</string></dict>
|
||||
<dict><key>foreground</key><string>#9adba8</string></dict>
|
||||
</dict>
|
||||
|
||||
<!-- Nombres -->
|
||||
@@ -44,23 +44,23 @@
|
||||
<key>name</key><string>Number</string>
|
||||
<key>scope</key><string>constant.numeric</string>
|
||||
<key>settings</key>
|
||||
<dict><key>foreground</key><string>#a6e3a1</string></dict>
|
||||
<dict><key>foreground</key><string>#e8c87a</string></dict>
|
||||
</dict>
|
||||
|
||||
<!-- Mots-clés -->
|
||||
<!-- Mots-cles -->
|
||||
<dict>
|
||||
<key>name</key><string>Keyword</string>
|
||||
<key>scope</key><string>keyword, keyword.control, storage, storage.type, storage.modifier</string>
|
||||
<key>settings</key>
|
||||
<dict><key>foreground</key><string>#ff79c6</string></dict>
|
||||
<dict><key>foreground</key><string>#ff4da6</string></dict>
|
||||
</dict>
|
||||
|
||||
<!-- Opérateurs -->
|
||||
<!-- Operateurs -->
|
||||
<dict>
|
||||
<key>name</key><string>Operator</string>
|
||||
<key>scope</key><string>keyword.operator</string>
|
||||
<key>settings</key>
|
||||
<dict><key>foreground</key><string>#ff79c6</string></dict>
|
||||
<dict><key>foreground</key><string>#ff4da6</string></dict>
|
||||
</dict>
|
||||
|
||||
<!-- Fonctions -->
|
||||
@@ -68,7 +68,7 @@
|
||||
<key>name</key><string>Function</string>
|
||||
<key>scope</key><string>entity.name.function, meta.function-call, support.function</string>
|
||||
<key>settings</key>
|
||||
<dict><key>foreground</key><string>#8be9fd</string></dict>
|
||||
<dict><key>foreground</key><string>#a4b4ff</string></dict>
|
||||
</dict>
|
||||
|
||||
<!-- Types / Classes -->
|
||||
@@ -76,15 +76,15 @@
|
||||
<key>name</key><string>Type</string>
|
||||
<key>scope</key><string>entity.name.class, entity.name.type, support.class, support.type</string>
|
||||
<key>settings</key>
|
||||
<dict><key>foreground</key><string>#e79cfe</string></dict>
|
||||
<dict><key>foreground</key><string>#c9a0ff</string></dict>
|
||||
</dict>
|
||||
|
||||
<!-- Constantes / Booléens -->
|
||||
<!-- Constantes / Booleens -->
|
||||
<dict>
|
||||
<key>name</key><string>Constant</string>
|
||||
<key>scope</key><string>constant, constant.language, variable.language</string>
|
||||
<key>settings</key>
|
||||
<dict><key>foreground</key><string>#8be9fd</string></dict>
|
||||
<dict><key>foreground</key><string>#a4b4ff</string></dict>
|
||||
</dict>
|
||||
|
||||
<!-- Variables -->
|
||||
@@ -92,7 +92,7 @@
|
||||
<key>name</key><string>Variable</string>
|
||||
<key>scope</key><string>variable, variable.other</string>
|
||||
<key>settings</key>
|
||||
<dict><key>foreground</key><string>#f8f8f2</string></dict>
|
||||
<dict><key>foreground</key><string>#f0eaf8</string></dict>
|
||||
</dict>
|
||||
|
||||
<!-- Tags HTML/XML -->
|
||||
@@ -100,7 +100,7 @@
|
||||
<key>name</key><string>Tag</string>
|
||||
<key>scope</key><string>entity.name.tag</string>
|
||||
<key>settings</key>
|
||||
<dict><key>foreground</key><string>#ff79c6</string></dict>
|
||||
<dict><key>foreground</key><string>#ff4da6</string></dict>
|
||||
</dict>
|
||||
|
||||
<!-- Attributs -->
|
||||
@@ -108,7 +108,10 @@
|
||||
<key>name</key><string>Attribute</string>
|
||||
<key>scope</key><string>entity.other.attribute-name</string>
|
||||
<key>settings</key>
|
||||
<dict><key>foreground</key><string>#8be9fd</string></dict>
|
||||
<dict>
|
||||
<key>foreground</key><string>#a4b4ff</string>
|
||||
<key>fontStyle</key><string>italic</string>
|
||||
</dict>
|
||||
</dict>
|
||||
|
||||
<!-- Ponctuation -->
|
||||
@@ -116,15 +119,15 @@
|
||||
<key>name</key><string>Punctuation</string>
|
||||
<key>scope</key><string>punctuation</string>
|
||||
<key>settings</key>
|
||||
<dict><key>foreground</key><string>#9399b2</string></dict>
|
||||
<dict><key>foreground</key><string>#9a8fad</string></dict>
|
||||
</dict>
|
||||
|
||||
<!-- CSS propriétés -->
|
||||
<!-- CSS proprietes -->
|
||||
<dict>
|
||||
<key>name</key><string>CSS Property</string>
|
||||
<key>scope</key><string>support.type.property-name.css, support.type.property-name.scss</string>
|
||||
<key>settings</key>
|
||||
<dict><key>foreground</key><string>#8be9fd</string></dict>
|
||||
<dict><key>foreground</key><string>#a4b4ff</string></dict>
|
||||
</dict>
|
||||
|
||||
<!-- CSS valeurs -->
|
||||
@@ -132,7 +135,7 @@
|
||||
<key>name</key><string>CSS Value</string>
|
||||
<key>scope</key><string>support.constant.property-value.css</string>
|
||||
<key>settings</key>
|
||||
<dict><key>foreground</key><string>#e79cfe</string></dict>
|
||||
<dict><key>foreground</key><string>#c9a0ff</string></dict>
|
||||
</dict>
|
||||
|
||||
<!-- SCSS variables -->
|
||||
@@ -140,7 +143,56 @@
|
||||
<key>name</key><string>SCSS Variable</string>
|
||||
<key>scope</key><string>variable.scss, variable.sass</string>
|
||||
<key>settings</key>
|
||||
<dict><key>foreground</key><string>#8be9fd</string></dict>
|
||||
<dict><key>foreground</key><string>#a4b4ff</string></dict>
|
||||
</dict>
|
||||
|
||||
<!-- Regex -->
|
||||
<dict>
|
||||
<key>name</key><string>Regex</string>
|
||||
<key>scope</key><string>string.regexp</string>
|
||||
<key>settings</key>
|
||||
<dict><key>foreground</key><string>#e8c87a</string></dict>
|
||||
</dict>
|
||||
|
||||
<!-- Markdown heading -->
|
||||
<dict>
|
||||
<key>name</key><string>Markdown Heading</string>
|
||||
<key>scope</key><string>markup.heading, entity.name.section</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key><string>#ff4da6</string>
|
||||
<key>fontStyle</key><string>bold</string>
|
||||
</dict>
|
||||
</dict>
|
||||
|
||||
<!-- Markdown bold -->
|
||||
<dict>
|
||||
<key>name</key><string>Markdown Bold</string>
|
||||
<key>scope</key><string>markup.bold</string>
|
||||
<key>settings</key>
|
||||
<dict><key>fontStyle</key><string>bold</string></dict>
|
||||
</dict>
|
||||
|
||||
<!-- Markdown italic -->
|
||||
<dict>
|
||||
<key>name</key><string>Markdown Italic</string>
|
||||
<key>scope</key><string>markup.italic</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key><string>#c9a0ff</string>
|
||||
<key>fontStyle</key><string>italic</string>
|
||||
</dict>
|
||||
</dict>
|
||||
|
||||
<!-- Markdown link -->
|
||||
<dict>
|
||||
<key>name</key><string>Markdown Link</string>
|
||||
<key>scope</key><string>markup.underline.link</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key><string>#a4b4ff</string>
|
||||
<key>fontStyle</key><string>underline</string>
|
||||
</dict>
|
||||
</dict>
|
||||
|
||||
<!-- Invalide -->
|
||||
@@ -149,7 +201,7 @@
|
||||
<key>scope</key><string>invalid</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key><string>#f38ba8</string>
|
||||
<key>foreground</key><string>#f25c7a</string>
|
||||
<key>fontStyle</key><string>bold</string>
|
||||
</dict>
|
||||
</dict>
|
||||
|
||||
@@ -1,75 +1,75 @@
|
||||
# violet-chaton btop theme
|
||||
# Palette : ~/Documents/config/violet-chaton-discord-theme/src/modules/_variables.scss
|
||||
# violet-chaton v2 btop theme
|
||||
# Palette : themes/palette.sh — zero emprunt
|
||||
|
||||
# Main background
|
||||
theme[main_bg]="#261537"
|
||||
|
||||
# Main text color
|
||||
theme[main_fg]="#f8f8f2"
|
||||
theme[main_fg]="#f0eaf8"
|
||||
|
||||
# Title color for boxes
|
||||
theme[title]="#e79cfe"
|
||||
theme[title]="#c9a0ff"
|
||||
|
||||
# Highlight color for keyboard shortcuts
|
||||
theme[hi_fg]="#ff79c6"
|
||||
theme[hi_fg]="#ff4da6"
|
||||
|
||||
# Background color of selected item in processes box
|
||||
theme[selected_bg]="#3d2454"
|
||||
theme[selected_bg]="#5a3875"
|
||||
|
||||
# Foreground color of selected item in processes box
|
||||
theme[selected_fg]="#f8f8f2"
|
||||
theme[selected_fg]="#f0eaf8"
|
||||
|
||||
# Color of inactive/disabled text
|
||||
theme[inactive_fg]="#6c7086"
|
||||
theme[inactive_fg]="#716686"
|
||||
|
||||
# Misc colors for processes box (mini cpu graphs, details, status)
|
||||
theme[proc_misc]="#8be9fd"
|
||||
theme[proc_misc]="#a4b4ff"
|
||||
|
||||
# Box outline colors
|
||||
theme[cpu_box]="#38234b"
|
||||
theme[mem_box]="#38234b"
|
||||
theme[net_box]="#38234b"
|
||||
theme[proc_box]="#38234b"
|
||||
theme[cpu_box]="#3d2454"
|
||||
theme[mem_box]="#3d2454"
|
||||
theme[net_box]="#3d2454"
|
||||
theme[proc_box]="#3d2454"
|
||||
|
||||
# Box divider line
|
||||
theme[div_line]="#341c4a"
|
||||
|
||||
# Temperature graph : cyan (froid) → warning (chaud) → danger (critique)
|
||||
theme[temp_start]="#8be9fd"
|
||||
theme[temp_mid]="#f9e2af"
|
||||
theme[temp_end]="#f38ba8"
|
||||
# Temperature graph : lavande (froid) → champagne (chaud) → danger (critique)
|
||||
theme[temp_start]="#a4b4ff"
|
||||
theme[temp_mid]="#e8c87a"
|
||||
theme[temp_end]="#f25c7a"
|
||||
|
||||
# CPU graph : purple → pink → danger
|
||||
theme[cpu_start]="#e79cfe"
|
||||
theme[cpu_mid]="#ff79c6"
|
||||
theme[cpu_end]="#f38ba8"
|
||||
# CPU graph : lilac → magenta → danger
|
||||
theme[cpu_start]="#c9a0ff"
|
||||
theme[cpu_mid]="#ff4da6"
|
||||
theme[cpu_end]="#f25c7a"
|
||||
|
||||
# Mem/Disk free meter : green → cyan → purple
|
||||
theme[free_start]="#a6e3a1"
|
||||
theme[free_mid]="#8be9fd"
|
||||
theme[free_end]="#e79cfe"
|
||||
# Mem/Disk free meter : mitsuri → lavande → lilac
|
||||
theme[free_start]="#9adba8"
|
||||
theme[free_mid]="#a4b4ff"
|
||||
theme[free_end]="#c9a0ff"
|
||||
|
||||
# Mem/Disk cached meter : purple subtil
|
||||
# Mem/Disk cached meter : surface subtil → lilac
|
||||
theme[cached_start]="#3d2454"
|
||||
theme[cached_mid]="#e79cfe"
|
||||
theme[cached_end]="#e79cfe"
|
||||
theme[cached_mid]="#c9a0ff"
|
||||
theme[cached_end]="#c9a0ff"
|
||||
|
||||
# Mem/Disk available meter : cyan → purple
|
||||
theme[available_start]="#8be9fd"
|
||||
theme[available_mid]="#e79cfe"
|
||||
theme[available_end]="#ff79c6"
|
||||
# Mem/Disk available meter : lavande → lilac → magenta
|
||||
theme[available_start]="#a4b4ff"
|
||||
theme[available_mid]="#c9a0ff"
|
||||
theme[available_end]="#ff4da6"
|
||||
|
||||
# Mem/Disk used meter : purple → pink → danger
|
||||
theme[used_start]="#e79cfe"
|
||||
theme[used_mid]="#ff79c6"
|
||||
theme[used_end]="#f38ba8"
|
||||
# Mem/Disk used meter : lilac → magenta → danger
|
||||
theme[used_start]="#c9a0ff"
|
||||
theme[used_mid]="#ff4da6"
|
||||
theme[used_end]="#f25c7a"
|
||||
|
||||
# Download graph : cyan → purple
|
||||
theme[download_start]="#8be9fd"
|
||||
theme[download_mid]="#e79cfe"
|
||||
theme[download_end]="#ff79c6"
|
||||
# Download graph : lavande → lilac → magenta
|
||||
theme[download_start]="#a4b4ff"
|
||||
theme[download_mid]="#c9a0ff"
|
||||
theme[download_end]="#ff4da6"
|
||||
|
||||
# Upload graph : pink → danger
|
||||
theme[upload_start]="#ff79c6"
|
||||
theme[upload_mid]="#f38ba8"
|
||||
theme[upload_end]="#f9e2af"
|
||||
# Upload graph : magenta → danger → champagne
|
||||
theme[upload_start]="#ff4da6"
|
||||
theme[upload_mid]="#f25c7a"
|
||||
theme[upload_end]="#e8c87a"
|
||||
|
||||
@@ -17,16 +17,16 @@ mono_option = average
|
||||
reverse = 0
|
||||
|
||||
[color]
|
||||
# background commenté = transparent
|
||||
# background commente = transparent
|
||||
gradient = 1
|
||||
gradient_color_1 = '#ff79c6'
|
||||
gradient_color_2 = '#f079d8'
|
||||
gradient_color_3 = '#e079ea'
|
||||
gradient_color_4 = '#e79cfe'
|
||||
gradient_color_5 = '#c0b0fe'
|
||||
gradient_color_6 = '#99c4fe'
|
||||
gradient_color_7 = '#8bd4fe'
|
||||
gradient_color_8 = '#8be9fd'
|
||||
gradient_color_1 = '#ff4da6'
|
||||
gradient_color_2 = '#e276d4'
|
||||
gradient_color_3 = '#c9a0ff'
|
||||
gradient_color_4 = '#b6a8ff'
|
||||
gradient_color_5 = '#a4b4ff'
|
||||
gradient_color_6 = '#9fc8d4'
|
||||
gradient_color_7 = '#9adba8'
|
||||
gradient_color_8 = '#82e8a0'
|
||||
|
||||
[smoothing]
|
||||
monstercat = 1
|
||||
|
||||
128
INSTALL/themes/violet-chaton-gtk-light.css
Normal file
128
INSTALL/themes/violet-chaton-gtk-light.css
Normal file
@@ -0,0 +1,128 @@
|
||||
/* ── violet-chaton v2 GTK Light theme (adw-gtk3 compatible) ──────────────────
|
||||
* Palette : themes/palette.sh — section LIGHT
|
||||
* Meme univers violet, fonds lavande clairs
|
||||
* ─────────────────────────────────────────────────────────────────────────── */
|
||||
|
||||
@define-color window_bg_color rgba(243, 237, 248, 1.00);
|
||||
@define-color window_fg_color rgba(38, 21, 55, 1.00);
|
||||
|
||||
@define-color view_bg_color rgba(248, 244, 252, 1.00);
|
||||
@define-color view_fg_color rgba(61, 36, 84, 1.00);
|
||||
|
||||
@define-color headerbar_bg_color rgba(235, 228, 242, 1.00);
|
||||
@define-color headerbar_fg_color rgba(38, 21, 55, 1.00);
|
||||
@define-color headerbar_border_color_color rgba(196, 184, 212, 1.00);
|
||||
@define-color headerbar_backdrop_color rgba(243, 237, 248, 1.00);
|
||||
|
||||
@define-color sidebar_bg_color rgba(235, 228, 242, 1.00);
|
||||
@define-color sidebar_fg_color rgba(61, 36, 84, 1.00);
|
||||
@define-color sidebar_shade_color rgba(0, 0, 0, 0.06);
|
||||
@define-color sidebar_backdrop_color rgba(221, 212, 232, 1.00);
|
||||
|
||||
@define-color secondary_sidebar_bg_color rgba(221, 212, 232, 1.00);
|
||||
@define-color secondary_sidebar_fg_color rgba(61, 36, 84, 1.00);
|
||||
@define-color secondary_sidebar_shade_color rgba(0, 0, 0, 0.06);
|
||||
@define-color secondary_sidebar_backdrop_color rgba(208, 198, 222, 1.00);
|
||||
|
||||
@define-color card_bg_color rgba(248, 244, 252, 1.00);
|
||||
@define-color card_fg_color rgba(61, 36, 84, 1.00);
|
||||
|
||||
@define-color thumbnail_bg_color rgba(248, 244, 252, 1.00);
|
||||
@define-color thumbnail_fg_color rgba(61, 36, 84, 1.00);
|
||||
|
||||
@define-color dialog_bg_color rgba(243, 237, 248, 1.00);
|
||||
@define-color dialog_fg_color rgba(38, 21, 55, 1.00);
|
||||
|
||||
@define-color popover_bg_color rgba(248, 244, 252, 1.00);
|
||||
@define-color popover_fg_color rgba(61, 36, 84, 1.00);
|
||||
|
||||
@define-color shade_color rgba(0, 0, 0, 0.12);
|
||||
@define-color scrollbar_outline_color rgba(196, 184, 212, 0.50);
|
||||
|
||||
/* Accent = lilac assombri */
|
||||
@define-color accent_color rgba(138, 92, 184, 1.00);
|
||||
@define-color accent_bg_color rgba(138, 92, 184, 1.00);
|
||||
@define-color accent_fg_color rgba(248, 244, 252, 1.00);
|
||||
|
||||
/* Destructive = danger */
|
||||
@define-color destructive_color rgba(201, 58, 90, 1.00);
|
||||
@define-color destructive_bg_color rgba(201, 58, 90, 1.00);
|
||||
@define-color destructive_fg_color rgba(248, 244, 252, 1.00);
|
||||
|
||||
/* Warning = champagne */
|
||||
@define-color warning_color rgba(184, 152, 64, 1.00);
|
||||
@define-color warning_bg_color rgba(184, 152, 64, 1.00);
|
||||
@define-color warning_fg_color rgba(38, 21, 55, 1.00);
|
||||
|
||||
/* Success = mitsuri */
|
||||
@define-color success_color rgba(61, 158, 104, 1.00);
|
||||
@define-color success_bg_color rgba(61, 158, 104, 1.00);
|
||||
@define-color success_fg_color rgba(248, 244, 252, 1.00);
|
||||
|
||||
/* Error = danger */
|
||||
@define-color error_color rgba(201, 58, 90, 1.00);
|
||||
@define-color error_bg_color rgba(201, 58, 90, 1.00);
|
||||
@define-color error_fg_color rgba(248, 244, 252, 1.00);
|
||||
|
||||
/* Bleu = lavande assombri */
|
||||
@define-color blue_1 rgba(110, 130, 224, 1.00);
|
||||
@define-color blue_2 rgba(100, 120, 216, 1.00);
|
||||
@define-color blue_3 rgba(90, 106, 208, 1.00);
|
||||
@define-color blue_4 rgba(72, 86, 180, 1.00);
|
||||
@define-color blue_5 rgba(54, 66, 152, 1.00);
|
||||
|
||||
/* Vert = mitsuri assombri */
|
||||
@define-color green_1 rgba(80, 176, 124, 1.00);
|
||||
@define-color green_2 rgba(70, 168, 114, 1.00);
|
||||
@define-color green_3 rgba(61, 158, 104, 1.00);
|
||||
@define-color green_4 rgba(48, 132, 84, 1.00);
|
||||
@define-color green_5 rgba(36, 106, 66, 1.00);
|
||||
|
||||
/* Jaune = champagne assombri */
|
||||
@define-color yellow_1 rgba(200, 170, 86, 1.00);
|
||||
@define-color yellow_2 rgba(192, 162, 76, 1.00);
|
||||
@define-color yellow_3 rgba(184, 152, 64, 1.00);
|
||||
@define-color yellow_4 rgba(158, 128, 44, 1.00);
|
||||
@define-color yellow_5 rgba(132, 104, 26, 1.00);
|
||||
|
||||
/* Rouge = danger assombri */
|
||||
@define-color red_1 rgba(218, 82, 114, 1.00);
|
||||
@define-color red_2 rgba(210, 70, 102, 1.00);
|
||||
@define-color red_3 rgba(201, 58, 90, 1.00);
|
||||
@define-color red_4 rgba(174, 42, 72, 1.00);
|
||||
@define-color red_5 rgba(148, 28, 56, 1.00);
|
||||
|
||||
/* Orange */
|
||||
@define-color orange_1 rgba(210, 154, 100, 1.00);
|
||||
@define-color orange_2 rgba(202, 144, 88, 1.00);
|
||||
@define-color orange_3 rgba(192, 132, 76, 1.00);
|
||||
@define-color orange_4 rgba(164, 108, 56, 1.00);
|
||||
@define-color orange_5 rgba(136, 84, 38, 1.00);
|
||||
|
||||
/* Purple = lilac → magenta assombris */
|
||||
@define-color purple_1 rgba(156, 116, 200, 1.00);
|
||||
@define-color purple_2 rgba(148, 104, 192, 1.00);
|
||||
@define-color purple_3 rgba(138, 92, 184, 1.00);
|
||||
@define-color purple_4 rgba(114, 72, 160, 1.00);
|
||||
@define-color purple_5 rgba(92, 54, 136, 1.00);
|
||||
|
||||
/* Echelle monochrome lavande */
|
||||
@define-color light_0 rgba(248, 244, 252, 1.00);
|
||||
@define-color light_1 rgba(243, 237, 248, 1.00);
|
||||
@define-color light_2 rgba(235, 228, 242, 1.00);
|
||||
@define-color light_3 rgba(221, 212, 232, 1.00);
|
||||
@define-color light_4 rgba(208, 198, 222, 1.00);
|
||||
@define-color dark_0 rgba(196, 184, 212, 1.00);
|
||||
@define-color dark_1 rgba(138, 123, 160, 1.00);
|
||||
@define-color dark_2 rgba(90, 56, 117, 1.00);
|
||||
@define-color dark_3 rgba(61, 36, 84, 1.00);
|
||||
@define-color dark_4 rgba(38, 21, 55, 1.00);
|
||||
|
||||
/* ── Variables GTK3 classiques (compat apps legacy) ─────────────────────── */
|
||||
@define-color theme_bg_color rgba(243, 237, 248, 1.00);
|
||||
@define-color theme_fg_color rgba(38, 21, 55, 1.00);
|
||||
@define-color theme_base_color rgba(248, 244, 252, 1.00);
|
||||
@define-color theme_selected_bg_color rgba(138, 92, 184, 1.00);
|
||||
@define-color theme_selected_fg_color rgba(248, 244, 252, 1.00);
|
||||
@define-color theme_text_color rgba(38, 21, 55, 1.00);
|
||||
@define-color borders rgba(196, 184, 212, 1.00);
|
||||
@@ -1,247 +1,127 @@
|
||||
/* ── violet-chaton GTK3 theme — Nemo & GTK apps ───────────────────────────────
|
||||
*
|
||||
* Couleurs extraites du thème COSMIC violet-chaton :
|
||||
* bg #341C4A background.base
|
||||
* surface #493161 background.component.base
|
||||
* hover #5B4671 background.component.hover
|
||||
* accent #E79CFE accent.base
|
||||
* text #FCFCF6 background.on
|
||||
* muted #7F849C neutral_7
|
||||
* border #5C496C background.divider
|
||||
* sidebar #2B1540 (bg légèrement plus sombre)
|
||||
/* ── violet-chaton v2 GTK theme (adw-gtk3-dark compatible) ───────────────────
|
||||
* Palette : themes/palette.sh — source de verite unique
|
||||
* ─────────────────────────────────────────────────────────────────────────── */
|
||||
|
||||
@define-color theme_bg_color #341C4A;
|
||||
@define-color theme_fg_color #FCFCF6;
|
||||
@define-color theme_base_color #493161;
|
||||
@define-color theme_selected_bg_color #E79CFE;
|
||||
@define-color theme_selected_fg_color #341C4A;
|
||||
@define-color theme_text_color #FCFCF6;
|
||||
@define-color borders #5C496C;
|
||||
@define-color window_bg_color rgba(38, 21, 55, 1.00);
|
||||
@define-color window_fg_color rgba(240, 234, 248, 1.00);
|
||||
|
||||
/* ── Fenêtre principale ────────────────────────────────────────────────────── */
|
||||
window, .background {
|
||||
background-color: #341C4A;
|
||||
color: #FCFCF6;
|
||||
}
|
||||
@define-color view_bg_color rgba(52, 28, 74, 1.00);
|
||||
@define-color view_fg_color rgba(196, 184, 212, 1.00);
|
||||
|
||||
/* ── Barre de titre / headerbar ───────────────────────────────────────────── */
|
||||
headerbar, .titlebar {
|
||||
background-color: #493161;
|
||||
color: #FCFCF6;
|
||||
border-bottom: 1px solid #5C496C;
|
||||
}
|
||||
@define-color headerbar_bg_color rgba(38, 21, 55, 1.00);
|
||||
@define-color headerbar_fg_color rgba(240, 234, 248, 1.00);
|
||||
@define-color headerbar_border_color_color rgba(90, 56, 117, 1.00);
|
||||
@define-color headerbar_backdrop_color rgba(38, 21, 55, 1.00);
|
||||
|
||||
headerbar button, .titlebar button {
|
||||
background-color: transparent;
|
||||
color: #FCFCF6;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
}
|
||||
@define-color sidebar_bg_color rgba(52, 28, 74, 1.00);
|
||||
@define-color sidebar_fg_color rgba(196, 184, 212, 1.00);
|
||||
@define-color sidebar_shade_color rgba(0, 0, 0, 0.08);
|
||||
@define-color sidebar_backdrop_color rgba(61, 36, 84, 1.00);
|
||||
|
||||
headerbar button:hover, .titlebar button:hover {
|
||||
background-color: #5B4671;
|
||||
}
|
||||
@define-color secondary_sidebar_bg_color rgba(61, 36, 84, 1.00);
|
||||
@define-color secondary_sidebar_fg_color rgba(196, 184, 212, 1.00);
|
||||
@define-color secondary_sidebar_shade_color rgba(0, 0, 0, 0.08);
|
||||
@define-color secondary_sidebar_backdrop_color rgba(73, 49, 97, 1.00);
|
||||
|
||||
headerbar button:active, .titlebar button:active {
|
||||
background-color: #E79CFE;
|
||||
color: #341C4A;
|
||||
}
|
||||
@define-color card_bg_color rgba(61, 36, 84, 1.00);
|
||||
@define-color card_fg_color rgba(196, 184, 212, 1.00);
|
||||
|
||||
/* ── Sidebar Nemo (paneau des emplacements) ───────────────────────────────── */
|
||||
.sidebar, placessidebar {
|
||||
background-color: #2B1540;
|
||||
color: #FCFCF6;
|
||||
border-right: 1px solid #5C496C;
|
||||
}
|
||||
@define-color thumbnail_bg_color rgba(61, 36, 84, 1.00);
|
||||
@define-color thumbnail_fg_color rgba(196, 184, 212, 1.00);
|
||||
|
||||
.sidebar row, placessidebar row {
|
||||
border-radius: 6px;
|
||||
padding: 2px 4px;
|
||||
}
|
||||
@define-color dialog_bg_color rgba(52, 28, 74, 1.00);
|
||||
@define-color dialog_fg_color rgba(196, 184, 212, 1.00);
|
||||
|
||||
.sidebar row:hover, placessidebar row:hover {
|
||||
background-color: #5B4671;
|
||||
}
|
||||
@define-color popover_bg_color rgba(61, 36, 84, 1.00);
|
||||
@define-color popover_fg_color rgba(196, 184, 212, 1.00);
|
||||
|
||||
.sidebar row:selected, placessidebar row:selected {
|
||||
background-color: #E79CFE;
|
||||
color: #341C4A;
|
||||
}
|
||||
@define-color shade_color rgba(0, 0, 0, 0.32);
|
||||
@define-color scrollbar_outline_color rgba(38, 21, 55, 0.50);
|
||||
|
||||
.sidebar .sidebar-section-header, placessidebar .sidebar-section-header {
|
||||
color: #7F849C;
|
||||
font-size: smaller;
|
||||
}
|
||||
/* Accent = lilac (v2) */
|
||||
@define-color accent_color rgba(201, 160, 255, 1.00);
|
||||
@define-color accent_bg_color rgba(201, 160, 255, 1.00);
|
||||
@define-color accent_fg_color rgba(26, 14, 39, 1.00);
|
||||
|
||||
/* ── Vue fichiers (icônes + liste) ───────────────────────────────────────── */
|
||||
.view, iconview, treeview {
|
||||
background-color: #341C4A;
|
||||
color: #FCFCF6;
|
||||
}
|
||||
/* Destructive = danger */
|
||||
@define-color destructive_color rgba(242, 92, 122, 1.00);
|
||||
@define-color destructive_bg_color rgba(242, 92, 122, 1.00);
|
||||
@define-color destructive_fg_color rgba(26, 14, 39, 1.00);
|
||||
|
||||
.view:selected, iconview:selected,
|
||||
treeview:selected, .view:focus:selected {
|
||||
background-color: #E79CFE;
|
||||
color: #341C4A;
|
||||
}
|
||||
/* Warning = champagne */
|
||||
@define-color warning_color rgba(232, 200, 122, 1.00);
|
||||
@define-color warning_bg_color rgba(232, 200, 122, 1.00);
|
||||
@define-color warning_fg_color rgba(26, 14, 39, 1.00);
|
||||
|
||||
/* En-têtes de colonnes (vue liste) */
|
||||
treeview header button {
|
||||
background-color: #493161;
|
||||
color: #FCFCF6;
|
||||
border: none;
|
||||
border-right: 1px solid #5C496C;
|
||||
border-bottom: 1px solid #5C496C;
|
||||
}
|
||||
/* Success = mitsuri */
|
||||
@define-color success_color rgba(154, 219, 168, 1.00);
|
||||
@define-color success_bg_color rgba(154, 219, 168, 1.00);
|
||||
@define-color success_fg_color rgba(26, 14, 39, 1.00);
|
||||
|
||||
treeview header button:hover {
|
||||
background-color: #5B4671;
|
||||
}
|
||||
/* Error = danger */
|
||||
@define-color error_color rgba(242, 92, 122, 1.00);
|
||||
@define-color error_bg_color rgba(242, 92, 122, 1.00);
|
||||
@define-color error_fg_color rgba(26, 14, 39, 1.00);
|
||||
|
||||
/* ── Barre d'outils / pathbar ─────────────────────────────────────────────── */
|
||||
toolbar, .path-bar {
|
||||
background-color: #493161;
|
||||
border-bottom: 1px solid #5C496C;
|
||||
}
|
||||
/* Bleu = lavande */
|
||||
@define-color blue_1 rgba(180, 196, 255, 1.00);
|
||||
@define-color blue_2 rgba(172, 188, 255, 1.00);
|
||||
@define-color blue_3 rgba(164, 180, 255, 1.00);
|
||||
@define-color blue_4 rgba(138, 154, 228, 1.00);
|
||||
@define-color blue_5 rgba(112, 128, 200, 1.00);
|
||||
|
||||
.path-bar button {
|
||||
background-color: transparent;
|
||||
color: #FCFCF6;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
}
|
||||
/* Vert = mitsuri */
|
||||
@define-color green_1 rgba(170, 230, 182, 1.00);
|
||||
@define-color green_2 rgba(162, 226, 175, 1.00);
|
||||
@define-color green_3 rgba(154, 219, 168, 1.00);
|
||||
@define-color green_4 rgba(128, 192, 142, 1.00);
|
||||
@define-color green_5 rgba(102, 166, 116, 1.00);
|
||||
|
||||
.path-bar button:hover {
|
||||
background-color: #5B4671;
|
||||
}
|
||||
/* Jaune = champagne */
|
||||
@define-color yellow_1 rgba(242, 212, 140, 1.00);
|
||||
@define-color yellow_2 rgba(238, 206, 132, 1.00);
|
||||
@define-color yellow_3 rgba(232, 200, 122, 1.00);
|
||||
@define-color yellow_4 rgba(204, 174, 98, 1.00);
|
||||
@define-color yellow_5 rgba(176, 148, 74, 1.00);
|
||||
|
||||
.path-bar button:checked {
|
||||
background-color: #5B4671;
|
||||
color: #E79CFE;
|
||||
}
|
||||
/* Rouge = danger */
|
||||
@define-color red_1 rgba(254, 116, 146, 1.00);
|
||||
@define-color red_2 rgba(248, 104, 134, 1.00);
|
||||
@define-color red_3 rgba(242, 92, 122, 1.00);
|
||||
@define-color red_4 rgba(216, 70, 100, 1.00);
|
||||
@define-color red_5 rgba(190, 48, 78, 1.00);
|
||||
|
||||
/* ── Barre de recherche / entrée texte ────────────────────────────────────── */
|
||||
entry {
|
||||
background-color: #5B4671;
|
||||
color: #FCFCF6;
|
||||
border: 1px solid #5C496C;
|
||||
border-radius: 6px;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
/* Orange (derive du champagne chaud) */
|
||||
@define-color orange_1 rgba(248, 186, 140, 1.00);
|
||||
@define-color orange_2 rgba(244, 178, 130, 1.00);
|
||||
@define-color orange_3 rgba(238, 168, 118, 1.00);
|
||||
@define-color orange_4 rgba(210, 142, 94, 1.00);
|
||||
@define-color orange_5 rgba(182, 116, 70, 1.00);
|
||||
|
||||
entry:focus {
|
||||
border-color: #E79CFE;
|
||||
box-shadow: 0 0 0 2px alpha(#E79CFE, 0.3);
|
||||
}
|
||||
/* Purple = lilac → magenta */
|
||||
@define-color purple_1 rgba(216, 180, 255, 1.00);
|
||||
@define-color purple_2 rgba(208, 170, 255, 1.00);
|
||||
@define-color purple_3 rgba(201, 160, 255, 1.00);
|
||||
@define-color purple_4 rgba(174, 136, 228, 1.00);
|
||||
@define-color purple_5 rgba(148, 112, 200, 1.00);
|
||||
|
||||
entry placeholder {
|
||||
color: #7F849C;
|
||||
}
|
||||
/* Echelle monochrome violet */
|
||||
@define-color light_0 rgba(0, 0, 0, 1.00);
|
||||
@define-color light_1 rgba(10, 5, 16, 1.00);
|
||||
@define-color light_2 rgba(26, 14, 39, 1.00);
|
||||
@define-color light_3 rgba(52, 28, 74, 1.00);
|
||||
@define-color light_4 rgba(73, 49, 97, 1.00);
|
||||
@define-color dark_0 rgba(113, 102, 134, 1.00);
|
||||
@define-color dark_1 rgba(154, 143, 173, 1.00);
|
||||
@define-color dark_2 rgba(196, 184, 212, 1.00);
|
||||
@define-color dark_3 rgba(240, 234, 248, 1.00);
|
||||
@define-color dark_4 rgba(255, 255, 255, 1.00);
|
||||
|
||||
/* ── Scrollbar ────────────────────────────────────────────────────────────── */
|
||||
scrollbar {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
scrollbar slider {
|
||||
background-color: #5C496C;
|
||||
border-radius: 10px;
|
||||
min-width: 6px;
|
||||
min-height: 6px;
|
||||
}
|
||||
|
||||
scrollbar slider:hover {
|
||||
background-color: #E79CFE;
|
||||
}
|
||||
|
||||
/* ── Menu contextuel ──────────────────────────────────────────────────────── */
|
||||
menu, .context-menu, .popup {
|
||||
background-color: #493161;
|
||||
color: #FCFCF6;
|
||||
border: 1px solid #5C496C;
|
||||
border-radius: 8px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
menuitem {
|
||||
border-radius: 6px;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
menuitem:hover {
|
||||
background-color: #E79CFE;
|
||||
color: #341C4A;
|
||||
}
|
||||
|
||||
menuitem accelerator {
|
||||
color: #7F849C;
|
||||
}
|
||||
|
||||
separator, menuitem separator {
|
||||
background-color: #5C496C;
|
||||
min-height: 1px;
|
||||
}
|
||||
|
||||
/* ── Barre de statut ──────────────────────────────────────────────────────── */
|
||||
.statusbar, statusbar {
|
||||
background-color: #493161;
|
||||
color: #7F849C;
|
||||
border-top: 1px solid #5C496C;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
/* ── Boutons génériques ───────────────────────────────────────────────────── */
|
||||
button {
|
||||
background-color: #5B4671;
|
||||
color: #FCFCF6;
|
||||
border: 1px solid #5C496C;
|
||||
border-radius: 6px;
|
||||
padding: 4px 12px;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: #E79CFE;
|
||||
color: #341C4A;
|
||||
border-color: #E79CFE;
|
||||
}
|
||||
|
||||
button.suggested-action {
|
||||
background-color: #E79CFE;
|
||||
color: #341C4A;
|
||||
border-color: #E79CFE;
|
||||
}
|
||||
|
||||
button.destructive-action {
|
||||
background-color: #F38BA8;
|
||||
color: #341C4A;
|
||||
}
|
||||
|
||||
/* ── Notebooks / onglets ─────────────────────────────────────────────────── */
|
||||
notebook tab {
|
||||
background-color: #493161;
|
||||
color: #7F849C;
|
||||
border-radius: 6px 6px 0 0;
|
||||
padding: 4px 12px;
|
||||
}
|
||||
|
||||
notebook tab:checked {
|
||||
background-color: #5B4671;
|
||||
color: #FCFCF6;
|
||||
}
|
||||
|
||||
/* ── Popover ─────────────────────────────────────────────────────────────── */
|
||||
popover {
|
||||
background-color: #493161;
|
||||
color: #FCFCF6;
|
||||
border: 1px solid #5C496C;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
/* ── Tooltip ─────────────────────────────────────────────────────────────── */
|
||||
tooltip {
|
||||
background-color: #5B4671;
|
||||
color: #FCFCF6;
|
||||
border-radius: 6px;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
/* ── Variables GTK3 classiques (compat apps legacy) ─────────────────────── */
|
||||
@define-color theme_bg_color rgba(38, 21, 55, 1.00);
|
||||
@define-color theme_fg_color rgba(240, 234, 248, 1.00);
|
||||
@define-color theme_base_color rgba(61, 36, 84, 1.00);
|
||||
@define-color theme_selected_bg_color rgba(201, 160, 255, 1.00);
|
||||
@define-color theme_selected_fg_color rgba(26, 14, 39, 1.00);
|
||||
@define-color theme_text_color rgba(240, 234, 248, 1.00);
|
||||
@define-color borders rgba(90, 56, 117, 1.00);
|
||||
|
||||
@@ -1,23 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
# Génère les LS_COLORS violet-chaton depuis catppuccin-mocha
|
||||
# ── violet-chaton v2 — LS_COLORS ────────────────────────────────────────────
|
||||
# Genere les LS_COLORS depuis la palette v2 sans dependance a catppuccin
|
||||
# Usage : export LS_COLORS="$(bash violet-chaton-ls-colors.sh)"
|
||||
#
|
||||
# Palette v2 :
|
||||
# magenta #ff4da6 executables
|
||||
# lilac #c9a0ff dossiers
|
||||
# mitsuri #9adba8 fichiers texte/code
|
||||
# lavande #a4b4ff liens symboliques
|
||||
# champagne #e8c87a archives/comprimes
|
||||
# danger #f25c7a fichiers speciaux (devices, sockets)
|
||||
# text #f0eaf8 fichiers normaux
|
||||
# muted #716686 fichiers caches/backup
|
||||
# subtext0 #9a8fad metadata
|
||||
|
||||
vivid generate catppuccin-mocha | \
|
||||
sed \
|
||||
-e 's/38;2;137;180;250/38;2;231;156;254/g' \
|
||||
-e 's/48;2;137;180;250/48;2;231;156;254/g' \
|
||||
-e 's/38;2;245;194;231/38;2;255;121;198/g' \
|
||||
-e 's/48;2;245;194;231/48;2;255;121;198/g' \
|
||||
-e 's/38;2;116;199;236/38;2;139;233;253/g' \
|
||||
-e 's/48;2;116;199;236/48;2;139;233;253/g' \
|
||||
-e 's/38;2;88;91;112/38;2;127;132;156/g' \
|
||||
-e 's/48;2;88;91;112/48;2;127;132;156/g' \
|
||||
-e 's/38;2;30;30;46/38;2;52;28;74/g' \
|
||||
-e 's/48;2;30;30;46/48;2;52;28;74/g' \
|
||||
-e 's/38;2;49;50;68/38;2;61;36;84/g' \
|
||||
-e 's/48;2;49;50;68/48;2;61;36;84/g' \
|
||||
-e 's/38;2;203;166;247/38;2;231;156;254/g' \
|
||||
-e 's/48;2;203;166;247/48;2;231;156;254/g' \
|
||||
-e 's/38;2;205;214;244/38;2;248;248;242/g' \
|
||||
-e 's/38;2;180;190;254/38;2;231;156;254/g' \
|
||||
-e 's/38;2;148;226;213/38;2;139;233;253/g'
|
||||
cat << 'LSCOLORS'
|
||||
no=0:fi=0:rs=0:di=1;38;2;201;160;255:ln=38;2;164;180;255:mh=0:pi=38;2;232;200;122;48;2;38;21;55:so=1;38;2;242;92;122:do=1;38;2;242;92;122:bd=38;2;232;200;122;48;2;61;36;84:cd=38;2;232;200;122;48;2;38;21;55:or=1;38;2;242;92;122;48;2;38;21;55:su=38;2;240;234;248;48;2;242;92;122:sg=38;2;240;234;248;48;2;232;200;122:ca=0:tw=38;2;240;234;248;48;2;61;158;104:ow=38;2;201;160;255;48;2;61;36;84:st=38;2;240;234;248;48;2;164;180;255:ex=1;38;2;255;77;166:mi=1;38;2;242;92;122;48;2;38;21;55:*.tar=38;2;232;200;122:*.tgz=38;2;232;200;122:*.arc=38;2;232;200;122:*.arj=38;2;232;200;122:*.taz=38;2;232;200;122:*.lha=38;2;232;200;122:*.lz4=38;2;232;200;122:*.lzh=38;2;232;200;122:*.lzma=38;2;232;200;122:*.tlz=38;2;232;200;122:*.txz=38;2;232;200;122:*.tzo=38;2;232;200;122:*.t7z=38;2;232;200;122:*.zip=38;2;232;200;122:*.z=38;2;232;200;122:*.dz=38;2;232;200;122:*.gz=38;2;232;200;122:*.lrz=38;2;232;200;122:*.lz=38;2;232;200;122:*.lzo=38;2;232;200;122:*.xz=38;2;232;200;122:*.zst=38;2;232;200;122:*.tzst=38;2;232;200;122:*.bz2=38;2;232;200;122:*.bz=38;2;232;200;122:*.tbz=38;2;232;200;122:*.tbz2=38;2;232;200;122:*.tz=38;2;232;200;122:*.deb=38;2;232;200;122:*.rpm=38;2;232;200;122:*.jar=38;2;232;200;122:*.war=38;2;232;200;122:*.ear=38;2;232;200;122:*.sar=38;2;232;200;122:*.rar=38;2;232;200;122:*.alz=38;2;232;200;122:*.ace=38;2;232;200;122:*.zoo=38;2;232;200;122:*.cpio=38;2;232;200;122:*.7z=38;2;232;200;122:*.rz=38;2;232;200;122:*.cab=38;2;232;200;122:*.wim=38;2;232;200;122:*.swm=38;2;232;200;122:*.dwm=38;2;232;200;122:*.esd=38;2;232;200;122:*.apk=38;2;232;200;122:*.jpg=38;2;255;77;166:*.jpeg=38;2;255;77;166:*.mjpg=38;2;255;77;166:*.mjpeg=38;2;255;77;166:*.gif=38;2;255;77;166:*.bmp=38;2;255;77;166:*.pbm=38;2;255;77;166:*.pgm=38;2;255;77;166:*.ppm=38;2;255;77;166:*.tga=38;2;255;77;166:*.xbm=38;2;255;77;166:*.xpm=38;2;255;77;166:*.tif=38;2;255;77;166:*.tiff=38;2;255;77;166:*.png=38;2;255;77;166:*.svg=38;2;255;77;166:*.svgz=38;2;255;77;166:*.mng=38;2;255;77;166:*.pcx=38;2;255;77;166:*.webp=38;2;255;77;166:*.avif=38;2;255;77;166:*.ico=38;2;255;77;166:*.mov=38;2;201;160;255:*.mpg=38;2;201;160;255:*.mpeg=38;2;201;160;255:*.m2v=38;2;201;160;255:*.mkv=38;2;201;160;255:*.webm=38;2;201;160;255:*.ogm=38;2;201;160;255:*.mp4=38;2;201;160;255:*.m4v=38;2;201;160;255:*.mp4v=38;2;201;160;255:*.vob=38;2;201;160;255:*.qt=38;2;201;160;255:*.nuv=38;2;201;160;255:*.wmv=38;2;201;160;255:*.asf=38;2;201;160;255:*.rm=38;2;201;160;255:*.rmvb=38;2;201;160;255:*.flc=38;2;201;160;255:*.avi=38;2;201;160;255:*.fli=38;2;201;160;255:*.flv=38;2;201;160;255:*.gl=38;2;201;160;255:*.dl=38;2;201;160;255:*.xcf=38;2;201;160;255:*.xwd=38;2;201;160;255:*.yuv=38;2;201;160;255:*.cgm=38;2;201;160;255:*.emf=38;2;201;160;255:*.ogv=38;2;201;160;255:*.aac=38;2;164;180;255:*.au=38;2;164;180;255:*.flac=38;2;164;180;255:*.m4a=38;2;164;180;255:*.mid=38;2;164;180;255:*.midi=38;2;164;180;255:*.mka=38;2;164;180;255:*.mp3=38;2;164;180;255:*.mpc=38;2;164;180;255:*.ogg=38;2;164;180;255:*.ra=38;2;164;180;255:*.wav=38;2;164;180;255:*.oga=38;2;164;180;255:*.opus=38;2;164;180;255:*.spx=38;2;164;180;255:*.xspf=38;2;164;180;255:*.pdf=38;2;242;92;122:*.doc=38;2;154;219;168:*.docx=38;2;154;219;168:*.xls=38;2;154;219;168:*.xlsx=38;2;154;219;168:*.ppt=38;2;154;219;168:*.pptx=38;2;154;219;168:*.odt=38;2;154;219;168:*.ods=38;2;154;219;168:*.odp=38;2;154;219;168:*.md=38;2;154;219;168:*.json=38;2;154;219;168:*.yaml=38;2;154;219;168:*.yml=38;2;154;219;168:*.toml=38;2;154;219;168:*.xml=38;2;154;219;168:*.csv=38;2;154;219;168:*.js=38;2;154;219;168:*.ts=38;2;154;219;168:*.py=38;2;154;219;168:*.rs=38;2;154;219;168:*.go=38;2;154;219;168:*.sh=38;2;154;219;168:*.bash=38;2;154;219;168:*.zsh=38;2;154;219;168:*.fish=38;2;154;219;168:*.c=38;2;154;219;168:*.cpp=38;2;154;219;168:*.h=38;2;154;219;168:*.hpp=38;2;154;219;168:*.java=38;2;154;219;168:*.css=38;2;154;219;168:*.scss=38;2;154;219;168:*.html=38;2;154;219;168:*.vue=38;2;154;219;168:*.svelte=38;2;154;219;168:*.tsx=38;2;154;219;168:*.jsx=38;2;154;219;168:*.sql=38;2;154;219;168:*.lua=38;2;154;219;168:*.rb=38;2;154;219;168:*.php=38;2;154;219;168:*.swift=38;2;154;219;168:*.kt=38;2;154;219;168:*.bak=38;2;113;102;134:*.old=38;2;113;102;134:*.orig=38;2;113;102;134:*.swp=38;2;113;102;134:*~=38;2;113;102;134:*.tmp=38;2;113;102;134:*.log=38;2;113;102;134:*.lock=38;2;154;143;173:*.env=38;2;232;200;122:*.env.example=38;2;154;143;173:*.gitignore=38;2;154;143;173:*.dockerignore=38;2;154;143;173:*.editorconfig=38;2;154;143;173
|
||||
LSCOLORS
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
/* ── violet-chaton rofi theme ─────────────────────────────────────────────── */
|
||||
/* ── violet-chaton v2 rofi theme ──────────────────────────────────────────── */
|
||||
|
||||
* {
|
||||
bg0: #261537;
|
||||
bg1: #341c4a;
|
||||
bg0: #1a0e27;
|
||||
bg1: #261537;
|
||||
surface: #493161;
|
||||
pink: #ff79c6;
|
||||
purple: #e79cfe;
|
||||
cyan: #8be9fd;
|
||||
text: #f8f8f2;
|
||||
muted: #6c7086;
|
||||
overlay: #9399b2;
|
||||
magenta: #ff4da6;
|
||||
lilac: #c9a0ff;
|
||||
lavande: #a4b4ff;
|
||||
text: #f0eaf8;
|
||||
muted: #716686;
|
||||
subtext0: #9a8fad;
|
||||
|
||||
background-color: transparent;
|
||||
text-color: @text;
|
||||
}
|
||||
|
||||
/* ── Fenêtre — positionnée sous les pills ─────────────────────────────────── */
|
||||
/* ── Fenetre ─────────────────────────────────────────────────────────────── */
|
||||
|
||||
window {
|
||||
background-color: rgba(38, 21, 55, 0.94);
|
||||
background-color: rgba(26, 14, 39, 0.94);
|
||||
border: 2px;
|
||||
border-color: rgba(255, 121, 198, 0.38);
|
||||
border-color: rgba(255, 77, 166, 0.38);
|
||||
border-radius: 14px;
|
||||
width: 500px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
/* ── Layout — résultats en haut, recherche en bas ─────────────────────────── */
|
||||
/* ── Layout — resultats en haut, recherche en bas ────────────────────────── */
|
||||
|
||||
mainbox {
|
||||
background-color: transparent;
|
||||
@@ -35,7 +35,7 @@ mainbox {
|
||||
children: [ listview, inputbar ];
|
||||
}
|
||||
|
||||
/* ── Liste des résultats ──────────────────────────────────────────────────── */
|
||||
/* ── Liste des resultats ─────────────────────────────────────────────────── */
|
||||
|
||||
listview {
|
||||
background-color: transparent;
|
||||
@@ -56,15 +56,15 @@ element {
|
||||
}
|
||||
|
||||
element selected {
|
||||
background-color: rgba(255, 121, 198, 0.16);
|
||||
background-color: rgba(255, 77, 166, 0.16);
|
||||
border: 1px;
|
||||
border-color: rgba(255, 121, 198, 0.32);
|
||||
border-color: rgba(255, 77, 166, 0.32);
|
||||
}
|
||||
|
||||
element hover {
|
||||
background-color: rgba(255, 121, 198, 0.16);
|
||||
background-color: rgba(255, 77, 166, 0.16);
|
||||
border: 1px;
|
||||
border-color: rgba(255, 121, 198, 0.32);
|
||||
border-color: rgba(255, 77, 166, 0.32);
|
||||
}
|
||||
|
||||
element-icon {
|
||||
@@ -80,20 +80,20 @@ element-text {
|
||||
}
|
||||
|
||||
element-text selected {
|
||||
text-color: @pink;
|
||||
text-color: @magenta;
|
||||
}
|
||||
|
||||
element-text hover {
|
||||
text-color: @pink;
|
||||
text-color: @magenta;
|
||||
}
|
||||
|
||||
/* ── Séparateur visuel avant la recherche ─────────────────────────────────── */
|
||||
/* ── Barre de recherche ──────────────────────────────────────────────────── */
|
||||
|
||||
inputbar {
|
||||
background-color: rgba(52, 28, 74, 0.75);
|
||||
background-color: rgba(38, 21, 55, 0.75);
|
||||
border-radius: 0 0 12px 12px;
|
||||
border: 1px;
|
||||
border-color: rgba(92, 73, 108, 0.50);
|
||||
border-color: rgba(90, 56, 117, 0.50);
|
||||
padding: 9px 14px;
|
||||
spacing: 8px;
|
||||
children: [ prompt, entry ];
|
||||
@@ -101,30 +101,30 @@ inputbar {
|
||||
|
||||
prompt {
|
||||
background-color: transparent;
|
||||
text-color: @pink;
|
||||
font: "JetBrainsMono Nerd Font Bold 14";
|
||||
text-color: @magenta;
|
||||
font: "Maple Mono NF Bold 14";
|
||||
vertical-align: 0.5;
|
||||
}
|
||||
|
||||
entry {
|
||||
background-color: transparent;
|
||||
text-color: @text;
|
||||
placeholder: "Rechercher une application...";
|
||||
placeholder: "Rechercher...";
|
||||
placeholder-color: @muted;
|
||||
vertical-align: 0.5;
|
||||
}
|
||||
|
||||
/* ── Scrollbar ────────────────────────────────────────────────────────────── */
|
||||
/* ── Scrollbar ───────────────────────────────────────────────────────────── */
|
||||
|
||||
scrollbar {
|
||||
background-color: rgba(92, 73, 108, 0.30);
|
||||
handle-color: rgba(255, 121, 198, 0.40);
|
||||
background-color: rgba(90, 56, 117, 0.30);
|
||||
handle-color: rgba(255, 77, 166, 0.40);
|
||||
handle-width: 4px;
|
||||
border-radius: 2px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* ── Messages ─────────────────────────────────────────────────────────────── */
|
||||
/* ── Messages ────────────────────────────────────────────────────────────── */
|
||||
|
||||
message {
|
||||
background-color: transparent;
|
||||
@@ -132,6 +132,6 @@ message {
|
||||
}
|
||||
|
||||
textbox {
|
||||
text-color: @overlay;
|
||||
text-color: @subtext0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
@@ -4,20 +4,20 @@
|
||||
"accentOnWindow": true,
|
||||
"accentSaturationLimit": 1,
|
||||
"alpha": 1,
|
||||
"backgroundImage": "/resources/bg_pawel-czerwinski-Xk7ktUfyaNI-unsplash.webp",
|
||||
"backgroundImage": "",
|
||||
"backgroundPosition": "stretch",
|
||||
"backgroundSource": "",
|
||||
"blur": 0,
|
||||
"colorAccentBg": "#2c183e",
|
||||
"colorBg": "#341c4a",
|
||||
"colorFg": "#d3d9e3",
|
||||
"colorHighlightBg": "#b68fdc",
|
||||
"colorWindowBg": "#1D1E21",
|
||||
"colorAccentBg": "#1a0e27",
|
||||
"colorBg": "#261537",
|
||||
"colorFg": "#f0eaf8",
|
||||
"colorHighlightBg": "#c9a0ff",
|
||||
"colorWindowBg": "#1a0e27",
|
||||
"contrast": 0,
|
||||
"dimBlurred": false,
|
||||
"engineVersion": 1,
|
||||
"id": "11455bed-3b48-4de5-9a03-a83a1b4be775",
|
||||
"name": "Rice Violet-Chaton",
|
||||
"name": "Violet-Chaton v2",
|
||||
"preferSystemAccent": false,
|
||||
"radius": 14,
|
||||
"simpleScrollbar": true,
|
||||
|
||||
@@ -102,9 +102,11 @@ window#waybar {
|
||||
|
||||
#cpu,
|
||||
#temperature,
|
||||
#custom-cpu-temp,
|
||||
#custom-gpu,
|
||||
#memory,
|
||||
#disk,
|
||||
#custom-disks,
|
||||
#custom-network,
|
||||
#clock,
|
||||
#custom-date,
|
||||
@@ -140,7 +142,8 @@ window#waybar {
|
||||
|
||||
/* ── Température ──────────────────────────────────────────────────────────── */
|
||||
|
||||
#temperature {
|
||||
#temperature,
|
||||
#custom-cpu-temp {
|
||||
color: rgba(139, 233, 253, 0.60);
|
||||
font-size: 11px;
|
||||
font-weight: normal;
|
||||
@@ -148,12 +151,17 @@ window#waybar {
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
#temperature.critical {
|
||||
#temperature.critical,
|
||||
#custom-cpu-temp.critical {
|
||||
color: #f38ba8;
|
||||
font-weight: bold;
|
||||
animation: pulse-critical 0.8s linear infinite;
|
||||
}
|
||||
|
||||
#custom-cpu-temp.warning {
|
||||
color: #f9e2af;
|
||||
}
|
||||
|
||||
/* ── GPU ──────────────────────────────────────────────────────────────────── */
|
||||
|
||||
#custom-gpu {
|
||||
@@ -186,7 +194,8 @@ window#waybar {
|
||||
|
||||
/* ── Disque ───────────────────────────────────────────────────────────────── */
|
||||
|
||||
#disk {
|
||||
#disk,
|
||||
#custom-disks {
|
||||
color: rgba(255, 121, 198, 0.70);
|
||||
font-size: 11px;
|
||||
font-weight: normal;
|
||||
@@ -405,6 +414,8 @@ tooltip label {
|
||||
#cpu:hover,
|
||||
#memory:hover,
|
||||
#disk:hover,
|
||||
#custom-disks:hover,
|
||||
#custom-cpu-temp:hover,
|
||||
#custom-network:hover,
|
||||
#wireplumber:hover,
|
||||
#backlight:hover,
|
||||
|
||||
@@ -1,96 +1,96 @@
|
||||
# violet-chaton — thème yazi
|
||||
# violet-chaton v2 — theme yazi
|
||||
|
||||
[mgr]
|
||||
cwd = { fg = "#e79cfe" } # purple — dossier courant
|
||||
cwd = { fg = "#c9a0ff" }
|
||||
|
||||
find_keyword = { fg = "#f9e2af", bold = true, italic = true, underline = true }
|
||||
find_position = { fg = "#ff79c6", bg = "reset", bold = true, italic = true }
|
||||
find_keyword = { fg = "#e8c87a", bold = true, italic = true, underline = true }
|
||||
find_position = { fg = "#ff4da6", bg = "reset", bold = true, italic = true }
|
||||
|
||||
marker_copied = { fg = "#8be9fd", bg = "#8be9fd" } # cyan
|
||||
marker_cut = { fg = "#f38ba8", bg = "#f38ba8" } # danger
|
||||
marker_marked = { fg = "#e79cfe", bg = "#e79cfe" } # purple
|
||||
marker_selected = { fg = "#ff79c6", bg = "#ff79c6" } # pink
|
||||
marker_copied = { fg = "#a4b4ff", bg = "#a4b4ff" }
|
||||
marker_cut = { fg = "#f25c7a", bg = "#f25c7a" }
|
||||
marker_marked = { fg = "#c9a0ff", bg = "#c9a0ff" }
|
||||
marker_selected = { fg = "#ff4da6", bg = "#ff4da6" }
|
||||
|
||||
count_copied = { fg = "#261537", bg = "#8be9fd" }
|
||||
count_cut = { fg = "#261537", bg = "#f38ba8" }
|
||||
count_selected = { fg = "#261537", bg = "#ff79c6" }
|
||||
count_copied = { fg = "#261537", bg = "#a4b4ff" }
|
||||
count_cut = { fg = "#261537", bg = "#f25c7a" }
|
||||
count_selected = { fg = "#261537", bg = "#ff4da6" }
|
||||
|
||||
border_symbol = "│"
|
||||
border_style = { fg = "#6c7086" }
|
||||
border_style = { fg = "#716686" }
|
||||
|
||||
[tabs]
|
||||
active = { fg = "#261537", bg = "#ff79c6", bold = true }
|
||||
inactive = { fg = "#ff79c6", bg = "#3d2454" }
|
||||
active = { fg = "#261537", bg = "#ff4da6", bold = true }
|
||||
inactive = { fg = "#ff4da6", bg = "#3d2454" }
|
||||
|
||||
[mode]
|
||||
normal_main = { fg = "#261537", bg = "#ff79c6", bold = true }
|
||||
normal_alt = { fg = "#ff79c6", bg = "#3d2454" }
|
||||
normal_main = { fg = "#261537", bg = "#ff4da6", bold = true }
|
||||
normal_alt = { fg = "#ff4da6", bg = "#3d2454" }
|
||||
|
||||
select_main = { fg = "#261537", bg = "#8be9fd", bold = true }
|
||||
select_alt = { fg = "#8be9fd", bg = "#3d2454" }
|
||||
select_main = { fg = "#261537", bg = "#a4b4ff", bold = true }
|
||||
select_alt = { fg = "#a4b4ff", bg = "#3d2454" }
|
||||
|
||||
unset_main = { fg = "#261537", bg = "#e79cfe", bold = true }
|
||||
unset_alt = { fg = "#e79cfe", bg = "#3d2454" }
|
||||
unset_main = { fg = "#261537", bg = "#c9a0ff", bold = true }
|
||||
unset_alt = { fg = "#c9a0ff", bg = "#3d2454" }
|
||||
|
||||
[status]
|
||||
perm_sep = { fg = "#6c7086" }
|
||||
perm_type = { fg = "#e79cfe" } # purple
|
||||
perm_read = { fg = "#8be9fd" } # cyan
|
||||
perm_write = { fg = "#ff79c6" } # pink
|
||||
perm_exec = { fg = "#a6e3a1" } # green
|
||||
perm_sep = { fg = "#716686" }
|
||||
perm_type = { fg = "#c9a0ff" }
|
||||
perm_read = { fg = "#a4b4ff" }
|
||||
perm_write = { fg = "#ff4da6" }
|
||||
perm_exec = { fg = "#9adba8" }
|
||||
|
||||
progress_label = { fg = "#f8f8f2", bold = true }
|
||||
progress_normal = { fg = "#8be9fd", bg = "#3d2454" }
|
||||
progress_error = { fg = "#f38ba8", bg = "#3d2454" }
|
||||
progress_label = { fg = "#f0eaf8", bold = true }
|
||||
progress_normal = { fg = "#a4b4ff", bg = "#3d2454" }
|
||||
progress_error = { fg = "#f25c7a", bg = "#3d2454" }
|
||||
|
||||
[pick]
|
||||
border = { fg = "#ff79c6" }
|
||||
active = { fg = "#e79cfe", bold = true }
|
||||
border = { fg = "#ff4da6" }
|
||||
active = { fg = "#c9a0ff", bold = true }
|
||||
inactive = {}
|
||||
|
||||
[input]
|
||||
border = { fg = "#ff79c6" }
|
||||
title = { fg = "#e79cfe" }
|
||||
value = { fg = "#f8f8f2" }
|
||||
border = { fg = "#ff4da6" }
|
||||
title = { fg = "#c9a0ff" }
|
||||
value = { fg = "#f0eaf8" }
|
||||
selected = { reversed = true }
|
||||
|
||||
[completion]
|
||||
border = { fg = "#8be9fd" }
|
||||
active = { fg = "#ff79c6", bold = true }
|
||||
inactive = { fg = "#6c7086" }
|
||||
border = { fg = "#a4b4ff" }
|
||||
active = { fg = "#ff4da6", bold = true }
|
||||
inactive = { fg = "#716686" }
|
||||
|
||||
[tasks]
|
||||
border = { fg = "#ff79c6" }
|
||||
title = { fg = "#e79cfe" }
|
||||
hovered = { fg = "#ff79c6", underline = true }
|
||||
border = { fg = "#ff4da6" }
|
||||
title = { fg = "#c9a0ff" }
|
||||
hovered = { fg = "#ff4da6", underline = true }
|
||||
|
||||
[which]
|
||||
mask = { bg = "#261537" }
|
||||
cands = { fg = "#8be9fd" }
|
||||
rest = { fg = "#6c7086" }
|
||||
desc = { fg = "#e79cfe" }
|
||||
cands = { fg = "#a4b4ff" }
|
||||
rest = { fg = "#716686" }
|
||||
desc = { fg = "#c9a0ff" }
|
||||
separator = " › "
|
||||
separator_style = { fg = "#6c7086" }
|
||||
separator_style = { fg = "#716686" }
|
||||
|
||||
[help]
|
||||
on = { fg = "#ff79c6" }
|
||||
run = { fg = "#8be9fd" }
|
||||
desc = { fg = "#f8f8f2" }
|
||||
on = { fg = "#ff4da6" }
|
||||
run = { fg = "#a4b4ff" }
|
||||
desc = { fg = "#f0eaf8" }
|
||||
hovered = { bg = "#3d2454", bold = true }
|
||||
footer = { fg = "#261537", bg = "#e79cfe" }
|
||||
footer = { fg = "#261537", bg = "#c9a0ff" }
|
||||
|
||||
[notify]
|
||||
title_info = { fg = "#8be9fd" }
|
||||
title_warn = { fg = "#f9e2af" }
|
||||
title_error = { fg = "#f38ba8" }
|
||||
title_info = { fg = "#a4b4ff" }
|
||||
title_warn = { fg = "#e8c87a" }
|
||||
title_error = { fg = "#f25c7a" }
|
||||
|
||||
[filetype]
|
||||
rules = [
|
||||
{ mime = "image/*", style = { fg = "#ff79c6" } },
|
||||
{ mime = "video/*", style = { fg = "#e79cfe" } },
|
||||
{ mime = "audio/*", style = { fg = "#8be9fd" } },
|
||||
{ mime = "application/zip", style = { fg = "#f9e2af" } },
|
||||
{ mime = "application/x-tar", style = { fg = "#f9e2af" } },
|
||||
{ mime = "application/pdf", style = { fg = "#f38ba8" } },
|
||||
{ mime = "text/*", style = { fg = "#f8f8f2" } },
|
||||
{ mime = "image/*", style = { fg = "#ff4da6" } },
|
||||
{ mime = "video/*", style = { fg = "#c9a0ff" } },
|
||||
{ mime = "audio/*", style = { fg = "#a4b4ff" } },
|
||||
{ mime = "application/zip", style = { fg = "#e8c87a" } },
|
||||
{ mime = "application/x-tar", style = { fg = "#e8c87a" } },
|
||||
{ mime = "application/pdf", style = { fg = "#f25c7a" } },
|
||||
{ mime = "text/*", style = { fg = "#f0eaf8" } },
|
||||
]
|
||||
|
||||
537
README.md
537
README.md
@@ -1,416 +1,201 @@
|
||||
# violet-chaton — setup automatique
|
||||
# violet-chaton v2
|
||||
|
||||
Environnement terminal complet aux couleurs violet-chaton, pensé pour Pop!_OS / Ubuntu avec COSMIC Desktop.
|
||||
(Bonus thème Vesktop / Discord)
|
||||
> Rice Pop!\_OS complet — palette originale, zero emprunt.
|
||||
> Compatible **COSMIC** et **Hyprland**.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Démarrage rapide
|
||||
## Philosophie
|
||||
|
||||
Palette 100% originale inspiree du gradient de **Mitsuri Kanroji** (rose → vert pastel).
|
||||
Fond violet profond signature, 5 accents uniques, variantes dark + light.
|
||||
Source de verite unique : `INSTALL/themes/palette.sh`
|
||||
|
||||
---
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
bash install.sh
|
||||
git clone https://git.tetardtek.com/Tetardtek/dotfiles-violet-chaton.git
|
||||
cd dotfiles-violet-chaton
|
||||
bash INSTALL/install.sh
|
||||
```
|
||||
|
||||
Un menu s'affiche. Choisis **1** pour une installation complète.
|
||||
Choisir **1** (complete) ou **4** (configs uniquement si les outils sont deja la).
|
||||
|
||||
Prerequis : `sudo apt install -y curl git unzip`
|
||||
|
||||
---
|
||||
|
||||
## Prérequis
|
||||
## Ce que tu obtiens
|
||||
|
||||
- **Distribution :** Debian, Ubuntu, Pop!_OS (ou dérivé apt)
|
||||
- **Droits :** compte avec `sudo`
|
||||
- **Connexion internet** (téléchargement des binaires)
|
||||
- **Outils de base :**
|
||||
### Terminal
|
||||
- **kitty** — GPU-accelerated, ligatures, cursor trail magenta, splits tiling, GLSL shader glow
|
||||
- **Maple Mono NF** — italiques cursives, ligatures, fine et niche
|
||||
|
||||
```bash
|
||||
sudo apt install -y curl git unzip
|
||||
```
|
||||
### Shell
|
||||
- **zsh** + zinit + autosuggestions + syntax-highlighting (palette v2)
|
||||
- **starship** 3 lignes — separateur style, prompt signature, brain\_name env var
|
||||
- **vi-mode** — beam/block cursor adaptatif, keybindings emacs preserves
|
||||
- **atuin** — historique shell fuzzy
|
||||
|
||||
> Pour COSMIC Desktop : Pop!_OS 24.04 ou supérieur.
|
||||
### Outils CLI
|
||||
| Outil | Remplace | Description |
|
||||
|-------|----------|-------------|
|
||||
| `eza` | ls | Listing colore avec icones |
|
||||
| `bat` | cat | Coloration syntaxique + theme v2 |
|
||||
| `fd` | find | Recherche de fichiers |
|
||||
| `fzf` | — | Fuzzy finder (fichiers, dossiers, git log, process killer) |
|
||||
| `zoxide` | cd | Navigation intelligente |
|
||||
| `ripgrep` | grep | Recherche dans les fichiers |
|
||||
| `lazygit` | — | Git TUI avec couleurs v2 |
|
||||
| `delta` | diff | Diffs colores side-by-side |
|
||||
| `yazi` | — | Explorateur fichiers TUI + preview images kitty |
|
||||
| `btop` | top | Monitoring systeme avec theme v2 |
|
||||
| `dust` | du/ncdu | Analyse disque |
|
||||
| `procs` | ps | Process viewer |
|
||||
| `tokei` | — | Stats code par langage |
|
||||
| `sd` | sed | Remplacement simplifie |
|
||||
| `hyperfine` | time | Benchmarks CLI |
|
||||
| `gping` | ping | Ping avec graphe |
|
||||
|
||||
### Desktop
|
||||
- **AGS** (Aylur's GTK Shell) — barre 3-pills glassmorphism, OSD gradient Mitsuri, launcher, notifications
|
||||
- **Rofi** — backup launcher avec theme v2
|
||||
- Detection auto compositor (Hyprland = workspaces, COSMIC = mode compatible)
|
||||
|
||||
### Theming
|
||||
- **COSMIC** Dark + Light — palette v2 complete (accent, background, primary, semantiques)
|
||||
- **COSMIC Term** — Maple Mono NF + color schemes dark/light
|
||||
- **GTK3/GTK4** — dark + light css
|
||||
- **Vivaldi** — theme injecte automatiquement
|
||||
- **Vesktop/Discord** — theme css
|
||||
- Candy-icons
|
||||
|
||||
---
|
||||
|
||||
## Ce que fait le script — étape par étape
|
||||
## Palette v2
|
||||
|
||||
### Étape 1 — Paquets apt (`01-packages-apt.sh`)
|
||||
### Dark
|
||||
|
||||
Installe les outils via le gestionnaire de paquets système :
|
||||
| | Hex | Role |
|
||||
|-|-----|------|
|
||||
|  | `#261537` | base — fond principal |
|
||||
|  | `#341c4a` | mantle |
|
||||
|  | `#3d2454` | surface0 |
|
||||
|  | `#5a3875` | surface2 — selection |
|
||||
|  | `#ff4da6` | magenta — accent primaire |
|
||||
|  | `#c9a0ff` | lilac — accent secondaire |
|
||||
|  | `#9adba8` | mitsuri — vert pastel / success |
|
||||
|  | `#a4b4ff` | lavande — bleu-violet / info |
|
||||
|  | `#e8c87a` | champagne — or chaud / warning |
|
||||
|  | `#f25c7a` | danger |
|
||||
|  | `#f0eaf8` | text |
|
||||
|  | `#716686` | muted |
|
||||
|
||||
| Outil | Rôle |
|
||||
|------------------|------|
|
||||
| `zsh` | Shell principal (remplace bash) |
|
||||
| `eza` | Remplacement de `ls` avec icônes et couleurs |
|
||||
| `bat` | Remplacement de `cat` avec coloration syntaxique |
|
||||
| `fd-find` | Remplacement de `find`, plus rapide et intuitif |
|
||||
| `fzf` | Fuzzy finder — recherche floue de fichiers et dossiers |
|
||||
| `zoxide` | Remplacement de `cd` avec mémoire des dossiers fréquents |
|
||||
| `git-delta` | Pager git avec diff coloré côte à côte |
|
||||
| `vivid` | Générateur de LS_COLORS |
|
||||
| `ripgrep` | Remplacement de `grep`, très rapide |
|
||||
| `ncdu` | Analyse d'espace disque en TUI |
|
||||
| `thefuck` | Correction automatique de la dernière commande ratée |
|
||||
| `lolcat` | Arc-en-ciel sur n'importe quel output |
|
||||
| `cbonsai` | Bonsaï ASCII animé |
|
||||
| `chafa` | Affichage d'images dans le terminal (logo fastfetch) |
|
||||
| `cava` | Visualiseur audio animé |
|
||||
| `btop` | Moniteur système en TUI |
|
||||
| `nemo` | Explorateur de fichiers GUI |
|
||||
| `jq` | Processeur JSON en ligne de commande |
|
||||
| `vivaldi-stable` | Navigateur — dépôt officiel ajouté automatiquement |
|
||||
| `gh` | CLI GitHub (auth, PR, issues) — dépôt officiel ajouté automatiquement |
|
||||
| `cmatrix` | Pluie de caractères style Matrix |
|
||||
| `toilet` | Texte en gros ASCII art coloré (bannières dans le terminal) |
|
||||
| `w3m` | Navigateur web en mode texte dans le terminal |
|
||||
| `jp2a` | Conversion d'images JPEG/PNG en ASCII art |
|
||||
| `qalc` | Calculatrice CLI — unités, conversions, expressions complexes |
|
||||
| `waybar` | Barre de statut Wayland 3-pills glassmorphism |
|
||||
| `wob` | Overlay volume/luminosité animé |
|
||||
| `wofi` | Launcher d'applications et menu power |
|
||||
| `brightnessctl` | Contrôle de la luminosité rétroéclairage |
|
||||
| `playerctl` | Contrôle MPRIS (lecture/pause, titre en cours) |
|
||||
| `wireplumber` | Gestionnaire audio PipeWire (`wpctl`) |
|
||||
| `python3-gi` | Bindings Python GTK3 (popups volume/luminosité) |
|
||||
| `gir1.2-gtk-3.0` | Introspection GTK3 pour Python |
|
||||
| `gir1.2-gtklayershell-0.1` | Layer-shell Wayland pour popups GTK flottants |
|
||||
### Gradient signature
|
||||
|
||||
Définit aussi **zsh comme shell par défaut** via `chsh`.
|
||||
```
|
||||
magenta → lilac → lavande → mitsuri
|
||||
#ff4da6 → #c9a0ff → #a4b4ff → #9adba8
|
||||
```
|
||||
|
||||
### Light
|
||||
|
||||
Fonds lavande clairs (`#f3edf8`), accents assombris pour contraste WCAG.
|
||||
Meme identite violet, meme gradient. Voir `palette.sh` section LIGHT.
|
||||
|
||||
---
|
||||
|
||||
### Étape 2 — Binaires manuels (`02-packages-manual.sh`)
|
||||
## Raccourcis kitty
|
||||
|
||||
Télécharge les versions les plus récentes depuis GitHub et les installe dans `~/.local/bin/` :
|
||||
| Touche | Action |
|
||||
|--------|--------|
|
||||
| `Ctrl+Shift+\` | Split vertical |
|
||||
| `Ctrl+Shift+-` | Split horizontal |
|
||||
| `Ctrl+Shift+Z` | Zoom (stack toggle) |
|
||||
| `Ctrl+Shift+←→↑↓` | Naviguer entre splits |
|
||||
| `Ctrl+Shift+1-5` | Layouts (tall/fat/grid/h/v) |
|
||||
| `Ctrl+Shift+T` | Nouvel onglet |
|
||||
| `Ctrl+Shift+W` | Fermer onglet |
|
||||
| `Ctrl+Shift+R` | Redimensionner split |
|
||||
| `Ctrl+V` | Coller |
|
||||
| `Ctrl+C` | Copier / interrompre |
|
||||
|
||||
| Outil | Rôle |
|
||||
|--------------|------|
|
||||
| `lazygit` | Interface git complète en TUI (`lg`) |
|
||||
| `yazi` | Gestionnaire de fichiers en TUI |
|
||||
| `glow` | Rendu Markdown dans le terminal |
|
||||
| `tldr` | Man pages simplifiées avec exemples (tealdeer) |
|
||||
| `navi` | Cheatsheets interactives |
|
||||
| `pipes.sh` | Animation de tuyaux dans le terminal |
|
||||
| `fastfetch` | Infos système au démarrage du terminal — `.deb` depuis GitHub |
|
||||
| `uv` / `uvx` | Gestionnaire de paquets Python ultra-rapide — script officiel astral.sh |
|
||||
## Raccourcis shell
|
||||
|
||||
Installe également :
|
||||
- **starship** et **atuin** via leurs scripts officiels
|
||||
- **zinit** (gestionnaire de plugins zsh) via git clone
|
||||
- **Nerd Fonts** — JetBrainsMono NL et 0xProto, vers `~/.local/share/fonts/NerdFonts/`
|
||||
- **candy-icons** — thème d'icônes, vers `~/.local/share/icons/candy-icons-master/`
|
||||
| Touche | Action |
|
||||
|--------|--------|
|
||||
| `Ctrl+G` | fzf fichier |
|
||||
| `Ctrl+F` | fzf dossier |
|
||||
| `Ctrl+R` | Historique (atuin) |
|
||||
| `Ctrl+Space` | Accepter suggestion |
|
||||
| `Escape` | Vi normal mode |
|
||||
| `i` | Retour insert |
|
||||
|
||||
> **nomachine** — à installer manuellement depuis [nomachine.com](https://www.nomachine.com/download) (comme VSCode et Vesktop)
|
||||
## Commandes custom
|
||||
|
||||
Met à jour le cache des pages tldr et le cache de polices (`fc-cache`).
|
||||
| Commande | Description |
|
||||
|----------|-------------|
|
||||
| `colors` | Affiche la palette v2 |
|
||||
| `hotkeys` | Cheatsheet raccourcis |
|
||||
| `proj` | Project switcher fzf dans ~/Dev |
|
||||
| `glog` | Git log fzf avec preview |
|
||||
| `fkill` | Process killer fzf |
|
||||
| `y` | Yazi (cd au dossier visite) |
|
||||
| `weather [ville]` | Meteo rapide |
|
||||
|
||||
## Alias
|
||||
|
||||
| Alias | Commande reelle |
|
||||
|-------|-----------------|
|
||||
| `ls` | eza --icons |
|
||||
| `ll` | eza -l --icons --git |
|
||||
| `la` | eza -la --icons --git |
|
||||
| `lt` | eza --tree --level=3 |
|
||||
| `cat` | bat (sans pager) |
|
||||
| `bat` | batcat |
|
||||
| `fd` | fdfind |
|
||||
| `lg` | lazygit |
|
||||
| `tl` | tldr |
|
||||
| `disk` | dust |
|
||||
| `top` | btop |
|
||||
| `fetch` | fastfetch + chafa logo |
|
||||
|
||||
---
|
||||
|
||||
### Étape 3 — Déploiement des configs et thèmes (`03-deploy-configs.sh`)
|
||||
|
||||
Copie les fichiers de config et thèmes aux bons emplacements.
|
||||
|
||||
Avant chaque déploiement, les fichiers existants sont sauvegardés dans :
|
||||
```
|
||||
~/.config/violet-chaton-backups/YYYYMMDD-HHMMSS/
|
||||
```
|
||||
Le chemin exact est affiché à la fin du script si des fichiers ont été sauvegardés.
|
||||
|
||||
**Configs shell :**
|
||||
- `~/.zshrc` — configuration zsh complète
|
||||
- `~/.bashrc` — configuration bash minimale (PATH + `exec zsh`)
|
||||
- `~/.gitconfig` — git avec delta comme pager
|
||||
|
||||
> `user.name` et `user.email` présents dans le gitconfig existant sont **automatiquement préservés** après le déploiement.
|
||||
|
||||
**Configs outils :**
|
||||
- `~/.config/starship.toml` — prompt 2 lignes violet-chaton
|
||||
- `~/.config/bat/config` — thème violet-chaton, style header
|
||||
- `~/.config/btop/btop.conf` — moniteur avec thème violet-chaton
|
||||
- `~/.config/fastfetch/config.jsonc` — modules système + logo chafa
|
||||
- `~/.config/atuin/config.toml` — historique fuzzy, colonnes, thème
|
||||
- `~/.config/lazygit/config.yml` — couleurs violet-chaton + delta
|
||||
- `~/.config/yazi/yazi.toml` — config gestionnaire de fichiers
|
||||
- `~/.config/glow/glow.yml` — style markdown dark
|
||||
|
||||
**Thèmes CLI :**
|
||||
- `~/.config/bat/themes/violet-chaton.tmTheme`
|
||||
- `~/.config/btop/themes/violet-chaton.theme`
|
||||
- `~/.config/atuin/themes/violet-chaton.toml`
|
||||
- `~/.config/cava/config`
|
||||
- `~/.config/yazi/theme.toml`
|
||||
- `~/.config/vesktop/themes/violet-chaton.theme.css` — Vesktop natif (toujours déployé)
|
||||
- `~/.var/app/dev.vencord.Vesktop/config/vesktop/themes/` — Vesktop Flatpak (si installé)
|
||||
|
||||
**GTK3 et Nemo :**
|
||||
- `~/.config/gtk-3.0/gtk.css` — thème GTK3 violet-chaton (Nemo et applications GTK)
|
||||
- Nemo défini comme gestionnaire de fichiers par défaut (`xdg-mime`)
|
||||
- Préférences Nemo appliquées via `gsettings` : vue icônes, miniatures, zoom standard
|
||||
- Thème d'icônes **candy-icons** activé via `gsettings`
|
||||
|
||||
**COSMIC Desktop (entièrement automatique) :**
|
||||
- `~/.config/cosmic/com.system76.CosmicTheme.Dark/v1/` — palette violet-chaton complète
|
||||
- `~/.config/cosmic/com.system76.CosmicTheme.Light/v1/` — palette violet-chaton (mode clair)
|
||||
- `~/.config/cosmic/com.system76.CosmicTheme.Mode/v1/is_dark` — mode sombre activé
|
||||
- `~/.config/cosmic/com.system76.CosmicTerm/v1/` — police JetBrains Mono, couleurs, profil
|
||||
- `~/.config/cosmic/com.system76.CosmicTk/v1/` — icônes candy-icons, polices UI 0xProto
|
||||
|
||||
**Waybar — island floating 3 pills :**
|
||||
- `~/.config/waybar/config` — modules left/center/right
|
||||
- `~/.config/waybar/style.css` — glassmorphism, bordures roses, animations
|
||||
- `~/.config/waybar/cava-waybar.cfg` — config CAVA dédié waybar
|
||||
- `~/.config/waybar/scripts/` — tous les scripts (gpu, network, power-profile, cava, wob, popups GTK)
|
||||
- `~/.config/autostart/waybar.desktop` — démarrage automatique avec COSMIC
|
||||
- `~/.config/autostart/wob.desktop` — démarrage automatique de l'overlay wob
|
||||
|
||||
**Wofi — launcher + menu power :**
|
||||
- `~/.config/wofi/config` — configuration wofi
|
||||
- `~/.config/wofi/style.css` — thème violet-chaton (launcher apps)
|
||||
- `~/.config/wofi/power-style.css` — thème violet-chaton (menu power)
|
||||
|
||||
**wob — overlay volume/luminosité :**
|
||||
- `~/.config/wob.ini` — couleurs violet-chaton, position bas de l'écran
|
||||
|
||||
**Système (avec sudo) :**
|
||||
- `/etc/sudoers.d/waybar-power-profile` — changement de profil énergie sans mot de passe
|
||||
- `/etc/udev/rules.d/90-platform-profile.rules` — permissions groupe `video` sur platform_profile
|
||||
|
||||
**Vivaldi (avec pause de sécurité) :**
|
||||
- Si Vivaldi n'a pas encore été lancé, le script s'arrête et demande de le démarrer une fois
|
||||
- Le thème **Rice Violet-Chaton** est ensuite injecté directement dans `~/.config/vivaldi/Default/Preferences`
|
||||
|
||||
Reconstruit également le **cache bat** pour activer le thème de coloration syntaxique.
|
||||
|
||||
---
|
||||
|
||||
## Étapes manuelles après installation
|
||||
|
||||
### zinit — premier démarrage
|
||||
|
||||
Au premier lancement de zsh, zinit télécharge automatiquement les plugins :
|
||||
- `zsh-autosuggestions` — suggestions en gris au fil de la frappe
|
||||
- `zsh-syntax-highlighting` — coloration des commandes en temps réel
|
||||
- `zsh-completions` — complétion étendue
|
||||
|
||||
Cela peut prendre quelques secondes lors du tout premier démarrage.
|
||||
|
||||
### Polices — vérification
|
||||
|
||||
Si les icônes ne s'affichent pas correctement dans le terminal, forcer la reconstruction du cache de polices :
|
||||
|
||||
```bash
|
||||
fc-cache -f -v
|
||||
```
|
||||
|
||||
Puis sélectionner **JetBrainsMono NL Nerd Font** dans les préférences du terminal.
|
||||
|
||||
### atuin — synchronisation (optionnel)
|
||||
|
||||
atuin peut synchroniser l'historique entre machines. Pour activer la sync :
|
||||
|
||||
```bash
|
||||
atuin register # créer un compte
|
||||
atuin sync # synchroniser
|
||||
```
|
||||
|
||||
Sans compte, atuin fonctionne en local uniquement.
|
||||
|
||||
---
|
||||
|
||||
## Log d'installation
|
||||
|
||||
Chaque installation génère un fichier log horodaté :
|
||||
|
||||
```
|
||||
~/violet-chaton-install-YYYYMMDD-HHMMSS.log
|
||||
```
|
||||
|
||||
En cas d'erreur, consulter ce fichier pour identifier l'étape qui a échoué.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Icônes ne s'affichent pas
|
||||
|
||||
- Vérifier que la police **JetBrainsMono NL Nerd Font** est sélectionnée dans le terminal
|
||||
- Relancer `fc-cache -f` puis rouvrir le terminal
|
||||
|
||||
### zinit ne se lance pas
|
||||
|
||||
- Vérifier que `~/.local/share/zinit/zinit.git/zinit.zsh` existe
|
||||
- Relancer le script d'installation étape 3
|
||||
|
||||
### Injection Vivaldi échoue
|
||||
|
||||
- Lancer Vivaldi une première fois, le fermer complètement, puis relancer `bash install.sh` → option 4
|
||||
|
||||
### Thème bat ne s'applique pas
|
||||
|
||||
```bash
|
||||
bat cache --build
|
||||
```
|
||||
|
||||
### candy-icons ne s'affiche pas dans Nemo
|
||||
|
||||
```bash
|
||||
gtk-update-icon-cache ~/.local/share/icons/candy-icons-master
|
||||
gsettings set org.gnome.desktop.interface icon-theme 'candy-icons-master'
|
||||
```
|
||||
|
||||
### Waybar ne démarre pas
|
||||
|
||||
```bash
|
||||
waybar & # tester manuellement, lire les erreurs
|
||||
pkill -SIGUSR2 waybar # recharger la config à chaud
|
||||
```
|
||||
|
||||
### Popups volume/luminosité ne s'ouvrent pas
|
||||
|
||||
Vérifier que les dépendances Python sont installées :
|
||||
```bash
|
||||
python3 -c "import gi; gi.require_version('GtkLayerShell', '0.1'); print('OK')"
|
||||
```
|
||||
|
||||
### Profil énergie ne change pas au clic
|
||||
|
||||
Vérifier que la règle sudoers et les permissions udev sont en place :
|
||||
```bash
|
||||
ls -la /sys/firmware/acpi/platform_profile # doit être g+w groupe video
|
||||
cat /etc/sudoers.d/waybar-power-profile
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Raccourcis configurés
|
||||
|
||||
| Raccourci | Action |
|
||||
|----------------|--------|
|
||||
| `Ctrl+R` | Historique atuin (fuzzy search) |
|
||||
| `Ctrl+G` | Rechercher un fichier (fzf) |
|
||||
| `Ctrl+F` | Naviguer vers un dossier (fzf) |
|
||||
| `Ctrl+Space` | Accepter la suggestion autosuggestions |
|
||||
| `→` | Accepter la suggestion mot par mot |
|
||||
|
||||
---
|
||||
|
||||
## Alias configurés
|
||||
|
||||
| Alias | Commande réelle |
|
||||
|----------|-----------------|
|
||||
| `ls` | `eza --icons --git --group-directories-first` |
|
||||
| `ll` | `eza -l --icons --git` |
|
||||
| `lt` | `eza --tree --icons` |
|
||||
| `cat` | `batcat --paging=never` |
|
||||
| `bat` | `batcat` |
|
||||
| `fd` | `fdfind` |
|
||||
| `man` | `tldr` |
|
||||
| `lg` | `lazygit` |
|
||||
| `rg` | `rg --color=always` |
|
||||
| `disk` | `ncdu` |
|
||||
| `fetch` | `fastfetch` avec logo chafa |
|
||||
| `pipes` | `pipes.sh` |
|
||||
| `cd` | `zoxide` (avec mémoire) |
|
||||
| `fuck` | correction auto thefuck |
|
||||
| `grep` | `grep --color=auto` |
|
||||
|
||||
---
|
||||
|
||||
## Structure du dossier INSTALL/
|
||||
## Structure
|
||||
|
||||
```
|
||||
INSTALL/
|
||||
├── install.sh script principal — menu interactif
|
||||
├── scripts/
|
||||
│ ├── lib.sh couleurs et fonctions partagées
|
||||
│ ├── 01-packages-apt.sh installation apt + Vivaldi
|
||||
│ ├── 02-packages-manual.sh binaires GitHub + Nerd Fonts + candy-icons
|
||||
│ └── 03-deploy-configs.sh configs, thèmes, COSMIC, Vivaldi
|
||||
├── configs/ copies des fichiers de configuration
|
||||
│ ├── zshrc
|
||||
│ ├── bashrc
|
||||
│ ├── gitconfig
|
||||
│ ├── starship.toml
|
||||
│ ├── bat.conf
|
||||
│ ├── btop.conf
|
||||
│ ├── fastfetch.jsonc
|
||||
│ ├── atuin.toml
|
||||
│ ├── lazygit.yml
|
||||
│ ├── yazi.toml
|
||||
│ ├── glow.yml
|
||||
│ ├── autostart/
|
||||
│ │ ├── waybar.desktop démarrage automatique waybar
|
||||
│ │ └── wob.desktop démarrage automatique wob
|
||||
│ ├── waybar/
|
||||
│ │ ├── config modules 3-pills
|
||||
│ │ ├── cava-waybar.cfg config CAVA dédiée waybar
|
||||
│ │ └── scripts/ gpu, network, power-profile, cava, wob, popups GTK
|
||||
│ ├── wofi/
|
||||
│ │ └── config config wofi
|
||||
│ └── wob/
|
||||
│ └── wob.ini overlay volume/luminosité
|
||||
├── assets/
|
||||
│ └── violet-chaton-logo.png logo fastfetch (1024×1024)
|
||||
└── themes/ tous les fichiers de thème violet-chaton
|
||||
├── violet-chaton-bat.tmTheme
|
||||
├── violet-chaton-btop.theme
|
||||
├── violet-chaton-atuin.toml
|
||||
├── violet-chaton-cava.conf
|
||||
├── violet-chaton-yazi.toml
|
||||
├── violet-chaton-gtk.css thème GTK3 (Nemo + applications GTK)
|
||||
├── violet-chaton-ls-colors.sh
|
||||
├── violet-chaton-vivaldi.json thème Rice Violet-Chaton pour Vivaldi
|
||||
├── violet-chaton.theme.css thème Discord/Vesktop compilé
|
||||
├── violet-chaton-waybar.css CSS 3-pills glassmorphism
|
||||
├── violet-chaton-wofi.css thème wofi launcher
|
||||
├── violet-chaton-wofi-power.css thème wofi menu power
|
||||
├── cosmic/ configs COSMIC déployées automatiquement
|
||||
│ ├── com.system76.CosmicTheme.Dark/v1/
|
||||
│ ├── com.system76.CosmicTheme.Light/v1/
|
||||
│ ├── com.system76.CosmicTheme.Mode/v1/
|
||||
│ ├── com.system76.CosmicTerm/v1/
|
||||
│ └── com.system76.CosmicTk/v1/
|
||||
└── violet-chaton-discord-theme/ sources SCSS du thème (gitignored)
|
||||
install.sh — point d'entree (menu interactif)
|
||||
scripts/
|
||||
lib.sh — fonctions partagees (couleurs palette v2)
|
||||
01-packages-apt.sh — paquets apt
|
||||
02-packages-manual.sh — binaires GitHub + fonts + kitty + AGS
|
||||
03-deploy-configs.sh — deploy configs + themes + COSMIC + GTK
|
||||
configs/
|
||||
zshrc — shell config
|
||||
starship.toml — prompt 3 lignes
|
||||
kitty.conf — terminal + cursor trail + splits
|
||||
kitty/violet-chaton-glow.glsl — shader glow optionnel
|
||||
ags/ — AGS bar + OSD + launcher + notifications
|
||||
...
|
||||
themes/
|
||||
palette.sh — SOURCE DE VERITE UNIQUE
|
||||
violet-chaton-*.{css,toml,theme,rasi,json,sh,tmTheme}
|
||||
cosmic/ — COSMIC Dark + Light + Term + Tk
|
||||
assets/
|
||||
violet-chaton-logo.png
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Mettre à jour les configs
|
||||
## Credits
|
||||
|
||||
Après avoir modifié un fichier de config sur ta machine, re-copier vers INSTALL/ :
|
||||
|
||||
```bash
|
||||
# Exemple : mettre à jour la config starship
|
||||
cp ~/.config/starship.toml ~/Documents/config-violet-chaton/INSTALL/configs/starship.toml
|
||||
|
||||
# Mettre à jour les configs COSMIC
|
||||
cp ~/.config/cosmic/com.system76.CosmicTerm/v1/* \
|
||||
~/Documents/config-violet-chaton/INSTALL/themes/cosmic/com.system76.CosmicTerm/v1/
|
||||
|
||||
# Mettre à jour la config ou le CSS waybar
|
||||
cp ~/.config/waybar/config \
|
||||
~/Documents/config-violet-chaton/INSTALL/configs/waybar/config
|
||||
cp ~/.config/waybar/style.css \
|
||||
~/Documents/config-violet-chaton/INSTALL/themes/violet-chaton-waybar.css
|
||||
|
||||
# Mettre à jour un script waybar
|
||||
cp ~/.config/waybar/scripts/power-profile.sh \
|
||||
~/Documents/config-violet-chaton/INSTALL/configs/waybar/scripts/power-profile.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Palette violet-chaton
|
||||
|
||||
| Rôle | Hex |
|
||||
|------------|-----------|
|
||||
| Background | `#261537` |
|
||||
| BG medium | `#341c4a` |
|
||||
| BG high | `#3d2454` |
|
||||
| Pink | `#ff79c6` |
|
||||
| Purple | `#e79cfe` |
|
||||
| Cyan | `#8be9fd` |
|
||||
| Text | `#f8f8f2` |
|
||||
| Muted | `#6c7086` |
|
||||
| Overlay | `#9399b2` |
|
||||
| Success | `#a6e3a1` |
|
||||
| Warning | `#f9e2af` |
|
||||
| Danger | `#f38ba8` |
|
||||
- Palette : originale, inspiree Mitsuri Kanroji (Demon Slayer)
|
||||
- Font : [Maple Mono NF](https://github.com/subframe7536/maple-font)
|
||||
- Icones : [candy-icons](https://github.com/EliverLara/candy-icons)
|
||||
- Shell : [AGS](https://github.com/Aylur/ags) · [starship](https://starship.rs) · [kitty](https://sw.kovidgoyal.net/kitty/)
|
||||
|
||||
461
ags-v1/config.js
Normal file
461
ags-v1/config.js
Normal file
@@ -0,0 +1,461 @@
|
||||
// ── violet-chaton v2 — AGS config ───────────────────────────────────────────
|
||||
// Barre + OSD + Launcher + Notifications
|
||||
// API: AGS v1.8.2 (.hook/.bind/.poll — no connections)
|
||||
|
||||
const audio = await Service.import("audio");
|
||||
const battery = await Service.import("battery");
|
||||
const network = await Service.import("network");
|
||||
const systemtray = await Service.import("systemtray");
|
||||
const mpris = await Service.import("mpris");
|
||||
const notifications = await Service.import("notifications");
|
||||
const applications = await Service.import("applications");
|
||||
|
||||
// ── Compositor detection ────────────────────────────────────────────────────
|
||||
const compositor = (() => {
|
||||
const session = Utils.exec("bash -c 'echo $XDG_CURRENT_DESKTOP'").trim();
|
||||
if (session.includes("Hyprland")) return "hyprland";
|
||||
if (session.includes("COSMIC")) return "cosmic";
|
||||
return "unknown";
|
||||
})();
|
||||
|
||||
print(`[violet-chaton] compositor: ${compositor}`);
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
// BAR
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
const Separator = () => Widget.Label({ className: "separator", label: "│" });
|
||||
|
||||
const Clock = () => Widget.Label({ className: "clock" })
|
||||
.poll(1000, (self) => { self.label = Utils.exec("date +%H:%M"); });
|
||||
|
||||
const DateWidget = () => Widget.Label({ className: "date" })
|
||||
.poll(60000, (self) => { self.label = Utils.exec("date '+%a %d %b'"); });
|
||||
|
||||
const CPU = () => Widget.Label({ className: "cpu" })
|
||||
.poll(2000, (self) => {
|
||||
const usage = Math.round(
|
||||
Number(Utils.exec(['bash', '-c', "top -bn1 | awk '/^%Cpu/ {print 100-$8}'"]))
|
||||
);
|
||||
self.label = ` ${usage}%`;
|
||||
self.toggleClassName("warning", usage > 70);
|
||||
self.toggleClassName("critical", usage > 90);
|
||||
});
|
||||
|
||||
const RAM = () => Widget.Label({ className: "ram" })
|
||||
.poll(2000, (self) => {
|
||||
const used = Utils.exec(['bash', '-c', "free -m | awk '/^Mem:/ {printf \"%.1f\", $3/1024}'"]);
|
||||
const total = Utils.exec(['bash', '-c', "free -m | awk '/^Mem:/ {printf \"%.1f\", $2/1024}'"]);
|
||||
const pct = Math.round((parseFloat(used) / parseFloat(total)) * 100);
|
||||
self.label = ` ${used}G`;
|
||||
self.toggleClassName("warning", pct > 70);
|
||||
self.toggleClassName("critical", pct > 90);
|
||||
});
|
||||
|
||||
const Network = () => Widget.Label({ className: "network" })
|
||||
.hook(network, (self) => {
|
||||
if (network.primary === "wifi") {
|
||||
const wifi = network.wifi;
|
||||
self.label = ` ${wifi?.ssid || ""}`;
|
||||
self.toggleClassName("wifi", true);
|
||||
self.toggleClassName("disconnected", false);
|
||||
} else if (network.primary === "wired") {
|
||||
self.label = " Eth";
|
||||
self.toggleClassName("wifi", false);
|
||||
self.toggleClassName("disconnected", false);
|
||||
} else {
|
||||
self.label = " ";
|
||||
self.toggleClassName("disconnected", true);
|
||||
}
|
||||
});
|
||||
|
||||
const Volume = () => Widget.Button({
|
||||
className: "volume",
|
||||
onClicked: () => { audio.speaker.isMuted = !audio.speaker.isMuted; },
|
||||
child: Widget.Label()
|
||||
.hook(audio, (self) => {
|
||||
const vol = Math.round((audio.speaker?.volume || 0) * 100);
|
||||
const muted = audio.speaker?.isMuted;
|
||||
const icon = muted ? "" : vol > 66 ? "" : vol > 33 ? "" : "";
|
||||
self.label = `${icon} ${vol}%`;
|
||||
self.parent?.toggleClassName("muted", muted);
|
||||
}, "speaker-changed"),
|
||||
});
|
||||
|
||||
const Battery = () => Widget.Label({
|
||||
className: "battery",
|
||||
visible: battery.bind("available"),
|
||||
}).hook(battery, (self) => {
|
||||
const pct = battery.percent;
|
||||
const charging = battery.charging;
|
||||
const icon = charging ? "" : pct > 80 ? "" : pct > 60 ? "" :
|
||||
pct > 40 ? "" : pct > 20 ? "" : "";
|
||||
self.label = `${icon} ${pct}%`;
|
||||
self.toggleClassName("charging", charging);
|
||||
self.toggleClassName("low", pct <= 20 && !charging);
|
||||
self.toggleClassName("warning", pct <= 30 && !charging);
|
||||
});
|
||||
|
||||
const Media = () => Widget.Label({ className: "media" })
|
||||
.hook(mpris, (self) => {
|
||||
const player = mpris.players[0];
|
||||
if (!player) {
|
||||
self.visible = false;
|
||||
return;
|
||||
}
|
||||
self.visible = true;
|
||||
const artist = player.trackArtists?.join(", ") || "";
|
||||
const title = player.trackTitle || "";
|
||||
const icon = player.playBackStatus === "Playing" ? " " : " ";
|
||||
self.label = `${icon}${artist ? artist + " — " : ""}${title}`.slice(0, 50);
|
||||
self.toggleClassName("paused", player.playBackStatus !== "Playing");
|
||||
});
|
||||
|
||||
const SysTray = () => Widget.Box({
|
||||
className: "systray",
|
||||
children: systemtray.bind("items").as((items) =>
|
||||
items.map((item) =>
|
||||
Widget.Button({
|
||||
child: Widget.Icon({ icon: item.bind("icon"), size: 16 }),
|
||||
tooltipMarkup: item.bind("tooltip-markup"),
|
||||
onPrimaryClick: (_, event) => item.activate(event),
|
||||
onSecondaryClick: (_, event) => item.openMenu(event),
|
||||
})
|
||||
)
|
||||
),
|
||||
});
|
||||
|
||||
const LauncherBtn = () => Widget.Button({
|
||||
className: "launcher-btn",
|
||||
label: "",
|
||||
onClicked: () => App.toggleWindow("launcher"),
|
||||
});
|
||||
|
||||
const PowerBtn = () => Widget.Button({
|
||||
className: "power-btn",
|
||||
label: "⏻",
|
||||
onClicked: () => Utils.exec("bash -c 'systemctl poweroff'"),
|
||||
});
|
||||
|
||||
const Workspaces = () => {
|
||||
if (compositor !== "hyprland") return Widget.Box({});
|
||||
// Hyprland not running — return empty
|
||||
return Widget.Box({});
|
||||
};
|
||||
|
||||
const Bar = (monitor) => Widget.Window({
|
||||
name: `bar-${monitor}`,
|
||||
monitor,
|
||||
anchor: ["top", "left", "right"],
|
||||
exclusivity: "exclusive",
|
||||
className: "bar",
|
||||
child: Widget.CenterBox({
|
||||
startWidget: Widget.Box({
|
||||
className: "modules-left",
|
||||
children: [
|
||||
LauncherBtn(),
|
||||
Separator(),
|
||||
Workspaces(),
|
||||
CPU(),
|
||||
RAM(),
|
||||
],
|
||||
}),
|
||||
centerWidget: Widget.Box({
|
||||
className: "modules-center",
|
||||
children: [
|
||||
Media(),
|
||||
],
|
||||
}),
|
||||
endWidget: Widget.Box({
|
||||
className: "modules-right",
|
||||
hpack: "end",
|
||||
children: [
|
||||
Network(),
|
||||
Separator(),
|
||||
Volume(),
|
||||
Separator(),
|
||||
Battery(),
|
||||
Separator(),
|
||||
DateWidget(),
|
||||
Clock(),
|
||||
Separator(),
|
||||
SysTray(),
|
||||
Separator(),
|
||||
PowerBtn(),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
// OSD
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
const VolumeOSD = () => {
|
||||
const icon = Widget.Label({ className: "icon" });
|
||||
const progress = Widget.ProgressBar();
|
||||
const label = Widget.Label({ className: "label" });
|
||||
|
||||
return Widget.Box({
|
||||
className: "osd",
|
||||
children: [icon, progress, label],
|
||||
}).hook(audio, (self) => {
|
||||
const vol = audio.speaker?.volume || 0;
|
||||
const muted = audio.speaker?.isMuted;
|
||||
icon.label = muted ? "" : vol > 0.66 ? "" : vol > 0.33 ? "" : "";
|
||||
progress.value = vol;
|
||||
label.label = `${Math.round(vol * 100)}%`;
|
||||
}, "speaker-changed");
|
||||
};
|
||||
|
||||
const BrightnessOSD = () => {
|
||||
const icon = Widget.Label({ className: "icon", label: "" });
|
||||
const progress = Widget.ProgressBar();
|
||||
const label = Widget.Label({ className: "label" });
|
||||
|
||||
const getBrightness = () => {
|
||||
try {
|
||||
const max = Number(Utils.exec("brightnessctl max"));
|
||||
const cur = Number(Utils.exec("brightnessctl get"));
|
||||
return max > 0 ? cur / max : 0;
|
||||
} catch {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
return Widget.Box({
|
||||
className: "osd",
|
||||
children: [icon, progress, label],
|
||||
}).poll(500, (self) => {
|
||||
const val = getBrightness();
|
||||
progress.value = val;
|
||||
label.label = `${Math.round(val * 100)}%`;
|
||||
});
|
||||
};
|
||||
|
||||
const OSD = (monitor) => [
|
||||
Widget.Window({
|
||||
name: `osd-volume-${monitor}`,
|
||||
monitor,
|
||||
anchor: ["bottom"],
|
||||
layer: "overlay",
|
||||
visible: false,
|
||||
child: VolumeOSD(),
|
||||
}),
|
||||
Widget.Window({
|
||||
name: `osd-brightness-${monitor}`,
|
||||
monitor,
|
||||
anchor: ["bottom"],
|
||||
layer: "overlay",
|
||||
visible: false,
|
||||
child: BrightnessOSD(),
|
||||
}),
|
||||
];
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
// LAUNCHER
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
const AppItem = (app) => Widget.Button({
|
||||
className: "app-item",
|
||||
onClicked: () => {
|
||||
app.launch();
|
||||
App.closeWindow("launcher");
|
||||
},
|
||||
child: Widget.Box({
|
||||
children: [
|
||||
Widget.Icon({ icon: app.iconName || "application-x-executable", size: 24 }),
|
||||
Widget.Box({
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Label({ label: app.name, xalign: 0, truncate: "end" }),
|
||||
Widget.Label({
|
||||
label: app.description || "",
|
||||
xalign: 0,
|
||||
truncate: "end",
|
||||
css: "color: #716686; font-size: 11px; font-weight: normal;",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
const Launcher = (monitor) => {
|
||||
let apps = applications.list;
|
||||
|
||||
const list = Widget.Box({ vertical: true, spacing: 2 });
|
||||
|
||||
const entry = Widget.Entry({
|
||||
className: "search",
|
||||
placeholderText: "Rechercher...",
|
||||
onAccept: () => {
|
||||
const first = apps[0];
|
||||
if (first) {
|
||||
first.launch();
|
||||
App.closeWindow("launcher");
|
||||
}
|
||||
},
|
||||
onChange: ({ text }) => {
|
||||
apps = applications.query(text || "");
|
||||
list.children = apps.slice(0, 12).map(AppItem);
|
||||
if (apps.length === 0) {
|
||||
list.children = [Widget.Label({
|
||||
className: "no-results",
|
||||
label: "Aucun resultat",
|
||||
})];
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return Widget.Window({
|
||||
name: "launcher",
|
||||
monitor,
|
||||
anchor: ["top"],
|
||||
layer: "overlay",
|
||||
visible: false,
|
||||
keymode: "exclusive",
|
||||
setup: (self) => {
|
||||
self.keybind("Escape", () => App.closeWindow("launcher"));
|
||||
self.hook(App, (_, name, visible) => {
|
||||
if (name === "launcher" && visible) {
|
||||
entry.text = "";
|
||||
apps = applications.list;
|
||||
list.children = apps.slice(0, 12).map(AppItem);
|
||||
entry.grab_focus();
|
||||
}
|
||||
});
|
||||
},
|
||||
child: Widget.Box({
|
||||
className: "launcher",
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Scrollable({
|
||||
hscroll: "never",
|
||||
vscroll: "automatic",
|
||||
css: "min-height: 400px;",
|
||||
child: list,
|
||||
}),
|
||||
entry,
|
||||
],
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
// NOTIFICATIONS
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
notifications.popupTimeout = 5000;
|
||||
notifications.cacheActions = true;
|
||||
|
||||
const NotificationIcon = (notif) => {
|
||||
if (notif.image) {
|
||||
return Widget.Box({
|
||||
css: `
|
||||
min-width: 48px; min-height: 48px;
|
||||
background-image: url("${notif.image}");
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
border-radius: 8px;
|
||||
margin-right: 10px;
|
||||
`,
|
||||
});
|
||||
}
|
||||
return Widget.Icon({
|
||||
icon: notif.appIcon || notif.appEntry || "dialog-information",
|
||||
size: 36,
|
||||
css: "margin-right: 10px;",
|
||||
});
|
||||
};
|
||||
|
||||
const Notification = (notif) => Widget.Box({
|
||||
className: `notification ${notif.urgency}`,
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
children: [
|
||||
NotificationIcon(notif),
|
||||
Widget.Box({
|
||||
vertical: true,
|
||||
hexpand: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
children: [
|
||||
Widget.Label({
|
||||
className: "title",
|
||||
label: notif.summary,
|
||||
xalign: 0,
|
||||
hexpand: true,
|
||||
truncate: "end",
|
||||
}),
|
||||
Widget.Label({
|
||||
className: "time",
|
||||
label: new Date(notif.time * 1000)
|
||||
.toLocaleTimeString("fr-FR", {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
}),
|
||||
}),
|
||||
Widget.Button({
|
||||
className: "close-btn",
|
||||
label: "✕",
|
||||
onClicked: () => notif.close(),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Widget.Label({
|
||||
className: "app-name",
|
||||
label: notif.appName || "",
|
||||
xalign: 0,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
...(notif.body ? [Widget.Label({
|
||||
className: "body",
|
||||
label: notif.body,
|
||||
xalign: 0,
|
||||
wrap: true,
|
||||
useMarkup: true,
|
||||
})] : []),
|
||||
...(notif.actions.length > 0 ? [Widget.Box({
|
||||
className: "actions",
|
||||
children: notif.actions.map((action) =>
|
||||
Widget.Button({
|
||||
label: action.label,
|
||||
onClicked: () => notif.invoke(action.id),
|
||||
})
|
||||
),
|
||||
})] : []),
|
||||
],
|
||||
});
|
||||
|
||||
const Notifications = (monitor) => Widget.Window({
|
||||
name: `notifications-${monitor}`,
|
||||
monitor,
|
||||
anchor: ["top", "right"],
|
||||
layer: "overlay",
|
||||
child: Widget.Box({
|
||||
vertical: true,
|
||||
css: "min-width: 350px;",
|
||||
children: notifications.bind("popups").as((popups) =>
|
||||
popups.map(Notification)
|
||||
),
|
||||
}),
|
||||
});
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
// EXPORT
|
||||
// ══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
export default {
|
||||
style: `${App.configDir}/css/style.css`,
|
||||
windows: [
|
||||
Bar(0),
|
||||
...OSD(0),
|
||||
Launcher(0),
|
||||
Notifications(0),
|
||||
],
|
||||
};
|
||||
385
ags-v1/css/style.css
Normal file
385
ags-v1/css/style.css
Normal file
@@ -0,0 +1,385 @@
|
||||
/* ── violet-chaton v2 — AGS stylesheet ────────────────────────────────────────
|
||||
*
|
||||
* Palette :
|
||||
* crust #1a0e27
|
||||
* base #261537
|
||||
* mantle #341c4a
|
||||
* surface0 #3d2454
|
||||
* surface1 #493161
|
||||
* surface2 #5a3875
|
||||
* magenta #ff4da6 accent primaire
|
||||
* lilac #c9a0ff accent secondaire
|
||||
* mitsuri #9adba8 vert pastel
|
||||
* lavande #a4b4ff bleu-violet
|
||||
* champagne #e8c87a or chaud
|
||||
* danger #f25c7a
|
||||
* text #f0eaf8
|
||||
* subtext1 #c4b8d4
|
||||
* subtext0 #9a8fad
|
||||
* muted #716686
|
||||
*
|
||||
* ─────────────────────────────────────────────────────────────────────────── */
|
||||
|
||||
/* ── Reset ───────────────────────────────────────────────────────────────── */
|
||||
|
||||
* {
|
||||
font-family: "Maple Mono NF", "MapleMono Nerd Font", monospace;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* ══════════════════════════════════════════════════════════════════════════
|
||||
* BAR — 3 pills glassmorphism (island floating)
|
||||
* ══════════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
.bar {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.bar .modules-left,
|
||||
.bar .modules-center,
|
||||
.bar .modules-right {
|
||||
background: alpha(#261537, 0.88);
|
||||
border-radius: 14px;
|
||||
border: 3px solid alpha(#ff4da6, 0.60);
|
||||
margin: 8px 4px;
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.bar .modules-left:hover,
|
||||
.bar .modules-center:hover,
|
||||
.bar .modules-right:hover {
|
||||
border-color: #ff4da6;
|
||||
box-shadow: 0 4px 28px alpha(#c9a0ff, 0.18);
|
||||
}
|
||||
|
||||
/* ── Launcher button ─────────────────────────────────────────────────────── */
|
||||
|
||||
.bar .launcher-btn {
|
||||
color: #ff4da6;
|
||||
font-size: 19px;
|
||||
padding: 0 14px 0 18px;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.bar .launcher-btn:hover {
|
||||
color: #c9a0ff;
|
||||
}
|
||||
|
||||
/* ── Separator ───────────────────────────────────────────────────────────── */
|
||||
|
||||
.bar .separator {
|
||||
color: alpha(#f0eaf8, 0.12);
|
||||
font-size: 11px;
|
||||
padding: 0 4px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
/* ── Clock ───────────────────────────────────────────────────────────────── */
|
||||
|
||||
.bar .clock {
|
||||
color: #ff4da6;
|
||||
font-weight: 900;
|
||||
font-size: 14px;
|
||||
letter-spacing: 0.04em;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.bar .clock:hover {
|
||||
color: #c9a0ff;
|
||||
}
|
||||
|
||||
/* ── Date ────────────────────────────────────────────────────────────────── */
|
||||
|
||||
.bar .date {
|
||||
color: #a4b4ff;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
padding: 0 10px 0 2px;
|
||||
}
|
||||
|
||||
/* ── System modules ──────────────────────────────────────────────────────── */
|
||||
|
||||
.bar .cpu { color: #a4b4ff; }
|
||||
.bar .cpu.warning { color: #e8c87a; }
|
||||
.bar .cpu.critical { color: #f25c7a; }
|
||||
|
||||
.bar .ram { color: #ff4da6; }
|
||||
.bar .ram.warning { color: #e8c87a; }
|
||||
.bar .ram.critical { color: #f25c7a; }
|
||||
|
||||
.bar .temp {
|
||||
color: alpha(#a4b4ff, 0.60);
|
||||
font-size: 11px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.bar .temp.warning { color: #e8c87a; }
|
||||
.bar .temp.critical { color: #f25c7a; }
|
||||
|
||||
/* ── Network ─────────────────────────────────────────────────────────────── */
|
||||
|
||||
.bar .network {
|
||||
color: #a4b4ff;
|
||||
font-size: 11px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.bar .network.disconnected { color: #f25c7a; }
|
||||
.bar .network.wifi { color: alpha(#a4b4ff, 0.80); }
|
||||
|
||||
/* ── Volume ──────────────────────────────────────────────────────────────── */
|
||||
|
||||
.bar .volume { color: #ff4da6; }
|
||||
.bar .volume.muted { color: alpha(#ff4da6, 0.30); }
|
||||
|
||||
/* ── Battery ─────────────────────────────────────────────────────────────── */
|
||||
|
||||
.bar .battery { color: #ff4da6; }
|
||||
.bar .battery.charging { color: #9adba8; }
|
||||
.bar .battery.low { color: #f25c7a; }
|
||||
.bar .battery.warning { color: #e8c87a; }
|
||||
|
||||
/* ── Media (MPRIS) ───────────────────────────────────────────────────────── */
|
||||
|
||||
.bar .media {
|
||||
color: #c9a0ff;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.bar .media.paused {
|
||||
color: alpha(#c9a0ff, 0.50);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* ── Systray ─────────────────────────────────────────────────────────────── */
|
||||
|
||||
.bar .systray { padding: 0 8px; }
|
||||
.bar .systray .passive { opacity: 0.5; }
|
||||
|
||||
/* ── Workspaces (Hyprland only) ──────────────────────────────────────────── */
|
||||
|
||||
.bar .workspaces button {
|
||||
background: transparent;
|
||||
color: #716686;
|
||||
min-width: 24px;
|
||||
min-height: 24px;
|
||||
border-radius: 8px;
|
||||
margin: 2px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.bar .workspaces button.active {
|
||||
background: alpha(#ff4da6, 0.20);
|
||||
color: #ff4da6;
|
||||
border: 1px solid alpha(#ff4da6, 0.40);
|
||||
}
|
||||
|
||||
.bar .workspaces button.occupied {
|
||||
color: #c9a0ff;
|
||||
}
|
||||
|
||||
.bar .workspaces button:hover {
|
||||
background: alpha(#c9a0ff, 0.12);
|
||||
color: #c9a0ff;
|
||||
}
|
||||
|
||||
/* ── Power button ────────────────────────────────────────────────────────── */
|
||||
|
||||
.bar .power-btn {
|
||||
color: #f25c7a;
|
||||
font-size: 15px;
|
||||
padding: 0 14px 0 8px;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.bar .power-btn:hover { color: #ff4da6; }
|
||||
|
||||
/* ── Hover global modules ────────────────────────────────────────────────── */
|
||||
|
||||
.bar .cpu:hover,
|
||||
.bar .ram:hover,
|
||||
.bar .temp:hover,
|
||||
.bar .network:hover,
|
||||
.bar .volume:hover,
|
||||
.bar .battery:hover {
|
||||
color: #c9a0ff;
|
||||
}
|
||||
|
||||
/* ══════════════════════════════════════════════════════════════════════════
|
||||
* OSD — volume / brightness overlay
|
||||
* ══════════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
.osd {
|
||||
background: alpha(#261537, 0.92);
|
||||
border-radius: 14px;
|
||||
border: 2px solid alpha(#ff4da6, 0.40);
|
||||
padding: 12px 20px;
|
||||
margin: 0 0 40px 0;
|
||||
}
|
||||
|
||||
.osd .icon {
|
||||
color: #ff4da6;
|
||||
font-size: 24px;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.osd progressbar trough {
|
||||
background: #3d2454;
|
||||
border-radius: 8px;
|
||||
min-height: 8px;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.osd progressbar progress {
|
||||
border-radius: 8px;
|
||||
min-height: 8px;
|
||||
background: linear-gradient(to right, #ff4da6, #c9a0ff, #a4b4ff, #9adba8);
|
||||
}
|
||||
|
||||
.osd .label {
|
||||
color: #f0eaf8;
|
||||
font-size: 12px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
/* ══════════════════════════════════════════════════════════════════════════
|
||||
* LAUNCHER — app search
|
||||
* ══════════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
.launcher {
|
||||
background: alpha(#1a0e27, 0.94);
|
||||
border-radius: 14px;
|
||||
border: 2px solid alpha(#ff4da6, 0.38);
|
||||
padding: 10px;
|
||||
min-width: 500px;
|
||||
}
|
||||
|
||||
.launcher .search {
|
||||
background: alpha(#261537, 0.75);
|
||||
border-radius: 12px;
|
||||
border: 1px solid alpha(#5a3875, 0.50);
|
||||
padding: 9px 14px;
|
||||
color: #f0eaf8;
|
||||
caret-color: #ff4da6;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.launcher .search:focus {
|
||||
border-color: alpha(#ff4da6, 0.60);
|
||||
}
|
||||
|
||||
.launcher .app-item {
|
||||
background: transparent;
|
||||
border-radius: 8px;
|
||||
padding: 7px 10px;
|
||||
color: #f0eaf8;
|
||||
}
|
||||
|
||||
.launcher .app-item:hover,
|
||||
.launcher .app-item:focus {
|
||||
background: alpha(#ff4da6, 0.16);
|
||||
border: 1px solid alpha(#ff4da6, 0.32);
|
||||
}
|
||||
|
||||
.launcher .app-item:hover label,
|
||||
.launcher .app-item:focus label {
|
||||
color: #ff4da6;
|
||||
}
|
||||
|
||||
.launcher .app-item image {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.launcher .no-results {
|
||||
color: #716686;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/* ══════════════════════════════════════════════════════════════════════════
|
||||
* NOTIFICATIONS
|
||||
* ══════════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
.notification {
|
||||
background: alpha(#261537, 0.94);
|
||||
border-radius: 14px;
|
||||
border: 2px solid alpha(#c9a0ff, 0.30);
|
||||
padding: 12px;
|
||||
margin: 8px;
|
||||
min-width: 350px;
|
||||
}
|
||||
|
||||
.notification .title {
|
||||
color: #ff4da6;
|
||||
font-weight: bold;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.notification .body {
|
||||
color: #c4b8d4;
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.notification .app-name {
|
||||
color: #716686;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.notification .time {
|
||||
color: #716686;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.notification .close-btn {
|
||||
color: #716686;
|
||||
font-size: 14px;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
padding: 2px 6px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.notification .close-btn:hover {
|
||||
color: #f25c7a;
|
||||
background: alpha(#f25c7a, 0.12);
|
||||
}
|
||||
|
||||
.notification .actions button {
|
||||
background: alpha(#5a3875, 0.50);
|
||||
color: #c9a0ff;
|
||||
border-radius: 8px;
|
||||
padding: 4px 12px;
|
||||
margin: 4px 4px 0 0;
|
||||
}
|
||||
|
||||
.notification .actions button:hover {
|
||||
background: alpha(#ff4da6, 0.20);
|
||||
color: #ff4da6;
|
||||
}
|
||||
|
||||
/* ── Urgency levels ──────────────────────────────────────────────────────── */
|
||||
|
||||
.notification.critical {
|
||||
border-color: alpha(#f25c7a, 0.60);
|
||||
}
|
||||
|
||||
.notification.critical .title {
|
||||
color: #f25c7a;
|
||||
}
|
||||
|
||||
/* ══════════════════════════════════════════════════════════════════════════
|
||||
* TOOLTIP — shared
|
||||
* ══════════════════════════════════════════════════════════════════════════ */
|
||||
|
||||
tooltip {
|
||||
background: alpha(#1a0e27, 0.96);
|
||||
border: 1px solid alpha(#ff4da6, 0.30);
|
||||
border-radius: 10px;
|
||||
color: #f0eaf8;
|
||||
padding: 6px 10px;
|
||||
}
|
||||
228
ags-v1/widgets/Bar.js
Normal file
228
ags-v1/widgets/Bar.js
Normal file
@@ -0,0 +1,228 @@
|
||||
// ── violet-chaton v2 — Bar widget ───────────────────────────────────────────
|
||||
// 3 pills glassmorphism — modulaire selon compositor
|
||||
|
||||
const audio = Service.import("audio");
|
||||
const battery = Service.import("battery");
|
||||
const network = Service.import("network");
|
||||
const systemtray = Service.import("systemtray");
|
||||
const mpris = Service.import("mpris");
|
||||
|
||||
// ── Helpers ─────────────────────────────────────────────────────────────────
|
||||
|
||||
const Separator = () => Widget.Label({ className: "separator", label: "│" });
|
||||
|
||||
const Clock = () => Widget.Label({
|
||||
className: "clock",
|
||||
connections: [[1000, (self) => {
|
||||
self.label = Utils.exec("date +%H:%M");
|
||||
}]],
|
||||
});
|
||||
|
||||
const DateWidget = () => Widget.Label({
|
||||
className: "date",
|
||||
connections: [[60000, (self) => {
|
||||
self.label = Utils.exec("date '+%a %d %b'");
|
||||
}]],
|
||||
});
|
||||
|
||||
// ── System ──────────────────────────────────────────────────────────────────
|
||||
|
||||
const CPU = () => Widget.Label({
|
||||
className: "cpu",
|
||||
connections: [[2000, (self) => {
|
||||
const usage = Math.round(
|
||||
Number(Utils.exec(`bash -c "top -bn1 | awk '/^%Cpu/ {print 100-$8}'"`)
|
||||
));
|
||||
self.label = ` ${usage}%`;
|
||||
self.toggleClassName("warning", usage > 70);
|
||||
self.toggleClassName("critical", usage > 90);
|
||||
}]],
|
||||
});
|
||||
|
||||
const RAM = () => Widget.Label({
|
||||
className: "ram",
|
||||
connections: [[2000, (self) => {
|
||||
const used = Utils.exec(`bash -c "free -m | awk '/^Mem:/ {printf \"%.1f\", $3/1024}'"`)
|
||||
const total = Utils.exec(`bash -c "free -m | awk '/^Mem:/ {printf \"%.1f\", $2/1024}'"`)
|
||||
const pct = Math.round((parseFloat(used) / parseFloat(total)) * 100);
|
||||
self.label = ` ${used}G`;
|
||||
self.toggleClassName("warning", pct > 70);
|
||||
self.toggleClassName("critical", pct > 90);
|
||||
}]],
|
||||
});
|
||||
|
||||
// ── Network ─────────────────────────────────────────────────────────────────
|
||||
|
||||
const Network = () => Widget.Label({
|
||||
className: "network",
|
||||
connections: [[network, (self) => {
|
||||
if (network.primary === "wifi") {
|
||||
const wifi = network.wifi;
|
||||
self.label = ` ${wifi?.ssid || ""}`;
|
||||
self.toggleClassName("wifi", true);
|
||||
self.toggleClassName("disconnected", false);
|
||||
} else if (network.primary === "wired") {
|
||||
self.label = " Eth";
|
||||
self.toggleClassName("wifi", false);
|
||||
self.toggleClassName("disconnected", false);
|
||||
} else {
|
||||
self.label = " ";
|
||||
self.toggleClassName("disconnected", true);
|
||||
}
|
||||
}]],
|
||||
});
|
||||
|
||||
// ── Volume ──────────────────────────────────────────────────────────────────
|
||||
|
||||
const Volume = () => Widget.Button({
|
||||
className: "volume",
|
||||
onClicked: () => { audio.speaker.isMuted = !audio.speaker.isMuted; },
|
||||
child: Widget.Label({
|
||||
connections: [[audio, (self) => {
|
||||
const vol = Math.round((audio.speaker?.volume || 0) * 100);
|
||||
const muted = audio.speaker?.isMuted;
|
||||
const icon = muted ? "" : vol > 66 ? "" : vol > 33 ? "" : "";
|
||||
self.label = `${icon} ${vol}%`;
|
||||
self.parent?.toggleClassName("muted", muted);
|
||||
}, "speaker-changed"]],
|
||||
}),
|
||||
});
|
||||
|
||||
// ── Battery ─────────────────────────────────────────────────────────────────
|
||||
|
||||
const Battery = () => Widget.Label({
|
||||
className: "battery",
|
||||
visible: battery.bind("available"),
|
||||
connections: [[battery, (self) => {
|
||||
const pct = battery.percent;
|
||||
const charging = battery.charging;
|
||||
const icon = charging ? "" : pct > 80 ? "" : pct > 60 ? "" :
|
||||
pct > 40 ? "" : pct > 20 ? "" : "";
|
||||
self.label = `${icon} ${pct}%`;
|
||||
self.toggleClassName("charging", charging);
|
||||
self.toggleClassName("low", pct <= 20 && !charging);
|
||||
self.toggleClassName("warning", pct <= 30 && !charging);
|
||||
}]],
|
||||
});
|
||||
|
||||
// ── Media ───────────────────────────────────────────────────────────────────
|
||||
|
||||
const Media = () => Widget.Label({
|
||||
className: "media",
|
||||
connections: [[mpris, (self) => {
|
||||
const player = mpris.players[0];
|
||||
if (!player) {
|
||||
self.visible = false;
|
||||
return;
|
||||
}
|
||||
self.visible = true;
|
||||
const artist = player.trackArtists?.join(", ") || "";
|
||||
const title = player.trackTitle || "";
|
||||
const icon = player.playBackStatus === "Playing" ? " " : " ";
|
||||
self.label = `${icon}${artist ? artist + " — " : ""}${title}`.slice(0, 50);
|
||||
self.toggleClassName("paused", player.playBackStatus !== "Playing");
|
||||
}]],
|
||||
});
|
||||
|
||||
// ── Systray ─────────────────────────────────────────────────────────────────
|
||||
|
||||
const SysTray = () => Widget.Box({
|
||||
className: "systray",
|
||||
children: systemtray.bind("items").transform((items) =>
|
||||
items.map((item) =>
|
||||
Widget.Button({
|
||||
child: Widget.Icon({ icon: item.bind("icon"), size: 16 }),
|
||||
tooltipMarkup: item.bind("tooltip-markup"),
|
||||
onPrimaryClick: (_, event) => item.activate(event),
|
||||
onSecondaryClick: (_, event) => item.openMenu(event),
|
||||
})
|
||||
)
|
||||
),
|
||||
});
|
||||
|
||||
// ── Launcher button ─────────────────────────────────────────────────────────
|
||||
|
||||
const LauncherBtn = () => Widget.Button({
|
||||
className: "launcher-btn",
|
||||
label: "",
|
||||
onClicked: () => App.toggleWindow("launcher"),
|
||||
});
|
||||
|
||||
// ── Power button ────────────────────────────────────────────────────────────
|
||||
|
||||
const PowerBtn = () => Widget.Button({
|
||||
className: "power-btn",
|
||||
label: "⏻",
|
||||
onClicked: () => Utils.exec("bash -c 'systemctl poweroff'"),
|
||||
});
|
||||
|
||||
// ── Workspaces (Hyprland only) ──────────────────────────────────────────────
|
||||
|
||||
const Workspaces = (compositor) => {
|
||||
if (compositor !== "hyprland") return Widget.Box({});
|
||||
|
||||
const hyprland = Service.import("hyprland");
|
||||
return Widget.Box({
|
||||
className: "workspaces",
|
||||
children: hyprland.bind("workspaces").transform((ws) =>
|
||||
ws.sort((a, b) => a.id - b.id)
|
||||
.filter((w) => w.id > 0)
|
||||
.map((w) =>
|
||||
Widget.Button({
|
||||
onClicked: () => hyprland.messageAsync(`dispatch workspace ${w.id}`),
|
||||
child: Widget.Label({ label: `${w.id}` }),
|
||||
className: hyprland.active.workspace.bind("id").transform(
|
||||
(id) => id === w.id ? "active" : w.windows > 0 ? "occupied" : ""
|
||||
),
|
||||
})
|
||||
)
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
// ── Bar assembly ────────────────────────────────────────────────────────────
|
||||
|
||||
export const Bar = (monitor, compositor) => Widget.Window({
|
||||
name: `bar-${monitor}`,
|
||||
monitor,
|
||||
anchor: ["top", "left", "right"],
|
||||
exclusivity: "exclusive",
|
||||
className: "bar",
|
||||
child: Widget.CenterBox({
|
||||
startWidget: Widget.Box({
|
||||
className: "modules-left",
|
||||
children: [
|
||||
LauncherBtn(),
|
||||
Separator(),
|
||||
Workspaces(compositor),
|
||||
Separator(),
|
||||
CPU(),
|
||||
RAM(),
|
||||
],
|
||||
}),
|
||||
centerWidget: Widget.Box({
|
||||
className: "modules-center",
|
||||
children: [
|
||||
Media(),
|
||||
],
|
||||
}),
|
||||
endWidget: Widget.Box({
|
||||
className: "modules-right",
|
||||
hpack: "end",
|
||||
children: [
|
||||
Network(),
|
||||
Separator(),
|
||||
Volume(),
|
||||
Separator(),
|
||||
Battery(),
|
||||
Separator(),
|
||||
DateWidget(),
|
||||
Clock(),
|
||||
Separator(),
|
||||
SysTray(),
|
||||
Separator(),
|
||||
PowerBtn(),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
});
|
||||
99
ags-v1/widgets/Launcher.js
Normal file
99
ags-v1/widgets/Launcher.js
Normal file
@@ -0,0 +1,99 @@
|
||||
// ── violet-chaton v2 — Launcher widget ──────────────────────────────────────
|
||||
// App launcher avec recherche fuzzy
|
||||
|
||||
const applications = Service.import("applications");
|
||||
|
||||
const AppItem = (app) => Widget.Button({
|
||||
className: "app-item",
|
||||
onClicked: () => {
|
||||
app.launch();
|
||||
App.closeWindow("launcher");
|
||||
},
|
||||
child: Widget.Box({
|
||||
children: [
|
||||
Widget.Icon({ icon: app.iconName || "application-x-executable", size: 24 }),
|
||||
Widget.Box({
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Label({
|
||||
label: app.name,
|
||||
xalign: 0,
|
||||
truncate: "end",
|
||||
}),
|
||||
Widget.Label({
|
||||
label: app.description || "",
|
||||
xalign: 0,
|
||||
truncate: "end",
|
||||
className: "description",
|
||||
css: "color: #716686; font-size: 11px; font-weight: normal;",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
export const Launcher = (monitor) => {
|
||||
let apps = applications.list;
|
||||
|
||||
const list = Widget.Box({
|
||||
vertical: true,
|
||||
spacing: 2,
|
||||
});
|
||||
|
||||
const entry = Widget.Entry({
|
||||
className: "search",
|
||||
placeholderText: "Rechercher...",
|
||||
onAccept: () => {
|
||||
const first = apps[0];
|
||||
if (first) {
|
||||
first.launch();
|
||||
App.closeWindow("launcher");
|
||||
}
|
||||
},
|
||||
onChange: ({ text }) => {
|
||||
apps = applications.query(text || "");
|
||||
list.children = apps.slice(0, 12).map(AppItem);
|
||||
|
||||
if (apps.length === 0) {
|
||||
list.children = [Widget.Label({
|
||||
className: "no-results",
|
||||
label: "Aucun resultat",
|
||||
})];
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return Widget.Window({
|
||||
name: "launcher",
|
||||
monitor,
|
||||
anchor: ["top"],
|
||||
layer: "overlay",
|
||||
visible: false,
|
||||
keymode: "exclusive",
|
||||
setup: (self) => {
|
||||
self.keybind("Escape", () => App.closeWindow("launcher"));
|
||||
self.hook(App, (_, name, visible) => {
|
||||
if (name === "launcher" && visible) {
|
||||
entry.text = "";
|
||||
apps = applications.list;
|
||||
list.children = apps.slice(0, 12).map(AppItem);
|
||||
entry.grab_focus();
|
||||
}
|
||||
});
|
||||
},
|
||||
child: Widget.Box({
|
||||
className: "launcher",
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Scrollable({
|
||||
hscroll: "never",
|
||||
vscroll: "automatic",
|
||||
css: "min-height: 400px;",
|
||||
child: list,
|
||||
}),
|
||||
entry,
|
||||
],
|
||||
}),
|
||||
});
|
||||
};
|
||||
105
ags-v1/widgets/Notifications.js
Normal file
105
ags-v1/widgets/Notifications.js
Normal file
@@ -0,0 +1,105 @@
|
||||
// ── violet-chaton v2 — Notifications widget ─────────────────────────────────
|
||||
// Popup notifications stylees — urgency-aware
|
||||
|
||||
const notifications = Service.import("notifications");
|
||||
|
||||
// Ne pas déranger
|
||||
notifications.popupTimeout = 5000;
|
||||
notifications.cacheActions = true;
|
||||
|
||||
const NotificationIcon = (notif) => {
|
||||
if (notif.image) {
|
||||
return Widget.Box({
|
||||
css: `
|
||||
min-width: 48px; min-height: 48px;
|
||||
background-image: url("${notif.image}");
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
border-radius: 8px;
|
||||
margin-right: 10px;
|
||||
`,
|
||||
});
|
||||
}
|
||||
return Widget.Icon({
|
||||
icon: notif.appIcon || notif.appEntry || "dialog-information",
|
||||
size: 36,
|
||||
css: "margin-right: 10px;",
|
||||
});
|
||||
};
|
||||
|
||||
const Notification = (notif) => Widget.Box({
|
||||
className: `notification ${notif.urgency}`,
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
children: [
|
||||
NotificationIcon(notif),
|
||||
Widget.Box({
|
||||
vertical: true,
|
||||
hexpand: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
children: [
|
||||
Widget.Label({
|
||||
className: "title",
|
||||
label: notif.summary,
|
||||
xalign: 0,
|
||||
hexpand: true,
|
||||
truncate: "end",
|
||||
}),
|
||||
Widget.Label({
|
||||
className: "time",
|
||||
label: new Date(notif.time * 1000)
|
||||
.toLocaleTimeString("fr-FR", {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
}),
|
||||
}),
|
||||
Widget.Button({
|
||||
className: "close-btn",
|
||||
label: "✕",
|
||||
onClicked: () => notif.close(),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Widget.Label({
|
||||
className: "app-name",
|
||||
label: notif.appName || "",
|
||||
xalign: 0,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
...(notif.body ? [Widget.Label({
|
||||
className: "body",
|
||||
label: notif.body,
|
||||
xalign: 0,
|
||||
wrap: true,
|
||||
useMarkup: true,
|
||||
})] : []),
|
||||
...(notif.actions.length > 0 ? [Widget.Box({
|
||||
className: "actions",
|
||||
children: notif.actions.map((action) =>
|
||||
Widget.Button({
|
||||
label: action.label,
|
||||
onClicked: () => notif.invoke(action.id),
|
||||
})
|
||||
),
|
||||
})] : []),
|
||||
],
|
||||
});
|
||||
|
||||
export const Notifications = (monitor) => Widget.Window({
|
||||
name: `notifications-${monitor}`,
|
||||
monitor,
|
||||
anchor: ["top", "right"],
|
||||
layer: "overlay",
|
||||
child: Widget.Box({
|
||||
vertical: true,
|
||||
css: "min-width: 350px;",
|
||||
children: notifications.bind("popups").transform((popups) =>
|
||||
popups.map(Notification)
|
||||
),
|
||||
}),
|
||||
});
|
||||
95
ags-v1/widgets/OSD.js
Normal file
95
ags-v1/widgets/OSD.js
Normal file
@@ -0,0 +1,95 @@
|
||||
// ── violet-chaton v2 — OSD widget ───────────────────────────────────────────
|
||||
// Overlay volume / brightness avec gradient Mitsuri
|
||||
|
||||
const audio = Service.import("audio");
|
||||
|
||||
// ── OSD reveal timer ────────────────────────────────────────────────────────
|
||||
|
||||
let osdTimeout = null;
|
||||
|
||||
const showOSD = (window) => {
|
||||
window.visible = true;
|
||||
if (osdTimeout) clearTimeout(osdTimeout);
|
||||
osdTimeout = setTimeout(() => {
|
||||
window.visible = false;
|
||||
}, 1500);
|
||||
};
|
||||
|
||||
// ── Volume OSD ──────────────────────────────────────────────────────────────
|
||||
|
||||
const VolumeOSD = () => {
|
||||
const icon = Widget.Label({ className: "icon" });
|
||||
const progress = Widget.ProgressBar();
|
||||
const label = Widget.Label({ className: "label" });
|
||||
|
||||
const box = Widget.Box({
|
||||
className: "osd",
|
||||
children: [icon, progress, label],
|
||||
connections: [[audio, (self) => {
|
||||
const vol = audio.speaker?.volume || 0;
|
||||
const muted = audio.speaker?.isMuted;
|
||||
icon.label = muted ? "" : vol > 0.66 ? "" : vol > 0.33 ? "" : "";
|
||||
progress.value = vol;
|
||||
label.label = `${Math.round(vol * 100)}%`;
|
||||
}, "speaker-changed"]],
|
||||
});
|
||||
|
||||
return box;
|
||||
};
|
||||
|
||||
// ── Brightness OSD ──────────────────────────────────────────────────────────
|
||||
|
||||
const BrightnessOSD = () => {
|
||||
const icon = Widget.Label({ className: "icon", label: "" });
|
||||
const progress = Widget.ProgressBar();
|
||||
const label = Widget.Label({ className: "label" });
|
||||
|
||||
const getBrightness = () => {
|
||||
try {
|
||||
const max = Number(Utils.exec("brightnessctl max"));
|
||||
const cur = Number(Utils.exec("brightnessctl get"));
|
||||
return max > 0 ? cur / max : 0;
|
||||
} catch {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
const box = Widget.Box({
|
||||
className: "osd",
|
||||
children: [icon, progress, label],
|
||||
connections: [[500, (self) => {
|
||||
const val = getBrightness();
|
||||
progress.value = val;
|
||||
label.label = `${Math.round(val * 100)}%`;
|
||||
}]],
|
||||
});
|
||||
|
||||
return box;
|
||||
};
|
||||
|
||||
// ── OSD windows ─────────────────────────────────────────────────────────────
|
||||
|
||||
export const OSD = (monitor) => {
|
||||
const volumeWin = Widget.Window({
|
||||
name: `osd-volume-${monitor}`,
|
||||
monitor,
|
||||
anchor: ["bottom"],
|
||||
layer: "overlay",
|
||||
visible: false,
|
||||
child: VolumeOSD(),
|
||||
});
|
||||
|
||||
const brightnessWin = Widget.Window({
|
||||
name: `osd-brightness-${monitor}`,
|
||||
monitor,
|
||||
anchor: ["bottom"],
|
||||
layer: "overlay",
|
||||
visible: false,
|
||||
child: BrightnessOSD(),
|
||||
});
|
||||
|
||||
// Auto-show on volume change
|
||||
Utils.merge([audio.speaker?.bind("volume")], () => showOSD(volumeWin));
|
||||
|
||||
return [volumeWin, brightnessWin];
|
||||
};
|
||||
2
ags-v3/.gitignore
vendored
Normal file
2
ags-v3/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
node_modules/
|
||||
@girs/
|
||||
33
ags-v3/app.ts
Normal file
33
ags-v3/app.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import app from "ags/gtk3/app"
|
||||
import style from "./style.scss"
|
||||
import Heartbeat from "./widget/Heartbeat"
|
||||
import Bar from "./widget/Bar"
|
||||
import BrainPower from "./widget/panels/BrainPower"
|
||||
|
||||
app.start({
|
||||
css: style,
|
||||
main() {
|
||||
const monitors = app.get_monitors()
|
||||
for (const monitor of monitors) {
|
||||
Heartbeat(monitor)
|
||||
Bar(monitor)
|
||||
}
|
||||
// Brain Power on primary monitor only
|
||||
const primary = monitors[0]
|
||||
if (primary) BrainPower(primary)
|
||||
},
|
||||
requestHandler(request: any, res: (response: any) => void) {
|
||||
const cmd = String(request)
|
||||
if (cmd.includes("toggle-brain")) {
|
||||
const win = app.get_window("brain-power")
|
||||
if (win) {
|
||||
win.visible = !win.visible
|
||||
res("toggled")
|
||||
} else {
|
||||
res("window not found")
|
||||
}
|
||||
} else {
|
||||
res(`unknown: '${cmd}'`)
|
||||
}
|
||||
},
|
||||
})
|
||||
21
ags-v3/env.d.ts
vendored
Normal file
21
ags-v3/env.d.ts
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
declare const SRC: string
|
||||
|
||||
declare module "inline:*" {
|
||||
const content: string
|
||||
export default content
|
||||
}
|
||||
|
||||
declare module "*.scss" {
|
||||
const content: string
|
||||
export default content
|
||||
}
|
||||
|
||||
declare module "*.blp" {
|
||||
const content: string
|
||||
export default content
|
||||
}
|
||||
|
||||
declare module "*.css" {
|
||||
const content: string
|
||||
export default content
|
||||
}
|
||||
122
ags-v3/lib/brain.ts
Normal file
122
ags-v3/lib/brain.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
import GLib from "gi://GLib"
|
||||
import { exec } from "ags/process"
|
||||
|
||||
const BRAIN_ROOT = GLib.getenv("BRAIN_ROOT")
|
||||
|| readFile(GLib.get_home_dir() + "/.config/brain-path")?.trim()
|
||||
|| GLib.get_home_dir() + "/Dev/Brain"
|
||||
|
||||
export interface BrainState {
|
||||
focus: string
|
||||
todos: { open: number; done: number; top3: string[] }
|
||||
session: string | null
|
||||
intentions: { active: number; names: string[] }
|
||||
repos: { name: string; status: string }[]
|
||||
commits: string[]
|
||||
kernelVersion: string
|
||||
}
|
||||
|
||||
function readFile(path: string): string | null {
|
||||
try {
|
||||
const [ok, contents] = GLib.file_get_contents(path)
|
||||
if (ok && contents) {
|
||||
return new TextDecoder().decode(contents)
|
||||
}
|
||||
} catch {}
|
||||
return null
|
||||
}
|
||||
|
||||
function sh(cmd: string): string {
|
||||
try { return exec(`bash -c "${cmd}"`).trim() } catch { return "" }
|
||||
}
|
||||
|
||||
export function getFocus(): string {
|
||||
const content = readFile(`${BRAIN_ROOT}/focus.md`)
|
||||
if (!content) return "no focus"
|
||||
const lines = content.split("\n").filter(
|
||||
(l) => !l.startsWith("#") && !l.startsWith(">") && l.trim() !== "" && !l.startsWith("---")
|
||||
)
|
||||
return lines[0]?.trim() || "no focus"
|
||||
}
|
||||
|
||||
export function getTodos(): { open: number; done: number; top3: string[] } {
|
||||
const content = readFile(`${BRAIN_ROOT}/todo/README.md`)
|
||||
if (!content) return { open: 0, done: 0, top3: [] }
|
||||
|
||||
const lines = content.split("\n")
|
||||
const open: string[] = []
|
||||
let done = 0
|
||||
|
||||
for (const line of lines) {
|
||||
const trimmed = line.trim()
|
||||
if (trimmed.startsWith("- [ ]") || trimmed.startsWith("⬜")) {
|
||||
open.push(trimmed.replace(/^- \[ \] /, "").replace(/^⬜ ?/, ""))
|
||||
} else if (trimmed.startsWith("- [x]") || trimmed.startsWith("✅")) {
|
||||
done++
|
||||
}
|
||||
}
|
||||
|
||||
return { open: open.length, done, top3: open.slice(0, 3) }
|
||||
}
|
||||
|
||||
export function getSession(): string | null {
|
||||
try {
|
||||
const [ok, contents] = GLib.file_get_contents(
|
||||
GLib.get_home_dir() + "/.claude/session-role"
|
||||
)
|
||||
if (ok && contents) {
|
||||
return new TextDecoder().decode(contents).trim()
|
||||
}
|
||||
} catch {}
|
||||
return null
|
||||
}
|
||||
|
||||
export function getIntentions(): { active: number; names: string[] } {
|
||||
try {
|
||||
const out = sh(`grep -rl 'status: active' ${BRAIN_ROOT}/intentions/*.yml 2>/dev/null | while read f; do grep '^name:' "$f" | head -1 | sed 's/name: //'; done`)
|
||||
const names = out.split("\n").filter(Boolean)
|
||||
return { active: names.length, names: names.slice(0, 5) }
|
||||
} catch {
|
||||
return { active: 0, names: [] }
|
||||
}
|
||||
}
|
||||
|
||||
export function getRepoStatus(): { name: string; status: string }[] {
|
||||
const repos = [
|
||||
{ name: "brain", path: BRAIN_ROOT },
|
||||
{ name: "toolkit", path: `${BRAIN_ROOT}/toolkit` },
|
||||
{ name: "progression", path: `${BRAIN_ROOT}/progression` },
|
||||
]
|
||||
|
||||
return repos.map(({ name, path }) => {
|
||||
const count = sh(`git -C ${path} status --short 2>/dev/null | wc -l`)
|
||||
const n = parseInt(count) || 0
|
||||
return {
|
||||
name,
|
||||
status: n === 0 ? "✅" : `⚠️ ${n} fichiers`,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getRecentCommits(): string[] {
|
||||
const out = sh(`git -C ${BRAIN_ROOT} log --oneline -5 2>/dev/null`)
|
||||
return out.split("\n").filter(Boolean)
|
||||
}
|
||||
|
||||
export function getKernelVersion(): string {
|
||||
const content = readFile(`${BRAIN_ROOT}/brain-compose.yml`)
|
||||
if (!content) return "?"
|
||||
const match = content.match(/^version:\s*"?([^"\n]+)"?/m)
|
||||
return match ? match[1] : "?"
|
||||
}
|
||||
|
||||
export function getBrainState(): BrainState {
|
||||
return {
|
||||
focus: getFocus(),
|
||||
todos: getTodos(),
|
||||
session: getSession(),
|
||||
intentions: getIntentions(),
|
||||
repos: getRepoStatus(),
|
||||
commits: getRecentCommits(),
|
||||
kernelVersion: getKernelVersion(),
|
||||
}
|
||||
}
|
||||
10
ags-v3/package.json
Normal file
10
ags-v3/package.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"ags": "*",
|
||||
"gnim": "*"
|
||||
},
|
||||
"prettier": {
|
||||
"semi": false,
|
||||
"tabWidth": 2
|
||||
}
|
||||
}
|
||||
134
ags-v3/style.scss
Normal file
134
ags-v3/style.scss
Normal file
@@ -0,0 +1,134 @@
|
||||
@use "styles/palette" as *;
|
||||
@use "styles/heartbeat";
|
||||
@use "styles/bar";
|
||||
|
||||
* {
|
||||
font-family: $font;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
// ── Layer 3 — Brain Power Panel ──
|
||||
window.BrainPower {
|
||||
background: transparent;
|
||||
|
||||
.brain-panel {
|
||||
background: rgba(26, 14, 39, 0.94); // $crust heavy glass
|
||||
border-radius: 0 $radius $radius 0;
|
||||
border: 2px solid rgba(201, 160, 255, 0.40); // $lilac border
|
||||
border-left: none;
|
||||
min-width: 380px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.brain-header {
|
||||
padding: 0 0 12px 0;
|
||||
}
|
||||
|
||||
.brain-title {
|
||||
color: $magenta;
|
||||
font-size: 16px;
|
||||
font-weight: 900;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
.brain-close {
|
||||
background: transparent;
|
||||
border: none;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
padding: 2px 8px;
|
||||
|
||||
label {
|
||||
color: $muted;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
&:hover label {
|
||||
color: $danger;
|
||||
}
|
||||
}
|
||||
|
||||
.brain-content {
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.brain-section {
|
||||
padding: 8px 0 4px 0;
|
||||
}
|
||||
|
||||
.brain-section-title {
|
||||
color: $lilac;
|
||||
font-size: 11px;
|
||||
font-weight: 900;
|
||||
letter-spacing: 0.12em;
|
||||
}
|
||||
|
||||
.brain-divider {
|
||||
background: rgba(90, 56, 117, 0.30); // $surface2
|
||||
min-height: 1px;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.brain-focus {
|
||||
color: $text;
|
||||
font-size: 13px;
|
||||
padding: 4px 0 4px 16px;
|
||||
}
|
||||
|
||||
.brain-session {
|
||||
color: $champagne;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
padding: 4px 0 4px 16px;
|
||||
}
|
||||
|
||||
.brain-todos-count {
|
||||
color: $muted;
|
||||
font-size: 11px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.brain-todos-list {
|
||||
color: $subtext1;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
padding: 4px 0 4px 16px;
|
||||
}
|
||||
|
||||
.brain-version {
|
||||
color: $muted;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.brain-intentions-list {
|
||||
color: $mitsuri;
|
||||
font-size: 13px;
|
||||
font-weight: normal;
|
||||
padding: 4px 0 4px 16px;
|
||||
}
|
||||
|
||||
.brain-repos-status {
|
||||
color: $subtext1;
|
||||
font-size: 13px;
|
||||
font-weight: normal;
|
||||
font-family: "Maple Mono NF", monospace;
|
||||
padding: 4px 0 4px 16px;
|
||||
}
|
||||
|
||||
.brain-commits-list {
|
||||
color: $subtext0;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
font-family: "Maple Mono NF", monospace;
|
||||
padding: 4px 0 4px 16px;
|
||||
}
|
||||
|
||||
.brain-terminal {
|
||||
background: #1a0e27;
|
||||
border-radius: 0 0 $radius 0;
|
||||
padding: 4px;
|
||||
min-height: 400px;
|
||||
}
|
||||
}
|
||||
194
ags-v3/styles/_bar.scss
Normal file
194
ags-v3/styles/_bar.scss
Normal file
@@ -0,0 +1,194 @@
|
||||
@use "palette" as *;
|
||||
|
||||
// Layer 1 — Ghost bar (hover reveal)
|
||||
|
||||
window.Bar {
|
||||
background: transparent;
|
||||
|
||||
> centerbox {
|
||||
background: rgba(38, 21, 55, 0.88); // $base @ 0.88
|
||||
border-radius: $radius;
|
||||
border: 3px solid rgba(255, 77, 166, 0.60); // $magenta @ 0.60
|
||||
margin: 6px 8px;
|
||||
padding: 0 8px;
|
||||
min-height: 48px;
|
||||
}
|
||||
|
||||
.modules-left,
|
||||
.modules-center,
|
||||
.modules-right {
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.module {
|
||||
padding: 0 8px;
|
||||
color: $text;
|
||||
}
|
||||
|
||||
.prompt-name {
|
||||
color: $magenta;
|
||||
font-size: 17px;
|
||||
padding: 0 0 0 14px;
|
||||
}
|
||||
|
||||
.prompt-cursor {
|
||||
color: $lilac;
|
||||
font-size: 17px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.separator {
|
||||
color: rgba(240, 234, 248, 0.12); // $text @ 0.12
|
||||
font-size: 14px;
|
||||
padding: 0 6px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
// ── clock ──
|
||||
.clock {
|
||||
color: $magenta;
|
||||
font-weight: 900;
|
||||
font-size: 18px;
|
||||
letter-spacing: 0.04em;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.date {
|
||||
color: $lavande;
|
||||
font-size: 15px;
|
||||
font-weight: normal;
|
||||
padding: 0 10px 0 2px;
|
||||
}
|
||||
|
||||
// ── system stats ──
|
||||
.cpu { color: $lavande; }
|
||||
.ram { color: $magenta; }
|
||||
.temp {
|
||||
color: rgba(164, 180, 255, 0.60); // $lavande @ 0.60
|
||||
font-size: 11px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.gpu { color: $mitsuri; }
|
||||
|
||||
.cpu, .ram, .gpu, .temp {
|
||||
&.warning { color: $champagne; }
|
||||
&.critical { color: $danger; }
|
||||
}
|
||||
|
||||
// ── network ──
|
||||
.network {
|
||||
color: $lavande;
|
||||
font-size: 15px;
|
||||
padding: 0 10px;
|
||||
&.disconnected { color: $danger; }
|
||||
}
|
||||
|
||||
// ── volume ──
|
||||
button.volume,
|
||||
button.muted {
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 0 8px;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
|
||||
label { color: $magenta; }
|
||||
&.muted label { color: rgba(255, 77, 166, 0.30); }
|
||||
&:hover label { color: $lilac; }
|
||||
}
|
||||
|
||||
// ── battery ──
|
||||
.battery {
|
||||
color: $magenta;
|
||||
padding: 0 8px;
|
||||
&.charging { color: $mitsuri; }
|
||||
&.low { color: $danger; }
|
||||
&.warning { color: $champagne; }
|
||||
}
|
||||
|
||||
// ── media ──
|
||||
.media-module {
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.media {
|
||||
padding: 0 4px;
|
||||
|
||||
&.paused .media-text {
|
||||
color: rgba(201, 160, 255, 0.50); // $lilac @ 0.50
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
|
||||
.media-text {
|
||||
color: $lilac;
|
||||
font-size: 15px;
|
||||
font-weight: normal;
|
||||
padding: 0 6px;
|
||||
}
|
||||
|
||||
.media-prev,
|
||||
.media-play,
|
||||
.media-next {
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 0 3px;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
|
||||
label { color: $lilac; font-size: 16px; }
|
||||
&:hover label { color: $magenta; }
|
||||
}
|
||||
|
||||
// ── systray ──
|
||||
.systray {
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.systray-item {
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 0 3px;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
|
||||
&:hover {
|
||||
background: rgba(201, 160, 255, 0.12);
|
||||
border-radius: $radius-sm;
|
||||
}
|
||||
}
|
||||
|
||||
// ── hover effects ──
|
||||
.module:hover,
|
||||
.clock:hover,
|
||||
.cpu:hover,
|
||||
.ram:hover,
|
||||
.network:hover,
|
||||
.battery:hover {
|
||||
color: $lilac;
|
||||
}
|
||||
|
||||
// ── workspaces ──
|
||||
.workspaces button {
|
||||
background: transparent;
|
||||
color: $muted;
|
||||
min-width: 22px;
|
||||
min-height: 22px;
|
||||
border-radius: $radius-sm;
|
||||
margin: 2px;
|
||||
padding: 0;
|
||||
|
||||
&.active {
|
||||
background: rgba(255, 77, 166, 0.20);
|
||||
color: $magenta;
|
||||
border: 1px solid rgba(255, 77, 166, 0.40);
|
||||
}
|
||||
|
||||
&.occupied { color: $lilac; }
|
||||
&:hover {
|
||||
background: rgba(201, 160, 255, 0.12);
|
||||
color: $lilac;
|
||||
}
|
||||
}
|
||||
}
|
||||
21
ags-v3/styles/_heartbeat.scss
Normal file
21
ags-v3/styles/_heartbeat.scss
Normal file
@@ -0,0 +1,21 @@
|
||||
@use "palette" as *;
|
||||
|
||||
// Layer 0 — heartbeat line
|
||||
// Fin trait magenta en haut de l'écran — "le système est vivant"
|
||||
|
||||
window.Heartbeat {
|
||||
background: transparent;
|
||||
|
||||
> box {
|
||||
// gradient uses rgba() which SCSS understands natively
|
||||
background: linear-gradient(
|
||||
to right,
|
||||
rgba(255, 77, 166, 0.0),
|
||||
rgba(255, 77, 166, 0.6),
|
||||
rgba(201, 160, 255, 0.8),
|
||||
rgba(255, 77, 166, 0.6),
|
||||
rgba(255, 77, 166, 0.0)
|
||||
);
|
||||
min-height: 2px;
|
||||
}
|
||||
}
|
||||
35
ags-v3/styles/_palette.scss
Normal file
35
ags-v3/styles/_palette.scss
Normal file
@@ -0,0 +1,35 @@
|
||||
// ── violet-chaton v2 ──────────────────────────────────────────────────────
|
||||
// Mitsuri Kanroji inspired — gradient magenta → green
|
||||
// Ghost Shell edition
|
||||
|
||||
// backgrounds
|
||||
$crust: #1a0e27;
|
||||
$base: #261537;
|
||||
$mantle: #341c4a;
|
||||
$surface0: #3d2454;
|
||||
$surface1: #493161;
|
||||
$surface2: #5a3875;
|
||||
|
||||
// accents
|
||||
$magenta: #ff4da6;
|
||||
$lilac: #c9a0ff;
|
||||
$mitsuri: #9adba8;
|
||||
$lavande: #a4b4ff;
|
||||
$champagne: #e8c87a;
|
||||
$danger: #f25c7a;
|
||||
|
||||
// text
|
||||
$text: #f0eaf8;
|
||||
$subtext1: #c4b8d4;
|
||||
$subtext0: #9a8fad;
|
||||
$muted: #716686;
|
||||
|
||||
// shared
|
||||
$font: "Maple Mono NF", "MapleMono Nerd Font", monospace;
|
||||
$radius: 14px;
|
||||
$radius-sm: 8px;
|
||||
$transition: 300ms ease-out;
|
||||
|
||||
// Note: alpha() is a GTK CSS function, not SCSS.
|
||||
// Use it raw in GTK CSS values, not in SCSS variables.
|
||||
// For SCSS variables that need transparency, use rgba().
|
||||
32
ags-v3/toggle-brain.sh
Executable file
32
ags-v3/toggle-brain.sh
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
# Toggle Brain Power — dashboard AGS + terminal Kitty (single instance)
|
||||
BRAIN_ROOT="${BRAIN_ROOT:-$HOME/Dev/Brain}"
|
||||
KITTY_CLASS="brain-hud-terminal"
|
||||
|
||||
# Check if brain kitty is already running (by window class)
|
||||
kitty_pid=$(pgrep -f "class $KITTY_CLASS" | head -1)
|
||||
|
||||
if [ -n "$kitty_pid" ]; then
|
||||
# Close everything
|
||||
ags request "toggle-brain" 2>/dev/null
|
||||
kill "$kitty_pid" 2>/dev/null
|
||||
else
|
||||
# Open everything
|
||||
ags request "toggle-brain" 2>/dev/null
|
||||
kitty \
|
||||
--class "$KITTY_CLASS" \
|
||||
--title "🧠 Brain HUD" \
|
||||
--override remember_window_size=no \
|
||||
--override initial_window_width=60c \
|
||||
--override initial_window_height=30c \
|
||||
--override background_opacity=0.94 \
|
||||
--override background=#1a0e27 \
|
||||
--override foreground=#f0eaf8 \
|
||||
--override cursor=#ff4da6 \
|
||||
--override font_size=13 \
|
||||
--override confirm_os_window_close=0 \
|
||||
--directory "$BRAIN_ROOT" \
|
||||
-e zsh -c "echo '🧠 Brain HUD — navigate mode'; echo ''; exec zsh" \
|
||||
&
|
||||
disown
|
||||
fi
|
||||
14
ags-v3/tsconfig.json
Normal file
14
ags-v3/tsconfig.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"module": "ES2022",
|
||||
"target": "ES2020",
|
||||
"lib": ["ES2023"],
|
||||
"moduleResolution": "Bundler",
|
||||
// "checkJs": true,
|
||||
// "allowJs": true,
|
||||
"jsx": "react-jsx",
|
||||
"jsxImportSource": "ags/gtk3"
|
||||
}
|
||||
}
|
||||
70
ags-v3/widget/Bar.tsx
Normal file
70
ags-v3/widget/Bar.tsx
Normal file
@@ -0,0 +1,70 @@
|
||||
import app from "ags/gtk3/app"
|
||||
import { Astal, Gtk, Gdk } from "ags/gtk3"
|
||||
import Clock from "./modules/Clock"
|
||||
// import Battery from "./modules/Battery" // desktop — no battery
|
||||
import Volume from "./modules/Volume"
|
||||
import Network from "./modules/Network"
|
||||
import SystemStats from "./modules/SystemStats"
|
||||
import Media from "./modules/Media"
|
||||
// import SysTray from "./modules/SysTray" // TODO: needs astal-tray (appmenu-glib-translator)
|
||||
import Prompt from "./modules/Prompt"
|
||||
|
||||
export default function Bar(gdkmonitor: Gdk.Monitor) {
|
||||
const { TOP, LEFT, RIGHT } = Astal.WindowAnchor
|
||||
|
||||
let hideTimeout: number | null = null
|
||||
|
||||
function scheduleHide(win: Astal.Window) {
|
||||
if (hideTimeout) clearTimeout(hideTimeout)
|
||||
hideTimeout = setTimeout(() => {
|
||||
win.visible = false
|
||||
hideTimeout = null
|
||||
}, 800)
|
||||
}
|
||||
|
||||
function cancelHide() {
|
||||
if (hideTimeout) {
|
||||
clearTimeout(hideTimeout)
|
||||
hideTimeout = null
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<window
|
||||
class="Bar"
|
||||
name="bar"
|
||||
visible={true}
|
||||
gdkmonitor={gdkmonitor}
|
||||
exclusivity={Astal.Exclusivity.EXCLUSIVE}
|
||||
anchor={TOP | LEFT | RIGHT}
|
||||
application={app}
|
||||
layer={Astal.Layer.TOP}
|
||||
>
|
||||
<eventbox
|
||||
onHover={() => cancelHide()}
|
||||
onHoverLost={(_self) => {
|
||||
// disabled for debug — auto-hide off
|
||||
}}
|
||||
>
|
||||
<centerbox>
|
||||
<box $type="start" class="modules-left" halign={Gtk.Align.START}>
|
||||
<Prompt />
|
||||
<label class="separator" label="│" />
|
||||
<SystemStats />
|
||||
<label class="separator" label="│" />
|
||||
<Media />
|
||||
</box>
|
||||
<box $type="center" class="modules-center">
|
||||
<Clock />
|
||||
</box>
|
||||
<box $type="end" class="modules-right" halign={Gtk.Align.END}>
|
||||
{/* <SysTray /> */}
|
||||
<Network />
|
||||
<label class="separator" label="│" />
|
||||
<Volume />
|
||||
</box>
|
||||
</centerbox>
|
||||
</eventbox>
|
||||
</window>
|
||||
)
|
||||
}
|
||||
27
ags-v3/widget/Heartbeat.tsx
Normal file
27
ags-v3/widget/Heartbeat.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import app from "ags/gtk3/app"
|
||||
import { Astal, Gtk, Gdk } from "ags/gtk3"
|
||||
|
||||
export default function Heartbeat(gdkmonitor: Gdk.Monitor) {
|
||||
const { TOP, LEFT, RIGHT } = Astal.WindowAnchor
|
||||
|
||||
return (
|
||||
<window
|
||||
class="Heartbeat"
|
||||
gdkmonitor={gdkmonitor}
|
||||
exclusivity={Astal.Exclusivity.NONE}
|
||||
anchor={TOP | LEFT | RIGHT}
|
||||
application={app}
|
||||
layer={Astal.Layer.TOP}
|
||||
>
|
||||
<eventbox
|
||||
onHover={() => {
|
||||
// reveal the bar
|
||||
const bar = app.get_window("bar")
|
||||
if (bar) bar.visible = true
|
||||
}}
|
||||
>
|
||||
<box class="heartbeat-line" />
|
||||
</eventbox>
|
||||
</window>
|
||||
)
|
||||
}
|
||||
30
ags-v3/widget/modules/Battery.tsx
Normal file
30
ags-v3/widget/modules/Battery.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import AstalBattery from "gi://AstalBattery"
|
||||
import { createBinding } from "ags"
|
||||
|
||||
export default function Battery() {
|
||||
const bat = AstalBattery.get_default()
|
||||
|
||||
const text = createBinding(bat, "percentage")((p: number) => {
|
||||
const pct = Math.round(p * 100)
|
||||
const isCharging = bat.charging
|
||||
let icon = ""
|
||||
if (isCharging) icon = ""
|
||||
else if (pct > 90) icon = ""
|
||||
else if (pct > 70) icon = ""
|
||||
else if (pct > 50) icon = ""
|
||||
else if (pct > 30) icon = ""
|
||||
else if (pct > 10) icon = ""
|
||||
else icon = ""
|
||||
return `${icon} ${pct}%`
|
||||
})
|
||||
|
||||
const cls = createBinding(bat, "percentage")((p: number) => {
|
||||
const pct = Math.round(p * 100)
|
||||
if (bat.charging) return "battery charging"
|
||||
if (pct <= 10) return "battery low"
|
||||
if (pct <= 20) return "battery warning"
|
||||
return "battery"
|
||||
})
|
||||
|
||||
return <label class={cls} label={text} />
|
||||
}
|
||||
72
ags-v3/widget/modules/Clock.tsx
Normal file
72
ags-v3/widget/modules/Clock.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import { createPoll } from "ags/time"
|
||||
import { exec } from "ags/process"
|
||||
|
||||
function formatTime(): string {
|
||||
const now = new Date()
|
||||
return now.toLocaleTimeString("fr-FR", {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
})
|
||||
}
|
||||
|
||||
function formatDate(): string {
|
||||
const now = new Date()
|
||||
return now.toLocaleDateString("fr-FR", {
|
||||
weekday: "long",
|
||||
day: "numeric",
|
||||
month: "long",
|
||||
year: "numeric",
|
||||
})
|
||||
}
|
||||
|
||||
function formatDateShort(): string {
|
||||
const now = new Date()
|
||||
return now.toLocaleDateString("fr-FR", {
|
||||
weekday: "short",
|
||||
day: "numeric",
|
||||
month: "short",
|
||||
})
|
||||
}
|
||||
|
||||
function getCalendar(): string {
|
||||
try {
|
||||
return exec("bash -c \"cal -h\"").trim()
|
||||
} catch {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
function getUptime(): string {
|
||||
try {
|
||||
return exec("bash -c \"uptime -p | sed 's/up //'\"").trim()
|
||||
} catch {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
function buildTooltip(): string {
|
||||
const full = formatDate()
|
||||
const cal = getCalendar()
|
||||
const up = getUptime()
|
||||
return `${full}\n\n${cal}\n\n⏱ uptime: ${up}`
|
||||
}
|
||||
|
||||
export default function Clock() {
|
||||
const time = createPoll("", 1000, () => formatTime())
|
||||
const date = createPoll("", 60000, () => formatDateShort())
|
||||
|
||||
return (
|
||||
<box>
|
||||
<label class="clock" label={time} />
|
||||
<label class="separator" label="│" />
|
||||
<eventbox
|
||||
onHover={(self) => {
|
||||
self.tooltipText = buildTooltip()
|
||||
}}
|
||||
>
|
||||
<label class="date" label={date} hasTooltip />
|
||||
</eventbox>
|
||||
</box>
|
||||
)
|
||||
}
|
||||
54
ags-v3/widget/modules/Media.tsx
Normal file
54
ags-v3/widget/modules/Media.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
import AstalMpris from "gi://AstalMpris"
|
||||
import { createBinding, For } from "ags"
|
||||
|
||||
export default function Media() {
|
||||
const mpris = AstalMpris.get_default()
|
||||
const players = createBinding(mpris, "players")
|
||||
|
||||
// Filter to only show non-playerctld players
|
||||
const filtered = players((list: AstalMpris.Player[]) =>
|
||||
list.filter((p) => p.busName && !p.busName.includes("playerctld")).slice(0, 1)
|
||||
)
|
||||
|
||||
return (
|
||||
<box class="media-module">
|
||||
<For each={filtered}>
|
||||
{(player) => {
|
||||
const title = createBinding(player, "title")
|
||||
const status = createBinding(player, "playbackStatus")
|
||||
|
||||
const icon = status((s: AstalMpris.PlaybackStatus) =>
|
||||
s === AstalMpris.PlaybackStatus.PLAYING ? "▶" : "⏸"
|
||||
)
|
||||
|
||||
const label = title((t: string) => {
|
||||
const a = player.artist
|
||||
const display = a ? `${a} — ${t}` : t
|
||||
return display.length > 45
|
||||
? display.substring(0, 42) + "..."
|
||||
: display
|
||||
})
|
||||
|
||||
const cls = status((s: AstalMpris.PlaybackStatus) =>
|
||||
s === AstalMpris.PlaybackStatus.PLAYING ? "media" : "media paused"
|
||||
)
|
||||
|
||||
return (
|
||||
<box class={cls}>
|
||||
<button class="media-prev" onClicked={() => player.previous()}>
|
||||
<label label="⏮" />
|
||||
</button>
|
||||
<button class="media-play" onClicked={() => player.play_pause()}>
|
||||
<label label={icon} />
|
||||
</button>
|
||||
<button class="media-next" onClicked={() => player.next()}>
|
||||
<label label="⏭" />
|
||||
</button>
|
||||
<label class="media-text" label={label} />
|
||||
</box>
|
||||
)
|
||||
}}
|
||||
</For>
|
||||
</box>
|
||||
)
|
||||
}
|
||||
50
ags-v3/widget/modules/Network.tsx
Normal file
50
ags-v3/widget/modules/Network.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
import AstalNetwork from "gi://AstalNetwork"
|
||||
import { createBinding } from "ags"
|
||||
import { exec } from "ags/process"
|
||||
|
||||
function getIPs(): string {
|
||||
try {
|
||||
const lan = exec("bash -c \"hostname -I | awk '{print $1}'\"").trim()
|
||||
const wan = exec("bash -c \"curl -4 -s --max-time 2 ifconfig.me\"").trim()
|
||||
return `LAN: ${lan || "?"}\nWAN: ${wan || "?"}`
|
||||
} catch {
|
||||
return "IPs unavailable"
|
||||
}
|
||||
}
|
||||
|
||||
export default function Network() {
|
||||
const net = AstalNetwork.get_default()
|
||||
|
||||
const text = createBinding(net, "primary")((type: AstalNetwork.Primary) => {
|
||||
if (type === AstalNetwork.Primary.WIFI) {
|
||||
const wifi = net.wifi
|
||||
if (!wifi) return " offline"
|
||||
const ssid = wifi.ssid || "wifi"
|
||||
const strength = wifi.strength
|
||||
let icon = ""
|
||||
if (strength > 80) icon = ""
|
||||
else if (strength > 60) icon = ""
|
||||
else if (strength > 40) icon = ""
|
||||
else if (strength > 20) icon = ""
|
||||
return `${icon} ${ssid}`
|
||||
}
|
||||
if (type === AstalNetwork.Primary.WIRED) return " wired"
|
||||
return " offline"
|
||||
})
|
||||
|
||||
const cls = createBinding(net, "primary")((type: AstalNetwork.Primary) => {
|
||||
if (type === AstalNetwork.Primary.WIFI) return "network module wifi"
|
||||
if (type === AstalNetwork.Primary.WIRED) return "network module wired"
|
||||
return "network module disconnected"
|
||||
})
|
||||
|
||||
return (
|
||||
<eventbox
|
||||
onHover={(self) => {
|
||||
self.tooltipText = getIPs()
|
||||
}}
|
||||
>
|
||||
<label class={cls} label={text} hasTooltip />
|
||||
</eventbox>
|
||||
)
|
||||
}
|
||||
18
ags-v3/widget/modules/Prompt.tsx
Normal file
18
ags-v3/widget/modules/Prompt.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import GLib from "gi://GLib"
|
||||
import { createPoll } from "ags/time"
|
||||
|
||||
export default function Prompt() {
|
||||
const username = GLib.get_user_name() || "user"
|
||||
|
||||
const cursor = createPoll("_", 600, () => {
|
||||
// alternate between _ and empty to create blink
|
||||
return Date.now() % 1200 < 600 ? "_" : " "
|
||||
})
|
||||
|
||||
return (
|
||||
<box>
|
||||
<label class="prompt-name" label={username} />
|
||||
<label class="prompt-cursor" label={cursor} />
|
||||
</box>
|
||||
)
|
||||
}
|
||||
24
ags-v3/widget/modules/SysTray.tsx
Normal file
24
ags-v3/widget/modules/SysTray.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import AstalTray from "gi://AstalTray"
|
||||
import Gtk from "gi://Gtk?version=3.0"
|
||||
import { createBinding, For } from "ags"
|
||||
|
||||
export default function SysTray() {
|
||||
const tray = AstalTray.get_default()
|
||||
const items = createBinding(tray, "items")
|
||||
|
||||
return (
|
||||
<box class="systray">
|
||||
<For each={items}>
|
||||
{(item) => (
|
||||
<button
|
||||
class="systray-item"
|
||||
tooltipText={createBinding(item, "tooltipMarkup")}
|
||||
onClicked={() => item.activate(0, 0)}
|
||||
>
|
||||
<icon pixelSize={16} gicon={createBinding(item, "gicon")} />
|
||||
</button>
|
||||
)}
|
||||
</For>
|
||||
</box>
|
||||
)
|
||||
}
|
||||
89
ags-v3/widget/modules/SystemStats.tsx
Normal file
89
ags-v3/widget/modules/SystemStats.tsx
Normal file
@@ -0,0 +1,89 @@
|
||||
import GLib from "gi://GLib"
|
||||
import { createPoll } from "ags/time"
|
||||
import { exec } from "ags/process"
|
||||
|
||||
function readProc(path: string): string | null {
|
||||
try {
|
||||
const [ok, contents] = GLib.file_get_contents(path)
|
||||
if (ok && contents) return new TextDecoder().decode(contents)
|
||||
} catch {}
|
||||
return null
|
||||
}
|
||||
|
||||
let prevIdle = 0
|
||||
let prevTotal = 0
|
||||
|
||||
function getCpuUsage(): string {
|
||||
const content = readProc("/proc/stat")
|
||||
if (!content) return "?"
|
||||
|
||||
const line = content.split("\n")[0]
|
||||
const parts = line.split(/\s+/).slice(1).map(Number)
|
||||
const idle = parts[3] + parts[4]
|
||||
const total = parts.reduce((a, b) => a + b, 0)
|
||||
|
||||
const dIdle = idle - prevIdle
|
||||
const dTotal = total - prevTotal
|
||||
prevIdle = idle
|
||||
prevTotal = total
|
||||
|
||||
if (dTotal === 0) return "0"
|
||||
return `${Math.round(((dTotal - dIdle) / dTotal) * 100)}`
|
||||
}
|
||||
|
||||
function getRamUsage(): { pct: string; used: string; total: string } {
|
||||
const content = readProc("/proc/meminfo")
|
||||
if (!content) return { pct: "?", used: "?", total: "?" }
|
||||
|
||||
const lines = content.split("\n")
|
||||
let totalKb = 0, availableKb = 0
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.startsWith("MemTotal:")) totalKb = parseInt(line.split(/\s+/)[1])
|
||||
if (line.startsWith("MemAvailable:")) availableKb = parseInt(line.split(/\s+/)[1])
|
||||
if (totalKb && availableKb) break
|
||||
}
|
||||
|
||||
if (!totalKb) return { pct: "?", used: "?", total: "?" }
|
||||
const usedGb = ((totalKb - availableKb) / 1048576).toFixed(1)
|
||||
const totalGb = (totalKb / 1048576).toFixed(0)
|
||||
const pct = `${Math.round(((totalKb - availableKb) / totalKb) * 100)}`
|
||||
return { pct, used: usedGb, total: totalGb }
|
||||
}
|
||||
|
||||
function getGpuInfo(): string {
|
||||
try {
|
||||
const out = exec("bash -c \"nvidia-smi --query-gpu=utilization.gpu,temperature.gpu --format=csv,noheader,nounits 2>/dev/null\"")
|
||||
const [usage, temp] = out.trim().split(", ")
|
||||
return `GPU ${usage}% · ${temp}°C`
|
||||
} catch {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
export default function SystemStats() {
|
||||
const cpu = createPoll("0", 3000, () => getCpuUsage())
|
||||
const ram = createPoll("", 5000, () => {
|
||||
const r = getRamUsage()
|
||||
return JSON.stringify(r)
|
||||
})
|
||||
|
||||
const ramLabel = ram((v: string) => {
|
||||
try {
|
||||
const r = JSON.parse(v)
|
||||
return `RAM ${r.used}/${r.total}G`
|
||||
} catch { return "RAM ?" }
|
||||
})
|
||||
|
||||
const gpu = createPoll("", 5000, () => getGpuInfo())
|
||||
|
||||
return (
|
||||
<box>
|
||||
<label class="cpu module" label={cpu((v: string) => `CPU ${v}%`)} />
|
||||
<label class="separator" label="│" />
|
||||
<label class="ram module" label={ramLabel} />
|
||||
<label class="separator" label="│" />
|
||||
<label class="gpu module" label={gpu((v: string) => v || "GPU ?")} />
|
||||
</box>
|
||||
)
|
||||
}
|
||||
44
ags-v3/widget/modules/Volume.tsx
Normal file
44
ags-v3/widget/modules/Volume.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
import AstalWp from "gi://AstalWp"
|
||||
import { createBinding } from "ags"
|
||||
|
||||
export default function Volume() {
|
||||
const speaker = AstalWp.get_default()!.defaultSpeaker!
|
||||
|
||||
const volume = createBinding(speaker, "volume")
|
||||
const mute = createBinding(speaker, "mute")
|
||||
|
||||
const text = volume((v: number) => {
|
||||
const pct = Math.round(v * 100)
|
||||
const muted = speaker.mute
|
||||
let icon = ""
|
||||
if (muted) icon = ""
|
||||
else if (v > 0.66) icon = ""
|
||||
else if (v > 0.33) icon = ""
|
||||
else if (v > 0) icon = ""
|
||||
else icon = ""
|
||||
return `${icon} ${pct}%`
|
||||
})
|
||||
|
||||
const cls = mute((m: boolean) =>
|
||||
m ? "volume module muted" : "volume module"
|
||||
)
|
||||
|
||||
return (
|
||||
<button
|
||||
class={cls}
|
||||
onClicked={() => {
|
||||
speaker.mute = !speaker.mute
|
||||
}}
|
||||
onScroll={(_self: any, event: any) => {
|
||||
const delta = event.delta_y
|
||||
if (delta < 0) {
|
||||
speaker.volume = Math.min(speaker.volume + 0.05, 1.0)
|
||||
} else {
|
||||
speaker.volume = Math.max(speaker.volume - 0.05, 0.0)
|
||||
}
|
||||
}}
|
||||
>
|
||||
<label label={text} />
|
||||
</button>
|
||||
)
|
||||
}
|
||||
97
ags-v3/widget/panels/BrainPower.tsx
Normal file
97
ags-v3/widget/panels/BrainPower.tsx
Normal file
@@ -0,0 +1,97 @@
|
||||
import app from "ags/gtk3/app"
|
||||
import { Astal, Gtk, Gdk } from "ags/gtk3"
|
||||
import { createPoll } from "ags/time"
|
||||
import { getBrainState } from "../../lib/brain"
|
||||
import GLib from "gi://GLib"
|
||||
|
||||
function BrainContent() {
|
||||
const state = createPoll("", 10000, () => JSON.stringify(getBrainState()))
|
||||
|
||||
const version = state((s: string) => {
|
||||
try { return `kernel v${JSON.parse(s).kernelVersion}` } catch { return "" }
|
||||
})
|
||||
const focus = state((s: string) => {
|
||||
try { return JSON.parse(s).focus } catch { return "..." }
|
||||
})
|
||||
const session = state((s: string) => {
|
||||
try { return JSON.parse(s).session || "aucune session active" } catch { return "..." }
|
||||
})
|
||||
const intentionsTitle = state((s: string) => {
|
||||
try {
|
||||
const i = JSON.parse(s).intentions
|
||||
return ` INTENTIONS (${i.active} active${i.active > 1 ? "s" : ""})`
|
||||
} catch { return " INTENTIONS" }
|
||||
})
|
||||
const intentionsList = state((s: string) => {
|
||||
try {
|
||||
return JSON.parse(s).intentions.names.map((n: string) => ` • ${n}`).join("\n") || " aucune"
|
||||
} catch { return "..." }
|
||||
})
|
||||
const todosTitle = state((s: string) => {
|
||||
try { const t = JSON.parse(s).todos; return `${t.open} ouverts / ${t.done} faits` } catch { return "" }
|
||||
})
|
||||
const todosList = state((s: string) => {
|
||||
try {
|
||||
return JSON.parse(s).todos.top3.map((item: string) => ` ⬜ ${item}`).join("\n") || " rien"
|
||||
} catch { return "..." }
|
||||
})
|
||||
|
||||
return (
|
||||
<box orientation={Gtk.Orientation.VERTICAL} class="brain-content">
|
||||
<box class="brain-section">
|
||||
<label class="brain-section-title" label=" FOCUS" xalign={0} />
|
||||
<label class="brain-version" label={version} xalign={1} hexpand />
|
||||
</box>
|
||||
<label class="brain-focus" label={focus} xalign={0} wrap />
|
||||
<box class="brain-divider" />
|
||||
<box class="brain-section">
|
||||
<label class="brain-section-title" label=" SESSION" xalign={0} />
|
||||
</box>
|
||||
<label class="brain-session" label={session} xalign={0} />
|
||||
<box class="brain-divider" />
|
||||
<box class="brain-section">
|
||||
<label class="brain-section-title" label={intentionsTitle} xalign={0} />
|
||||
</box>
|
||||
<label class="brain-intentions-list" label={intentionsList} xalign={0} />
|
||||
<box class="brain-divider" />
|
||||
<box class="brain-section">
|
||||
<label class="brain-section-title" label=" TODOS" xalign={0} />
|
||||
<label class="brain-todos-count" label={todosTitle} xalign={1} hexpand />
|
||||
</box>
|
||||
<label class="brain-todos-list" label={todosList} xalign={0} />
|
||||
</box>
|
||||
)
|
||||
}
|
||||
|
||||
export default function BrainPower(gdkmonitor: Gdk.Monitor) {
|
||||
const { TOP, LEFT, BOTTOM } = Astal.WindowAnchor
|
||||
|
||||
return (
|
||||
<window
|
||||
class="BrainPower"
|
||||
name="brain-power"
|
||||
visible={false}
|
||||
gdkmonitor={gdkmonitor}
|
||||
exclusivity={Astal.Exclusivity.NONE}
|
||||
anchor={TOP | LEFT | BOTTOM}
|
||||
application={app}
|
||||
layer={Astal.Layer.OVERLAY}
|
||||
>
|
||||
<box orientation={Gtk.Orientation.VERTICAL} class="brain-panel">
|
||||
<box class="brain-header">
|
||||
<label class="brain-title" label=" BRAIN POWER" hexpand xalign={0} />
|
||||
<button
|
||||
class="brain-close"
|
||||
onClicked={() => {
|
||||
const win = app.get_window("brain-power")
|
||||
if (win) win.visible = false
|
||||
}}
|
||||
>
|
||||
<label label="✕" />
|
||||
</button>
|
||||
</box>
|
||||
<BrainContent />
|
||||
</box>
|
||||
</window>
|
||||
)
|
||||
}
|
||||
6
autostart/ghost-shell.desktop
Normal file
6
autostart/ghost-shell.desktop
Normal file
@@ -0,0 +1,6 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=Ghost Shell
|
||||
Comment=violet-chaton v2 AGS statusbar
|
||||
Exec=sh -c "ags run -d $HOME/.config/ags-v3 -g 3"
|
||||
X-GNOME-Autostart-enabled=true
|
||||
270
help.md
270
help.md
@@ -1,4 +1,6 @@
|
||||
# violet-chaton — référence des commandes
|
||||
# violet-chaton v2 — reference des commandes
|
||||
|
||||
> Tape `hotkeys` dans le terminal pour un rappel rapide.
|
||||
|
||||
---
|
||||
|
||||
@@ -6,28 +8,33 @@
|
||||
|
||||
| Commande | Alias | Description |
|
||||
|---|---|---|
|
||||
| `ls` | `eza --icons --git` | Listing coloré avec icônes |
|
||||
| `ll` | `eza -l --git` | Listing long avec infos git |
|
||||
| `lt` | `eza --tree` | Arborescence en arbre |
|
||||
| `cd <dossier>` | zoxide | Navigation intelligente (mémorise les dossiers visités) |
|
||||
| `cd <partiel>` | zoxide | Saute vers le dossier le plus probable — ex: `cd doc` → `~/Documents` |
|
||||
| `ls` | eza --icons | Listing colore avec icones |
|
||||
| `ll` | eza -l --git | Listing long avec infos git |
|
||||
| `la` | eza -la --git | Listing complet (fichiers caches inclus) |
|
||||
| `lt` | eza --tree | Arborescence en arbre (3 niveaux) |
|
||||
| `cd <dossier>` | zoxide | Navigation intelligente (memorise les dossiers visites) |
|
||||
| `cd <partiel>` | zoxide | Saute vers le dossier le plus probable |
|
||||
| `<nom_dossier>` | AUTO_CD | Entrer dans un dossier sans taper `cd` |
|
||||
| `yazi` | — | Explorateur de fichiers TUI (clavier) |
|
||||
| `y` | yazi + cd | Explorateur fichiers TUI — cd au dossier visite en quittant |
|
||||
| `proj` | fzf ~/Dev | Project switcher — navigue dans tous les projets |
|
||||
| `nemo` | — | Explorateur de fichiers GUI |
|
||||
| `fd <pattern>` | fdfind | Recherche de fichiers (remplace `find`) |
|
||||
| `mkcd <nom>` | mkdir + cd | Creer un dossier et y entrer |
|
||||
|
||||
### yazi — raccourcis principaux
|
||||
| Touche | Action |
|
||||
|---|---|
|
||||
| `h/j/k/l` ou flèches | Navigation |
|
||||
| `Entrée` | Ouvrir / entrer dans le dossier |
|
||||
| `Espace` | Sélectionner |
|
||||
| `h/j/k/l` ou fleches | Navigation |
|
||||
| `Entree` | Ouvrir / entrer dans le dossier |
|
||||
| `Espace` | Selectionner |
|
||||
| `y` | Copier |
|
||||
| `d` | Couper |
|
||||
| `p` | Coller |
|
||||
| `r` | Renommer |
|
||||
| `D` | Supprimer |
|
||||
| `q` | Quitter |
|
||||
| `q` | Quitter (retour au dossier visite) |
|
||||
|
||||
> yazi utilise le protocole image kitty — les images s'affichent en preview native.
|
||||
|
||||
---
|
||||
|
||||
@@ -35,12 +42,13 @@
|
||||
|
||||
| Commande | Alias | Description |
|
||||
|---|---|---|
|
||||
| `cat <fichier>` | batcat | Affichage avec coloration syntaxique, sans pager |
|
||||
| `bat <fichier>` | batcat | Comme cat avec numéros de lignes et pager |
|
||||
| `cat <fichier>` | batcat | Affichage avec coloration syntaxique (theme violet-chaton) |
|
||||
| `bat <fichier>` | batcat | Comme cat avec numeros de lignes et pager |
|
||||
| `glow <fichier.md>` | — | Rendu Markdown dans le terminal |
|
||||
| `man <commande>` | tldr | Pages de manuel simplifiées (remplace man) |
|
||||
| `tldr <commande>` | — | Exemples pratiques d'une commande |
|
||||
| `fetch` | — | Affiche les infos système avec le logo violet-chaton |
|
||||
| `tl <commande>` | tldr | Pages de manuel simplifiees avec exemples |
|
||||
| `man <commande>` | — | Pages de manuel completes (man reste intact) |
|
||||
| `fetch` | — | Infos systeme avec le logo violet-chaton |
|
||||
| `colors` | — | Affiche la palette violet-chaton v2 complete |
|
||||
|
||||
---
|
||||
|
||||
@@ -48,58 +56,120 @@
|
||||
|
||||
| Commande | Description |
|
||||
|---|---|
|
||||
| `grep <pattern> <fichier>` | Recherche dans un fichier (--color=auto actif par défaut) |
|
||||
| `rg <pattern>` | Recherche dans les fichiers (ripgrep, remplace grep) |
|
||||
| `fd <pattern>` | Recherche de fichiers (remplace find) |
|
||||
| `fzf` | Fuzzy finder interactif (pipe ou seul) |
|
||||
| `rg <pattern>` | Recherche dans les fichiers (ripgrep) |
|
||||
| `fd <pattern>` | Recherche de fichiers |
|
||||
| `fzf` | Fuzzy finder interactif |
|
||||
|
||||
### fzf — raccourcis clavier
|
||||
| Touche | Action |
|
||||
|---|---|
|
||||
| `Ctrl+G` | Recherche fuzzy d'un **fichier** dans `$HOME` (aperçu batcat) |
|
||||
| `Ctrl+F` | Recherche fuzzy d'un **dossier** dans `$HOME` |
|
||||
| `Ctrl+G` | Recherche fuzzy d'un **fichier** (apercu bat) |
|
||||
| `Ctrl+F` | Recherche fuzzy d'un **dossier** |
|
||||
| `Ctrl+R` | Recherche dans l'**historique** (via atuin) |
|
||||
|
||||
### fzf — commandes avancees
|
||||
| Commande | Description |
|
||||
|---|---|
|
||||
| `glog` | Git log interactif — preview du commit, copie hash au presse-papier |
|
||||
| `fkill` | Process killer — selectionne et tue un process |
|
||||
|
||||
---
|
||||
|
||||
## Git
|
||||
|
||||
| Commande | Alias | Description |
|
||||
|---|---|---|
|
||||
| `lg` | lazygit | Interface TUI complète pour git |
|
||||
| `git diff` | — | Affichage amélioré par git-delta (couleurs, side-by-side) |
|
||||
| `gh pr create` | — | Créer une pull request depuis le terminal |
|
||||
| `gh issue list` | — | Lister les issues du dépôt courant |
|
||||
| `gh auth login` | — | S'authentifier sur GitHub |
|
||||
| `lg` | lazygit | Interface TUI complete pour git (theme violet-chaton v2) |
|
||||
| `glog` | — | Git log fzf avec preview des commits |
|
||||
| `git diff` | — | Diffs colores par delta (side-by-side, violet-chaton) |
|
||||
|
||||
### lazygit — raccourcis principaux
|
||||
| Touche | Action |
|
||||
|---|---|
|
||||
| `1/2/3/4/5` | Changer de panneau (status/branches/commits/stash/reflog) |
|
||||
| `Espace` | Stage / unstage un fichier |
|
||||
| `1/2/3/4/5` | Changer de panneau |
|
||||
| `Espace` | Stage / unstage |
|
||||
| `c` | Commit |
|
||||
| `p` | Push |
|
||||
| `P` | Pull |
|
||||
| `b` | Gérer les branches |
|
||||
| `z` | Undo |
|
||||
| `q` | Quitter |
|
||||
|
||||
### git-delta — navigation dans les diffs
|
||||
### git-delta — navigation
|
||||
| Touche | Action |
|
||||
|---|---|
|
||||
| `n` | Hunk suivant |
|
||||
| `N` | Hunk précédent |
|
||||
| `N` | Hunk precedent |
|
||||
| `q` | Quitter |
|
||||
|
||||
---
|
||||
|
||||
## Monitoring & système
|
||||
## Terminal kitty — splits & layouts
|
||||
|
||||
| Touche | Action |
|
||||
|---|---|
|
||||
| `Ctrl+Shift+\` | Split vertical |
|
||||
| `Ctrl+Shift+-` | Split horizontal |
|
||||
| `Ctrl+Shift+Z` | Zoom — stack toggle (fullscreen le split actif) |
|
||||
| `Ctrl+Shift+←→↑↓` | Naviguer entre splits |
|
||||
| `Ctrl+Shift+F` | Deplacer split en avant |
|
||||
| `Ctrl+Shift+B` | Deplacer split en arriere |
|
||||
| `Ctrl+Shift+R` | Redimensionner split |
|
||||
| `Ctrl+Shift+1` | Layout tall |
|
||||
| `Ctrl+Shift+2` | Layout fat |
|
||||
| `Ctrl+Shift+3` | Layout grid |
|
||||
| `Ctrl+Shift+4` | Layout horizontal |
|
||||
| `Ctrl+Shift+5` | Layout vertical |
|
||||
| `Ctrl+Shift+T` | Nouvel onglet |
|
||||
| `Ctrl+Shift+W` | Fermer onglet |
|
||||
| `Ctrl+Shift+H/L` | Onglet precedent/suivant |
|
||||
| `Ctrl+Shift+,` | Renommer onglet |
|
||||
| `Ctrl+V` | Coller |
|
||||
| `Ctrl+C` | Copier / interrompre |
|
||||
| `Ctrl+Shift++/-/0` | Zoom police |
|
||||
| `Ctrl+Shift+F5` | Recharger la config |
|
||||
|
||||
---
|
||||
|
||||
## Vi-mode zsh
|
||||
|
||||
Le shell demarre en **mode insert** (beam cursor). `Escape` passe en **mode normal** (block cursor).
|
||||
|
||||
### Mode normal (Escape)
|
||||
| Touche | Action |
|
||||
|---|---|
|
||||
| `h/j/k/l` | Deplacement gauche/bas/haut/droite |
|
||||
| `w` / `b` | Mot suivant / precedent |
|
||||
| `0` / `$` | Debut / fin de ligne |
|
||||
| `x` | Supprimer caractere |
|
||||
| `dd` | Supprimer la ligne |
|
||||
| `yy` | Copier la ligne |
|
||||
| `p` | Coller |
|
||||
| `i` | Retour mode insert |
|
||||
| `a` | Insert apres le curseur |
|
||||
| `A` | Insert en fin de ligne |
|
||||
|
||||
### Mode insert (keybindings preserves)
|
||||
| Touche | Action |
|
||||
|---|---|
|
||||
| `Ctrl+A` | Debut de ligne |
|
||||
| `Ctrl+E` | Fin de ligne |
|
||||
| `Ctrl+W` | Supprimer mot precedent |
|
||||
| `Ctrl+U` | Supprimer jusqu'au debut |
|
||||
| `Ctrl+K` | Supprimer jusqu'a la fin |
|
||||
| `Ctrl+Y` | Coller (yank) |
|
||||
| `Ctrl+Space` | Accepter suggestion auto |
|
||||
|
||||
---
|
||||
|
||||
## Monitoring & systeme
|
||||
|
||||
| Commande | Alias | Description |
|
||||
|---|---|---|
|
||||
| `btop` | — | Moniteur système interactif (CPU, RAM, réseau, disque) |
|
||||
| `disk` | ncdu | Analyse de l'espace disque interactif |
|
||||
| `ncdu` | — | Idem (nom original) |
|
||||
| `btop` / `top` | — | Moniteur systeme (theme violet-chaton v2) |
|
||||
| `disk` / `dust` | — | Analyse de l'espace disque |
|
||||
| `procs` | — | Process viewer moderne |
|
||||
| `tokei` | — | Stats code par langage |
|
||||
| `hyperfine <cmd>` | — | Benchmark d'une commande |
|
||||
| `gping <host>` | — | Ping avec graphe temps reel |
|
||||
|
||||
---
|
||||
|
||||
@@ -107,14 +177,9 @@
|
||||
|
||||
| Commande / Touche | Description |
|
||||
|---|---|
|
||||
| `Ctrl+R` | Recherche dans l'historique avec atuin (fuzzy, filtré par dossier/host) |
|
||||
| `atuin search <terme>` | Recherche dans l'historique en ligne de commande |
|
||||
| `atuin stats` | Statistiques sur les commandes les plus utilisées |
|
||||
| `atuin sync` | Synchroniser l'historique entre machines (compte requis) |
|
||||
| `atuin register` | Créer un compte atuin pour la synchronisation |
|
||||
|
||||
> L'interface atuin affiche : code de sortie | durée | timestamp | commande.
|
||||
> L'historique est partagé entre sessions et machines si atuin est configuré avec un compte.
|
||||
| `Ctrl+R` | Recherche fuzzy dans l'historique |
|
||||
| `atuin stats` | Statistiques commandes |
|
||||
| `atuin sync` | Synchroniser entre machines |
|
||||
|
||||
---
|
||||
|
||||
@@ -122,12 +187,10 @@
|
||||
|
||||
| Commande / Touche | Description |
|
||||
|---|---|
|
||||
| `fuck` | Corrige la dernière commande ratée (thefuck) |
|
||||
| `Ctrl+Space` | Accepte la suggestion automatique complète |
|
||||
| `→` (flèche droite) | Accepte partiellement la suggestion (mot par mot) |
|
||||
| `Tab` | Autocomplétion avec menu interactif |
|
||||
|
||||
> zsh corrige aussi automatiquement les petites typos de commandes (option `CORRECT`).
|
||||
| `fuck` | Corrige la derniere commande ratee (thefuck) |
|
||||
| `Ctrl+Space` | Accepte la suggestion complete |
|
||||
| `→` (fleche droite) | Accepte partiellement (mot par mot) |
|
||||
| `Tab` | Autocompletion avec menu interactif |
|
||||
|
||||
---
|
||||
|
||||
@@ -135,15 +198,13 @@
|
||||
|
||||
| Commande | Description |
|
||||
|---|---|
|
||||
| `cava` | Visualiseur audio dans le terminal |
|
||||
| `pipes` | Animation de tuyaux colorés |
|
||||
| `cbonsai` | Bonsaï animé dans le terminal |
|
||||
| `cava` | Visualiseur audio (gradient Mitsuri) |
|
||||
| `pipes` | Animation de tuyaux colores |
|
||||
| `cbonsai` | Bonsai anime |
|
||||
| `chafa <image>` | Affiche une image dans le terminal |
|
||||
| `lolcat` | Colorie la sortie d'une commande en arc-en-ciel (ex: `ls \| lolcat`) |
|
||||
| `cmatrix` | Pluie de caractères style Matrix |
|
||||
| `toilet -f big <texte>` | Affiche du texte en gros ASCII art coloré |
|
||||
| `jp2a <image.jpg>` | Convertit une image en ASCII art dans le terminal |
|
||||
| `w3m <url>` | Navigue sur le web en mode texte depuis le terminal |
|
||||
| `lolcat` | Colorie en arc-en-ciel (ex: `ls \| lolcat`) |
|
||||
| `cmatrix` | Pluie de caracteres Matrix |
|
||||
| `toilet -f big <texte>` | Texte en gros ASCII art |
|
||||
|
||||
---
|
||||
|
||||
@@ -151,76 +212,41 @@
|
||||
|
||||
| Commande | Description |
|
||||
|---|---|
|
||||
| `qalc` | Calculatrice interactive (unités, conversions, ex: `150 EUR to USD`) |
|
||||
| `jq <filtre> <fichier.json>` | Traite et formate du JSON en ligne de commande |
|
||||
| `uv` | Gestionnaire de paquets Python ultra-rapide (remplace pip/venv) |
|
||||
| `uvx <outil>` | Exécute un outil Python dans un environnement isolé temporaire |
|
||||
| `sd <ancien> <nouveau>` | Remplacement simplifie (remplace sed) |
|
||||
| `qalc` | Calculatrice interactive (unites, conversions) |
|
||||
| `jq` | Traite et formate du JSON |
|
||||
| `weather [ville]` | Meteo rapide |
|
||||
| `uv` / `uvx` | Gestionnaire Python ultra-rapide |
|
||||
|
||||
---
|
||||
|
||||
## Cheat sheets interactifs
|
||||
|
||||
| Commande | Description |
|
||||
|---|---|
|
||||
| `navi` | Interface interactive de cheat sheets (chercher des exemples de commandes) |
|
||||
| `tldr <commande>` | Résumé rapide d'une commande avec exemples |
|
||||
|
||||
---
|
||||
|
||||
## Prompt (starship)
|
||||
|
||||
Le prompt affiche automatiquement sur **2 lignes** :
|
||||
|
||||
**Ligne 1 :** OS | User@Host | Dossier courant | Branche git + état | Langage détecté + version | Durée dernière commande (si >2s) | RAM | Heure
|
||||
|
||||
**Ligne 2 :** Code de retour si erreur | Caractère `❯` (bleu ok / rouge erreur)
|
||||
|
||||
**État git affiché :**
|
||||
| Symbole | Signification |
|
||||
|---|---|
|
||||
| `⇡N` | N commits en avance sur le remote |
|
||||
| `⇣N` | N commits en retard |
|
||||
| `?N` | N fichiers non trackés |
|
||||
| `!N` | N fichiers modifiés |
|
||||
| `+N` | N fichiers stagés |
|
||||
| `✘N` | Conflits |
|
||||
|
||||
---
|
||||
|
||||
## Plugins zsh actifs
|
||||
|
||||
| Plugin | Effet |
|
||||
|---|---|
|
||||
| `zsh-autosuggestions` | Suggestions grises basées sur l'historique |
|
||||
| `zsh-syntax-highlighting` | Coloration de la commande en cours de frappe |
|
||||
| `zsh-completions` | Complétions supplémentaires pour de nombreux outils |
|
||||
| `zinit` | Gestionnaire de plugins (chargement automatique au démarrage) |
|
||||
|
||||
---
|
||||
|
||||
## Coloration syntaxique du terminal
|
||||
## Coloration syntaxique zsh
|
||||
|
||||
| Type | Couleur |
|
||||
|---|---|
|
||||
| Commandes | Cyan |
|
||||
| Alias | Violet |
|
||||
| Builtins zsh | Rose |
|
||||
| Chaînes | Violet |
|
||||
| Chemins | Blanc souligné |
|
||||
| Erreurs / inconnu | Rouge gras |
|
||||
| Commentaires | Gris italique |
|
||||
| Globs (`*`, `?`) | Jaune |
|
||||
| Commandes | Lavande `#a4b4ff` |
|
||||
| Alias | Lilac `#c9a0ff` |
|
||||
| Builtins | Magenta `#ff4da6` |
|
||||
| Chaines | Mitsuri `#9adba8` |
|
||||
| Options `--flag` | Champagne `#e8c87a` |
|
||||
| Chemins | Text souligne |
|
||||
| Erreurs / inconnu | Danger `#f25c7a` bold |
|
||||
| Commentaires | Muted `#716686` italic |
|
||||
| Redirections `> \|` | Magenta bold |
|
||||
| Globs `* ?` | Champagne |
|
||||
|
||||
---
|
||||
|
||||
## Options zsh actives
|
||||
## Prompt starship (3 lignes)
|
||||
|
||||
| Option | Effet |
|
||||
|---|---|
|
||||
| `AUTO_CD` | Entrer dans un dossier sans taper `cd` |
|
||||
| `CORRECT` | Correction automatique des typos |
|
||||
| `GLOB_DOTS` | Les fichiers cachés `.xxx` inclus dans les globs |
|
||||
| `SHARE_HISTORY` | Historique partagé entre toutes les sessions zsh |
|
||||
| `HIST_IGNORE_DUPS` | Ne pas enregistrer les doublons dans l'historique |
|
||||
| `HIST_IGNORE_SPACE` | Les commandes précédées d'un espace ne sont pas enregistrées |
|
||||
| `NO_BEEP` | Silence — pas de bip |
|
||||
```
|
||||
┌── [OS] [dossier] [git branch] [git status] [langages] ─── [duree] [batterie] [heure]
|
||||
└─ [status] ❯
|
||||
```
|
||||
|
||||
- **Ligne 1** : separateur + infos (remplissage pointille entre gauche/droite)
|
||||
- **Ligne 2** : prompt `❯` — vert mitsuri si OK, magenta si erreur
|
||||
- **username@host** : cache en local, apparait en SSH
|
||||
- **sudo** : indicateur discret quand actif
|
||||
- **battery** : visible sous 70%, rouge sous 30%
|
||||
- **brain\_name** : affiche en italic quand la variable est definie
|
||||
|
||||
68
palette/violet-chaton-v2.md
Normal file
68
palette/violet-chaton-v2.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# violet-chaton v2 — Palette Reference
|
||||
|
||||
> Mitsuri Kanroji inspired gradient magenta → green
|
||||
> Created by Tetardtek — 2026
|
||||
|
||||
## Colors
|
||||
|
||||
### Backgrounds
|
||||
| Name | Hex | Usage |
|
||||
|------|-----|-------|
|
||||
| crust | `#1a0e27` | Deepest background, panels heavy glass |
|
||||
| base | `#261537` | Primary background, bar glass |
|
||||
| mantle | `#341c4a` | Elevated surfaces |
|
||||
| surface0 | `#3d2454` | Input backgrounds, troughs |
|
||||
| surface1 | `#493161` | Hover states, subtle borders |
|
||||
| surface2 | `#5a3875` | Active states, dividers |
|
||||
|
||||
### Accents
|
||||
| Name | Hex | Usage |
|
||||
|------|-----|-------|
|
||||
| magenta | `#ff4da6` | Primary accent — clock, battery, volume, borders, heartbeat |
|
||||
| lilac | `#c9a0ff` | Secondary accent — hover states, media, brain panel |
|
||||
| mitsuri | `#9adba8` | Green pastel — charging state, success, health good |
|
||||
| lavande | `#a4b4ff` | Blue-violet — date, CPU, network, info states |
|
||||
| champagne | `#e8c87a` | Warm gold — warnings, session info |
|
||||
| danger | `#f25c7a` | Red-pink — errors, low battery, disconnected |
|
||||
|
||||
### Text
|
||||
| Name | Hex | Usage |
|
||||
|------|-----|-------|
|
||||
| text | `#f0eaf8` | Primary text |
|
||||
| subtext1 | `#c4b8d4` | Secondary text, todo items |
|
||||
| subtext0 | `#9a8fad` | Tertiary text |
|
||||
| muted | `#716686` | Disabled, placeholders, empty states |
|
||||
|
||||
## Font
|
||||
- **Primary**: Maple Mono NF (cursive italics)
|
||||
- **Size**: 13px bold (bar), 14px 900 (clock, prompt)
|
||||
- **Icons**: Nerd Font glyphs from Maple Mono NF
|
||||
|
||||
## Signature Visual Elements
|
||||
- Glassmorphism: `rgba(38, 21, 55, 0.88)` (base @ 88%)
|
||||
- Heavy glass: `rgba(26, 14, 39, 0.94)` (crust @ 94%)
|
||||
- Border accent: `3px solid rgba(255, 77, 166, 0.60)` (magenta @ 60%)
|
||||
- Hover glow: `box-shadow: 0 4px 28px rgba(201, 160, 255, 0.18)` (lilac @ 18%)
|
||||
- Gradient progress: `linear-gradient(to right, magenta, lilac, lavande, mitsuri)`
|
||||
- Heartbeat: gradient `magenta 0% → magenta 60% → lilac 80% → magenta 60% → magenta 0%`
|
||||
- Border radius: 14px (pills), 8px (buttons)
|
||||
|
||||
## SCSS Variables
|
||||
```scss
|
||||
$crust: #1a0e27;
|
||||
$base: #261537;
|
||||
$mantle: #341c4a;
|
||||
$surface0: #3d2454;
|
||||
$surface1: #493161;
|
||||
$surface2: #5a3875;
|
||||
$magenta: #ff4da6;
|
||||
$lilac: #c9a0ff;
|
||||
$mitsuri: #9adba8;
|
||||
$lavande: #a4b4ff;
|
||||
$champagne: #e8c87a;
|
||||
$danger: #f25c7a;
|
||||
$text: #f0eaf8;
|
||||
$subtext1: #c4b8d4;
|
||||
$subtext0: #9a8fad;
|
||||
$muted: #716686;
|
||||
```
|
||||
Reference in New Issue
Block a user