diff --git a/src/renderer/components/Toolbar.tsx b/src/renderer/components/Toolbar.tsx
index 325def8..4f3fc3d 100644
--- a/src/renderer/components/Toolbar.tsx
+++ b/src/renderer/components/Toolbar.tsx
@@ -621,10 +621,11 @@ export default function Toolbar({ onOpenSettings, settingsOpen }: ToolbarProps):
diff --git a/src/renderer/popouts/ScopePopoutWindow.tsx b/src/renderer/popouts/ScopePopoutWindow.tsx
index de7f85c..de42051 100644
--- a/src/renderer/popouts/ScopePopoutWindow.tsx
+++ b/src/renderer/popouts/ScopePopoutWindow.tsx
@@ -259,10 +259,11 @@ export default function ScopePopoutWindow({ scopeKind }: ScopePopoutWindowProps)
diff --git a/src/renderer/styles/globals.css b/src/renderer/styles/globals.css
index a5870d6..7627011 100644
--- a/src/renderer/styles/globals.css
+++ b/src/renderer/styles/globals.css
@@ -780,10 +780,26 @@ button.toolbar__version:hover {
transform: translateY(-1px);
}
-.toolbar__icon-button.is-active {
+.toolbar__icon-button.is-active,
+.toolbar__icon-button.is-active:hover:not(:disabled) {
color: var(--accent);
border-color: var(--control-border-active);
background: var(--control-bg-active);
+ transform: none;
+}
+
+.toolbar__icon-button--pin:hover:not(:disabled):not(.is-active) {
+ border-color: var(--control-border);
+ background: var(--control-bg);
+}
+
+.toolbar__icon-button--pin.is-active,
+.toolbar__icon-button--pin.is-active:hover:not(:disabled) {
+ border-color: var(--accent);
+}
+
+.toolbar__icon-button--pin.is-active svg path {
+ fill: currentColor;
}
.toolbar__icon-button--danger:hover:not(:disabled) {
@@ -2407,12 +2423,33 @@ button.toolbar__version:hover {
height: 14px;
}
-.scope-popout__button:hover:not(:disabled),
-.scope-popout__button.is-active {
+.scope-popout__button:hover:not(:disabled) {
+ color: var(--control-text);
+ border-color: var(--control-border-active);
+ background: var(--control-bg-hover);
+ transform: translateY(-1px);
+}
+
+.scope-popout__button.is-active,
+.scope-popout__button.is-active:hover:not(:disabled) {
color: var(--accent);
border-color: var(--control-border-active);
background: var(--control-bg-active);
- transform: translateY(-1px);
+ transform: none;
+}
+
+.scope-popout__button--pin:hover:not(:disabled):not(.is-active) {
+ border-color: transparent;
+ background: var(--control-bg);
+}
+
+.scope-popout__button--pin.is-active,
+.scope-popout__button--pin.is-active:hover:not(:disabled) {
+ border-color: var(--accent);
+}
+
+.scope-popout__button--pin.is-active svg path {
+ fill: currentColor;
}
.scope-popout__button:disabled {
diff --git a/test/renderer-helpers.test.ts b/test/renderer-helpers.test.ts
index f4520e8..6a0236d 100644
--- a/test/renderer-helpers.test.ts
+++ b/test/renderer-helpers.test.ts
@@ -3992,6 +3992,40 @@ test('BottomBar close button uses flat themed control backgrounds', async () =>
assert.doesNotMatch(closeHoverBlock, /linear-gradient/)
})
+test('pin buttons use a persistent filled active state distinct from inactive hover', async () => {
+ const toolbarSource = await readFile(join(process.cwd(), 'src', 'renderer', 'components', 'Toolbar.tsx'), 'utf8')
+ const popoutSource = await readFile(join(process.cwd(), 'src', 'renderer', 'popouts', 'ScopePopoutWindow.tsx'), 'utf8')
+ const stylesSource = await readFile(join(process.cwd(), 'src', 'renderer', 'styles', 'globals.css'), 'utf8')
+ const toolbarHoverBlock = stylesSource.match(
+ /\.toolbar__icon-button--pin:hover:not\(:disabled\):not\(\.is-active\) \{([\s\S]*?)\n\}/,
+ )?.[1]
+ const toolbarActiveBlock = stylesSource.match(
+ /\.toolbar__icon-button--pin\.is-active,\n\.toolbar__icon-button--pin\.is-active:hover:not\(:disabled\) \{([\s\S]*?)\n\}/,
+ )?.[1]
+ const popoutHoverBlock = stylesSource.match(
+ /\.scope-popout__button--pin:hover:not\(:disabled\):not\(\.is-active\) \{([\s\S]*?)\n\}/,
+ )?.[1]
+ const popoutActiveBlock = stylesSource.match(
+ /\.scope-popout__button--pin\.is-active,\n\.scope-popout__button--pin\.is-active:hover:not\(:disabled\) \{([\s\S]*?)\n\}/,
+ )?.[1]
+
+ assert.match(toolbarSource, /toolbar__icon-button toolbar__icon-button--pin/)
+ assert.match(toolbarSource, /aria-pressed=\{isAlwaysOnTop\}/)
+ assert.match(popoutSource, /scope-popout__button scope-popout__button--pin/)
+ assert.match(popoutSource, /aria-pressed=\{isAlwaysOnTop\}/)
+ assert.ok(toolbarHoverBlock)
+ assert.ok(toolbarActiveBlock)
+ assert.ok(popoutHoverBlock)
+ assert.ok(popoutActiveBlock)
+
+ assert.match(toolbarHoverBlock, /background: var\(--control-bg\);/)
+ assert.match(popoutHoverBlock, /background: var\(--control-bg\);/)
+ assert.match(toolbarActiveBlock, /border-color: var\(--accent\);/)
+ assert.match(popoutActiveBlock, /border-color: var\(--accent\);/)
+ assert.match(stylesSource, /\.toolbar__icon-button--pin\.is-active svg path \{\n fill: currentColor;/)
+ assert.match(stylesSource, /\.scope-popout__button--pin\.is-active svg path \{\n fill: currentColor;/)
+})
+
test('toolbar uses the Prism logo support link and static package icons are configured', async () => {
const toolbarSource = await readFile(join(process.cwd(), 'src', 'renderer', 'components', 'Toolbar.tsx'), 'utf8')
const stylesSource = await readFile(join(process.cwd(), 'src', 'renderer', 'styles', 'globals.css'), 'utf8')