'use client'; import { useDarkMode } from '@/state/darkModeStore'; import { themeTokens, getResponsiveFz } from '@/utils/themeTokens'; import { Text, Title, Box, BoxProps } from '@mantine/core'; import React from 'react'; type TextTruncate = 'end' | 'start' | boolean; /** * Unified Typography Components * * Komponen text dengan styling konsisten di seluruh aplikasi * Mendukung dark mode sesuai spesifikasi darkMode.md * * Usage: * import { UnifiedText, UnifiedTitle } from '@/components/admin/UnifiedTypography'; * * Judul Halaman * Konten teks */ // ============================================================================ // Unified Title Component // ============================================================================ interface UnifiedTitleProps { order?: 1 | 2 | 3 | 4 | 5 | 6; children: React.ReactNode; align?: 'left' | 'center' | 'right'; color?: 'primary' | 'secondary' | 'brand' | string; mb?: string; mt?: string; ml?: string; mr?: string; mx?: string; my?: string; style?: React.CSSProperties; } export function UnifiedTitle({ order = 1, children, align = 'left', color = 'primary', mb, mt, ml, mr, mx, my, style, }: UnifiedTitleProps) { const { isDark } = useDarkMode(); const tokens = themeTokens(isDark); const responsiveFz = getResponsiveFz(isDark); const getTypography = () => { switch (order) { case 1: return tokens.typography.h1; case 2: return tokens.typography.h2; case 3: return tokens.typography.h3; case 4: return tokens.typography.h4; default: return tokens.typography.body; } }; const typo = getTypography(); const getColor = () => { if (color === 'primary') return tokens.colors.text.primary; if (color === 'secondary') return tokens.colors.text.secondary; if (color === 'brand') return tokens.colors.text.brand; return color; }; return ( {children} ); } // ============================================================================ // Unified Text Component // ============================================================================ interface UnifiedTextProps { size?: 'small' | 'body' | 'label'; weight?: 'normal' | 'medium' | 'bold'; children: React.ReactNode; align?: 'left' | 'center' | 'right'; color?: 'primary' | 'secondary' | 'tertiary' | 'muted' | 'brand' | 'link' | string; lineClamp?: number; truncate?: TextTruncate; span?: boolean; mt?: string; mb?: string; ml?: string; mr?: string; mx?: string; my?: string; style?: React.CSSProperties; } export function UnifiedText({ size = 'body', weight = 'normal', children, align = 'left', color = 'primary', lineClamp, truncate, span = false, mt, mb, ml, mr, mx, my, style, }: UnifiedTextProps) { const { isDark } = useDarkMode(); const tokens = themeTokens(isDark); const getTypography = () => { switch (size) { case 'small': return tokens.typography.small; case 'label': return tokens.typography.label; default: return tokens.typography.body; } }; const getWeight = () => { switch (weight) { case 'normal': return 400; case 'medium': return 500; case 'bold': return 700; default: return 400; } }; const getColor = () => { switch (color) { case 'primary': return tokens.colors.text.primary; case 'secondary': return tokens.colors.text.secondary; case 'tertiary': return tokens.colors.text.tertiary; case 'muted': return tokens.colors.text.muted; case 'brand': return tokens.colors.text.brand; case 'link': return tokens.colors.text.link; default: return color; } }; const typo = getTypography(); const fw = getWeight(); const textColor = getColor(); if (span) { return ( {children} ); } return ( {children} ); } // ============================================================================ // Unified Page Header Component // // Header standar untuk setiap halaman admin // Sesuai spesifikasi: Section Header dengan font weight lebih besar // ============================================================================ interface UnifiedPageHeaderProps extends BoxProps { title: string; subtitle?: string; action?: React.ReactNode; showBorder?: boolean; } export function UnifiedPageHeader({ title, subtitle, action, showBorder = true, style, ...props }: UnifiedPageHeaderProps) { const { isDark } = useDarkMode(); const tokens = themeTokens(isDark); return (
{title} {subtitle && ( {subtitle} )}
{action &&
{action}
}
); } export default UnifiedText;