feat: add mobile shell and unified search
Some checks failed
ci / 정본·보안·린트·타입·테스트 (push) Failing after 50s
ci / 워크스페이스 빌드 검증 (push) Has been skipped
ci / Supabase Edge Functions + Cloudflare Worker (push) Successful in 20s
ci / .NET API 서버 테스트 (push) Successful in 12s
deploy-site / deploy (push) Successful in 39s
ci / 모바일 린트·타입·Jest (push) Failing after 3h10m31s
Some checks failed
ci / 정본·보안·린트·타입·테스트 (push) Failing after 50s
ci / 워크스페이스 빌드 검증 (push) Has been skipped
ci / Supabase Edge Functions + Cloudflare Worker (push) Successful in 20s
ci / .NET API 서버 테스트 (push) Successful in 12s
deploy-site / deploy (push) Successful in 39s
ci / 모바일 린트·타입·Jest (push) Failing after 3h10m31s
This commit is contained in:
parent
f505a03d34
commit
5ca3709b32
98 changed files with 5168 additions and 2093 deletions
|
|
@ -9,12 +9,20 @@ import {
|
|||
type ViewProps,
|
||||
type ViewStyle,
|
||||
} from 'react-native'
|
||||
import { d3roNativeFonts, d3roNativeRadius, d3roNativeTypo, type D3roNativeTypoKey } from '@d3ro/ui-native'
|
||||
import {
|
||||
d3roNativeControl,
|
||||
d3roNativeFonts,
|
||||
d3roNativeRadius,
|
||||
d3roNativeTypo,
|
||||
type D3roNativePalette,
|
||||
type D3roNativeTypoKey,
|
||||
} from '@d3ro/ui-native'
|
||||
import { useMobilePreferences } from '../lib/preferences-context'
|
||||
|
||||
type ThemeTextColor =
|
||||
| 'primary'
|
||||
| 'secondary'
|
||||
| 'tertiary'
|
||||
| 'muted'
|
||||
| 'accent'
|
||||
| 'success'
|
||||
|
|
@ -38,11 +46,12 @@ export function ThemeText({
|
|||
const resolvedColor: Record<ThemeTextColor, string> = {
|
||||
primary: palette.text.primary,
|
||||
secondary: palette.text.secondary,
|
||||
muted: palette.text.muted,
|
||||
accent: palette.accent.main,
|
||||
success: palette.tag.green,
|
||||
danger: palette.tag.red,
|
||||
onAccent: palette.text.onAccent,
|
||||
tertiary: palette.text.tertiary,
|
||||
muted: palette.text.tertiary,
|
||||
accent: palette.accent.light,
|
||||
success: palette.status?.success ?? palette.tag.green,
|
||||
danger: palette.status?.danger ?? palette.tag.red,
|
||||
onAccent: palette.accent.ink,
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
@ -82,16 +91,10 @@ export function ThemeCard({
|
|||
style={[
|
||||
{
|
||||
backgroundColor: inset ? palette.bg.inset : palette.bg.card,
|
||||
borderColor: palette.border.subtle,
|
||||
borderWidth: inset ? 0 : 1,
|
||||
// 카드 반경은 SSOT 토큰 사용
|
||||
borderColor: inset ? palette.border.subtle : palette.border.default,
|
||||
borderWidth: 1,
|
||||
borderRadius: inset ? d3roNativeRadius.inner : d3roNativeRadius.card,
|
||||
padding: inset ? 10 : 16,
|
||||
shadowColor: palette.shadow,
|
||||
shadowOffset: { width: 0, height: 4 },
|
||||
shadowOpacity: inset ? 0 : 0.12,
|
||||
shadowRadius: inset ? 0 : 8,
|
||||
elevation: inset ? 0 : 2,
|
||||
padding: inset ? 12 : 16,
|
||||
},
|
||||
style,
|
||||
]}
|
||||
|
|
@ -108,6 +111,49 @@ interface ThemeButtonProps extends Omit<PressableProps, 'children' | 'style'> {
|
|||
textStyle?: StyleProp<TextStyle>
|
||||
}
|
||||
|
||||
interface ThemeButtonTone {
|
||||
background: string
|
||||
pressed: string
|
||||
border: string
|
||||
text: ThemeTextColor
|
||||
}
|
||||
|
||||
export function resolveThemeButtonTone(
|
||||
palette: D3roNativePalette,
|
||||
variant: NonNullable<ThemeButtonProps['variant']>,
|
||||
): ThemeButtonTone {
|
||||
switch (variant) {
|
||||
case 'primary':
|
||||
return {
|
||||
background: palette.accent.solid,
|
||||
pressed: palette.accent.solidHover,
|
||||
border: palette.accent.solid,
|
||||
text: 'onAccent',
|
||||
}
|
||||
case 'danger':
|
||||
return {
|
||||
background: 'transparent',
|
||||
pressed: palette.status.dangerBg,
|
||||
border: palette.border.strong,
|
||||
text: 'danger',
|
||||
}
|
||||
case 'quiet':
|
||||
return {
|
||||
background: 'transparent',
|
||||
pressed: palette.overlay.soft,
|
||||
border: 'transparent',
|
||||
text: 'secondary',
|
||||
}
|
||||
case 'secondary':
|
||||
return {
|
||||
background: 'transparent',
|
||||
pressed: palette.overlay.soft,
|
||||
border: palette.border.strong,
|
||||
text: 'primary',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function ThemeButton({
|
||||
label,
|
||||
variant = 'primary',
|
||||
|
|
@ -117,51 +163,38 @@ export function ThemeButton({
|
|||
...pressableProps
|
||||
}: ThemeButtonProps): React.ReactElement {
|
||||
const { palette } = useMobilePreferences()
|
||||
const primary = variant === 'primary'
|
||||
const danger = variant === 'danger'
|
||||
const quiet = variant === 'quiet'
|
||||
const backgroundColor = primary
|
||||
? palette.accent.main
|
||||
: danger
|
||||
? palette.tag.red
|
||||
: 'transparent'
|
||||
const borderColor = quiet
|
||||
? 'transparent'
|
||||
: primary
|
||||
? palette.accent.main
|
||||
: danger
|
||||
? palette.tag.red
|
||||
: palette.border.strong
|
||||
const tone = resolveThemeButtonTone(palette, variant)
|
||||
const isDisabled = disabled === true
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
{...pressableProps}
|
||||
accessibilityRole={pressableProps.accessibilityRole ?? 'button'}
|
||||
disabled={disabled}
|
||||
accessibilityState={{
|
||||
...pressableProps.accessibilityState,
|
||||
disabled: isDisabled,
|
||||
}}
|
||||
disabled={isDisabled}
|
||||
style={({ pressed }) => [
|
||||
{
|
||||
minHeight: 48,
|
||||
minHeight: d3roNativeControl.h,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
paddingHorizontal: 18,
|
||||
paddingHorizontal: d3roNativeControl.padX,
|
||||
paddingVertical: 12,
|
||||
borderRadius: d3roNativeRadius.button,
|
||||
borderWidth: quiet ? 0 : 1,
|
||||
borderColor,
|
||||
backgroundColor: pressed && primary
|
||||
? palette.accent.pressed
|
||||
: pressed && !primary
|
||||
? palette.bg.cardHover
|
||||
: backgroundColor,
|
||||
opacity: disabled ? 0.48 : 1,
|
||||
borderWidth: 1,
|
||||
borderColor: tone.border,
|
||||
backgroundColor: pressed && !isDisabled ? tone.pressed : tone.background,
|
||||
opacity: isDisabled ? 0.5 : 1,
|
||||
},
|
||||
style,
|
||||
]}
|
||||
>
|
||||
<ThemeText
|
||||
variant="small"
|
||||
color={primary || danger ? 'onAccent' : quiet ? 'muted' : 'primary'}
|
||||
style={[{ textAlign: 'center' }, textStyle]}
|
||||
color={tone.text}
|
||||
style={[{ textAlign: 'center', fontWeight: '500' }, textStyle]}
|
||||
>
|
||||
{label}
|
||||
</ThemeText>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue