mirror of
https://github.com/Boof2015/prism.git
synced 2026-08-16 00:00:31 +02:00
reorder the scopes
This commit is contained in:
@@ -13,6 +13,7 @@ export default function Strip(): JSX.Element {
|
||||
const hiddenScopes = useSettingsStore((s) => s.hiddenScopes)
|
||||
const scopePopouts = useSettingsStore((s) => s.scopePopouts)
|
||||
const widthWeights = useSettingsStore((s) => s.widthWeights)
|
||||
const moveDockedScope = useSettingsStore((s) => s.moveDockedScope)
|
||||
const setScopeWidthWeight = useSettingsStore((s) => s.setScopeWidthWeight)
|
||||
const popOutScope = useSettingsStore((s) => s.popOutScope)
|
||||
const accent = useThemeStore((s) => s.accent)
|
||||
@@ -192,7 +193,7 @@ export default function Strip(): JSX.Element {
|
||||
return (
|
||||
<div ref={stripRef} className="scope-strip">
|
||||
<div ref={gridRef} className="scope-strip__grid" style={gridStyle}>
|
||||
{dockedScopes.map((kind) => (
|
||||
{dockedScopes.map((kind, index) => (
|
||||
<div
|
||||
key={kind}
|
||||
ref={(element) => {
|
||||
@@ -200,6 +201,34 @@ export default function Strip(): JSX.Element {
|
||||
}}
|
||||
className="scope-strip__cell"
|
||||
>
|
||||
{dockedScopes.length > 1 && (
|
||||
<div className="scope-strip__reorder-controls">
|
||||
<button
|
||||
type="button"
|
||||
className="scope-strip__reorder-button"
|
||||
onClick={() => moveDockedScope(kind, 'left')}
|
||||
aria-label={`Move ${SCOPE_LABELS[kind]} left`}
|
||||
title={`Move ${SCOPE_LABELS[kind]} left`}
|
||||
disabled={index === 0}
|
||||
>
|
||||
<span className="scope-strip__reorder-icon" aria-hidden="true">
|
||||
←
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="scope-strip__reorder-button"
|
||||
onClick={() => moveDockedScope(kind, 'right')}
|
||||
aria-label={`Move ${SCOPE_LABELS[kind]} right`}
|
||||
title={`Move ${SCOPE_LABELS[kind]} right`}
|
||||
disabled={index === dockedScopes.length - 1}
|
||||
>
|
||||
<span className="scope-strip__reorder-icon" aria-hidden="true">
|
||||
→
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
className="scope-strip__popout-button"
|
||||
|
||||
@@ -68,7 +68,7 @@ interface SettingsState {
|
||||
|
||||
// Actions
|
||||
toggleScope: (kind: ScopeKind) => void
|
||||
moveScope: (kind: ScopeKind, direction: 'left' | 'right') => void
|
||||
moveDockedScope: (kind: ScopeKind, direction: 'left' | 'right') => void
|
||||
setScopeWidthWeight: (kind: ScopeKind, weight: number) => void
|
||||
updateScopeSettings: <K extends ScopeKind>(kind: K, settings: Partial<ScopeSettings[K]>) => void
|
||||
popOutScope: (kind: ScopeKind, bounds?: WindowBounds) => void
|
||||
@@ -199,6 +199,49 @@ function normalizeScopePopouts(raw: unknown): ScopePopoutStateMap {
|
||||
return defaults
|
||||
}
|
||||
|
||||
function isDockedScope(
|
||||
kind: ScopeKind,
|
||||
hiddenScopes: ReadonlySet<ScopeKind>,
|
||||
scopePopouts: ScopePopoutStateMap,
|
||||
): boolean {
|
||||
return !hiddenScopes.has(kind) && !scopePopouts[kind]?.poppedOut
|
||||
}
|
||||
|
||||
export function moveDockedScopeOrder(
|
||||
scopeOrder: ScopeKind[],
|
||||
hiddenScopes: ReadonlySet<ScopeKind>,
|
||||
scopePopouts: ScopePopoutStateMap,
|
||||
kind: ScopeKind,
|
||||
direction: 'left' | 'right',
|
||||
): ScopeKind[] {
|
||||
const dockedScopes = scopeOrder.filter((scope) => isDockedScope(scope, hiddenScopes, scopePopouts))
|
||||
const index = dockedScopes.indexOf(kind)
|
||||
if (index === -1) return scopeOrder
|
||||
|
||||
const targetIndex = direction === 'left' ? index - 1 : index + 1
|
||||
if (targetIndex < 0 || targetIndex >= dockedScopes.length) return scopeOrder
|
||||
|
||||
const reorderedDockedScopes = [...dockedScopes]
|
||||
;[reorderedDockedScopes[index], reorderedDockedScopes[targetIndex]] = [
|
||||
reorderedDockedScopes[targetIndex],
|
||||
reorderedDockedScopes[index],
|
||||
]
|
||||
|
||||
let reorderedIndex = 0
|
||||
let didChange = false
|
||||
const mergedOrder = scopeOrder.map((scope) => {
|
||||
if (!isDockedScope(scope, hiddenScopes, scopePopouts)) return scope
|
||||
const nextScope = reorderedDockedScopes[reorderedIndex] ?? scope
|
||||
reorderedIndex += 1
|
||||
if (nextScope !== scope) {
|
||||
didChange = true
|
||||
}
|
||||
return nextScope
|
||||
})
|
||||
|
||||
return didChange ? mergedOrder : scopeOrder
|
||||
}
|
||||
|
||||
function cloneScopeSettings(settings: ScopeSettings): ScopeSettings {
|
||||
return JSON.parse(JSON.stringify(settings)) as ScopeSettings
|
||||
}
|
||||
@@ -262,15 +305,17 @@ export const useSettingsStore = create<SettingsState>((set, get) => ({
|
||||
})
|
||||
},
|
||||
|
||||
moveScope: (kind: ScopeKind, direction: 'left' | 'right') => {
|
||||
moveDockedScope: (kind: ScopeKind, direction: 'left' | 'right') => {
|
||||
set((state) => {
|
||||
const order = [...state.scopeOrder]
|
||||
const idx = order.indexOf(kind)
|
||||
if (idx === -1) return state
|
||||
const swap = direction === 'left' ? idx - 1 : idx + 1
|
||||
if (swap < 0 || swap >= order.length) return state
|
||||
;[order[idx], order[swap]] = [order[swap], order[idx]]
|
||||
const newState = { ...state, scopeOrder: order }
|
||||
const nextOrder = moveDockedScopeOrder(
|
||||
state.scopeOrder,
|
||||
state.hiddenScopes,
|
||||
state.scopePopouts,
|
||||
kind,
|
||||
direction,
|
||||
)
|
||||
if (nextOrder === state.scopeOrder) return state
|
||||
const newState = { ...state, scopeOrder: nextOrder }
|
||||
saveToStorage(newState as SettingsState)
|
||||
return newState
|
||||
})
|
||||
|
||||
@@ -342,13 +342,24 @@ select {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.scope-strip__popout-button {
|
||||
.scope-strip__reorder-controls {
|
||||
position: absolute;
|
||||
bottom: 8px;
|
||||
right: 8px;
|
||||
left: 8px;
|
||||
z-index: 3;
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
opacity: 0;
|
||||
transform: translateY(-2px);
|
||||
transition: opacity 120ms ease, transform 120ms ease;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.scope-strip__reorder-button,
|
||||
.scope-strip__popout-button {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
padding: 0;
|
||||
border-radius: 999px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
background: rgba(8, 12, 18, 0.74);
|
||||
@@ -356,24 +367,57 @@ select {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
transform: translateY(-2px);
|
||||
transition: opacity 120ms ease, transform 120ms ease, border-color 120ms ease, color 120ms ease;
|
||||
backdrop-filter: blur(14px) saturate(1.04);
|
||||
-webkit-backdrop-filter: blur(14px) saturate(1.04);
|
||||
}
|
||||
|
||||
.scope-strip__reorder-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.scope-strip__popout-button {
|
||||
position: absolute;
|
||||
bottom: 8px;
|
||||
right: 8px;
|
||||
z-index: 3;
|
||||
opacity: 0;
|
||||
transform: translateY(-2px);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.scope-strip__cell:hover .scope-strip__reorder-controls,
|
||||
.scope-strip__cell:focus-within .scope-strip__reorder-controls,
|
||||
.scope-strip__cell:hover .scope-strip__popout-button,
|
||||
.scope-strip__cell:focus-within .scope-strip__popout-button,
|
||||
.scope-strip__popout-button:focus-visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.scope-strip__popout-button:hover {
|
||||
.scope-strip__reorder-button:hover:not(:disabled),
|
||||
.scope-strip__reorder-button:focus-visible,
|
||||
.scope-strip__popout-button:hover,
|
||||
.scope-strip__popout-button:focus-visible {
|
||||
color: var(--accent);
|
||||
border-color: rgba(var(--accent-rgb), 0.28);
|
||||
}
|
||||
|
||||
.scope-strip__reorder-button:focus-visible,
|
||||
.scope-strip__popout-button:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.scope-strip__reorder-button:disabled {
|
||||
color: rgba(255, 255, 255, 0.32);
|
||||
border-color: rgba(255, 255, 255, 0.08);
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.scope-strip__reorder-icon,
|
||||
.scope-strip__popout-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
Reference in New Issue
Block a user