wip
This commit is contained in:
commit
d8f2407ddf
1 changed files with 10377 additions and 0 deletions
96
src/components/Fields.tsx
Normal file
96
src/components/Fields.tsx
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
import { useId, useState } from 'react';
|
||||
import type { Issue } from '../lib/types';
|
||||
import { AlertCircle, Info, Check } from 'lucide-react';
|
||||
export function NumberField({
|
||||
label,
|
||||
value,
|
||||
onChange,
|
||||
unit = 'mm',
|
||||
min = 0,
|
||||
max,
|
||||
step = 1,
|
||||
hint,
|
||||
tooltip,
|
||||
}: {
|
||||
label: string;
|
||||
value: number;
|
||||
onChange: (n: number) => void;
|
||||
unit?: string;
|
||||
min?: number;
|
||||
max?: number;
|
||||
step?: number;
|
||||
hint?: string;
|
||||
tooltip?: string;
|
||||
}) {
|
||||
const id = useId();
|
||||
const [showTooltip, setShowTooltip] = useState(false);
|
||||
return (
|
||||
<div className="field">
|
||||
<span className="field-label">
|
||||
<label htmlFor={id}>{label}</label>
|
||||
{tooltip && (
|
||||
<span className="field-tooltip">
|
||||
<button
|
||||
type="button"
|
||||
className="tooltip-button"
|
||||
aria-label={`What is ${label.toLowerCase()}?`}
|
||||
aria-expanded={showTooltip}
|
||||
aria-controls={`${id}-tooltip`}
|
||||
aria-describedby={showTooltip ? `${id}-tooltip` : undefined}
|
||||
onClick={() => setShowTooltip((shown) => !shown)}
|
||||
onBlur={() => setShowTooltip(false)}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Escape') setShowTooltip(false);
|
||||
}}
|
||||
>
|
||||
?
|
||||
</button>
|
||||
{showTooltip && (
|
||||
<span id={`${id}-tooltip`} role="tooltip" className="tooltip-content">
|
||||
{tooltip}
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
<span className="number-input">
|
||||
<input
|
||||
id={id}
|
||||
type="number"
|
||||
inputMode="decimal"
|
||||
value={value}
|
||||
min={min}
|
||||
max={max}
|
||||
step={step}
|
||||
aria-describedby={hint ? `${id}-hint` : undefined}
|
||||
onChange={(e) => onChange(Number(e.target.value))}
|
||||
/>
|
||||
<span>{unit}</span>
|
||||
</span>
|
||||
{hint && <small id={`${id}-hint`}>{hint}</small>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export function Issues({ issues, compact = false }: { issues: Issue[]; compact?: boolean }) {
|
||||
const unique = issues.filter(
|
||||
(issue, i) => issues.findIndex((item) => item.message === issue.message) === i,
|
||||
);
|
||||
return (
|
||||
<div className={`issues ${compact ? 'compact' : ''}`} role="status">
|
||||
{unique.map((issue, i) => (
|
||||
<div className={`issue ${issue.severity}`} key={i}>
|
||||
{issue.severity === 'info' ? <Info size={16} /> : <AlertCircle size={16} />}
|
||||
<span>{issue.message}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export function ClosedBadge({ closed }: { closed: boolean }) {
|
||||
return (
|
||||
<span className={`badge ${closed ? 'success' : 'pending'}`}>
|
||||
{closed ? <Check size={12} /> : <AlertCircle size={12} />}{' '}
|
||||
{closed ? 'Outline closed' : 'Check outline'}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in a new issue