Refine admin PWA layout and tamagui usage
This commit is contained in:
@@ -2,27 +2,32 @@ import React from 'react';
|
||||
import { YStack, XStack } from '@tamagui/stacks';
|
||||
import { SizableText as Text } from '@tamagui/text';
|
||||
import { Pressable } from '@tamagui/react-native-web-lite';
|
||||
import { useAdminTheme } from '../theme';
|
||||
import { ADMIN_GRADIENTS, useAdminTheme } from '../theme';
|
||||
import { withAlpha } from './colors';
|
||||
|
||||
export function MobileCard({
|
||||
children,
|
||||
className,
|
||||
style,
|
||||
...rest
|
||||
}: React.ComponentProps<typeof YStack>) {
|
||||
const { surface, border, shadow } = useAdminTheme();
|
||||
const { surface, border, shadow, glassSurface, glassBorder, glassShadow } = useAdminTheme();
|
||||
return (
|
||||
<YStack
|
||||
className={['admin-fade-up', className].filter(Boolean).join(' ')}
|
||||
backgroundColor={surface}
|
||||
borderRadius={18}
|
||||
borderWidth={1}
|
||||
borderColor={border}
|
||||
shadowColor={shadow}
|
||||
shadowOpacity={0.08}
|
||||
shadowRadius={14}
|
||||
backgroundColor={glassSurface ?? surface}
|
||||
borderRadius={20}
|
||||
borderWidth={2}
|
||||
borderColor={glassBorder ?? border}
|
||||
shadowColor={glassShadow ?? shadow}
|
||||
shadowOpacity={0.16}
|
||||
shadowRadius={16}
|
||||
shadowOffset={{ width: 0, height: 10 }}
|
||||
padding="$3.5"
|
||||
space="$2"
|
||||
style={{
|
||||
...style,
|
||||
}}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
@@ -99,13 +104,18 @@ export function CTAButton({
|
||||
iconLeft?: React.ReactNode;
|
||||
iconRight?: React.ReactNode;
|
||||
}) {
|
||||
const { primary, surface, border, text, danger } = useAdminTheme();
|
||||
const { primary, surface, border, text, danger, glassSurfaceStrong } = useAdminTheme();
|
||||
const isPrimary = tone === 'primary';
|
||||
const isDanger = tone === 'danger';
|
||||
const isDisabled = disabled || loading;
|
||||
const backgroundColor = isDanger ? danger : isPrimary ? primary : surface;
|
||||
const backgroundColor = isDanger ? danger : isPrimary ? primary : glassSurfaceStrong ?? surface;
|
||||
const borderColor = isPrimary || isDanger ? 'transparent' : border;
|
||||
const labelColor = isPrimary || isDanger ? 'white' : text;
|
||||
const primaryStyle = isPrimary
|
||||
? {
|
||||
boxShadow: `0 18px 28px ${withAlpha(primary, 0.4)}`,
|
||||
}
|
||||
: undefined;
|
||||
return (
|
||||
<Pressable
|
||||
onPress={isDisabled ? undefined : onPress}
|
||||
@@ -119,13 +129,14 @@ export function CTAButton({
|
||||
>
|
||||
<XStack
|
||||
height={52}
|
||||
borderRadius={16}
|
||||
borderRadius={18}
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
backgroundColor={backgroundColor}
|
||||
borderWidth={isPrimary || isDanger ? 0 : 1}
|
||||
borderWidth={isPrimary || isDanger ? 0 : 2}
|
||||
borderColor={borderColor}
|
||||
space="$2"
|
||||
style={primaryStyle}
|
||||
>
|
||||
{iconLeft}
|
||||
<Text fontSize="$sm" fontWeight="800" color={labelColor}>
|
||||
@@ -183,6 +194,7 @@ export function ActionTile({
|
||||
color,
|
||||
onPress,
|
||||
disabled = false,
|
||||
variant = 'grid',
|
||||
delayMs = 0,
|
||||
}: {
|
||||
icon: React.ComponentType<{ size?: number; color?: string }>;
|
||||
@@ -190,49 +202,56 @@ export function ActionTile({
|
||||
color: string;
|
||||
onPress?: () => void;
|
||||
disabled?: boolean;
|
||||
variant?: 'grid' | 'cluster';
|
||||
delayMs?: number;
|
||||
}) {
|
||||
const { textStrong } = useAdminTheme();
|
||||
const backgroundColor = `${color}18`;
|
||||
const borderColor = `${color}40`;
|
||||
const shadowColor = `${color}2b`;
|
||||
const iconShadow = `${color}55`;
|
||||
const { textStrong, glassSurface } = useAdminTheme();
|
||||
const isCluster = variant === 'cluster';
|
||||
const backgroundColor = withAlpha(color, 0.12);
|
||||
const borderColor = withAlpha(color, 0.4);
|
||||
const shadowColor = withAlpha(color, 0.35);
|
||||
const iconShadow = withAlpha(color, 0.5);
|
||||
const tileStyle = {
|
||||
...(delayMs ? { animationDelay: `${delayMs}ms` } : {}),
|
||||
backgroundImage: `linear-gradient(135deg, ${backgroundColor}, ${color}0f)`,
|
||||
boxShadow: `0 10px 24px ${shadowColor}`,
|
||||
backgroundImage: `linear-gradient(135deg, ${backgroundColor}, ${withAlpha(color, 0.08)})`,
|
||||
boxShadow: isCluster ? `0 12px 18px ${shadowColor}` : `0 20px 30px ${shadowColor}`,
|
||||
};
|
||||
return (
|
||||
<Pressable
|
||||
onPress={disabled ? undefined : onPress}
|
||||
style={{ width: '48%', marginBottom: 12, opacity: disabled ? 0.5 : 1 }}
|
||||
style={{
|
||||
width: isCluster ? '100%' : '48%',
|
||||
flex: isCluster ? 1 : undefined,
|
||||
marginBottom: isCluster ? 0 : 12,
|
||||
opacity: disabled ? 0.5 : 1,
|
||||
}}
|
||||
disabled={disabled}
|
||||
>
|
||||
<YStack
|
||||
className="admin-fade-up"
|
||||
style={tileStyle}
|
||||
borderRadius={16}
|
||||
borderRadius={isCluster ? 14 : 16}
|
||||
padding="$3"
|
||||
space="$2.5"
|
||||
backgroundColor={backgroundColor}
|
||||
borderWidth={1}
|
||||
backgroundColor={glassSurface ?? backgroundColor}
|
||||
borderWidth={2}
|
||||
borderColor={borderColor}
|
||||
minHeight={110}
|
||||
minHeight={120}
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
>
|
||||
<XStack
|
||||
width={36}
|
||||
height={36}
|
||||
borderRadius={12}
|
||||
width={44}
|
||||
height={44}
|
||||
borderRadius={14}
|
||||
backgroundColor={color}
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
style={{ boxShadow: `0 6px 14px ${iconShadow}` }}
|
||||
>
|
||||
<IconCmp size={16} color="white" />
|
||||
<IconCmp size={18} color="white" />
|
||||
</XStack>
|
||||
<Text fontSize="$sm" fontWeight="700" color={textStrong} textAlign="center">
|
||||
<Text fontSize="$sm" fontWeight="800" color={textStrong} textAlign="center">
|
||||
{label}
|
||||
</Text>
|
||||
</YStack>
|
||||
|
||||
Reference in New Issue
Block a user