123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 | // herbstluftwm workspace (tag) switcher. Renders one button per tag from the
// `divebar://hlwm` event stream; clicking a tag switches to it.
export default {
name: "workspaces",
css: `
.widget-workspaces {
/* How far each tag button sits inside the pill. The hit-target
variables (see style.css) extend each tag's clickable area over
this inset and halfway across the 2px gap between tags. */
--tag-inset: 3px;
--hit-inset-x: var(--tag-inset);
--hit-inset-y: var(--tag-inset);
--hit-gap-x: 1px;
display: flex;
align-items: center;
gap: 2px;
height: var(--chip-height);
padding: 0 var(--tag-inset);
border-radius: var(--chip-radius);
background: rgba(0, 0, 0, 0.26);
box-shadow:
inset 0 1px 2px rgba(0, 0, 0, 0.35),
inset 0 -1px 0 rgba(255, 255, 255, 0.04);
}
.widget-workspaces .tag {
min-width: 1.3em;
height: calc(var(--chip-height) - 2 * var(--tag-inset));
padding: 0 0.25em;
border: none;
border-radius: calc((var(--chip-height) - 2 * var(--tag-inset)) / 2);
background: transparent;
color: var(--bar-fg-dim);
font: inherit;
font-variant-numeric: tabular-nums;
cursor: pointer;
transition: background 120ms ease, color 120ms ease;
}
.widget-workspaces .tag:hover { background: var(--chip-bg-hover); }
.widget-workspaces .tag.empty { color: rgba(255, 255, 255, 0.25); }
.widget-workspaces .tag.occupied { color: var(--bar-fg); }
.widget-workspaces .tag.visible,
.widget-workspaces .tag.focused-elsewhere {
color: var(--bar-fg);
background: var(--chip-bg-hover);
}
.widget-workspaces .tag.focused {
color: #10121a;
background: var(--accent);
font-weight: 700;
}
.widget-workspaces .tag.urgent {
color: #10121a;
background: var(--critical);
font-weight: 700;
animation: divebar-urgent-pulse 1.6s ease-in-out infinite;
}
@keyframes divebar-urgent-pulse {
0%, 100% { box-shadow: 0 0 0 0 rgba(247, 118, 142, 0); filter: brightness(1); }
50% { box-shadow: 0 0 8px 1px rgba(247, 118, 142, 0.55); filter: brightness(1.18); }
}
`,
settings: [
{
key: "labels",
label: "Tag labels",
type: "select",
choices: ["numbers", "names"],
default: "numbers",
},
],
create({ options, onEvent, invoke }) {
const el = document.createElement("div");
el.className = "widget-workspaces";
const unsubscribe = onEvent("divebar://hlwm", ({ tags }) => {
if (!tags) return;
// Rebuild only when the tag list changes; otherwise just update classes.
const buttons = el.querySelectorAll(".tag");
const sameTags =
buttons.length === tags.length &&
tags.every((tag, i) => buttons[i].dataset.tag === tag.name);
if (!sameTags) {
el.replaceChildren(
...tags.map((tag, i) => {
const btn = document.createElement("button");
btn.className = "tag hit-target";
btn.dataset.tag = tag.name;
// Position number by default; the name is always used for
// switching and shown as a tooltip.
btn.textContent =
options.labels === "names" ? tag.name : String(i + 1);
btn.title = tag.name;
btn.addEventListener("click", () =>
invoke("hlwm_use_tag", { tag: tag.name }),
);
return btn;
}),
);
}
el.querySelectorAll(".tag").forEach((btn, i) => {
btn.className = `tag hit-target ${tags[i].state}`;
});
});
return { el, destroy: unsubscribe };
},
};
|