Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
134 lines
4.3 KiB
TypeScript
134 lines
4.3 KiB
TypeScript
import { cn } from '@/lib/cn'
|
|
|
|
/** Shared HeroUI field wrapper classes — Remi design system (8px radius, white surface). */
|
|
export const FIELD_WRAPPER =
|
|
'bg-surface shadow-none border border-divider hover:!border-primary-hover group-data-[focus=true]:!border-primary group-data-[focus=true]:hover:!border-primary'
|
|
|
|
/** Reserve no empty space under fields when there is no error message. */
|
|
export const FIELD_HELPER_WRAPPER = 'min-h-0 p-0'
|
|
|
|
export const FIELD_RADIUS = 'md' as const
|
|
|
|
export const DATE_PICKER_CLASSNAME = 'date-picker-input'
|
|
|
|
export type RemiFieldVariant = 'flat' | 'bordered' | 'faded' | 'underlined'
|
|
export type RemiFieldSize = 'sm' | 'md' | 'lg'
|
|
|
|
interface RemiDatePickerStyleOptions {
|
|
variant?: RemiFieldVariant
|
|
size?: RemiFieldSize
|
|
isInvalid?: boolean
|
|
/** When true, border/background live on {@link REMI_BORDERED_DATE_PICKER_WRAPPER} / underlined wrapper. */
|
|
inWrapper?: boolean
|
|
}
|
|
|
|
/** Wrapper for table filters — matches HeroUI bordered `sm` Input (`h-8`, `px-2`, `rounded-medium`). */
|
|
export const REMI_BORDERED_DATE_PICKER_WRAPPER = cn(
|
|
FIELD_WRAPPER,
|
|
'flex h-8 min-h-8 w-full items-center rounded-medium px-2',
|
|
'focus-within:!border-primary focus-within:hover:!border-primary'
|
|
)
|
|
|
|
/** Wrapper for modal filters — matches HeroUI underlined `md` Input. */
|
|
export const REMI_UNDERLINED_DATE_PICKER_WRAPPER = cn(
|
|
'flex h-10 min-h-10 w-full items-center rounded-none border-b border-divider bg-surface px-1 pb-1 shadow-none',
|
|
'hover:!border-primary-hover focus-within:!border-primary'
|
|
)
|
|
|
|
/** Inline styles for react-multi-date-picker — aligned with HeroUI Input sizes in PaginatedList. */
|
|
export function getRemiDatePickerStyles({
|
|
variant = 'bordered',
|
|
size = 'md',
|
|
isInvalid = false,
|
|
inWrapper = false,
|
|
}: RemiDatePickerStyleOptions = {}) {
|
|
const errorColor = 'var(--color-fourth)'
|
|
const neutralBorder = 'var(--color-divider)'
|
|
|
|
const height = size === 'sm' ? '32px' : size === 'lg' ? '48px' : '40px'
|
|
const horizontalPadding = size === 'sm' ? '8px' : '12px'
|
|
|
|
if (inWrapper) {
|
|
return {
|
|
width: '100%',
|
|
boxSizing: 'border-box' as const,
|
|
height: '100%',
|
|
minHeight: height,
|
|
border: 'none',
|
|
background: 'transparent',
|
|
borderRadius: '0',
|
|
color: 'var(--color-text-main)',
|
|
padding: '0',
|
|
textAlign: 'right' as const,
|
|
boxShadow: 'none',
|
|
outline: 'none',
|
|
}
|
|
}
|
|
|
|
const baseStyles = {
|
|
width: '100%',
|
|
boxSizing: 'border-box' as const,
|
|
height,
|
|
borderRadius: '8px',
|
|
color: 'var(--color-text-main)',
|
|
padding: `0 ${horizontalPadding}`,
|
|
textAlign: 'right' as const,
|
|
boxShadow: 'none',
|
|
outline: 'none',
|
|
}
|
|
|
|
switch (variant) {
|
|
case 'bordered':
|
|
return {
|
|
...baseStyles,
|
|
background: 'var(--color-surface)',
|
|
border: '1px solid',
|
|
borderColor: isInvalid ? errorColor : neutralBorder,
|
|
}
|
|
case 'faded':
|
|
return {
|
|
...baseStyles,
|
|
background: '#f4f4f5',
|
|
border: '1px solid',
|
|
borderColor: isInvalid ? errorColor : neutralBorder,
|
|
}
|
|
case 'underlined':
|
|
return {
|
|
...baseStyles,
|
|
background: 'transparent',
|
|
border: 'none',
|
|
borderBottom: `1px solid ${isInvalid ? errorColor : neutralBorder}`,
|
|
borderRadius: '0',
|
|
borderColor: isInvalid ? errorColor : neutralBorder,
|
|
}
|
|
case 'flat':
|
|
default:
|
|
return {
|
|
...baseStyles,
|
|
background: '#f4f4f5',
|
|
border: isInvalid ? `1px solid ${errorColor}` : 'none',
|
|
borderColor: isInvalid ? errorColor : '#f4f4f5',
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Listbox option styling — light hover/focus, no borders. */
|
|
export const REMI_LISTBOX_ITEM_CLASSES = {
|
|
base: [
|
|
'bg-surface rounded-md border-none shadow-none outline-none',
|
|
'data-[hover=true]:border-none data-[hover=true]:bg-accent-light/50 data-[hover=true]:shadow-none',
|
|
'data-[focus=true]:border-none data-[focus=true]:bg-accent-light/50 data-[focus=true]:shadow-none',
|
|
'data-[focus-visible=true]:outline-none data-[focus-visible=true]:border-none',
|
|
'data-[selected=true]:bg-primary/10 data-[selected=true]:border-none',
|
|
].join(' '),
|
|
}
|
|
|
|
export const REMI_LISTBOX_PROPS = {
|
|
emptyContent: 'موردی یافت نشد',
|
|
itemClasses: REMI_LISTBOX_ITEM_CLASSES,
|
|
classNames: {
|
|
base: 'bg-surface',
|
|
list: 'bg-surface',
|
|
},
|
|
} as const
|