mitai-jinkendo/frontend/src/components/pilot/PilotVizAdminCard.jsx
Lars 8c8f595385
All checks were successful
Deploy Development / deploy (push) Successful in 54s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s
feat: Refactor PilotVizPage and widget registry for improved layout and rendering
- Replaced the previous widget retrieval method with a new layout-based approach in PilotVizPage.
- Introduced a PilotVizAdminCard for layout configuration and management.
- Updated widget definitions in the registry to include new components and default order.
- Enhanced user feedback for widget visibility with a message when no widgets are active.
2026-04-07 10:21:11 +02:00

129 lines
4.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Settings2, RotateCcw, ChevronUp, ChevronDown } from 'lucide-react'
import { PILOT_WIDGET_DEFS, PILOT_WIDGET_IDS_DEFAULT_ORDER } from '../../pilot/widgetRegistry'
import { resetPilotLayout, savePilotLayout } from '../../pilot/pilotLayoutStorage'
/**
* Pilot: lokale Konfiguration (Ein/Aus, Reihenfolge). Kein Admin-Recht nötig.
*/
export default function PilotVizAdminCard({ layout, onLayoutChange }) {
const persist = (next) => {
savePilotLayout(next)
onLayoutChange(next)
}
const move = (index, dir) => {
const nextOrder = [...layout.order]
const j = index + dir
if (j < 0 || j >= nextOrder.length) return
;[nextOrder[index], nextOrder[j]] = [nextOrder[j], nextOrder[index]]
persist({ ...layout, order: nextOrder })
}
const toggle = (id) => {
persist({
...layout,
enabled: { ...layout.enabled, [id]: !layout.enabled[id] },
})
}
const handleReset = () => {
onLayoutChange(resetPilotLayout())
}
return (
<section
className="card section-gap"
style={{
borderStyle: 'solid',
borderColor: 'var(--accent)',
borderWidth: 1,
background: 'var(--surface)',
}}
>
<div className="card-title" style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
<Settings2 size={18} color="var(--accent)" />
Widget-Konfiguration (Pilot)
</div>
<p style={{ fontSize: 12, color: 'var(--text2)', marginTop: 4, marginBottom: 14, lineHeight: 1.5 }}>
Sichtbarkeit und Reihenfolge steuern. Wird nur <strong>lokal in diesem Browser</strong> gespeichert
(<code style={{ fontSize: 11 }}>localStorage</code>) gut zum Ausprobieren vor einer serverseitigen
Profil-Konfiguration.
</p>
<ul style={{ listStyle: 'none', margin: 0, padding: 0, display: 'flex', flexDirection: 'column', gap: 8 }}>
{layout.order.map((id, index) => {
const def = PILOT_WIDGET_DEFS[id]
if (!def) return null
const on = !!layout.enabled[id]
return (
<li
key={id}
style={{
display: 'flex',
alignItems: 'center',
gap: 8,
flexWrap: 'wrap',
padding: '10px 12px',
borderRadius: 10,
background: on ? 'var(--surface2)' : 'var(--surface)',
border: '1px solid var(--border)',
opacity: on ? 1 : 0.72,
}}
>
<div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
<button
type="button"
className="btn btn-secondary"
style={{ padding: '4px 8px', minWidth: 36 }}
title="Nach oben"
disabled={index === 0}
onClick={() => move(index, -1)}
>
<ChevronUp size={16} />
</button>
<button
type="button"
className="btn btn-secondary"
style={{ padding: '4px 8px', minWidth: 36 }}
title="Nach unten"
disabled={index === layout.order.length - 1}
onClick={() => move(index, 1)}
>
<ChevronDown size={16} />
</button>
</div>
<div style={{ flex: 1, minWidth: 140 }}>
<div style={{ fontSize: 13, fontWeight: 600, color: 'var(--text1)' }}>{def.title}</div>
<code style={{ fontSize: 10, color: 'var(--text3)' }}>{id}</code>
</div>
<label
style={{
display: 'flex',
alignItems: 'center',
gap: 8,
fontSize: 13,
cursor: 'pointer',
userSelect: 'none',
}}
>
<input type="checkbox" checked={on} onChange={() => toggle(id)} />
sichtbar
</label>
</li>
)
})}
</ul>
<div style={{ marginTop: 14, display: 'flex', flexWrap: 'wrap', gap: 8, alignItems: 'center' }}>
<button type="button" className="btn btn-secondary" onClick={handleReset} style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
<RotateCcw size={14} />
Standard wiederherstellen
</button>
<span style={{ fontSize: 11, color: 'var(--text3)' }}>
Standard-Reihenfolge: {PILOT_WIDGET_IDS_DEFAULT_ORDER.join(' → ')}
</span>
</div>
</section>
)
}