Improve admin mobile dark mode contrast
This commit is contained in:
@@ -46,14 +46,19 @@ function DashboardCard({
|
|||||||
}: React.ComponentProps<typeof Card> & { variant?: 'default' | 'embedded' }) {
|
}: React.ComponentProps<typeof Card> & { variant?: 'default' | 'embedded' }) {
|
||||||
const theme = useAdminTheme();
|
const theme = useAdminTheme();
|
||||||
const isEmbedded = variant === 'embedded';
|
const isEmbedded = variant === 'embedded';
|
||||||
|
const cardSurface = isEmbedded
|
||||||
|
? (theme.surfaceMuted ?? theme.glassSurface ?? theme.surface)
|
||||||
|
: (theme.glassSurfaceStrong ?? theme.surface);
|
||||||
|
const cardBorder = theme.glassBorder ?? theme.border;
|
||||||
|
const cardShadow = theme.glassShadow ?? theme.shadow;
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
backgroundColor={theme.surface}
|
backgroundColor={cardSurface}
|
||||||
borderRadius={isEmbedded ? 16 : 20}
|
borderRadius={isEmbedded ? 16 : 20}
|
||||||
borderWidth={1}
|
borderWidth={1}
|
||||||
borderColor={theme.border}
|
borderColor={cardBorder}
|
||||||
padding="$3.5"
|
padding="$3.5"
|
||||||
shadowColor={theme.shadow}
|
shadowColor={cardShadow}
|
||||||
shadowOpacity={isEmbedded ? 0 : 0.16}
|
shadowOpacity={isEmbedded ? 0 : 0.16}
|
||||||
shadowRadius={isEmbedded ? 0 : 16}
|
shadowRadius={isEmbedded ? 0 : 16}
|
||||||
shadowOffset={isEmbedded ? { width: 0, height: 0 } : { width: 0, height: 10 }}
|
shadowOffset={isEmbedded ? { width: 0, height: 0 } : { width: 0, height: 10 }}
|
||||||
@@ -444,7 +449,8 @@ function LifecycleHero({
|
|||||||
alignItems="center"
|
alignItems="center"
|
||||||
justifyContent="space-between"
|
justifyContent="space-between"
|
||||||
borderWidth={1}
|
borderWidth={1}
|
||||||
borderColor={theme.border}
|
borderColor={theme.glassBorder ?? theme.border}
|
||||||
|
backgroundColor={theme.surfaceMuted}
|
||||||
borderRadius={12}
|
borderRadius={12}
|
||||||
paddingHorizontal="$2.5"
|
paddingHorizontal="$2.5"
|
||||||
paddingVertical="$2"
|
paddingVertical="$2"
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ export function BottomNav({ active, onNavigate }: { active: NavKey; onNavigate:
|
|||||||
const theme = useAdminTheme();
|
const theme = useAdminTheme();
|
||||||
|
|
||||||
// Modern Glass Background
|
// Modern Glass Background
|
||||||
const navSurface = 'rgba(255, 255, 255, 0.85)';
|
const navSurface = theme.glassSurfaceStrong ?? theme.surfaceMuted ?? theme.surface;
|
||||||
const navBorder = theme.border;
|
const navBorder = theme.glassBorder ?? theme.border;
|
||||||
const navShadow = theme.shadow;
|
const navShadow = theme.glassShadow ?? theme.shadow;
|
||||||
|
|
||||||
const [pressedKey, setPressedKey] = React.useState<NavKey | null>(null);
|
const [pressedKey, setPressedKey] = React.useState<NavKey | null>(null);
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ export function BottomNav({ active, onNavigate }: { active: NavKey; onNavigate:
|
|||||||
const IconCmp = item.icon;
|
const IconCmp = item.icon;
|
||||||
|
|
||||||
// Dynamic Styles
|
// Dynamic Styles
|
||||||
const color = activeState ? theme.primary : theme.subtle;
|
const color = activeState ? theme.primary : theme.muted;
|
||||||
const strokeWidth = activeState ? 2.5 : 2;
|
const strokeWidth = activeState ? 2.5 : 2;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -253,9 +253,13 @@ export function MobileSelect({
|
|||||||
style,
|
style,
|
||||||
...props
|
...props
|
||||||
}: MobileSelectProps) {
|
}: MobileSelectProps) {
|
||||||
const { border, surface, text, primary, danger, subtle } = useAdminTheme();
|
const { border, surface, text, primary, danger, subtle, glassSurfaceStrong, surfaceMuted, glassBorder } = useAdminTheme();
|
||||||
const borderColor = hasError ? danger : border;
|
const borderColor = hasError ? danger : (glassBorder ?? border);
|
||||||
const ringColor = hasError ? withAlpha(danger, 0.18) : withAlpha(primary, 0.18);
|
const ringColor = hasError ? withAlpha(danger, 0.18) : withAlpha(primary, 0.18);
|
||||||
|
const triggerSurface = surfaceMuted ?? glassSurfaceStrong ?? surface;
|
||||||
|
const contentSurface = glassSurfaceStrong ?? surface;
|
||||||
|
const itemSurface = surface;
|
||||||
|
const itemHover = surfaceMuted ?? surface;
|
||||||
const hasSizing =
|
const hasSizing =
|
||||||
typeof containerStyle === 'object' &&
|
typeof containerStyle === 'object' &&
|
||||||
containerStyle !== null &&
|
containerStyle !== null &&
|
||||||
@@ -298,7 +302,7 @@ export function MobileSelect({
|
|||||||
borderRadius={12}
|
borderRadius={12}
|
||||||
borderWidth={1}
|
borderWidth={1}
|
||||||
borderColor={borderColor as any}
|
borderColor={borderColor as any}
|
||||||
backgroundColor={surface as any}
|
backgroundColor={triggerSurface as any}
|
||||||
paddingVertical={compact ? 6 : 10}
|
paddingVertical={compact ? 6 : 10}
|
||||||
paddingHorizontal="$3"
|
paddingHorizontal="$3"
|
||||||
disabled={props.disabled}
|
disabled={props.disabled}
|
||||||
@@ -320,14 +324,22 @@ export function MobileSelect({
|
|||||||
zIndex={200000}
|
zIndex={200000}
|
||||||
{...({ borderRadius: 14 } as any)}
|
{...({ borderRadius: 14 } as any)}
|
||||||
borderWidth={1}
|
borderWidth={1}
|
||||||
borderColor={border}
|
borderColor={glassBorder ?? border}
|
||||||
backgroundColor={surface as any}
|
backgroundColor={contentSurface as any}
|
||||||
>
|
>
|
||||||
<Select.Viewport {...({ padding: "$2" } as any)}>
|
<Select.Viewport {...({ padding: "$2" } as any)}>
|
||||||
<Select.Group>
|
<Select.Group>
|
||||||
{options.map((option, index) => (
|
{options.map((option, index) => (
|
||||||
<Select.Item index={index} key={`${option.value}-${index}`} value={option.value} disabled={option.disabled}>
|
<Select.Item
|
||||||
<Select.ItemText>{option.label}</Select.ItemText>
|
index={index}
|
||||||
|
key={`${option.value}-${index}`}
|
||||||
|
value={option.value}
|
||||||
|
disabled={option.disabled}
|
||||||
|
backgroundColor={itemSurface as any}
|
||||||
|
hoverStyle={{ backgroundColor: itemHover as any }}
|
||||||
|
pressStyle={{ backgroundColor: itemHover as any }}
|
||||||
|
>
|
||||||
|
<Select.ItemText {...({ color: text } as any)}>{option.label}</Select.ItemText>
|
||||||
</Select.Item>
|
</Select.Item>
|
||||||
))}
|
))}
|
||||||
</Select.Group>
|
</Select.Group>
|
||||||
|
|||||||
@@ -44,27 +44,27 @@ export function PillBadge({
|
|||||||
tone?: 'success' | 'warning' | 'danger' | 'muted';
|
tone?: 'success' | 'warning' | 'danger' | 'muted';
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
const { theme } = useAdminTheme();
|
const { successText, warningText, dangerText, muted, surfaceMuted, border } = useAdminTheme();
|
||||||
const palette: Record<typeof tone, { bg: string; text: string; border: string }> = {
|
const palette: Record<typeof tone, { bg: string; text: string; border: string }> = {
|
||||||
success: {
|
success: {
|
||||||
bg: String(theme.backgroundStrong?.val ?? '#ecfdf3'),
|
bg: withAlpha(successText, 0.16),
|
||||||
text: String(theme.green10?.val ?? '#047857'),
|
text: successText,
|
||||||
border: String(theme.green6?.val ?? '#bbf7d0'),
|
border: withAlpha(successText, 0.35),
|
||||||
},
|
},
|
||||||
warning: {
|
warning: {
|
||||||
bg: String(theme.yellow3?.val ?? '#fffbeb'),
|
bg: withAlpha(warningText, 0.16),
|
||||||
text: String(theme.yellow11?.val ?? '#92400e'),
|
text: warningText,
|
||||||
border: String(theme.yellow6?.val ?? '#fef3c7'),
|
border: withAlpha(warningText, 0.35),
|
||||||
},
|
},
|
||||||
danger: {
|
danger: {
|
||||||
bg: String(theme.red3?.val ?? '#FEE2E2'),
|
bg: withAlpha(dangerText, 0.16),
|
||||||
text: String(theme.red11?.val ?? '#B91C1C'),
|
text: dangerText,
|
||||||
border: String(theme.red6?.val ?? '#FCA5A5'),
|
border: withAlpha(dangerText, 0.35),
|
||||||
},
|
},
|
||||||
muted: {
|
muted: {
|
||||||
bg: String(theme.gray3?.val ?? '#f3f4f6'),
|
bg: surfaceMuted,
|
||||||
text: String(theme.gray11?.val ?? '#374151'),
|
text: muted,
|
||||||
border: String(theme.gray6?.val ?? '#e5e7eb'),
|
border,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const colors = palette[tone] ?? palette.muted;
|
const colors = palette[tone] ?? palette.muted;
|
||||||
@@ -210,7 +210,11 @@ export function KpiStrip({
|
|||||||
tone?: 'accent' | 'neutral';
|
tone?: 'accent' | 'neutral';
|
||||||
}>
|
}>
|
||||||
}) {
|
}) {
|
||||||
const { glassSurface, border, textStrong, textMuted, primary, surfaceMuted, surface } = useAdminTheme();
|
const { glassSurface, glassSurfaceStrong, glassBorder, border, textStrong, textMuted, primary, surfaceMuted, surface } = useAdminTheme();
|
||||||
|
const cardSurface = surfaceMuted ?? glassSurfaceStrong ?? glassSurface ?? surface;
|
||||||
|
const cardBorder = glassBorder ?? border;
|
||||||
|
const separatorColor = withAlpha(textStrong, 0.12);
|
||||||
|
const innerSeparatorColor = withAlpha(textStrong, 0.08);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<XStack flexWrap="wrap" gap="$2">
|
<XStack flexWrap="wrap" gap="$2">
|
||||||
@@ -222,10 +226,10 @@ export function KpiStrip({
|
|||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
key={index}
|
key={index}
|
||||||
backgroundColor={glassSurface ?? surface}
|
backgroundColor={cardSurface}
|
||||||
borderRadius={14}
|
borderRadius={14}
|
||||||
borderWidth={1}
|
borderWidth={1}
|
||||||
borderColor={border}
|
borderColor={cardBorder}
|
||||||
padding="$2.5"
|
padding="$2.5"
|
||||||
flexGrow={1}
|
flexGrow={1}
|
||||||
flexBasis="48%"
|
flexBasis="48%"
|
||||||
@@ -242,7 +246,7 @@ export function KpiStrip({
|
|||||||
>
|
>
|
||||||
{item.value}
|
{item.value}
|
||||||
</Text>
|
</Text>
|
||||||
<Separator vertical backgroundColor={border} height={32} opacity={0.6} />
|
<Separator vertical backgroundColor={separatorColor} height={32} />
|
||||||
<YStack alignItems="center" space="$0.5">
|
<YStack alignItems="center" space="$0.5">
|
||||||
<XStack
|
<XStack
|
||||||
width={28}
|
width={28}
|
||||||
@@ -264,7 +268,7 @@ export function KpiStrip({
|
|||||||
>
|
>
|
||||||
{item.label}
|
{item.label}
|
||||||
</Text>
|
</Text>
|
||||||
<Separator backgroundColor={border} opacity={0.4} width={28} alignSelf="center" />
|
<Separator backgroundColor={innerSeparatorColor} width={28} alignSelf="center" />
|
||||||
{item.note ? (
|
{item.note ? (
|
||||||
<Text fontSize={9} fontWeight="800" color={iconColor} opacity={0.9} textTransform="uppercase">
|
<Text fontSize={9} fontWeight="800" color={iconColor} opacity={0.9} textTransform="uppercase">
|
||||||
{item.note}
|
{item.note}
|
||||||
|
|||||||
@@ -127,6 +127,8 @@ export function useAdminTheme() {
|
|||||||
border,
|
border,
|
||||||
text,
|
text,
|
||||||
textStrong: text, // Alias
|
textStrong: text, // Alias
|
||||||
|
textMuted: muted, // Alias for legacy usage
|
||||||
|
textSubtle: subtle, // Alias for legacy usage
|
||||||
muted, // Now properly derived from text color
|
muted, // Now properly derived from text color
|
||||||
subtle, // Now properly derived from text color
|
subtle, // Now properly derived from text color
|
||||||
primary,
|
primary,
|
||||||
@@ -134,12 +136,12 @@ export function useAdminTheme() {
|
|||||||
accentSoft: String(theme.blue3?.val ?? ADMIN_COLORS.accentSoft),
|
accentSoft: String(theme.blue3?.val ?? ADMIN_COLORS.accentSoft),
|
||||||
accentStrong: String(theme.blue11?.val ?? ADMIN_COLORS.primaryStrong),
|
accentStrong: String(theme.blue11?.val ?? ADMIN_COLORS.primaryStrong),
|
||||||
successBg: String(theme.backgroundStrong?.val ?? '#DCFCE7'),
|
successBg: String(theme.backgroundStrong?.val ?? '#DCFCE7'),
|
||||||
successText: String(theme.green10?.val ?? '#166534'),
|
successText: String(theme.green10?.val ?? ADMIN_COLORS.success),
|
||||||
dangerBg: String(theme.red3?.val ?? '#FEE2E2'),
|
dangerBg: String(theme.red3?.val ?? '#FEE2E2'),
|
||||||
dangerText: String(theme.red11?.val ?? ADMIN_COLORS.danger),
|
dangerText: String(theme.red11?.val ?? ADMIN_COLORS.danger),
|
||||||
warningBg: String(theme.yellow3?.val ?? '#FEF3C7'),
|
warningBg: String(theme.yellow3?.val ?? '#FEF3C7'),
|
||||||
warningBorder: String(theme.yellow6?.val ?? '#FCD34D'),
|
warningBorder: String(theme.yellow6?.val ?? '#FCD34D'),
|
||||||
warningText: String(theme.yellow11?.val ?? '#B45309'),
|
warningText: String(theme.yellow11?.val ?? ADMIN_COLORS.warning),
|
||||||
infoBg: String(theme.blue3?.val ?? ADMIN_COLORS.accentSoft),
|
infoBg: String(theme.blue3?.val ?? ADMIN_COLORS.accentSoft),
|
||||||
infoText: String(theme.blue10?.val ?? ADMIN_COLORS.primaryStrong),
|
infoText: String(theme.blue10?.val ?? ADMIN_COLORS.primaryStrong),
|
||||||
danger: String(theme.danger?.val ?? ADMIN_COLORS.danger),
|
danger: String(theme.danger?.val ?? ADMIN_COLORS.danger),
|
||||||
|
|||||||
Reference in New Issue
Block a user