lovdacn 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -106
- package/dist/index.d.ts +1 -0
- package/dist/index.js +224 -0
- package/package.json +41 -63
- package/templates/nativewind/.vscode/extensions.json +1 -0
- package/templates/nativewind/.vscode/settings.json +7 -0
- package/templates/nativewind/AGENTS.md +3 -0
- package/templates/nativewind/CLAUDE.md +1 -0
- package/{LICENSE → templates/nativewind/LICENSE} +21 -21
- package/templates/nativewind/README.md +56 -0
- package/templates/nativewind/app.json +43 -0
- package/templates/nativewind/assets/expo.icon/Assets/expo-symbol 2.svg +3 -0
- package/templates/nativewind/assets/expo.icon/Assets/grid.png +0 -0
- package/templates/nativewind/assets/expo.icon/icon.json +40 -0
- package/templates/nativewind/assets/images/android-icon-background.png +0 -0
- package/templates/nativewind/assets/images/android-icon-foreground.png +0 -0
- package/templates/nativewind/assets/images/android-icon-monochrome.png +0 -0
- package/templates/nativewind/assets/images/expo-badge-white.png +0 -0
- package/templates/nativewind/assets/images/expo-badge.png +0 -0
- package/templates/nativewind/assets/images/expo-logo.png +0 -0
- package/templates/nativewind/assets/images/favicon.png +0 -0
- package/templates/nativewind/assets/images/icon.png +0 -0
- package/templates/nativewind/assets/images/logo-glow.png +0 -0
- package/templates/nativewind/assets/images/react-logo.png +0 -0
- package/templates/nativewind/assets/images/react-logo@2x.png +0 -0
- package/templates/nativewind/assets/images/react-logo@3x.png +0 -0
- package/templates/nativewind/assets/images/splash-icon.png +0 -0
- package/templates/nativewind/assets/images/tabIcons/explore.png +0 -0
- package/templates/nativewind/assets/images/tabIcons/explore@2x.png +0 -0
- package/templates/nativewind/assets/images/tabIcons/explore@3x.png +0 -0
- package/templates/nativewind/assets/images/tabIcons/home.png +0 -0
- package/templates/nativewind/assets/images/tabIcons/home@2x.png +0 -0
- package/templates/nativewind/assets/images/tabIcons/home@3x.png +0 -0
- package/templates/nativewind/assets/images/tutorial-web.png +0 -0
- package/templates/nativewind/babel.config.js +9 -0
- package/templates/nativewind/expo-env.d.ts +3 -0
- package/templates/nativewind/lvcn.json +16 -0
- package/templates/nativewind/metro.config.js +6 -0
- package/templates/nativewind/nativewind-env.d.ts +3 -0
- package/templates/nativewind/package.json +55 -0
- package/templates/nativewind/postcss.config.js +6 -0
- package/templates/nativewind/scripts/reset-project.js +114 -0
- package/templates/nativewind/src/app/_layout.tsx +25 -0
- package/templates/nativewind/src/app/explore.tsx +180 -0
- package/templates/nativewind/src/app/index.tsx +12 -0
- package/templates/nativewind/src/components/animated-icon.module.css +6 -0
- package/templates/nativewind/src/components/animated-icon.tsx +148 -0
- package/templates/nativewind/src/components/animated-icon.web.tsx +108 -0
- package/templates/nativewind/src/components/app-tabs.tsx +32 -0
- package/templates/nativewind/src/components/app-tabs.web.tsx +115 -0
- package/templates/nativewind/src/components/external-link.tsx +25 -0
- package/templates/nativewind/src/components/hint-row.tsx +35 -0
- package/templates/nativewind/src/components/themed-text.tsx +73 -0
- package/templates/nativewind/src/components/themed-view.tsx +16 -0
- package/templates/nativewind/src/components/ui/button.tsx +106 -0
- package/templates/nativewind/src/components/ui/collapsible.tsx +65 -0
- package/templates/nativewind/src/components/ui/text.tsx +89 -0
- package/templates/nativewind/src/components/web-badge.tsx +43 -0
- package/templates/nativewind/src/constants/theme.ts +65 -0
- package/templates/nativewind/src/global.css +13 -0
- package/templates/nativewind/src/hooks/use-color-scheme.ts +1 -0
- package/templates/nativewind/src/hooks/use-color-scheme.web.ts +21 -0
- package/templates/nativewind/src/hooks/use-theme.ts +14 -0
- package/templates/nativewind/tailwind.config.js +86 -0
- package/templates/nativewind/tsconfig.json +21 -0
- package/templates/uniwind/.claude/settings.json +5 -0
- package/templates/uniwind/.vscode/extensions.json +1 -0
- package/templates/uniwind/.vscode/settings.json +7 -0
- package/templates/uniwind/AGENTS.md +3 -0
- package/templates/uniwind/CLAUDE.md +1 -0
- package/templates/uniwind/LICENSE +21 -0
- package/templates/uniwind/README.md +56 -0
- package/templates/uniwind/app.json +42 -0
- package/templates/uniwind/assets/expo.icon/Assets/expo-symbol 2.svg +3 -0
- package/templates/uniwind/assets/expo.icon/Assets/grid.png +0 -0
- package/templates/uniwind/assets/expo.icon/icon.json +40 -0
- package/templates/uniwind/assets/images/android-icon-background.png +0 -0
- package/templates/uniwind/assets/images/android-icon-foreground.png +0 -0
- package/templates/uniwind/assets/images/android-icon-monochrome.png +0 -0
- package/templates/uniwind/assets/images/expo-badge-white.png +0 -0
- package/templates/uniwind/assets/images/expo-badge.png +0 -0
- package/templates/uniwind/assets/images/expo-logo.png +0 -0
- package/templates/uniwind/assets/images/favicon.png +0 -0
- package/templates/uniwind/assets/images/icon.png +0 -0
- package/templates/uniwind/assets/images/logo-glow.png +0 -0
- package/templates/uniwind/assets/images/react-logo.png +0 -0
- package/templates/uniwind/assets/images/react-logo@2x.png +0 -0
- package/templates/uniwind/assets/images/react-logo@3x.png +0 -0
- package/templates/uniwind/assets/images/splash-icon.png +0 -0
- package/templates/uniwind/assets/images/tabIcons/explore.png +0 -0
- package/templates/uniwind/assets/images/tabIcons/explore@2x.png +0 -0
- package/templates/uniwind/assets/images/tabIcons/explore@3x.png +0 -0
- package/templates/uniwind/assets/images/tabIcons/home.png +0 -0
- package/templates/uniwind/assets/images/tabIcons/home@2x.png +0 -0
- package/templates/uniwind/assets/images/tabIcons/home@3x.png +0 -0
- package/templates/uniwind/assets/images/tutorial-web.png +0 -0
- package/templates/uniwind/expo-env.d.ts +3 -0
- package/templates/uniwind/lvcn.json +16 -0
- package/templates/uniwind/metro.config.js +14 -0
- package/templates/uniwind/package.json +46 -0
- package/templates/uniwind/scripts/reset-project.js +114 -0
- package/templates/uniwind/src/app/_layout.tsx +23 -0
- package/templates/uniwind/src/app/explore.tsx +180 -0
- package/templates/uniwind/src/app/index.tsx +98 -0
- package/templates/uniwind/src/components/animated-icon.module.css +6 -0
- package/templates/uniwind/src/components/animated-icon.tsx +148 -0
- package/templates/uniwind/src/components/animated-icon.web.tsx +108 -0
- package/templates/uniwind/src/components/app-tabs.tsx +32 -0
- package/templates/uniwind/src/components/app-tabs.web.tsx +115 -0
- package/templates/uniwind/src/components/external-link.tsx +25 -0
- package/templates/uniwind/src/components/hint-row.tsx +35 -0
- package/templates/uniwind/src/components/themed-text.tsx +73 -0
- package/templates/uniwind/src/components/themed-view.tsx +16 -0
- package/templates/uniwind/src/components/ui/collapsible.tsx +65 -0
- package/templates/uniwind/src/components/web-badge.tsx +43 -0
- package/templates/uniwind/src/constants/theme.ts +65 -0
- package/templates/uniwind/src/global.css +12 -0
- package/templates/uniwind/src/hooks/use-color-scheme.ts +1 -0
- package/templates/uniwind/src/hooks/use-color-scheme.web.ts +21 -0
- package/templates/uniwind/src/hooks/use-theme.ts +14 -0
- package/templates/uniwind/src/uniwind-types.d.ts +10 -0
- package/templates/uniwind/tsconfig.json +20 -0
- package/.changeset/config.json +0 -17
- package/.github/actions/setup/action.yml +0 -21
- package/.github/workflows/check.yml +0 -54
- package/.github/workflows/release.yml +0 -0
- package/.github/workflows/snapshot.yml +0 -24
- package/.prettierrc +0 -8
- package/.vscode/extensions.json +0 -6
- package/.vscode/settings.json +0 -46
- package/eslint.config.mjs +0 -118
- package/patches/@changesets__get-github-info@0.6.0.patch +0 -48
- package/scripts/copy-package-json.ts +0 -35
- package/src/bin.ts +0 -18
- package/src/cli.ts +0 -66
- package/src/contexts/cli-options.ts +0 -29
- package/src/project-manifest.ts +0 -370
- package/src/services/commands/add.ts +0 -128
- package/src/services/commands/doctor.ts +0 -287
- package/src/services/commands/init.ts +0 -94
- package/src/services/git.ts +0 -39
- package/src/services/package-manager.ts +0 -48
- package/src/services/project-config.ts +0 -295
- package/src/services/required-files-checker.ts +0 -375
- package/src/services/spinner.ts +0 -15
- package/src/services/template.ts +0 -223
- package/src/utils/retry-with.ts +0 -9
- package/src/utils/run-command.ts +0 -10
- package/test/Dummy.test.ts +0 -7
- package/tsconfig.base.json +0 -53
- package/tsconfig.json +0 -14
- package/tsconfig.scripts.json +0 -17
- package/tsconfig.src.json +0 -10
- package/tsconfig.test.json +0 -10
- package/tsup.config.ts +0 -9
- package/vitest.config.ts +0 -12
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Platform, StyleSheet, Text, type TextProps } from 'react-native';
|
|
2
|
+
|
|
3
|
+
import { Fonts, ThemeColor } from '@/constants/theme';
|
|
4
|
+
import { useTheme } from '@/hooks/use-theme';
|
|
5
|
+
|
|
6
|
+
export type ThemedTextProps = TextProps & {
|
|
7
|
+
type?: 'default' | 'title' | 'small' | 'smallBold' | 'subtitle' | 'link' | 'linkPrimary' | 'code';
|
|
8
|
+
themeColor?: ThemeColor;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export function ThemedText({ style, type = 'default', themeColor, ...rest }: ThemedTextProps) {
|
|
12
|
+
const theme = useTheme();
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<Text
|
|
16
|
+
style={[
|
|
17
|
+
{ color: theme[themeColor ?? 'text'] },
|
|
18
|
+
type === 'default' && styles.default,
|
|
19
|
+
type === 'title' && styles.title,
|
|
20
|
+
type === 'small' && styles.small,
|
|
21
|
+
type === 'smallBold' && styles.smallBold,
|
|
22
|
+
type === 'subtitle' && styles.subtitle,
|
|
23
|
+
type === 'link' && styles.link,
|
|
24
|
+
type === 'linkPrimary' && styles.linkPrimary,
|
|
25
|
+
type === 'code' && styles.code,
|
|
26
|
+
style,
|
|
27
|
+
]}
|
|
28
|
+
{...rest}
|
|
29
|
+
/>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const styles = StyleSheet.create({
|
|
34
|
+
small: {
|
|
35
|
+
fontSize: 14,
|
|
36
|
+
lineHeight: 20,
|
|
37
|
+
fontWeight: 500,
|
|
38
|
+
},
|
|
39
|
+
smallBold: {
|
|
40
|
+
fontSize: 14,
|
|
41
|
+
lineHeight: 20,
|
|
42
|
+
fontWeight: 700,
|
|
43
|
+
},
|
|
44
|
+
default: {
|
|
45
|
+
fontSize: 16,
|
|
46
|
+
lineHeight: 24,
|
|
47
|
+
fontWeight: 500,
|
|
48
|
+
},
|
|
49
|
+
title: {
|
|
50
|
+
fontSize: 48,
|
|
51
|
+
fontWeight: 600,
|
|
52
|
+
lineHeight: 52,
|
|
53
|
+
},
|
|
54
|
+
subtitle: {
|
|
55
|
+
fontSize: 32,
|
|
56
|
+
lineHeight: 44,
|
|
57
|
+
fontWeight: 600,
|
|
58
|
+
},
|
|
59
|
+
link: {
|
|
60
|
+
lineHeight: 30,
|
|
61
|
+
fontSize: 14,
|
|
62
|
+
},
|
|
63
|
+
linkPrimary: {
|
|
64
|
+
lineHeight: 30,
|
|
65
|
+
fontSize: 14,
|
|
66
|
+
color: '#3c87f7',
|
|
67
|
+
},
|
|
68
|
+
code: {
|
|
69
|
+
fontFamily: Fonts.mono,
|
|
70
|
+
fontWeight: Platform.select({ android: 700 }) ?? 500,
|
|
71
|
+
fontSize: 12,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { View, type ViewProps } from 'react-native';
|
|
2
|
+
|
|
3
|
+
import { ThemeColor } from '@/constants/theme';
|
|
4
|
+
import { useTheme } from '@/hooks/use-theme';
|
|
5
|
+
|
|
6
|
+
export type ThemedViewProps = ViewProps & {
|
|
7
|
+
lightColor?: string;
|
|
8
|
+
darkColor?: string;
|
|
9
|
+
type?: ThemeColor;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export function ThemedView({ style, lightColor, darkColor, type, ...otherProps }: ThemedViewProps) {
|
|
13
|
+
const theme = useTheme();
|
|
14
|
+
|
|
15
|
+
return <View style={[{ backgroundColor: theme[type ?? 'background'] }, style]} {...otherProps} />;
|
|
16
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { TextClassContext } from '@/components/ui/text';
|
|
2
|
+
import { cn } from '@/lib/utils';
|
|
3
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
4
|
+
import { Platform, Pressable } from 'react-native';
|
|
5
|
+
|
|
6
|
+
const buttonVariants = cva(
|
|
7
|
+
cn(
|
|
8
|
+
'group shrink-0 flex-row items-center justify-center gap-2 rounded-md shadow-none',
|
|
9
|
+
Platform.select({
|
|
10
|
+
web: "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive whitespace-nowrap outline-none transition-all focus-visible:ring-[3px] disabled:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
11
|
+
})
|
|
12
|
+
),
|
|
13
|
+
{
|
|
14
|
+
variants: {
|
|
15
|
+
variant: {
|
|
16
|
+
default: cn(
|
|
17
|
+
'bg-primary active:bg-primary/90 shadow-sm shadow-black/5',
|
|
18
|
+
Platform.select({ web: 'hover:bg-primary/90' })
|
|
19
|
+
),
|
|
20
|
+
destructive: cn(
|
|
21
|
+
'bg-destructive active:bg-destructive/90 dark:bg-destructive/60 shadow-sm shadow-black/5',
|
|
22
|
+
Platform.select({
|
|
23
|
+
web: 'hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40',
|
|
24
|
+
})
|
|
25
|
+
),
|
|
26
|
+
outline: cn(
|
|
27
|
+
'border-border bg-background active:bg-accent dark:bg-input/30 dark:border-input dark:active:bg-input/50 border shadow-sm shadow-black/5',
|
|
28
|
+
Platform.select({
|
|
29
|
+
web: 'hover:bg-accent dark:hover:bg-input/50',
|
|
30
|
+
})
|
|
31
|
+
),
|
|
32
|
+
secondary: cn(
|
|
33
|
+
'bg-secondary active:bg-secondary/80 shadow-sm shadow-black/5',
|
|
34
|
+
Platform.select({ web: 'hover:bg-secondary/80' })
|
|
35
|
+
),
|
|
36
|
+
ghost: cn(
|
|
37
|
+
'active:bg-accent dark:active:bg-accent/50',
|
|
38
|
+
Platform.select({ web: 'hover:bg-accent dark:hover:bg-accent/50' })
|
|
39
|
+
),
|
|
40
|
+
link: '',
|
|
41
|
+
},
|
|
42
|
+
size: {
|
|
43
|
+
default: cn('h-10 px-4 py-2 sm:h-9', Platform.select({ web: 'has-[>svg]:px-3' })),
|
|
44
|
+
sm: cn('h-9 gap-1.5 rounded-md px-3 sm:h-8', Platform.select({ web: 'has-[>svg]:px-2.5' })),
|
|
45
|
+
lg: cn('h-11 rounded-md px-6 sm:h-10', Platform.select({ web: 'has-[>svg]:px-4' })),
|
|
46
|
+
icon: 'h-10 w-10 sm:h-9 sm:w-9',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
defaultVariants: {
|
|
50
|
+
variant: 'default',
|
|
51
|
+
size: 'default',
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const buttonTextVariants = cva(
|
|
57
|
+
cn(
|
|
58
|
+
'text-foreground text-sm font-medium',
|
|
59
|
+
Platform.select({ web: 'pointer-events-none transition-colors' })
|
|
60
|
+
),
|
|
61
|
+
{
|
|
62
|
+
variants: {
|
|
63
|
+
variant: {
|
|
64
|
+
default: 'text-primary-foreground',
|
|
65
|
+
destructive: 'text-white',
|
|
66
|
+
outline: cn(
|
|
67
|
+
'group-active:text-accent-foreground',
|
|
68
|
+
Platform.select({ web: 'group-hover:text-accent-foreground' })
|
|
69
|
+
),
|
|
70
|
+
secondary: 'text-secondary-foreground',
|
|
71
|
+
ghost: 'group-active:text-accent-foreground',
|
|
72
|
+
link: cn(
|
|
73
|
+
'text-primary group-active:underline',
|
|
74
|
+
Platform.select({ web: 'underline-offset-4 hover:underline group-hover:underline' })
|
|
75
|
+
),
|
|
76
|
+
},
|
|
77
|
+
size: {
|
|
78
|
+
default: '',
|
|
79
|
+
sm: '',
|
|
80
|
+
lg: '',
|
|
81
|
+
icon: '',
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
defaultVariants: {
|
|
85
|
+
variant: 'default',
|
|
86
|
+
size: 'default',
|
|
87
|
+
},
|
|
88
|
+
}
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
type ButtonProps = React.ComponentProps<typeof Pressable> & React.RefAttributes<typeof Pressable> & VariantProps<typeof buttonVariants>;
|
|
92
|
+
|
|
93
|
+
function Button({ className, variant, size, ...props }: ButtonProps) {
|
|
94
|
+
return (
|
|
95
|
+
<TextClassContext.Provider value={buttonTextVariants({ variant, size })}>
|
|
96
|
+
<Pressable
|
|
97
|
+
className={cn(props.disabled && 'opacity-50', buttonVariants({ variant, size }), className)}
|
|
98
|
+
role="button"
|
|
99
|
+
{...props}
|
|
100
|
+
/>
|
|
101
|
+
</TextClassContext.Provider>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export { Button, buttonTextVariants, buttonVariants };
|
|
106
|
+
export type { ButtonProps };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { SymbolView } from 'expo-symbols';
|
|
2
|
+
import { PropsWithChildren, useState } from 'react';
|
|
3
|
+
import { Pressable, StyleSheet } from 'react-native';
|
|
4
|
+
import Animated, { FadeIn } from 'react-native-reanimated';
|
|
5
|
+
|
|
6
|
+
import { ThemedText } from '@/components/themed-text';
|
|
7
|
+
import { ThemedView } from '@/components/themed-view';
|
|
8
|
+
import { Spacing } from '@/constants/theme';
|
|
9
|
+
import { useTheme } from '@/hooks/use-theme';
|
|
10
|
+
|
|
11
|
+
export function Collapsible({ children, title }: PropsWithChildren & { title: string }) {
|
|
12
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
13
|
+
const theme = useTheme();
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<ThemedView>
|
|
17
|
+
<Pressable
|
|
18
|
+
style={({ pressed }) => [styles.heading, pressed && styles.pressedHeading]}
|
|
19
|
+
onPress={() => setIsOpen((value) => !value)}>
|
|
20
|
+
<ThemedView type="backgroundElement" style={styles.button}>
|
|
21
|
+
<SymbolView
|
|
22
|
+
name={{ ios: 'chevron.right', android: 'chevron_right', web: 'chevron_right' }}
|
|
23
|
+
size={14}
|
|
24
|
+
weight="bold"
|
|
25
|
+
tintColor={theme.text}
|
|
26
|
+
style={{ transform: [{ rotate: isOpen ? '-90deg' : '90deg' }] }}
|
|
27
|
+
/>
|
|
28
|
+
</ThemedView>
|
|
29
|
+
|
|
30
|
+
<ThemedText type="small">{title}</ThemedText>
|
|
31
|
+
</Pressable>
|
|
32
|
+
{isOpen && (
|
|
33
|
+
<Animated.View entering={FadeIn.duration(200)}>
|
|
34
|
+
<ThemedView type="backgroundElement" style={styles.content}>
|
|
35
|
+
{children}
|
|
36
|
+
</ThemedView>
|
|
37
|
+
</Animated.View>
|
|
38
|
+
)}
|
|
39
|
+
</ThemedView>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const styles = StyleSheet.create({
|
|
44
|
+
heading: {
|
|
45
|
+
flexDirection: 'row',
|
|
46
|
+
alignItems: 'center',
|
|
47
|
+
gap: Spacing.two,
|
|
48
|
+
},
|
|
49
|
+
pressedHeading: {
|
|
50
|
+
opacity: 0.7,
|
|
51
|
+
},
|
|
52
|
+
button: {
|
|
53
|
+
width: Spacing.four,
|
|
54
|
+
height: Spacing.four,
|
|
55
|
+
borderRadius: 12,
|
|
56
|
+
justifyContent: 'center',
|
|
57
|
+
alignItems: 'center',
|
|
58
|
+
},
|
|
59
|
+
content: {
|
|
60
|
+
marginTop: Spacing.three,
|
|
61
|
+
borderRadius: Spacing.three,
|
|
62
|
+
marginLeft: Spacing.four,
|
|
63
|
+
padding: Spacing.four,
|
|
64
|
+
},
|
|
65
|
+
});
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { cn } from '@/lib/utils';
|
|
2
|
+
import { Slot } from '@rn-primitives/slot';
|
|
3
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import { Platform, Text as RNText, type Role } from 'react-native';
|
|
6
|
+
|
|
7
|
+
const textVariants = cva(
|
|
8
|
+
cn(
|
|
9
|
+
'text-foreground text-base',
|
|
10
|
+
Platform.select({
|
|
11
|
+
web: 'select-text',
|
|
12
|
+
})
|
|
13
|
+
),
|
|
14
|
+
{
|
|
15
|
+
variants: {
|
|
16
|
+
variant: {
|
|
17
|
+
default: '',
|
|
18
|
+
h1: cn(
|
|
19
|
+
'text-center text-4xl font-extrabold tracking-tight',
|
|
20
|
+
Platform.select({ web: 'scroll-m-20 text-balance' })
|
|
21
|
+
),
|
|
22
|
+
h2: cn(
|
|
23
|
+
'border-border border-b pb-2 text-3xl font-semibold tracking-tight',
|
|
24
|
+
Platform.select({ web: 'scroll-m-20 first:mt-0' })
|
|
25
|
+
),
|
|
26
|
+
h3: cn('text-2xl font-semibold tracking-tight', Platform.select({ web: 'scroll-m-20' })),
|
|
27
|
+
h4: cn('text-xl font-semibold tracking-tight', Platform.select({ web: 'scroll-m-20' })),
|
|
28
|
+
p: 'mt-3 leading-7 sm:mt-6',
|
|
29
|
+
blockquote: 'mt-4 border-l-2 pl-3 italic sm:mt-6 sm:pl-6',
|
|
30
|
+
code: cn(
|
|
31
|
+
'bg-muted relative rounded px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold'
|
|
32
|
+
),
|
|
33
|
+
lead: 'text-muted-foreground text-xl',
|
|
34
|
+
large: 'text-lg font-semibold',
|
|
35
|
+
small: 'text-sm font-medium leading-none',
|
|
36
|
+
muted: 'text-muted-foreground text-sm',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
defaultVariants: {
|
|
40
|
+
variant: 'default',
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
type TextVariantProps = VariantProps<typeof textVariants>;
|
|
46
|
+
|
|
47
|
+
type TextVariant = NonNullable<TextVariantProps['variant']>;
|
|
48
|
+
|
|
49
|
+
const ROLE: Partial<Record<TextVariant, Role>> = {
|
|
50
|
+
h1: 'heading',
|
|
51
|
+
h2: 'heading',
|
|
52
|
+
h3: 'heading',
|
|
53
|
+
h4: 'heading',
|
|
54
|
+
blockquote: Platform.select({ web: 'blockquote' as Role }),
|
|
55
|
+
code: Platform.select({ web: 'code' as Role }),
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const ARIA_LEVEL: Partial<Record<TextVariant, string>> = {
|
|
59
|
+
h1: '1',
|
|
60
|
+
h2: '2',
|
|
61
|
+
h3: '3',
|
|
62
|
+
h4: '4',
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const TextClassContext = React.createContext<string | undefined>(undefined);
|
|
66
|
+
|
|
67
|
+
function Text({
|
|
68
|
+
className,
|
|
69
|
+
asChild = false,
|
|
70
|
+
variant = 'default',
|
|
71
|
+
...props
|
|
72
|
+
}: React.ComponentProps<typeof RNText> &
|
|
73
|
+
React.RefAttributes<typeof RNText> &
|
|
74
|
+
TextVariantProps & {
|
|
75
|
+
asChild?: boolean;
|
|
76
|
+
}) {
|
|
77
|
+
const textClass = React.useContext(TextClassContext);
|
|
78
|
+
const Component = asChild ? Slot : RNText;
|
|
79
|
+
return (
|
|
80
|
+
<Component
|
|
81
|
+
className={cn(textVariants({ variant }), textClass, className)}
|
|
82
|
+
role={variant ? ROLE[variant] : undefined}
|
|
83
|
+
aria-level={variant ? ARIA_LEVEL[variant] : undefined}
|
|
84
|
+
{...props}
|
|
85
|
+
/>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export { Text, TextClassContext };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { version } from 'expo/package.json';
|
|
2
|
+
import { Image } from 'expo-image';
|
|
3
|
+
import { useColorScheme, StyleSheet } from 'react-native';
|
|
4
|
+
|
|
5
|
+
import { ThemedText } from './themed-text';
|
|
6
|
+
import { ThemedView } from './themed-view';
|
|
7
|
+
|
|
8
|
+
import { Spacing } from '@/constants/theme';
|
|
9
|
+
|
|
10
|
+
export function WebBadge() {
|
|
11
|
+
const scheme = useColorScheme();
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<ThemedView style={styles.container}>
|
|
15
|
+
<ThemedText type="code" themeColor="textSecondary" style={styles.versionText}>
|
|
16
|
+
v{version}
|
|
17
|
+
</ThemedText>
|
|
18
|
+
<Image
|
|
19
|
+
source={
|
|
20
|
+
scheme === 'dark'
|
|
21
|
+
? require('@/assets/images/expo-badge-white.png')
|
|
22
|
+
: require('@/assets/images/expo-badge.png')
|
|
23
|
+
}
|
|
24
|
+
style={styles.badgeImage}
|
|
25
|
+
/>
|
|
26
|
+
</ThemedView>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const styles = StyleSheet.create({
|
|
31
|
+
container: {
|
|
32
|
+
padding: Spacing.five,
|
|
33
|
+
alignItems: 'center',
|
|
34
|
+
gap: Spacing.two,
|
|
35
|
+
},
|
|
36
|
+
versionText: {
|
|
37
|
+
textAlign: 'center',
|
|
38
|
+
},
|
|
39
|
+
badgeImage: {
|
|
40
|
+
width: 123,
|
|
41
|
+
aspectRatio: 123 / 24,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Below are the colors that are used in the app. The colors are defined in the light and dark mode.
|
|
3
|
+
* There are many other ways to style your app. For example, [Nativewind](https://www.nativewind.dev/), [Tamagui](https://tamagui.dev/), [unistyles](https://reactnativeunistyles.vercel.app), etc.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import '@/global.css';
|
|
7
|
+
|
|
8
|
+
import { Platform } from 'react-native';
|
|
9
|
+
|
|
10
|
+
export const Colors = {
|
|
11
|
+
light: {
|
|
12
|
+
text: '#000000',
|
|
13
|
+
background: '#ffffff',
|
|
14
|
+
backgroundElement: '#F0F0F3',
|
|
15
|
+
backgroundSelected: '#E0E1E6',
|
|
16
|
+
textSecondary: '#60646C',
|
|
17
|
+
},
|
|
18
|
+
dark: {
|
|
19
|
+
text: '#ffffff',
|
|
20
|
+
background: '#000000',
|
|
21
|
+
backgroundElement: '#212225',
|
|
22
|
+
backgroundSelected: '#2E3135',
|
|
23
|
+
textSecondary: '#B0B4BA',
|
|
24
|
+
},
|
|
25
|
+
} as const;
|
|
26
|
+
|
|
27
|
+
export type ThemeColor = keyof typeof Colors.light & keyof typeof Colors.dark;
|
|
28
|
+
|
|
29
|
+
export const Fonts = Platform.select({
|
|
30
|
+
ios: {
|
|
31
|
+
/** iOS `UIFontDescriptorSystemDesignDefault` */
|
|
32
|
+
sans: 'system-ui',
|
|
33
|
+
/** iOS `UIFontDescriptorSystemDesignSerif` */
|
|
34
|
+
serif: 'ui-serif',
|
|
35
|
+
/** iOS `UIFontDescriptorSystemDesignRounded` */
|
|
36
|
+
rounded: 'ui-rounded',
|
|
37
|
+
/** iOS `UIFontDescriptorSystemDesignMonospaced` */
|
|
38
|
+
mono: 'ui-monospace',
|
|
39
|
+
},
|
|
40
|
+
default: {
|
|
41
|
+
sans: 'normal',
|
|
42
|
+
serif: 'serif',
|
|
43
|
+
rounded: 'normal',
|
|
44
|
+
mono: 'monospace',
|
|
45
|
+
},
|
|
46
|
+
web: {
|
|
47
|
+
sans: 'var(--font-display)',
|
|
48
|
+
serif: 'var(--font-serif)',
|
|
49
|
+
rounded: 'var(--font-rounded)',
|
|
50
|
+
mono: 'var(--font-mono)',
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
export const Spacing = {
|
|
55
|
+
half: 2,
|
|
56
|
+
one: 4,
|
|
57
|
+
two: 8,
|
|
58
|
+
three: 16,
|
|
59
|
+
four: 24,
|
|
60
|
+
five: 32,
|
|
61
|
+
six: 64,
|
|
62
|
+
} as const;
|
|
63
|
+
|
|
64
|
+
export const BottomTabInset = Platform.select({ ios: 50, android: 80 }) ?? 0;
|
|
65
|
+
export const MaxContentWidth = 800;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
@tailwind base;
|
|
2
|
+
@tailwind components;
|
|
3
|
+
@tailwind utilities;
|
|
4
|
+
|
|
5
|
+
:root {
|
|
6
|
+
--font-display:
|
|
7
|
+
Spline Sans, Inter, ui-sans-serif, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji,
|
|
8
|
+
Segoe UI Symbol, Noto Color Emoji;
|
|
9
|
+
--font-mono:
|
|
10
|
+
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace;
|
|
11
|
+
--font-rounded: 'SF Pro Rounded', 'Hiragino Maru Gothic ProN', Meiryo, 'MS PGothic', sans-serif;
|
|
12
|
+
--font-serif: Georgia, 'Times New Roman', serif;
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useColorScheme } from 'react-native';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { useColorScheme as useRNColorScheme } from 'react-native';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* To support static rendering, this value needs to be re-calculated on the client side for web
|
|
6
|
+
*/
|
|
7
|
+
export function useColorScheme() {
|
|
8
|
+
const [hasHydrated, setHasHydrated] = useState(false);
|
|
9
|
+
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
setHasHydrated(true);
|
|
12
|
+
}, []);
|
|
13
|
+
|
|
14
|
+
const colorScheme = useRNColorScheme();
|
|
15
|
+
|
|
16
|
+
if (hasHydrated) {
|
|
17
|
+
return colorScheme;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return 'light';
|
|
21
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Learn more about light and dark modes:
|
|
3
|
+
* https://docs.expo.dev/guides/color-schemes/
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Colors } from '@/constants/theme';
|
|
7
|
+
import { useColorScheme } from '@/hooks/use-color-scheme';
|
|
8
|
+
|
|
9
|
+
export function useTheme() {
|
|
10
|
+
const scheme = useColorScheme();
|
|
11
|
+
const theme = scheme === 'unspecified' ? 'light' : scheme;
|
|
12
|
+
|
|
13
|
+
return Colors[theme];
|
|
14
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
const { hairlineWidth } = require("nativewind/theme");
|
|
2
|
+
|
|
3
|
+
/** @type {import('tailwindcss').Config} */
|
|
4
|
+
module.exports = {
|
|
5
|
+
darkMode: "class",
|
|
6
|
+
content: [
|
|
7
|
+
"./src/**/*.{js,jsx,ts,tsx}",
|
|
8
|
+
"./app/**/*.{js,jsx,ts,tsx}",
|
|
9
|
+
"./components/**/*.{js,jsx,ts,tsx}",
|
|
10
|
+
],
|
|
11
|
+
presets: [require("nativewind/preset")],
|
|
12
|
+
theme: {
|
|
13
|
+
extend: {
|
|
14
|
+
colors: {
|
|
15
|
+
border: "hsl(var(--border))",
|
|
16
|
+
input: "hsl(var(--input))",
|
|
17
|
+
ring: "hsl(var(--ring))",
|
|
18
|
+
background: "hsl(var(--background))",
|
|
19
|
+
foreground: "hsl(var(--foreground))",
|
|
20
|
+
primary: {
|
|
21
|
+
DEFAULT: "hsl(var(--primary))",
|
|
22
|
+
foreground: "hsl(var(--primary-foreground))",
|
|
23
|
+
},
|
|
24
|
+
secondary: {
|
|
25
|
+
DEFAULT: "hsl(var(--secondary))",
|
|
26
|
+
foreground: "hsl(var(--secondary-foreground))",
|
|
27
|
+
},
|
|
28
|
+
destructive: {
|
|
29
|
+
DEFAULT: "hsl(var(--destructive))",
|
|
30
|
+
foreground: "hsl(var(--destructive-foreground))",
|
|
31
|
+
},
|
|
32
|
+
muted: {
|
|
33
|
+
DEFAULT: "hsl(var(--muted))",
|
|
34
|
+
foreground: "hsl(var(--muted-foreground))",
|
|
35
|
+
},
|
|
36
|
+
accent: {
|
|
37
|
+
DEFAULT: "hsl(var(--accent))",
|
|
38
|
+
foreground: "hsl(var(--accent-foreground))",
|
|
39
|
+
},
|
|
40
|
+
popover: {
|
|
41
|
+
DEFAULT: "hsl(var(--popover))",
|
|
42
|
+
foreground: "hsl(var(--popover-foreground))",
|
|
43
|
+
},
|
|
44
|
+
card: {
|
|
45
|
+
DEFAULT: "hsl(var(--card))",
|
|
46
|
+
foreground: "hsl(var(--card-foreground))",
|
|
47
|
+
},
|
|
48
|
+
"chart-1": "hsl(var(--chart-1))",
|
|
49
|
+
"chart-2": "hsl(var(--chart-2))",
|
|
50
|
+
"chart-3": "hsl(var(--chart-3))",
|
|
51
|
+
"chart-4": "hsl(var(--chart-4))",
|
|
52
|
+
"chart-5": "hsl(var(--chart-5))",
|
|
53
|
+
},
|
|
54
|
+
borderRadius: {
|
|
55
|
+
"4xl": "min(calc(var(--radius) * 2.6), 32px)",
|
|
56
|
+
"3xl": "min(calc(var(--radius) * 2.2), 32px)",
|
|
57
|
+
"2xl": "min(calc(var(--radius) * 1.8), 28px)",
|
|
58
|
+
xl: "min(calc(var(--radius) * 1.4), 24px)",
|
|
59
|
+
lg: "min(var(--radius), 20px)",
|
|
60
|
+
md: "calc(var(--radius) * 0.8)",
|
|
61
|
+
sm: "calc(var(--radius) * 0.6)",
|
|
62
|
+
},
|
|
63
|
+
borderWidth: {
|
|
64
|
+
hairline: hairlineWidth(),
|
|
65
|
+
},
|
|
66
|
+
keyframes: {
|
|
67
|
+
"accordion-down": {
|
|
68
|
+
from: { height: "0" },
|
|
69
|
+
to: { height: "var(--radix-accordion-content-height)" },
|
|
70
|
+
},
|
|
71
|
+
"accordion-up": {
|
|
72
|
+
from: { height: "var(--radix-accordion-content-height)" },
|
|
73
|
+
to: { height: "0" },
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
animation: {
|
|
77
|
+
"accordion-down": "accordion-down 0.2s ease-out",
|
|
78
|
+
"accordion-up": "accordion-up 0.2s ease-out",
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
future: {
|
|
83
|
+
hoverOnlyWhenSupported: true,
|
|
84
|
+
},
|
|
85
|
+
plugins: [require("tailwindcss-animate")],
|
|
86
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "expo/tsconfig.base",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"strict": true,
|
|
5
|
+
"paths": {
|
|
6
|
+
"@/*": [
|
|
7
|
+
"./src/*"
|
|
8
|
+
],
|
|
9
|
+
"@/assets/*": [
|
|
10
|
+
"./assets/*"
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"include": [
|
|
15
|
+
"**/*.ts",
|
|
16
|
+
"**/*.tsx",
|
|
17
|
+
".expo/types/**/*.ts",
|
|
18
|
+
"expo-env.d.ts",
|
|
19
|
+
"nativewind-env.d.ts"
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "recommendations": ["expo.vscode-expo-tools"] }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@AGENTS.md
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|