5180 fichiers 38.5 Mo 0 téléchargements 466 vues mis à jour il y a 7 heures ui
HousekeepingParts.tsx 6.5 Ko Télécharger le fichier
import { FC, PropsWithChildren, ReactNode } from 'react';
import { NumberInput } from '../../../../common/NumberInput';
import { BaseButton } from '../../../../common/BaseButton';
import { Hint } from '../../../../common/Tooltip';
import { NativeTextTree } from '../../../../common/native-text/NativeTextTree';

/**
 * Small building blocks shared by the housekeeping tabs, so every tab uses the
 * same section frame, status pills and label/value tiles instead of repeating
 * the class lists inline.
 */

export type HousekeepingTone = 'neutral' | 'info' | 'success' | 'warning' | 'danger' | 'accent';

const PILL_TONES: Record<HousekeepingTone, string> = {
    neutral: 'bg-zinc-100 border-zinc-200 text-zinc-600',
    info: 'bg-sky-50 border-sky-200 text-sky-700',
    success: 'bg-emerald-50 border-emerald-200 text-emerald-700',
    warning: 'bg-amber-50 border-amber-200 text-amber-800',
    danger: 'bg-rose-50 border-rose-200 text-rose-700',
    accent: 'bg-violet-50 border-violet-200 text-violet-700'
};

const SECTION_TONES: Record<HousekeepingTone, string> = {
    neutral: 'border-zinc-200 bg-white',
    info: 'border-sky-200 bg-sky-50/40',
    success: 'border-emerald-200 bg-emerald-50/40',
    warning: 'border-amber-200 bg-amber-50/40',
    danger: 'border-rose-200 bg-rose-50/40',
    accent: 'border-violet-200 bg-violet-50/40'
};

export const HousekeepingPill: FC<PropsWithChildren<{ tone?: HousekeepingTone; icon?: ReactNode; title?: string }>> = ({
    tone = 'neutral',
    icon,
    title,
    children
}) => (
    <span
        className={`inline-flex items-center gap-1 whitespace-nowrap rounded-full border px-1.5 py-0.5 text-[11px] font-bold leading-none ${PILL_TONES[tone]}`}
        title={title}
    >
        {icon}
        {children}
    </span>
);

export const HousekeepingSection: FC<PropsWithChildren<{ title?: string; icon?: ReactNode; tone?: HousekeepingTone; aside?: ReactNode }>> = ({
    title,
    icon,
    tone = 'neutral',
    aside,
    children
}) => (
    <section className={`flex flex-col gap-1.5 rounded-md border p-2 ${SECTION_TONES[tone]}`}>
        {(title || aside) && (
            <header className="flex items-center gap-1.5">
                {title && (
                    <h3 className="hk-air-heading m-0 flex items-center gap-1 text-[14px] font-bold text-black">
                        {icon}
                        {title}
                    </h3>
                )}
                {aside && <div className="ml-auto flex items-center gap-1">{aside}</div>}
            </header>
        )}
        {children}
    </section>
);

/** A label over a value, for the fact grids of the user and room cards. */
export const HousekeepingFact: FC<{ label: string; value: ReactNode; icon?: ReactNode; title?: string }> = ({ label, value, icon, title }) => (
    <NativeTextTree>
        <div className="flex min-w-0 flex-col rounded border border-zinc-200 bg-white/80 px-1.5 py-1" title={title}>
            <span className="flex items-center gap-1 text-[11px] text-[#666666]">
                {icon}
                {label}
            </span>
            <span className="truncate text-xs font-bold tabular-nums text-black">{value}</span>
        </div>
    </NativeTextTree>
);

export const HousekeepingEmptyState: FC<PropsWithChildren<{ icon?: ReactNode }>> = ({ icon, children }) => (
    <NativeTextTree>
        <div className="flex items-center gap-2 rounded-lg border border-dashed border-zinc-300 bg-zinc-50/60 p-3 text-xs italic text-[#666666]">
            {icon}
            {children}
        </div>
    </NativeTextTree>
);

/** Numeric field with its unit, used next to the timed sanction buttons. */
export const HousekeepingNumberField: FC<{
    value: number;
    onChange: (value: number) => void;
    unit?: string;
    min?: number;
    max?: number;
    label?: string;
    widthClass?: string;
}> = ({ value, onChange, unit, min = 1, max, label, widthClass = 'w-14' }) => (
    <label className="flex shrink-0 items-center gap-1">
        {label && <span className="text-[11px] font-bold text-black">{label}</span>}
        <NumberInput aria-label={label ?? unit} className={`${widthClass} rounded border border-zinc-300 bg-white px-1.5 py-0.5 text-xs tabular-nums focus:outline-none focus:ring-1 focus:ring-sky-400`} max={max} min={min} value={Number.isFinite(value) && value > 0 ? value : ''} onChange={(event) => onChange(parseInt(event.target.value) || 0)} />
        {unit && <span className="text-[11px] text-[#666666]">{unit}</span>}
    </label>
);

export const HOUSEKEEPING_INPUT_CLASS =
    'w-full rounded border border-zinc-300 bg-white px-2 py-1 text-xs text-black placeholder:italic placeholder:text-zinc-400 focus:outline-none focus:ring-1 focus:ring-sky-400';

export const HousekeepingField: FC<PropsWithChildren<{ label: string; hint?: string; className?: string }>> = ({ label, hint, className = '', children }) => (
    <NativeTextTree>
        <label className={`flex min-w-0 flex-col gap-0.5 ${className}`}>
            <span className="flex items-baseline gap-1 text-[11px] font-bold text-black">
                {label}
                {hint && <span className="ml-auto font-normal normal-case tracking-normal text-zinc-400">{hint}</span>}
            </span>
            {children}
        </label>
    </NativeTextTree>
);

export type HousekeepingButtonVariant = 'primary' | 'success' | 'warning' | 'danger' | 'secondary' | 'neutral';

const BUTTON_TONES: Record<HousekeepingButtonVariant, string> = {
    primary: 'hk-btn--primary',
    success: 'hk-btn--success',
    warning: 'hk-btn--warning',
    danger: 'hk-btn--danger',
    secondary: 'hk-btn--neutral',
    neutral: 'hk-btn--neutral'
};

/**
 * The housekeeping button. Styled in HousekeepingView.css (the card theme
 * overrides utility classes inside a card); disabled looks disabled in every tone.
 * Takes the same props the panels used with the shared Button.
 */
export const HousekeepingButton: FC<
    PropsWithChildren<{
        variant?: HousekeepingButtonVariant;
        size?: 'sm' | 'md';
        disabled?: boolean;
        title?: string;
        classNames?: string[];
        gap?: number;
        type?: 'button' | 'submit';
        onClick?: () => void;
    }>
> = ({ variant = 'primary', size = 'md', disabled = false, title, classNames = [], type = 'button', onClick, children }) => (
    <Hint content={title}><BaseButton
        className={['hk-btn', BUTTON_TONES[variant], size === 'sm' ? 'hk-btn--sm' : '', ...classNames].filter(Boolean).join(' ')}
        disabled={disabled}
        type={type}
        onClick={onClick}
    >
        {children}
    </BaseButton></Hint>
);
15Sujets
1Dépôts
20Membres
3En ligne
Profile
Inscrit
Dernière visite
Messages
0
Votes positifs
0
Votes négatifs
0

Nous utilisons des cookies pour assurer le bon fonctionnement du site et améliorer votre expérience. en savoir plus

Autoriser