ui/ux QoL improvements

This commit is contained in:
Boof2015
2026-08-16 19:53:39 -04:00
parent 3b302d5526
commit 806c58c9cb
7 changed files with 56 additions and 4 deletions
+1
View File
@@ -1895,6 +1895,7 @@ function createScopePopoutWindow(kind: ScopeKind, rawBounds?: WindowBounds): Bro
autoHideMenuBar: true,
title: `Prism ${SCOPE_LABELS[kind]}`,
alwaysOnTop: getWindowStateStore().getPopoutAlwaysOnTop(kind),
...(process.platform === 'darwin' ? { acceptFirstMouse: true } : {}),
show: false,
...getStaticWindowIconOptions(),
webPreferences: {
+3 -2
View File
@@ -20,6 +20,7 @@ import { getRendererWindowCapabilities } from './windowCapabilities'
export default function App(): JSX.Element {
const [toolbarVisible, setToolbarVisible] = useState(false)
const [measurementActive, setMeasurementActive] = useState(false)
const [settingsPanelHeight, setSettingsPanelHeight] = useState(0)
const [bottomBarHeight, setBottomBarHeight] = useState(0)
const [trayReady, setTrayReady] = useState(false)
@@ -302,13 +303,13 @@ export default function App(): JSX.Element {
onMouseUp={useNativeDragRegions ? undefined : handleAltDragEnd}
>
<div
className={`prism-toolbar-layer ${toolbarVisible ? 'is-visible' : ''}`.trim()}
className={`prism-toolbar-layer ${toolbarVisible && !measurementActive ? 'is-visible' : ''}`.trim()}
>
<Toolbar onOpenSettings={handleToggleSettings} settingsOpen={settingsOpen} />
</div>
<div className="prism-strip-region">
<Strip />
<Strip onMeasurementActiveChange={setMeasurementActive} />
</div>
<ScopePopoutBridge />
+3
View File
@@ -55,6 +55,7 @@ interface ScopeModuleProps {
theme?: ScopeModuleTheme
settings?: ScopeSettings[ScopeKind]
frameScheduler?: FrameScheduler
onMeasurementActiveChange?: (active: boolean) => void
dataSource?:
| SpectrumAnalyzerDataSource
| OscilloscopeDataSource
@@ -400,6 +401,7 @@ export default function ScopeModule({
theme,
settings,
frameScheduler,
onMeasurementActiveChange,
dataSource,
}: ScopeModuleProps): JSX.Element {
const containerRef = useRef<HTMLDivElement>(null)
@@ -447,6 +449,7 @@ export default function ScopeModule({
? visualizer as ScopeMeasurementSource
: null
},
onActiveChange: onMeasurementActiveChange,
})
useEffect(() => {
+6 -1
View File
@@ -9,7 +9,11 @@ import { usePerformanceStore } from '../stores/performanceStore'
import { FrameScheduler } from '../visualizers/frameScheduler'
import { getRendererWindowCapabilities } from '../windowCapabilities'
export default function Strip(): JSX.Element {
interface StripProps {
onMeasurementActiveChange?: (active: boolean) => void
}
export default function Strip({ onMeasurementActiveChange }: StripProps): JSX.Element {
const scopeOrder = useSettingsStore((s) => s.scopeOrder)
const hiddenScopes = useSettingsStore((s) => s.hiddenScopes)
const scopePopouts = useSettingsStore((s) => s.scopePopouts)
@@ -268,6 +272,7 @@ export default function Strip(): JSX.Element {
<ScopeModule
scopeKind={kind}
frameScheduler={frameScheduler}
onMeasurementActiveChange={onMeasurementActiveChange}
/>
</div>
))}
@@ -62,6 +62,7 @@ export default function ScopePopoutWindow({ scopeKind }: ScopePopoutWindowProps)
const [snapshot, setSnapshot] = useState<ScopePopoutSnapshot<ScopeKind> | null>(null)
const [isAlwaysOnTop, setIsAlwaysOnTop] = useState(false)
const [cursorInsideWindow, setCursorInsideWindow] = useState(false)
const [measurementActive, setMeasurementActive] = useState(false)
const prevMiniSettingsOpenRef = useRef(false)
const frameTarget = usePerformanceStore((s) => s.frameTarget)
const miniSettingsOpen = useUiStore((s) => s.settingsOpen)
@@ -230,6 +231,7 @@ export default function ScopePopoutWindow({ scopeKind }: ScopePopoutWindowProps)
'scope-popout__chrome',
miniSettingsOpen ? 'is-expanded' : '',
cursorInsideWindow ? 'is-cursor-inside' : '',
measurementActive ? 'is-measuring' : '',
].join(' ').trim()}
>
<header className={`scope-popout__header ${useWindowManagerDragRegions ? 'is-native-drag' : ''}`.trim()}>
@@ -294,6 +296,7 @@ export default function ScopePopoutWindow({ scopeKind }: ScopePopoutWindowProps)
settings={effectiveSettings}
frameScheduler={frameScheduler}
dataSource={dataSource}
onMeasurementActiveChange={setMeasurementActive}
/>
</div>
</div>
+8 -1
View File
@@ -2284,7 +2284,7 @@ button.toolbar__version:hover {
.scope-popout__viewport:hover .scope-popout__chrome,
.scope-popout__chrome:hover,
.scope-popout__chrome:focus-within,
.scope-popout__chrome:has(:focus-visible),
.scope-popout__chrome.is-cursor-inside,
.scope-popout__chrome.is-expanded {
max-height: 58px;
@@ -2293,6 +2293,13 @@ button.toolbar__version:hover {
transform: translateY(0);
}
.scope-popout__viewport .scope-popout__chrome.is-measuring {
max-height: 0;
opacity: 0;
pointer-events: none;
transform: translateY(-8px);
}
.scope-popout__header {
display: flex;
align-items: center;
+32
View File
@@ -4212,6 +4212,38 @@ test('main and detached windows keep frameless Prism chrome while enabling snap-
assert.doesNotMatch(nowPlayingSource, /WindowResizeOverlay/)
})
test('detached scope interactions accept the first macOS click and hide chrome during measurement', async () => {
const mainSource = await readFile(join(process.cwd(), 'src', 'main', 'index.ts'), 'utf8')
const scopeModuleSource = await readFile(join(process.cwd(), 'src', 'renderer', 'components', 'ScopeModule.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 mainWindowFactorySource = mainSource.slice(
mainSource.indexOf('function createMainWindow'),
mainSource.indexOf('function createScopePopoutWindow'),
)
assert.match(mainSource, /function createScopePopoutWindow\([\s\S]*?process\.platform === 'darwin' \? \{ acceptFirstMouse: true \} : \{\}/)
assert.doesNotMatch(mainWindowFactorySource, /acceptFirstMouse/)
assert.match(scopeModuleSource, /onMeasurementActiveChange\?: \(active: boolean\) => void/)
assert.match(scopeModuleSource, /onActiveChange: onMeasurementActiveChange/)
assert.match(popoutSource, /measurementActive \? 'is-measuring' : ''/)
assert.match(popoutSource, /onMeasurementActiveChange=\{setMeasurementActive\}/)
assert.match(stylesSource, /\.scope-popout__chrome:has\(:focus-visible\)/)
assert.doesNotMatch(stylesSource, /\.scope-popout__chrome:focus-within/)
assert.match(stylesSource, /\.scope-popout__viewport \.scope-popout__chrome\.is-measuring \{[\s\S]*?max-height: 0;[\s\S]*?opacity: 0;[\s\S]*?pointer-events: none;[\s\S]*?transform: translateY\(-8px\);[\s\S]*?\}/)
})
test('main window hides its toolbar while a docked scope measurement is active', async () => {
const appSource = await readFile(join(process.cwd(), 'src', 'renderer', 'App.tsx'), 'utf8')
const stripSource = await readFile(join(process.cwd(), 'src', 'renderer', 'components', 'Strip.tsx'), 'utf8')
assert.match(stripSource, /onMeasurementActiveChange\?: \(active: boolean\) => void/)
assert.match(stripSource, /onMeasurementActiveChange=\{onMeasurementActiveChange\}/)
assert.match(appSource, /const \[measurementActive, setMeasurementActive\] = useState\(false\)/)
assert.match(appSource, /toolbarVisible && !measurementActive \? 'is-visible' : ''/)
assert.match(appSource, /<Strip onMeasurementActiveChange=\{setMeasurementActive\} \/>/)
})
test('programmatic top/bottom reposition flushes fresh bounds through persistence channels', async () => {
const mainSource = await readFile(join(process.cwd(), 'src', 'main', 'index.ts'), 'utf8')