feat(companion): initial rn port scaffold
This commit is contained in:
24
aris/.gitignore
vendored
Normal file
24
aris/.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
node_modules/
|
||||||
|
.expo/
|
||||||
|
dist/
|
||||||
|
npm-debug.*
|
||||||
|
*.jks
|
||||||
|
*.p8
|
||||||
|
*.p12
|
||||||
|
*.key
|
||||||
|
*.mobileprovision
|
||||||
|
*.orig.*
|
||||||
|
web-build/
|
||||||
|
# expo router
|
||||||
|
expo-env.d.ts
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ios
|
||||||
|
android
|
||||||
|
|
||||||
|
# macOS
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Temporary files created by Metro to check the health of the file watcher
|
||||||
|
.metro-health-check*
|
||||||
44
aris/app.json
Normal file
44
aris/app.json
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"expo": {
|
||||||
|
"name": "aris",
|
||||||
|
"slug": "aris",
|
||||||
|
"version": "1.0.0",
|
||||||
|
|
||||||
|
"scheme": "aris",
|
||||||
|
"platforms": ["ios", "android"],
|
||||||
|
"web": {
|
||||||
|
"bundler": "metro",
|
||||||
|
"output": "static",
|
||||||
|
"favicon": "./assets/favicon.png"
|
||||||
|
},
|
||||||
|
"plugins": ["expo-router"],
|
||||||
|
"experiments": {
|
||||||
|
"typedRoutes": true,
|
||||||
|
|
||||||
|
"tsconfigPaths": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"orientation": "portrait",
|
||||||
|
"icon": "./assets/icon.png",
|
||||||
|
|
||||||
|
"userInterfaceStyle": "light",
|
||||||
|
|
||||||
|
"splash": {
|
||||||
|
"image": "./assets/splash.png",
|
||||||
|
"resizeMode": "contain",
|
||||||
|
"backgroundColor": "#ffffff"
|
||||||
|
},
|
||||||
|
"assetBundlePatterns": ["**/*"],
|
||||||
|
"ios": {
|
||||||
|
"supportsTablet": true,
|
||||||
|
"bundleIdentifier": "sh.nym.aris"
|
||||||
|
},
|
||||||
|
"android": {
|
||||||
|
"package": "sh.nym.aris",
|
||||||
|
"adaptiveIcon": {
|
||||||
|
"foregroundImage": "./assets/adaptive-icon.png",
|
||||||
|
"backgroundColor": "#ffffff"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
81
aris/app/(tabs)/_layout.tsx
Normal file
81
aris/app/(tabs)/_layout.tsx
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
|
import { Tabs } from "expo-router";
|
||||||
|
|
||||||
|
const iconSize = 22;
|
||||||
|
|
||||||
|
export default function TabLayout() {
|
||||||
|
return (
|
||||||
|
<Tabs screenOptions={{ headerShown: false }}>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="index"
|
||||||
|
options={{
|
||||||
|
title: "BLE",
|
||||||
|
tabBarLabel: "BLE",
|
||||||
|
tabBarIcon: ({ color, focused }) => (
|
||||||
|
<Ionicons
|
||||||
|
color={color}
|
||||||
|
name={focused ? "bluetooth" : "bluetooth-outline"}
|
||||||
|
size={iconSize}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="orchestrator"
|
||||||
|
options={{
|
||||||
|
title: "Orchestrator",
|
||||||
|
tabBarLabel: "Orchestrator",
|
||||||
|
tabBarIcon: ({ color, focused }) => (
|
||||||
|
<Ionicons
|
||||||
|
color={color}
|
||||||
|
name={focused ? "flash" : "flash-outline"}
|
||||||
|
size={iconSize}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="todos"
|
||||||
|
options={{
|
||||||
|
title: "Todos",
|
||||||
|
tabBarLabel: "Todos",
|
||||||
|
tabBarIcon: ({ color, focused }) => (
|
||||||
|
<Ionicons
|
||||||
|
color={color}
|
||||||
|
name={focused ? "checkmark-done" : "checkmark-done-outline"}
|
||||||
|
size={iconSize}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="stocks"
|
||||||
|
options={{
|
||||||
|
title: "Stocks",
|
||||||
|
tabBarLabel: "Stocks",
|
||||||
|
tabBarIcon: ({ color, focused }) => (
|
||||||
|
<Ionicons
|
||||||
|
color={color}
|
||||||
|
name={focused ? "stats-chart" : "stats-chart-outline"}
|
||||||
|
size={iconSize}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tabs.Screen
|
||||||
|
name="settings"
|
||||||
|
options={{
|
||||||
|
title: "Settings",
|
||||||
|
tabBarLabel: "Settings",
|
||||||
|
tabBarIcon: ({ color, focused }) => (
|
||||||
|
<Ionicons
|
||||||
|
color={color}
|
||||||
|
name={focused ? "settings" : "settings-outline"}
|
||||||
|
size={iconSize}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tabs>
|
||||||
|
);
|
||||||
|
}
|
||||||
22
aris/app/(tabs)/index.tsx
Normal file
22
aris/app/(tabs)/index.tsx
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { View } from "react-native";
|
||||||
|
|
||||||
|
import { Container } from "@/components/Container";
|
||||||
|
import { Text } from "@/components/ui/text";
|
||||||
|
|
||||||
|
export default function BleScreen() {
|
||||||
|
return (
|
||||||
|
<View className={styles.container}>
|
||||||
|
<Container>
|
||||||
|
<Text variant="h3">BLE</Text>
|
||||||
|
<Text className={styles.subtitle}>
|
||||||
|
Port of SwiftUI BleStatusView will live here.
|
||||||
|
</Text>
|
||||||
|
</Container>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
container: "flex flex-1 bg-white",
|
||||||
|
subtitle: "mt-2 text-sm text-muted-foreground",
|
||||||
|
};
|
||||||
22
aris/app/(tabs)/orchestrator.tsx
Normal file
22
aris/app/(tabs)/orchestrator.tsx
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { View } from "react-native";
|
||||||
|
|
||||||
|
import { Container } from "@/components/Container";
|
||||||
|
import { Text } from "@/components/ui/text";
|
||||||
|
|
||||||
|
export default function OrchestratorScreen() {
|
||||||
|
return (
|
||||||
|
<View className={styles.container}>
|
||||||
|
<Container>
|
||||||
|
<Text variant="h3">Orchestrator</Text>
|
||||||
|
<Text className={styles.subtitle}>
|
||||||
|
Port of SwiftUI OrchestratorView will live here.
|
||||||
|
</Text>
|
||||||
|
</Container>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
container: "flex flex-1 bg-white",
|
||||||
|
subtitle: "mt-2 text-sm text-muted-foreground",
|
||||||
|
};
|
||||||
22
aris/app/(tabs)/settings.tsx
Normal file
22
aris/app/(tabs)/settings.tsx
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { View } from "react-native";
|
||||||
|
|
||||||
|
import { Container } from "@/components/Container";
|
||||||
|
import { Text } from "@/components/ui/text";
|
||||||
|
|
||||||
|
export default function SettingsScreen() {
|
||||||
|
return (
|
||||||
|
<View className={styles.container}>
|
||||||
|
<Container>
|
||||||
|
<Text variant="h3">Settings</Text>
|
||||||
|
<Text className={styles.subtitle}>
|
||||||
|
Port of SwiftUI SettingsView will live here.
|
||||||
|
</Text>
|
||||||
|
</Container>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
container: "flex flex-1 bg-white",
|
||||||
|
subtitle: "mt-2 text-sm text-muted-foreground",
|
||||||
|
};
|
||||||
22
aris/app/(tabs)/stocks.tsx
Normal file
22
aris/app/(tabs)/stocks.tsx
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { View } from "react-native";
|
||||||
|
|
||||||
|
import { Container } from "@/components/Container";
|
||||||
|
import { Text } from "@/components/ui/text";
|
||||||
|
|
||||||
|
export default function StocksScreen() {
|
||||||
|
return (
|
||||||
|
<View className={styles.container}>
|
||||||
|
<Container>
|
||||||
|
<Text variant="h3">Stocks</Text>
|
||||||
|
<Text className={styles.subtitle}>
|
||||||
|
Port of SwiftUI StockSettingsView will live here.
|
||||||
|
</Text>
|
||||||
|
</Container>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
container: "flex flex-1 bg-white",
|
||||||
|
subtitle: "mt-2 text-sm text-muted-foreground",
|
||||||
|
};
|
||||||
22
aris/app/(tabs)/todos.tsx
Normal file
22
aris/app/(tabs)/todos.tsx
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { View } from "react-native";
|
||||||
|
|
||||||
|
import { Container } from "@/components/Container";
|
||||||
|
import { Text } from "@/components/ui/text";
|
||||||
|
|
||||||
|
export default function TodosScreen() {
|
||||||
|
return (
|
||||||
|
<View className={styles.container}>
|
||||||
|
<Container>
|
||||||
|
<Text variant="h3">Todos</Text>
|
||||||
|
<Text className={styles.subtitle}>
|
||||||
|
Port of SwiftUI TodosView will live here.
|
||||||
|
</Text>
|
||||||
|
</Container>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
container: "flex flex-1 bg-white",
|
||||||
|
subtitle: "mt-2 text-sm text-muted-foreground",
|
||||||
|
};
|
||||||
46
aris/app/+html.tsx
Normal file
46
aris/app/+html.tsx
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { ScrollViewStyleReset } from 'expo-router/html';
|
||||||
|
|
||||||
|
// This file is web-only and used to configure the root HTML for every
|
||||||
|
// web page during static rendering.
|
||||||
|
// The contents of this function only run in Node.js environments and
|
||||||
|
// do not have access to the DOM or browser APIs.
|
||||||
|
export default function Root({ children }: { children: React.ReactNode }) {
|
||||||
|
return (
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charSet="utf-8" />
|
||||||
|
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
|
||||||
|
{/*
|
||||||
|
This viewport disables scaling which makes the mobile website act more like a native app.
|
||||||
|
However this does reduce built-in accessibility. If you want to enable scaling, use this instead:
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
||||||
|
*/}
|
||||||
|
<meta
|
||||||
|
name="viewport"
|
||||||
|
content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1.00001,viewport-fit=cover"
|
||||||
|
/>
|
||||||
|
{/*
|
||||||
|
Disable body scrolling on web. This makes ScrollView components work closer to how they do on native.
|
||||||
|
However, body scrolling is often nice to have for mobile web. If you want to enable it, remove this line.
|
||||||
|
*/}
|
||||||
|
<ScrollViewStyleReset />
|
||||||
|
|
||||||
|
{/* Using raw CSS styles as an escape-hatch to ensure the background color never flickers in dark-mode. */}
|
||||||
|
<style dangerouslySetInnerHTML={{ __html: responsiveBackground }} />
|
||||||
|
{/* Add any additional <head> elements that you want globally available on web... */}
|
||||||
|
</head>
|
||||||
|
<body>{children}</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const responsiveBackground = `
|
||||||
|
body {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
body {
|
||||||
|
background-color: #000;
|
||||||
|
}
|
||||||
|
}`;
|
||||||
26
aris/app/+not-found.tsx
Normal file
26
aris/app/+not-found.tsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { Link, Stack } from 'expo-router';
|
||||||
|
|
||||||
|
import { Text, View } from 'react-native';
|
||||||
|
|
||||||
|
import { Container } from '@/components/Container';
|
||||||
|
|
||||||
|
export default function NotFoundScreen() {
|
||||||
|
return (
|
||||||
|
<View className={styles.container}>
|
||||||
|
<Stack.Screen options={{ title: 'Oops!' }} />
|
||||||
|
<Container>
|
||||||
|
<Text className={styles.title}>{"This screen doesn't exist."}</Text>
|
||||||
|
<Link href="/" className={styles.link}>
|
||||||
|
<Text className={styles.linkText}>Go to home screen!</Text>
|
||||||
|
</Link>
|
||||||
|
</Container>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
container: `flex flex-1 bg-white`,
|
||||||
|
title: `text-xl font-bold`,
|
||||||
|
link: `mt-4 pt-4`,
|
||||||
|
linkText: `text-base text-[#2e78b7]`,
|
||||||
|
};
|
||||||
15
aris/app/_layout.tsx
Normal file
15
aris/app/_layout.tsx
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import "../global.css";
|
||||||
|
|
||||||
|
import { Stack } from "expo-router";
|
||||||
|
import { PortalHost } from "@rn-primitives/portal";
|
||||||
|
|
||||||
|
export default function Layout() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Stack>
|
||||||
|
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
|
||||||
|
</Stack>
|
||||||
|
<PortalHost />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
23
aris/app/details.tsx
Normal file
23
aris/app/details.tsx
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { View } from 'react-native';
|
||||||
|
|
||||||
|
import { Stack, useLocalSearchParams } from 'expo-router';
|
||||||
|
|
||||||
|
import { Container } from '@/components/Container';
|
||||||
|
import { ScreenContent } from '@/components/ScreenContent';
|
||||||
|
|
||||||
|
export default function Details() {
|
||||||
|
const { name } = useLocalSearchParams();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View className={styles.container}>
|
||||||
|
<Stack.Screen options={{ title: 'Details' }} />
|
||||||
|
<Container>
|
||||||
|
<ScreenContent path="screens/details.tsx" title={`Showing details for user ${name}`} />
|
||||||
|
</Container>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
container: 'flex flex-1 bg-white',
|
||||||
|
};
|
||||||
BIN
aris/assets/adaptive-icon.png
Normal file
BIN
aris/assets/adaptive-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
BIN
aris/assets/favicon.png
Normal file
BIN
aris/assets/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
BIN
aris/assets/icon.png
Normal file
BIN
aris/assets/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
BIN
aris/assets/splash.png
Normal file
BIN
aris/assets/splash.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 46 KiB |
12
aris/babel.config.js
Normal file
12
aris/babel.config.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
module.exports = function (api) {
|
||||||
|
api.cache(true);
|
||||||
|
let plugins = [];
|
||||||
|
|
||||||
|
plugins.push('react-native-worklets/plugin');
|
||||||
|
|
||||||
|
return {
|
||||||
|
presets: [['babel-preset-expo', { jsxImportSource: 'nativewind' }], 'nativewind/babel'],
|
||||||
|
|
||||||
|
plugins,
|
||||||
|
};
|
||||||
|
};
|
||||||
2062
aris/bun.lock
Normal file
2062
aris/bun.lock
Normal file
File diff suppressed because it is too large
Load Diff
42
aris/cesconfig.jsonc
Normal file
42
aris/cesconfig.jsonc
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
// This is an optional configuration file used primarily for debugging purposes when reporting issues.
|
||||||
|
// It is safe to delete this file as it does not affect the functionality of your application.
|
||||||
|
{
|
||||||
|
"cesVersion": "2.20.1",
|
||||||
|
"projectName": "aris",
|
||||||
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "expo-router",
|
||||||
|
"type": "navigation",
|
||||||
|
"options": {
|
||||||
|
"type": "stack"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "nativewind",
|
||||||
|
"type": "styling"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "zustand",
|
||||||
|
"type": "state-management"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"flags": {
|
||||||
|
"noGit": false,
|
||||||
|
"noInstall": false,
|
||||||
|
"overwrite": false,
|
||||||
|
"importAlias": true,
|
||||||
|
"packageManager": "bun",
|
||||||
|
"eas": false,
|
||||||
|
"publish": false
|
||||||
|
},
|
||||||
|
"packageManager": {
|
||||||
|
"type": "bun",
|
||||||
|
"version": "1.2.21"
|
||||||
|
},
|
||||||
|
"os": {
|
||||||
|
"type": "Darwin",
|
||||||
|
"platform": "darwin",
|
||||||
|
"arch": "arm64",
|
||||||
|
"kernelVersion": "24.5.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
19
aris/components.json
Normal file
19
aris/components.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://ui.shadcn.com/schema.json",
|
||||||
|
"style": "new-york",
|
||||||
|
"rsc": false,
|
||||||
|
"tsx": true,
|
||||||
|
"tailwind": {
|
||||||
|
"config": "tailwind.config.js",
|
||||||
|
"css": "global.css",
|
||||||
|
"baseColor": "neutral",
|
||||||
|
"cssVariables": true
|
||||||
|
},
|
||||||
|
"aliases": {
|
||||||
|
"components": "@/components",
|
||||||
|
"utils": "@/lib/utils",
|
||||||
|
"ui": "@/components/ui",
|
||||||
|
"lib": "@/lib",
|
||||||
|
"hooks": "@/hooks"
|
||||||
|
}
|
||||||
|
}
|
||||||
24
aris/components/Button.tsx
Normal file
24
aris/components/Button.tsx
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { forwardRef } from 'react';
|
||||||
|
import { Text, TouchableOpacity, TouchableOpacityProps, View } from 'react-native';
|
||||||
|
|
||||||
|
type ButtonProps = {
|
||||||
|
title: string;
|
||||||
|
} & TouchableOpacityProps;
|
||||||
|
|
||||||
|
export const Button = forwardRef<View, ButtonProps>(({ title, ...touchableProps }, ref) => {
|
||||||
|
return (
|
||||||
|
<TouchableOpacity
|
||||||
|
ref={ref}
|
||||||
|
{...touchableProps}
|
||||||
|
className={`${styles.button} ${touchableProps.className}`}>
|
||||||
|
<Text className={styles.buttonText}>{title}</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Button.displayName = 'Button';
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
button: 'items-center bg-indigo-500 rounded-[28px] shadow-md p-4',
|
||||||
|
buttonText: 'text-white text-lg font-semibold text-center',
|
||||||
|
};
|
||||||
9
aris/components/Container.tsx
Normal file
9
aris/components/Container.tsx
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { SafeAreaView } from 'react-native';
|
||||||
|
|
||||||
|
export const Container = ({ children }: { children: React.ReactNode }) => {
|
||||||
|
return <SafeAreaView className={styles.container}>{children}</SafeAreaView>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
container: 'flex flex-1 m-6',
|
||||||
|
};
|
||||||
29
aris/components/EditScreenInfo.tsx
Normal file
29
aris/components/EditScreenInfo.tsx
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { Text, View } from 'react-native';
|
||||||
|
|
||||||
|
export const EditScreenInfo = ({ path }: { path: string }) => {
|
||||||
|
const title = 'Open up the code for this screen:';
|
||||||
|
const description =
|
||||||
|
'Change any of the text, save the file, and your app will automatically update.';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<View className={styles.getStartedContainer}>
|
||||||
|
<Text className={styles.getStartedText}>{title}</Text>
|
||||||
|
<View className={styles.codeHighlightContainer + styles.homeScreenFilename}>
|
||||||
|
<Text>{path}</Text>
|
||||||
|
</View>
|
||||||
|
<Text className={styles.getStartedText}>{description}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
codeHighlightContainer: `rounded-md px-1`,
|
||||||
|
getStartedContainer: `items-center mx-12`,
|
||||||
|
getStartedText: `text-lg leading-6 text-center`,
|
||||||
|
helpContainer: `items-center mx-5 mt-4`,
|
||||||
|
helpLink: `py-4`,
|
||||||
|
helpLinkText: `text-center`,
|
||||||
|
homeScreenFilename: `my-2`,
|
||||||
|
};
|
||||||
26
aris/components/ScreenContent.tsx
Normal file
26
aris/components/ScreenContent.tsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Text, View } from 'react-native';
|
||||||
|
|
||||||
|
import { EditScreenInfo } from './EditScreenInfo';
|
||||||
|
|
||||||
|
type ScreenContentProps = {
|
||||||
|
title: string;
|
||||||
|
path: string;
|
||||||
|
children?: React.ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ScreenContent = ({ title, path, children }: ScreenContentProps) => {
|
||||||
|
return (
|
||||||
|
<View className={styles.container}>
|
||||||
|
<Text className={styles.title}>{title}</Text>
|
||||||
|
<View className={styles.separator} />
|
||||||
|
<EditScreenInfo path={path} />
|
||||||
|
{children}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const styles = {
|
||||||
|
container: `items-center flex-1 justify-center bg-white`,
|
||||||
|
separator: `h-[1px] my-7 w-4/5 bg-gray-200`,
|
||||||
|
title: `text-xl font-bold`,
|
||||||
|
};
|
||||||
108
aris/components/ui/button.tsx
Normal file
108
aris/components/ui/button.tsx
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
import { TextClassContext } from '@/components/ui/text';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
import { cva, type VariantProps } from 'class-variance-authority';
|
||||||
|
import { Platform, Pressable } from 'react-native';
|
||||||
|
|
||||||
|
const buttonVariants = cva(
|
||||||
|
cn(
|
||||||
|
'group shrink-0 flex-row items-center justify-center gap-2 rounded-md shadow-none',
|
||||||
|
Platform.select({
|
||||||
|
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",
|
||||||
|
})
|
||||||
|
),
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default: cn(
|
||||||
|
'bg-primary active:bg-primary/90 shadow-sm shadow-black/5',
|
||||||
|
Platform.select({ web: 'hover:bg-primary/90' })
|
||||||
|
),
|
||||||
|
destructive: cn(
|
||||||
|
'bg-destructive active:bg-destructive/90 dark:bg-destructive/60 shadow-sm shadow-black/5',
|
||||||
|
Platform.select({
|
||||||
|
web: 'hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40',
|
||||||
|
})
|
||||||
|
),
|
||||||
|
outline: cn(
|
||||||
|
'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',
|
||||||
|
Platform.select({
|
||||||
|
web: 'hover:bg-accent dark:hover:bg-input/50',
|
||||||
|
})
|
||||||
|
),
|
||||||
|
secondary: cn(
|
||||||
|
'bg-secondary active:bg-secondary/80 shadow-sm shadow-black/5',
|
||||||
|
Platform.select({ web: 'hover:bg-secondary/80' })
|
||||||
|
),
|
||||||
|
ghost: cn(
|
||||||
|
'active:bg-accent dark:active:bg-accent/50',
|
||||||
|
Platform.select({ web: 'hover:bg-accent dark:hover:bg-accent/50' })
|
||||||
|
),
|
||||||
|
link: '',
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
default: cn('h-10 px-4 py-2 sm:h-9', Platform.select({ web: 'has-[>svg]:px-3' })),
|
||||||
|
sm: cn('h-9 gap-1.5 rounded-md px-3 sm:h-8', Platform.select({ web: 'has-[>svg]:px-2.5' })),
|
||||||
|
lg: cn('h-11 rounded-md px-6 sm:h-10', Platform.select({ web: 'has-[>svg]:px-4' })),
|
||||||
|
icon: 'h-10 w-10 sm:h-9 sm:w-9',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: 'default',
|
||||||
|
size: 'default',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const buttonTextVariants = cva(
|
||||||
|
cn(
|
||||||
|
'text-foreground text-sm font-medium',
|
||||||
|
Platform.select({ web: 'pointer-events-none transition-colors' })
|
||||||
|
),
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default: 'text-primary-foreground',
|
||||||
|
destructive: 'text-white',
|
||||||
|
outline: cn(
|
||||||
|
'group-active:text-accent-foreground',
|
||||||
|
Platform.select({ web: 'group-hover:text-accent-foreground' })
|
||||||
|
),
|
||||||
|
secondary: 'text-secondary-foreground',
|
||||||
|
ghost: 'group-active:text-accent-foreground',
|
||||||
|
link: cn(
|
||||||
|
'text-primary group-active:underline',
|
||||||
|
Platform.select({ web: 'underline-offset-4 hover:underline group-hover:underline' })
|
||||||
|
),
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
default: '',
|
||||||
|
sm: '',
|
||||||
|
lg: '',
|
||||||
|
icon: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: 'default',
|
||||||
|
size: 'default',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
type ButtonProps = React.ComponentProps<typeof Pressable> &
|
||||||
|
React.RefAttributes<typeof Pressable> &
|
||||||
|
VariantProps<typeof buttonVariants>;
|
||||||
|
|
||||||
|
function Button({ className, variant, size, ...props }: ButtonProps) {
|
||||||
|
return (
|
||||||
|
<TextClassContext.Provider value={buttonTextVariants({ variant, size })}>
|
||||||
|
<Pressable
|
||||||
|
className={cn(props.disabled && 'opacity-50', buttonVariants({ variant, size }), className)}
|
||||||
|
role="button"
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</TextClassContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Button, buttonTextVariants, buttonVariants };
|
||||||
|
export type { ButtonProps };
|
||||||
52
aris/components/ui/card.tsx
Normal file
52
aris/components/ui/card.tsx
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import { Text, TextClassContext } from '@/components/ui/text';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
import { View, type ViewProps } from 'react-native';
|
||||||
|
|
||||||
|
function Card({ className, ...props }: ViewProps & React.RefAttributes<View>) {
|
||||||
|
return (
|
||||||
|
<TextClassContext.Provider value="text-card-foreground">
|
||||||
|
<View
|
||||||
|
className={cn(
|
||||||
|
'bg-card border-border flex flex-col gap-6 rounded-xl border py-6 shadow-sm shadow-black/5',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</TextClassContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardHeader({ className, ...props }: ViewProps & React.RefAttributes<View>) {
|
||||||
|
return <View className={cn('flex flex-col gap-1.5 px-6', className)} {...props} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardTitle({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof Text> & React.RefAttributes<Text>) {
|
||||||
|
return (
|
||||||
|
<Text
|
||||||
|
role="heading"
|
||||||
|
aria-level={3}
|
||||||
|
className={cn('font-semibold leading-none', className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardDescription({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof Text> & React.RefAttributes<Text>) {
|
||||||
|
return <Text className={cn('text-muted-foreground text-sm', className)} {...props} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardContent({ className, ...props }: ViewProps & React.RefAttributes<View>) {
|
||||||
|
return <View className={cn('px-6', className)} {...props} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardFooter({ className, ...props }: ViewProps & React.RefAttributes<View>) {
|
||||||
|
return <View className={cn('flex flex-row items-center px-6', className)} {...props} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle };
|
||||||
89
aris/components/ui/text.tsx
Normal file
89
aris/components/ui/text.tsx
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
import * as Slot from '@rn-primitives/slot';
|
||||||
|
import { cva, type VariantProps } from 'class-variance-authority';
|
||||||
|
import * as React from 'react';
|
||||||
|
import { Platform, Text as RNText, type Role } from 'react-native';
|
||||||
|
|
||||||
|
const textVariants = cva(
|
||||||
|
cn(
|
||||||
|
'text-foreground text-base',
|
||||||
|
Platform.select({
|
||||||
|
web: 'select-text',
|
||||||
|
})
|
||||||
|
),
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default: '',
|
||||||
|
h1: cn(
|
||||||
|
'text-center text-4xl font-extrabold tracking-tight',
|
||||||
|
Platform.select({ web: 'scroll-m-20 text-balance' })
|
||||||
|
),
|
||||||
|
h2: cn(
|
||||||
|
'border-border border-b pb-2 text-3xl font-semibold tracking-tight',
|
||||||
|
Platform.select({ web: 'scroll-m-20 first:mt-0' })
|
||||||
|
),
|
||||||
|
h3: cn('text-2xl font-semibold tracking-tight', Platform.select({ web: 'scroll-m-20' })),
|
||||||
|
h4: cn('text-xl font-semibold tracking-tight', Platform.select({ web: 'scroll-m-20' })),
|
||||||
|
p: 'mt-3 leading-7 sm:mt-6',
|
||||||
|
blockquote: 'mt-4 border-l-2 pl-3 italic sm:mt-6 sm:pl-6',
|
||||||
|
code: cn(
|
||||||
|
'bg-muted relative rounded px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold'
|
||||||
|
),
|
||||||
|
lead: 'text-muted-foreground text-xl',
|
||||||
|
large: 'text-lg font-semibold',
|
||||||
|
small: 'text-sm font-medium leading-none',
|
||||||
|
muted: 'text-muted-foreground text-sm',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: 'default',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
type TextVariantProps = VariantProps<typeof textVariants>;
|
||||||
|
|
||||||
|
type TextVariant = NonNullable<TextVariantProps['variant']>;
|
||||||
|
|
||||||
|
const ROLE: Partial<Record<TextVariant, Role>> = {
|
||||||
|
h1: 'heading',
|
||||||
|
h2: 'heading',
|
||||||
|
h3: 'heading',
|
||||||
|
h4: 'heading',
|
||||||
|
blockquote: Platform.select({ web: 'blockquote' as Role }),
|
||||||
|
code: Platform.select({ web: 'code' as Role }),
|
||||||
|
};
|
||||||
|
|
||||||
|
const ARIA_LEVEL: Partial<Record<TextVariant, string>> = {
|
||||||
|
h1: '1',
|
||||||
|
h2: '2',
|
||||||
|
h3: '3',
|
||||||
|
h4: '4',
|
||||||
|
};
|
||||||
|
|
||||||
|
const TextClassContext = React.createContext<string | undefined>(undefined);
|
||||||
|
|
||||||
|
function Text({
|
||||||
|
className,
|
||||||
|
asChild = false,
|
||||||
|
variant = 'default',
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof RNText> &
|
||||||
|
TextVariantProps &
|
||||||
|
React.RefAttributes<RNText> & {
|
||||||
|
asChild?: boolean;
|
||||||
|
}) {
|
||||||
|
const textClass = React.useContext(TextClassContext);
|
||||||
|
const Component = asChild ? Slot.Text : RNText;
|
||||||
|
return (
|
||||||
|
<Component
|
||||||
|
className={cn(textVariants({ variant }), textClass, className)}
|
||||||
|
role={variant ? ROLE[variant] : undefined}
|
||||||
|
aria-level={variant ? ARIA_LEVEL[variant] : undefined}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Text, TextClassContext };
|
||||||
15
aris/eslint.config.js
Normal file
15
aris/eslint.config.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/* eslint-env node */
|
||||||
|
const { defineConfig } = require('eslint/config');
|
||||||
|
const expoConfig = require('eslint-config-expo/flat');
|
||||||
|
|
||||||
|
module.exports = defineConfig([
|
||||||
|
expoConfig,
|
||||||
|
{
|
||||||
|
ignores: ['dist/*'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rules: {
|
||||||
|
'react/display-name': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
58
aris/global.css
Normal file
58
aris/global.css
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
:root {
|
||||||
|
--background: 0 0% 100%;
|
||||||
|
--foreground: 0 0% 3.9%;
|
||||||
|
--card: 0 0% 100%;
|
||||||
|
--card-foreground: 0 0% 3.9%;
|
||||||
|
--popover: 0 0% 100%;
|
||||||
|
--popover-foreground: 0 0% 3.9%;
|
||||||
|
--primary: 0 0% 9%;
|
||||||
|
--primary-foreground: 0 0% 98%;
|
||||||
|
--secondary: 0 0% 96.1%;
|
||||||
|
--secondary-foreground: 0 0% 9%;
|
||||||
|
--muted: 0 0% 96.1%;
|
||||||
|
--muted-foreground: 0 0% 45.1%;
|
||||||
|
--accent: 0 0% 96.1%;
|
||||||
|
--accent-foreground: 0 0% 9%;
|
||||||
|
--destructive: 0 84.2% 60.2%;
|
||||||
|
--border: 0 0% 89.8%;
|
||||||
|
--input: 0 0% 89.8%;
|
||||||
|
--ring: 0 0% 63%;
|
||||||
|
--radius: 0.625rem;
|
||||||
|
--chart-1: 12 76% 61%;
|
||||||
|
--chart-2: 173 58% 39%;
|
||||||
|
--chart-3: 197 37% 24%;
|
||||||
|
--chart-4: 43 74% 66%;
|
||||||
|
--chart-5: 27 87% 67%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark:root {
|
||||||
|
--background: 0 0% 3.9%;
|
||||||
|
--foreground: 0 0% 98%;
|
||||||
|
--card: 0 0% 3.9%;
|
||||||
|
--card-foreground: 0 0% 98%;
|
||||||
|
--popover: 0 0% 3.9%;
|
||||||
|
--popover-foreground: 0 0% 98%;
|
||||||
|
--primary: 0 0% 98%;
|
||||||
|
--primary-foreground: 0 0% 9%;
|
||||||
|
--secondary: 0 0% 14.9%;
|
||||||
|
--secondary-foreground: 0 0% 98%;
|
||||||
|
--muted: 0 0% 14.9%;
|
||||||
|
--muted-foreground: 0 0% 63.9%;
|
||||||
|
--accent: 0 0% 14.9%;
|
||||||
|
--accent-foreground: 0 0% 98%;
|
||||||
|
--destructive: 0 70.9% 59.4%;
|
||||||
|
--border: 0 0% 14.9%;
|
||||||
|
--input: 0 0% 14.9%;
|
||||||
|
--ring: 300 0% 45%;
|
||||||
|
--chart-1: 220 70% 50%;
|
||||||
|
--chart-2: 160 60% 45%;
|
||||||
|
--chart-3: 30 80% 55%;
|
||||||
|
--chart-4: 280 65% 60%;
|
||||||
|
--chart-5: 340 75% 55%;
|
||||||
|
}
|
||||||
|
}
|
||||||
81
aris/lib/theme.ts
Normal file
81
aris/lib/theme.ts
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import { DarkTheme, DefaultTheme, type Theme } from "@react-navigation/native";
|
||||||
|
|
||||||
|
export const THEME = {
|
||||||
|
light: {
|
||||||
|
background: "hsl(0 0% 100%)",
|
||||||
|
foreground: "hsl(0 0% 3.9%)",
|
||||||
|
card: "hsl(0 0% 100%)",
|
||||||
|
cardForeground: "hsl(0 0% 3.9%)",
|
||||||
|
popover: "hsl(0 0% 100%)",
|
||||||
|
popoverForeground: "hsl(0 0% 3.9%)",
|
||||||
|
primary: "hsl(0 0% 9%)",
|
||||||
|
primaryForeground: "hsl(0 0% 98%)",
|
||||||
|
secondary: "hsl(0 0% 96.1%)",
|
||||||
|
secondaryForeground: "hsl(0 0% 9%)",
|
||||||
|
muted: "hsl(0 0% 96.1%)",
|
||||||
|
mutedForeground: "hsl(0 0% 45.1%)",
|
||||||
|
accent: "hsl(0 0% 96.1%)",
|
||||||
|
accentForeground: "hsl(0 0% 9%)",
|
||||||
|
destructive: "hsl(0 84.2% 60.2%)",
|
||||||
|
border: "hsl(0 0% 89.8%)",
|
||||||
|
input: "hsl(0 0% 89.8%)",
|
||||||
|
ring: "hsl(0 0% 63%)",
|
||||||
|
radius: "0.625rem",
|
||||||
|
chart1: "hsl(12 76% 61%)",
|
||||||
|
chart2: "hsl(173 58% 39%)",
|
||||||
|
chart3: "hsl(197 37% 24%)",
|
||||||
|
chart4: "hsl(43 74% 66%)",
|
||||||
|
chart5: "hsl(27 87% 67%)",
|
||||||
|
},
|
||||||
|
dark: {
|
||||||
|
background: "hsl(0 0% 3.9%)",
|
||||||
|
foreground: "hsl(0 0% 98%)",
|
||||||
|
card: "hsl(0 0% 3.9%)",
|
||||||
|
cardForeground: "hsl(0 0% 98%)",
|
||||||
|
popover: "hsl(0 0% 3.9%)",
|
||||||
|
popoverForeground: "hsl(0 0% 98%)",
|
||||||
|
primary: "hsl(0 0% 98%)",
|
||||||
|
primaryForeground: "hsl(0 0% 9%)",
|
||||||
|
secondary: "hsl(0 0% 14.9%)",
|
||||||
|
secondaryForeground: "hsl(0 0% 98%)",
|
||||||
|
muted: "hsl(0 0% 14.9%)",
|
||||||
|
mutedForeground: "hsl(0 0% 63.9%)",
|
||||||
|
accent: "hsl(0 0% 14.9%)",
|
||||||
|
accentForeground: "hsl(0 0% 98%)",
|
||||||
|
destructive: "hsl(0 70.9% 59.4%)",
|
||||||
|
border: "hsl(0 0% 14.9%)",
|
||||||
|
input: "hsl(0 0% 14.9%)",
|
||||||
|
ring: "hsl(300 0% 45%)",
|
||||||
|
radius: "0.625rem",
|
||||||
|
chart1: "hsl(220 70% 50%)",
|
||||||
|
chart2: "hsl(160 60% 45%)",
|
||||||
|
chart3: "hsl(30 80% 55%)",
|
||||||
|
chart4: "hsl(280 65% 60%)",
|
||||||
|
chart5: "hsl(340 75% 55%)",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const NAV_THEME: Record<"light" | "dark", Theme> = {
|
||||||
|
light: {
|
||||||
|
...DefaultTheme,
|
||||||
|
colors: {
|
||||||
|
background: THEME.light.background,
|
||||||
|
border: THEME.light.border,
|
||||||
|
card: THEME.light.card,
|
||||||
|
notification: THEME.light.destructive,
|
||||||
|
primary: THEME.light.primary,
|
||||||
|
text: THEME.light.foreground,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
dark: {
|
||||||
|
...DarkTheme,
|
||||||
|
colors: {
|
||||||
|
background: THEME.dark.background,
|
||||||
|
border: THEME.dark.border,
|
||||||
|
card: THEME.dark.card,
|
||||||
|
notification: THEME.dark.destructive,
|
||||||
|
primary: THEME.dark.primary,
|
||||||
|
text: THEME.dark.foreground,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
6
aris/lib/utils.ts
Normal file
6
aris/lib/utils.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { clsx, type ClassValue } from "clsx";
|
||||||
|
import { twMerge } from "tailwind-merge";
|
||||||
|
|
||||||
|
export function cn(...inputs: ClassValue[]) {
|
||||||
|
return twMerge(clsx(inputs));
|
||||||
|
}
|
||||||
13
aris/metro.config.js
Normal file
13
aris/metro.config.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// Learn more https://docs.expo.io/guides/customizing-metro
|
||||||
|
const { getDefaultConfig } = require("expo/metro-config");
|
||||||
|
|
||||||
|
const { withNativeWind } = require("nativewind/metro");
|
||||||
|
|
||||||
|
/** @type {import('expo/metro-config').MetroConfig} */
|
||||||
|
|
||||||
|
const config = getDefaultConfig(__dirname);
|
||||||
|
|
||||||
|
module.exports = withNativeWind(config, {
|
||||||
|
input: "./global.css",
|
||||||
|
inlineRem: 16,
|
||||||
|
});
|
||||||
2
aris/nativewind-env.d.ts
vendored
Normal file
2
aris/nativewind-env.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
// @ts-ignore
|
||||||
|
/// <reference types="nativewind/types" />
|
||||||
54
aris/package.json
Normal file
54
aris/package.json
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
{
|
||||||
|
"name": "aris",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "expo-router/entry",
|
||||||
|
"scripts": {
|
||||||
|
"android": "expo run:android",
|
||||||
|
"ios": "expo run:ios",
|
||||||
|
"start": "expo start",
|
||||||
|
"prebuild": "expo prebuild",
|
||||||
|
"lint": "eslint \"**/*.{js,jsx,ts,tsx}\" && prettier -c \"**/*.{js,jsx,ts,tsx,json}\"",
|
||||||
|
"format": "eslint \"**/*.{js,jsx,ts,tsx}\" --fix && prettier \"**/*.{js,jsx,ts,tsx,json}\" --write",
|
||||||
|
"web": "expo start --web"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@expo/vector-icons": "^15.0.2",
|
||||||
|
"@react-navigation/native": "^7.1.6",
|
||||||
|
"@rn-primitives/portal": "^1.3.0",
|
||||||
|
"@rn-primitives/slot": "^1.2.0",
|
||||||
|
"class-variance-authority": "^0.7.1",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"expo": "^54.0.0",
|
||||||
|
"expo-constants": "~18.0.9",
|
||||||
|
"expo-linking": "~8.0.8",
|
||||||
|
"expo-router": "~6.0.10",
|
||||||
|
"expo-status-bar": "~3.0.8",
|
||||||
|
"expo-system-ui": "~6.0.7",
|
||||||
|
"expo-web-browser": "~15.0.7",
|
||||||
|
"nativewind": "latest",
|
||||||
|
"react": "19.1.0",
|
||||||
|
"react-dom": "19.1.0",
|
||||||
|
"react-native": "0.81.5",
|
||||||
|
"react-native-gesture-handler": "~2.28.0",
|
||||||
|
"react-native-reanimated": "~4.1.1",
|
||||||
|
"react-native-safe-area-context": "~5.6.0",
|
||||||
|
"react-native-screens": "~4.16.0",
|
||||||
|
"react-native-web": "^0.21.0",
|
||||||
|
"react-native-worklets": "0.5.1",
|
||||||
|
"tailwind-merge": "^3.4.0",
|
||||||
|
"tailwindcss-animate": "^1.0.7",
|
||||||
|
"zustand": "^4.5.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.20.0",
|
||||||
|
"@types/react": "~19.1.10",
|
||||||
|
"eslint": "^9.25.1",
|
||||||
|
"eslint-config-expo": "~10.0.0",
|
||||||
|
"eslint-config-prettier": "^10.1.2",
|
||||||
|
"prettier": "^3.2.5",
|
||||||
|
"tailwindcss": "^3.4.0",
|
||||||
|
"prettier-plugin-tailwindcss": "^0.5.11",
|
||||||
|
"typescript": "~5.9.2"
|
||||||
|
},
|
||||||
|
"private": true
|
||||||
|
}
|
||||||
10
aris/prettier.config.js
Normal file
10
aris/prettier.config.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
module.exports = {
|
||||||
|
printWidth: 100,
|
||||||
|
tabWidth: 2,
|
||||||
|
singleQuote: true,
|
||||||
|
bracketSameLine: true,
|
||||||
|
trailingComma: 'es5',
|
||||||
|
|
||||||
|
plugins: [require.resolve('prettier-plugin-tailwindcss')],
|
||||||
|
tailwindAttributes: ['className'],
|
||||||
|
};
|
||||||
15
aris/store/store.ts
Normal file
15
aris/store/store.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { create } from 'zustand';
|
||||||
|
|
||||||
|
export interface BearState {
|
||||||
|
bears: number;
|
||||||
|
increasePopulation: () => void;
|
||||||
|
removeAllBears: () => void;
|
||||||
|
updateBears: (newBears: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useStore = create<BearState>((set) => ({
|
||||||
|
bears: 0,
|
||||||
|
increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
|
||||||
|
removeAllBears: () => set({ bears: 0 }),
|
||||||
|
updateBears: (newBears) => set({ bears: newBears }),
|
||||||
|
}));
|
||||||
73
aris/tailwind.config.js
Normal file
73
aris/tailwind.config.js
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
const { hairlineWidth } = require("nativewind/theme");
|
||||||
|
|
||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
module.exports = {
|
||||||
|
darkMode: "class",
|
||||||
|
content: ["./app/**/*.{ts,tsx}", "./components/**/*.{ts,tsx}"],
|
||||||
|
presets: [require("nativewind/preset")],
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
border: "hsl(var(--border))",
|
||||||
|
input: "hsl(var(--input))",
|
||||||
|
ring: "hsl(var(--ring))",
|
||||||
|
background: "hsl(var(--background))",
|
||||||
|
foreground: "hsl(var(--foreground))",
|
||||||
|
primary: {
|
||||||
|
DEFAULT: "hsl(var(--primary))",
|
||||||
|
foreground: "hsl(var(--primary-foreground))",
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
DEFAULT: "hsl(var(--secondary))",
|
||||||
|
foreground: "hsl(var(--secondary-foreground))",
|
||||||
|
},
|
||||||
|
destructive: {
|
||||||
|
DEFAULT: "hsl(var(--destructive))",
|
||||||
|
foreground: "hsl(var(--destructive-foreground))",
|
||||||
|
},
|
||||||
|
muted: {
|
||||||
|
DEFAULT: "hsl(var(--muted))",
|
||||||
|
foreground: "hsl(var(--muted-foreground))",
|
||||||
|
},
|
||||||
|
accent: {
|
||||||
|
DEFAULT: "hsl(var(--accent))",
|
||||||
|
foreground: "hsl(var(--accent-foreground))",
|
||||||
|
},
|
||||||
|
popover: {
|
||||||
|
DEFAULT: "hsl(var(--popover))",
|
||||||
|
foreground: "hsl(var(--popover-foreground))",
|
||||||
|
},
|
||||||
|
card: {
|
||||||
|
DEFAULT: "hsl(var(--card))",
|
||||||
|
foreground: "hsl(var(--card-foreground))",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
borderRadius: {
|
||||||
|
lg: "var(--radius)",
|
||||||
|
md: "calc(var(--radius) - 2px)",
|
||||||
|
sm: "calc(var(--radius) - 4px)",
|
||||||
|
},
|
||||||
|
borderWidth: {
|
||||||
|
hairline: hairlineWidth(),
|
||||||
|
},
|
||||||
|
keyframes: {
|
||||||
|
"accordion-down": {
|
||||||
|
from: { height: "0" },
|
||||||
|
to: { height: "var(--radix-accordion-content-height)" },
|
||||||
|
},
|
||||||
|
"accordion-up": {
|
||||||
|
from: { height: "var(--radix-accordion-content-height)" },
|
||||||
|
to: { height: "0" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
animation: {
|
||||||
|
"accordion-down": "accordion-down 0.2s ease-out",
|
||||||
|
"accordion-up": "accordion-up 0.2s ease-out",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
future: {
|
||||||
|
hoverOnlyWhenSupported: true,
|
||||||
|
},
|
||||||
|
plugins: [require("tailwindcss-animate")],
|
||||||
|
};
|
||||||
11
aris/tsconfig.json
Normal file
11
aris/tsconfig.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"extends": "expo/tsconfig.base",
|
||||||
|
"compilerOptions": {
|
||||||
|
"strict": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": ["**/*.ts", "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts", "nativewind-env.d.ts"]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user