- Stack selection lifted to App.jsx: stacks fetched on login, selectedStack state shared via StatusBar (pills) and Pivot (view switching); Stacks page calls onStacksChange to keep list fresh - Pivot: derive selectedView/viewType from props, remove local stack state; toolbar replaced with dedicated layouts sub-bar (h-9, layouts only) - Records panel: merge read-only and override sections into single field list; known cols seeded from record's transformed fields; rule-derived fields (transformed minus data) will be editable in follow-up refactor - Pivot theme: setAttribute moved to after flush() so restore() can't reset it Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
74 lines
2.9 KiB
JavaScript
74 lines
2.9 KiB
JavaScript
import { NavLink } from 'react-router-dom'
|
|
import useTheme from '../theme.jsx'
|
|
|
|
export default function StatusBar({ sources = [], source, setSource, stacks = [], selectedStack, setSelectedStack }) {
|
|
const { dark, setDark } = useTheme()
|
|
|
|
return (
|
|
<div className="bg-white border-b border-gray-200 px-3 h-9 flex items-center gap-3 shrink-0 text-xs">
|
|
<span className="text-gray-400">Source</span>
|
|
<select
|
|
value={source || ''}
|
|
onChange={e => setSource(e.target.value)}
|
|
disabled={sources.length === 0}
|
|
className="border border-gray-200 rounded px-2 py-0.5 bg-white focus:outline-none focus:border-blue-400"
|
|
>
|
|
{sources.length === 0
|
|
? <option value="">— no sources —</option>
|
|
: sources.map(s => <option key={s.name} value={s.name}>{s.name}</option>)}
|
|
</select>
|
|
<NavLink
|
|
to="/sources?new=1"
|
|
className="text-blue-400 hover:text-blue-600 leading-none"
|
|
title="New source"
|
|
>+</NavLink>
|
|
|
|
{stacks.length > 0 && (
|
|
<>
|
|
<span className="text-gray-200">|</span>
|
|
<span className="text-gray-400">Stacks</span>
|
|
{stacks.map(s => (
|
|
<button
|
|
key={s.name}
|
|
onClick={() => setSelectedStack(n => n === s.name ? null : s.name)}
|
|
className={`rounded px-2 py-0.5 border transition-colors ${
|
|
selectedStack === s.name
|
|
? 'bg-purple-50 border-purple-300 text-purple-700'
|
|
: 'bg-white border-gray-200 text-gray-500 hover:border-gray-400'
|
|
}`}
|
|
>
|
|
{s.name}
|
|
</button>
|
|
))}
|
|
</>
|
|
)}
|
|
|
|
<div className="ml-auto">
|
|
<button
|
|
onClick={() => setDark(d => !d)}
|
|
className="w-6 h-6 flex items-center justify-center rounded hover:bg-gray-100 text-gray-500"
|
|
title={dark ? 'Switch to light mode' : 'Switch to dark mode'}
|
|
>
|
|
{dark ? (
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
<circle cx="12" cy="12" r="4"/>
|
|
<line x1="12" y1="2" x2="12" y2="5"/>
|
|
<line x1="12" y1="19" x2="12" y2="22"/>
|
|
<line x1="4.93" y1="4.93" x2="7.05" y2="7.05"/>
|
|
<line x1="16.95" y1="16.95" x2="19.07" y2="19.07"/>
|
|
<line x1="2" y1="12" x2="5" y2="12"/>
|
|
<line x1="19" y1="12" x2="22" y2="12"/>
|
|
<line x1="4.93" y1="19.07" x2="7.05" y2="16.95"/>
|
|
<line x1="16.95" y1="7.05" x2="19.07" y2="4.93"/>
|
|
</svg>
|
|
) : (
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
|
|
</svg>
|
|
)}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|