admin/components/consumer/consumerButtonStyles.ts
alisaza e1eaf5eff5 feat: initial ghabilee-admin backoffice app
Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js
app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
2026-09-05 13:12:59 +03:30

138 lines
4.0 KiB
TypeScript

import type {
ConsumerButtonAlign,
ConsumerButtonFill,
ConsumerButtonRadius,
ConsumerButtonSize,
ResolvedConsumerButtonStyle,
} from '@/components/consumer/consumerButtonTypes'
import { cn } from '@/lib/cn'
/** xs/sm/md/lg/xl → px heights (Figma). */
export const CONSUMER_BUTTON_HEIGHT_PX: Record<ConsumerButtonSize, number> = {
xs: 40,
sm: 44,
md: 48,
lg: 52,
xl: 60,
}
const HEIGHT_CLASS: Record<ConsumerButtonSize, string> = {
xs: 'h-10 min-h-10',
sm: 'h-11 min-h-11',
md: 'h-12 min-h-12',
lg: 'h-[52px] min-h-[52px]',
xl: 'h-[60px] min-h-[60px]',
}
const ICON_ONLY_CLASS: Record<ConsumerButtonSize, string> = {
xs: 'h-10 w-10 min-h-10 min-w-10',
sm: 'h-11 w-11 min-h-11 min-w-11',
md: 'h-12 w-12 min-h-12 min-w-12',
lg: 'h-[52px] w-[52px] min-h-[52px] min-w-[52px]',
xl: 'h-[60px] w-[60px] min-h-[60px] min-w-[60px]',
}
const RADIUS_CLASS: Record<ConsumerButtonRadius, string> = {
full: 'rounded-full',
control: 'rounded-[10px]',
}
const FILL_CLASS: Record<ConsumerButtonFill, string> = {
orange: 'bg-primary hover:bg-primary-600 active:bg-primary-700',
navy: 'bg-tertiary-900 hover:bg-tertiary-800 active:bg-tertiary-900',
fourth: 'bg-fourth-900 hover:bg-fourth-700 active:bg-fourth-900',
fifth: 'bg-fifth-900 hover:bg-fifth-700 active:bg-fifth-900',
gray: 'bg-[#F5F5F5] hover:bg-secondary-40 active:bg-secondary-200',
none: 'bg-transparent',
}
const DEFAULT_TEXT_CLASS: Record<ConsumerButtonFill, string | undefined> = {
orange: 'text-white',
navy: 'text-white',
fourth: 'text-white',
fifth: 'text-white',
gray: 'text-consumer-text',
none: undefined,
}
const DEFAULT_SIZE: Record<'default' | 'icon', ConsumerButtonSize> = {
default: 'lg',
icon: 'sm',
}
function resolveTextColorClass(textColor: string | undefined, fill: ConsumerButtonFill): string | undefined {
if (!textColor) return DEFAULT_TEXT_CLASS[fill]
if (textColor === 'white') return 'text-white'
if (textColor.startsWith('text-') || textColor.startsWith('!text-')) return textColor
return undefined
}
function resolveTextColorStyle(textColor: string | undefined): string | undefined {
if (!textColor || textColor === 'white' || textColor.startsWith('text-') || textColor.startsWith('!text-')) {
return undefined
}
if (textColor.startsWith('#')) return textColor
return undefined
}
/** وقتی از بیرون `px-*` داده شده، padding افقی پیش‌فرض اعمال نمی‌شود. */
function hasHorizontalPaddingOverride(className?: string): boolean {
return className != null && /\b!?px-/.test(className)
}
function resolveHorizontalPaddingClass(iconOnly: boolean, className?: string): string | undefined {
if (hasHorizontalPaddingOverride(className)) return undefined
return iconOnly ? 'px-0' : 'px-4'
}
export function buildConsumerButtonStyle({
align = 'center',
className,
radius = 'full',
fill = 'orange',
fontSize = 14,
fullWidth = false,
iconOnly = false,
size,
textColor,
}: {
align?: ConsumerButtonAlign
className?: string
radius?: ConsumerButtonRadius
fill?: ConsumerButtonFill
fontSize?: number
fullWidth?: boolean
iconOnly?: boolean
size?: ConsumerButtonSize
textColor?: string
}): ResolvedConsumerButtonStyle {
const resolvedSize = size ?? (iconOnly ? DEFAULT_SIZE.icon : DEFAULT_SIZE.default)
const textClass = resolveTextColorClass(textColor, fill)
const inlineColor = resolveTextColorStyle(textColor)
return {
className: cn(
'consumer-focus-ring inline-flex shrink-0 items-center gap-2 font-medium transition-colors',
'disabled:pointer-events-none disabled:opacity-50',
resolveHorizontalPaddingClass(iconOnly, className),
iconOnly
? cn(ICON_ONLY_CLASS[resolvedSize], 'justify-center')
: cn(HEIGHT_CLASS[resolvedSize], align === 'center' ? 'justify-center' : 'justify-start'),
!iconOnly && 'min-w-0',
RADIUS_CLASS[radius],
FILL_CLASS[fill],
textClass,
fullWidth && 'w-full',
className
),
style: {
fontSize,
...(inlineColor ? { color: inlineColor } : {}),
},
}
}