feat: 로그인 화면 및 공통 속성 생성
This commit is contained in:
27
App.tsx
27
App.tsx
@@ -1,20 +1,17 @@
|
||||
import { StatusBar } from 'expo-status-bar';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import { NavigationContainer } from "@react-navigation/native";
|
||||
import React from "react";
|
||||
import { enableScreens } from "react-native-screens";
|
||||
import AuthGate from "./src/navigation/AuthGate";
|
||||
import { AuthProvider } from "./src/store/auth";
|
||||
|
||||
enableScreens();
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text>Open up App.tsx to start working on your app!</Text>
|
||||
<StatusBar style="auto" />
|
||||
</View>
|
||||
<AuthProvider>
|
||||
<NavigationContainer>
|
||||
<AuthGate />
|
||||
</NavigationContainer>
|
||||
</AuthProvider>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#fff',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
});
|
||||
|
||||
312
package-lock.json
generated
312
package-lock.json
generated
@@ -8,10 +8,14 @@
|
||||
"name": "audiobook-app",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@react-navigation/native": "^7.1.26",
|
||||
"@react-navigation/native-stack": "^7.9.0",
|
||||
"expo": "~54.0.30",
|
||||
"expo-status-bar": "~3.0.9",
|
||||
"react": "19.1.0",
|
||||
"react-native": "0.81.5"
|
||||
"react-native": "0.81.5",
|
||||
"react-native-safe-area-context": "~5.6.0",
|
||||
"react-native-screens": "~4.16.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "~19.1.0",
|
||||
@@ -2972,6 +2976,123 @@
|
||||
"integrity": "sha512-0HuJ8YtqlTVRXGZuGeBejLE04wSQsibpTI+RGOyVqxZvgtlLLC/Ssw0UmbHhT4lYMp2fhdtvKZSs5emWB1zR/g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@react-navigation/core": {
|
||||
"version": "7.13.7",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-7.13.7.tgz",
|
||||
"integrity": "sha512-k2ABo3250vq1ovOh/iVwXS6Hwr5PVRGXoPh/ewVFOOuEKTvOx9i//OBzt8EF+HokBxS2HBRlR2b+aCOmscRqBw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@react-navigation/routers": "^7.5.3",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"nanoid": "^3.3.11",
|
||||
"query-string": "^7.1.3",
|
||||
"react-is": "^19.1.0",
|
||||
"use-latest-callback": "^0.2.4",
|
||||
"use-sync-external-store": "^1.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">= 18.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-navigation/core/node_modules/escape-string-regexp": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-navigation/core/node_modules/react-is": {
|
||||
"version": "19.2.3",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.3.tgz",
|
||||
"integrity": "sha512-qJNJfu81ByyabuG7hPFEbXqNcWSU3+eVus+KJs+0ncpGfMyYdvSmxiJxbWR65lYi1I+/0HBcliO029gc4F+PnA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@react-navigation/elements": {
|
||||
"version": "2.9.3",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.9.3.tgz",
|
||||
"integrity": "sha512-3+eyvWiVPIEf6tN9UdduhOEHcTuNe3R5WovgiVkfH9+jApHMTZDc2loePTpY/i2HDJhObhhChpJzO6BVjrpdYQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color": "^4.2.3",
|
||||
"use-latest-callback": "^0.2.4",
|
||||
"use-sync-external-store": "^1.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@react-native-masked-view/masked-view": ">= 0.2.0",
|
||||
"@react-navigation/native": "^7.1.26",
|
||||
"react": ">= 18.2.0",
|
||||
"react-native": "*",
|
||||
"react-native-safe-area-context": ">= 4.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@react-native-masked-view/masked-view": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@react-navigation/native": {
|
||||
"version": "7.1.26",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.1.26.tgz",
|
||||
"integrity": "sha512-RhKmeD0E2ejzKS6z8elAfdfwShpcdkYY8zJzvHYLq+wv183BBcElTeyMLcIX6wIn7QutXeI92Yi21t7aUWfqNQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@react-navigation/core": "^7.13.7",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"nanoid": "^3.3.11",
|
||||
"use-latest-callback": "^0.2.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">= 18.2.0",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-navigation/native-stack": {
|
||||
"version": "7.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-7.9.0.tgz",
|
||||
"integrity": "sha512-C/mNPhI0Pnerl7C2cB+6fAkdgSmfKECMERrbyfjx3P6JmEuTC54o+GV1c62FUmlRaRUassVHbtw4EeaY2uLh0g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@react-navigation/elements": "^2.9.3",
|
||||
"color": "^4.2.3",
|
||||
"sf-symbols-typescript": "^2.1.0",
|
||||
"warn-once": "^0.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@react-navigation/native": "^7.1.26",
|
||||
"react": ">= 18.2.0",
|
||||
"react-native": "*",
|
||||
"react-native-safe-area-context": ">= 4.0.0",
|
||||
"react-native-screens": ">= 4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-navigation/native/node_modules/escape-string-regexp": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-navigation/routers": {
|
||||
"version": "7.5.3",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-7.5.3.tgz",
|
||||
"integrity": "sha512-1tJHg4KKRJuQ1/EvJxatrMef3NZXEPzwUIUZ3n1yJ2t7Q97siwRtbynRpQG9/69ebbtiZ8W3ScOZF/OmhvM4Rg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11"
|
||||
}
|
||||
},
|
||||
"node_modules/@sinclair/typebox": {
|
||||
"version": "0.27.8",
|
||||
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
|
||||
@@ -3916,6 +4037,19 @@
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/color": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
|
||||
"integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1",
|
||||
"color-string": "^1.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
@@ -3931,6 +4065,34 @@
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/color-string": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
|
||||
"integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-name": "^1.0.0",
|
||||
"simple-swizzle": "^0.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/color/node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/color/node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/commander": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
|
||||
@@ -4096,6 +4258,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/decode-uri-component": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
|
||||
"integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/deep-extend": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
|
||||
@@ -4301,6 +4472,7 @@
|
||||
"resolved": "https://registry.npmjs.org/expo/-/expo-54.0.30.tgz",
|
||||
"integrity": "sha512-6q+aFfKL0SpT8prfdpR3V8HcN51ov0mCGuwQTzyuk6eeO9rg7a7LWbgPv9rEVXGZEuyULstL8LGNwHqusand7Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.0",
|
||||
"@expo/cli": "54.0.20",
|
||||
@@ -4885,6 +5057,12 @@
|
||||
"integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fast-json-stable-stringify": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
||||
@@ -4912,6 +5090,15 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/filter-obj": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz",
|
||||
"integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/finalhandler": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
|
||||
@@ -5284,6 +5471,12 @@
|
||||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-arrayish": {
|
||||
"version": "0.3.4",
|
||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz",
|
||||
"integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/is-core-module": {
|
||||
"version": "2.16.1",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
|
||||
@@ -7222,6 +7415,24 @@
|
||||
"qrcode-terminal": "bin/qrcode-terminal.js"
|
||||
}
|
||||
},
|
||||
"node_modules/query-string": {
|
||||
"version": "7.1.3",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz",
|
||||
"integrity": "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"decode-uri-component": "^0.2.2",
|
||||
"filter-obj": "^1.1.0",
|
||||
"split-on-first": "^1.0.0",
|
||||
"strict-uri-encode": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/queue": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz",
|
||||
@@ -7274,6 +7485,18 @@
|
||||
"ws": "^7"
|
||||
}
|
||||
},
|
||||
"node_modules/react-freeze": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/react-freeze/-/react-freeze-1.0.4.tgz",
|
||||
"integrity": "sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=17.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "18.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
|
||||
@@ -7347,6 +7570,33 @@
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-safe-area-context": {
|
||||
"version": "5.6.2",
|
||||
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.6.2.tgz",
|
||||
"integrity": "sha512-4XGqMNj5qjUTYywJqpdWZ9IG8jgkS3h06sfVjfw5yZQZfWnRFXczi0GnYyFyCc2EBps/qFmoCH8fez//WumdVg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-screens": {
|
||||
"version": "4.16.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.16.0.tgz",
|
||||
"integrity": "sha512-yIAyh7F/9uWkOzCi1/2FqvNvK6Wb9Y1+Kzn16SuGfN9YFJDTbwlzGRvePCNTOX0recpLQF3kc2FmvMUhyTCH1Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"react-freeze": "^1.0.0",
|
||||
"react-native-is-edge-to-edge": "^1.2.1",
|
||||
"warn-once": "^0.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native/node_modules/@react-native/virtualized-lists": {
|
||||
"version": "0.81.5",
|
||||
"resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.81.5.tgz",
|
||||
@@ -7820,6 +8070,15 @@
|
||||
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/sf-symbols-typescript": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/sf-symbols-typescript/-/sf-symbols-typescript-2.2.0.tgz",
|
||||
"integrity": "sha512-TPbeg0b7ylrswdGCji8FRGFAKuqbpQlLbL8SOle3j1iHSs5Ob5mhvMAxWN2UItOjgALAB5Zp3fmMfj8mbWvXKw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
@@ -7870,6 +8129,15 @@
|
||||
"plist": "^3.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-swizzle": {
|
||||
"version": "0.2.4",
|
||||
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz",
|
||||
"integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-arrayish": "^0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/sisteransi": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
||||
@@ -7931,6 +8199,15 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/split-on-first": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
|
||||
"integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/sprintf-js": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||
@@ -7994,6 +8271,15 @@
|
||||
"node": ">= 0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/strict-uri-encode": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
|
||||
"integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
@@ -8499,6 +8785,24 @@
|
||||
"browserslist": ">= 4.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/use-latest-callback": {
|
||||
"version": "0.2.6",
|
||||
"resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.2.6.tgz",
|
||||
"integrity": "sha512-FvRG9i1HSo0wagmX63Vrm8SnlUU3LMM3WyZkQ76RnslpBrX694AdG4A0zQBx2B3ZifFA0yv/BaEHGBnEax5rZg==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/use-sync-external-store": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
|
||||
"integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/utils-merge": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||
@@ -8550,6 +8854,12 @@
|
||||
"makeerror": "1.0.12"
|
||||
}
|
||||
},
|
||||
"node_modules/warn-once": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/warn-once/-/warn-once-0.1.1.tgz",
|
||||
"integrity": "sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/wcwidth": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
|
||||
|
||||
@@ -9,10 +9,14 @@
|
||||
"web": "expo start --web"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-navigation/native": "^7.1.26",
|
||||
"@react-navigation/native-stack": "^7.9.0",
|
||||
"expo": "~54.0.30",
|
||||
"expo-status-bar": "~3.0.9",
|
||||
"react": "19.1.0",
|
||||
"react-native": "0.81.5"
|
||||
"react-native": "0.81.5",
|
||||
"react-native-safe-area-context": "~5.6.0",
|
||||
"react-native-screens": "~4.16.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "~19.1.0",
|
||||
|
||||
27
src/components/ui/AppText.tsx
Normal file
27
src/components/ui/AppText.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import React from "react";
|
||||
import { Text, type TextProps, type TextStyle } from "react-native";
|
||||
import { Theme } from "../../theme/theme";
|
||||
|
||||
type Variant = "logo" | "title" | "body" | "muted" | "error";
|
||||
|
||||
type Props = TextProps & {
|
||||
variant?: Variant;
|
||||
style?: TextStyle | TextStyle[];
|
||||
};
|
||||
|
||||
export default function AppText({ variant = "body", style, ...props }: Props) {
|
||||
const base: TextStyle = {
|
||||
color: Theme.Colors.text,
|
||||
fontSize: Theme.FontSize.md,
|
||||
};
|
||||
|
||||
const variants: Record<Variant, TextStyle> = {
|
||||
logo: { fontSize: Theme.FontSize.xxl, fontWeight: Theme.FontWeight.bold },
|
||||
title: { fontSize: Theme.FontSize.xl, fontWeight: Theme.FontWeight.bold },
|
||||
body: { fontSize: Theme.FontSize.md },
|
||||
muted: { color: Theme.Colors.mutedText, fontSize: Theme.FontSize.sm },
|
||||
error: { color: Theme.Colors.danger, fontSize: Theme.FontSize.sm },
|
||||
};
|
||||
|
||||
return <Text {...props} style={[base, variants[variant], style]} />;
|
||||
}
|
||||
73
src/components/ui/Button.tsx
Normal file
73
src/components/ui/Button.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
import React from "react";
|
||||
import { Pressable, type PressableProps, StyleSheet, View } from "react-native";
|
||||
import { Theme } from "../../theme/theme";
|
||||
import AppText from "./AppText";
|
||||
|
||||
type Props = PressableProps & {
|
||||
title: string;
|
||||
variant?: "primary" | "secondary";
|
||||
};
|
||||
|
||||
export default function Button({
|
||||
title,
|
||||
variant = "primary",
|
||||
style,
|
||||
...props
|
||||
}: Props) {
|
||||
const isPrimary = variant === "primary";
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
{...props}
|
||||
style={({ pressed }) => [
|
||||
styles.base,
|
||||
isPrimary ? styles.primary : styles.secondary,
|
||||
pressed &&
|
||||
(isPrimary ? styles.primaryPressed : styles.secondaryPressed),
|
||||
typeof style === "function" ? style({ pressed }) : style,
|
||||
]}
|
||||
>
|
||||
<View>
|
||||
<AppText
|
||||
style={{
|
||||
textAlign: "center",
|
||||
fontWeight: Theme.FontWeight.bold,
|
||||
color: isPrimary ? Theme.Colors.text : Theme.Colors.text,
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</AppText>
|
||||
</View>
|
||||
</Pressable>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
base: {
|
||||
height: 48,
|
||||
paddingVertical: 0,
|
||||
paddingHorizontal: Theme.Spacing.lg,
|
||||
borderRadius: Theme.Radius.md,
|
||||
alignItems: "center", // 가로 가운데
|
||||
justifyContent: "center", // 세로 가운데
|
||||
},
|
||||
text: {
|
||||
textAlign: "center",
|
||||
fontWeight: Theme.FontWeight.bold,
|
||||
lineHeight: 20,
|
||||
},
|
||||
primary: {
|
||||
backgroundColor: Theme.Colors.primary,
|
||||
},
|
||||
primaryPressed: {
|
||||
backgroundColor: Theme.Colors.primaryPressed,
|
||||
},
|
||||
secondary: {
|
||||
backgroundColor: Theme.Colors.surface,
|
||||
borderWidth: 1,
|
||||
borderColor: Theme.Colors.border,
|
||||
},
|
||||
secondaryPressed: {
|
||||
opacity: 0.9,
|
||||
},
|
||||
});
|
||||
32
src/components/ui/Input.tsx
Normal file
32
src/components/ui/Input.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
import React from "react";
|
||||
import { StyleSheet, TextInput, type TextInputProps, View } from "react-native";
|
||||
import { Theme } from "../../theme/theme";
|
||||
|
||||
type Props = TextInputProps;
|
||||
|
||||
export default function Input(props: Props) {
|
||||
return (
|
||||
<View style={styles.wrap}>
|
||||
<TextInput
|
||||
{...props}
|
||||
placeholderTextColor={Theme.Colors.placeholder}
|
||||
style={[styles.input, props.style]}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
wrap: {
|
||||
borderWidth: 1,
|
||||
borderColor: Theme.Colors.border,
|
||||
borderRadius: Theme.Radius.md,
|
||||
backgroundColor: Theme.Colors.inputBg,
|
||||
},
|
||||
input: {
|
||||
paddingHorizontal: Theme.Spacing.md,
|
||||
paddingVertical: Theme.Spacing.md,
|
||||
color: Theme.Colors.text,
|
||||
fontSize: Theme.FontSize.md,
|
||||
},
|
||||
});
|
||||
17
src/navigation/AppStack.tsx
Normal file
17
src/navigation/AppStack.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import { createNativeStackNavigator } from "@react-navigation/native-stack";
|
||||
import React from "react";
|
||||
import HomeScreen from "../screens/HomeScreen";
|
||||
|
||||
export type AppStackParamList = {
|
||||
Home: undefined;
|
||||
};
|
||||
|
||||
const Stack = createNativeStackNavigator<AppStackParamList>();
|
||||
|
||||
export default function AppStack() {
|
||||
return (
|
||||
<Stack.Navigator screenOptions={{ headerShown: false }}>
|
||||
<Stack.Screen name="Home" component={HomeScreen} />
|
||||
</Stack.Navigator>
|
||||
);
|
||||
}
|
||||
10
src/navigation/AuthGate.tsx
Normal file
10
src/navigation/AuthGate.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
import React from "react";
|
||||
import AppStack from "./AppStack";
|
||||
import AuthStack from "./AuthStack";
|
||||
|
||||
export default function AuthGate() {
|
||||
// const { isAuthed } = useAuth();
|
||||
const isAuthed = true;
|
||||
// return <AuthStack />;
|
||||
return isAuthed ? <AppStack /> : <AuthStack />;
|
||||
}
|
||||
17
src/navigation/AuthStack.tsx
Normal file
17
src/navigation/AuthStack.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import { createNativeStackNavigator } from "@react-navigation/native-stack";
|
||||
import React from "react";
|
||||
import LoginScreen from "../screens/LoginScreen";
|
||||
|
||||
export type AuthStackParamList = {
|
||||
Login: undefined;
|
||||
};
|
||||
|
||||
const Stack = createNativeStackNavigator<AuthStackParamList>();
|
||||
|
||||
export default function AuthStack() {
|
||||
return (
|
||||
<Stack.Navigator screenOptions={{ headerShown: false }}>
|
||||
<Stack.Screen name="Login" component={LoginScreen} />
|
||||
</Stack.Navigator>
|
||||
);
|
||||
}
|
||||
18
src/screens/HomeScreen.tsx
Normal file
18
src/screens/HomeScreen.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import { StyleSheet, Text, View } from "react-native";
|
||||
|
||||
export default function HomeScreen() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text>feawfewa</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: "red",
|
||||
alignContent: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
});
|
||||
74
src/screens/LoginScreen.tsx
Normal file
74
src/screens/LoginScreen.tsx
Normal file
@@ -0,0 +1,74 @@
|
||||
import React from "react";
|
||||
import { Pressable, StyleSheet, View } from "react-native";
|
||||
import { SafeAreaView } from "react-native-safe-area-context";
|
||||
import AppText from "../components/ui/AppText";
|
||||
import Button from "../components/ui/Button";
|
||||
import Input from "../components/ui/Input";
|
||||
import { Theme } from "../theme/theme";
|
||||
|
||||
export default function LoginScreen() {
|
||||
return (
|
||||
<SafeAreaView style={styles.safe}>
|
||||
<View style={styles.container}>
|
||||
<AppText variant="title">Your personal growth podcast</AppText>
|
||||
<AppText variant="muted">Sign in to continue</AppText>
|
||||
|
||||
<View style={{ height: Theme.Spacing.lg }} />
|
||||
|
||||
<Input
|
||||
placeholder="Username"
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
textContentType="username"
|
||||
/>
|
||||
|
||||
<View style={{ height: Theme.Spacing.sm }} />
|
||||
|
||||
<Input
|
||||
placeholder="Password"
|
||||
secureTextEntry
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
textContentType="password"
|
||||
/>
|
||||
|
||||
<View style={{ height: Theme.Spacing.lg }} />
|
||||
|
||||
<Button title="Continue" onPress={() => {}} />
|
||||
|
||||
<View style={{ height: Theme.Spacing.md }} />
|
||||
|
||||
<Pressable
|
||||
onPress={() => {
|
||||
console.log("feawf");
|
||||
}}
|
||||
>
|
||||
<AppText variant="muted" style={styles.signupLine}>
|
||||
Don't have an account?{" "}
|
||||
<AppText style={styles.signupLink}>Sign up</AppText>
|
||||
</AppText>
|
||||
</Pressable>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
safe: {
|
||||
flex: 1,
|
||||
backgroundColor: Theme.Colors.bg,
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
padding: Theme.Spacing.xl,
|
||||
justifyContent: "center",
|
||||
gap: Theme.Spacing.sm,
|
||||
},
|
||||
signupLine: {
|
||||
textAlign: "center",
|
||||
},
|
||||
signupLink: {
|
||||
color: Theme.Colors.primary,
|
||||
fontWeight: Theme.FontWeight.bold,
|
||||
},
|
||||
});
|
||||
31
src/store/auth.tsx
Normal file
31
src/store/auth.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import React, { createContext, useContext, useMemo, useState } from "react";
|
||||
|
||||
export type AuthContextValue = {
|
||||
isAuthed: boolean;
|
||||
login: () => void;
|
||||
logout: () => void;
|
||||
};
|
||||
|
||||
const AuthContext = createContext<AuthContextValue | null>(null);
|
||||
|
||||
export function AuthProvider({ children }: { children: React.ReactNode }) {
|
||||
const [isAuthed, setIsAuthed] = useState<boolean>(false);
|
||||
console.log("isAuthed: " + isAuthed);
|
||||
|
||||
const value = useMemo<AuthContextValue>(
|
||||
() => ({
|
||||
isAuthed,
|
||||
login: () => setIsAuthed(true),
|
||||
logout: () => setIsAuthed(false),
|
||||
}),
|
||||
[isAuthed]
|
||||
);
|
||||
|
||||
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
|
||||
}
|
||||
|
||||
export function useAuth(): AuthContextValue {
|
||||
const ctx = useContext(AuthContext);
|
||||
if (!ctx) throw new Error("useAuth must be used within AuthProvider");
|
||||
return ctx;
|
||||
}
|
||||
22
src/theme/colors.ts
Normal file
22
src/theme/colors.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
export const Colors = {
|
||||
// base
|
||||
bg: "#0B1220",
|
||||
surface: "#111827",
|
||||
card: "#0F172A",
|
||||
|
||||
// text
|
||||
text: "#FFFFFF",
|
||||
mutedText: "#9CA3AF",
|
||||
placeholder: "#6B7280",
|
||||
|
||||
// brand
|
||||
primary: "#4F46E5",
|
||||
primaryPressed: "#4338CA",
|
||||
|
||||
// status
|
||||
danger: "#EF4444",
|
||||
|
||||
// lines
|
||||
border: "#22304A",
|
||||
inputBg: "#0B1220",
|
||||
} as const;
|
||||
6
src/theme/radius.ts
Normal file
6
src/theme/radius.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export const Radius = {
|
||||
sm: 10,
|
||||
md: 12,
|
||||
lg: 16,
|
||||
xl: 20,
|
||||
} as const;
|
||||
8
src/theme/spacing.ts
Normal file
8
src/theme/spacing.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export const Spacing = {
|
||||
xs: 4,
|
||||
sm: 8,
|
||||
md: 12,
|
||||
lg: 16,
|
||||
xl: 20,
|
||||
"2xl": 24,
|
||||
} as const;
|
||||
12
src/theme/theme.ts
Normal file
12
src/theme/theme.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Colors } from "./colors";
|
||||
import { Radius } from "./radius";
|
||||
import { Spacing } from "./spacing";
|
||||
import { FontSize, FontWeight } from "./typography";
|
||||
|
||||
export const Theme = {
|
||||
Colors,
|
||||
Spacing,
|
||||
Radius,
|
||||
FontSize,
|
||||
FontWeight,
|
||||
} as const;
|
||||
14
src/theme/typography.ts
Normal file
14
src/theme/typography.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export const FontSize = {
|
||||
sm: 13,
|
||||
md: 15,
|
||||
lg: 18,
|
||||
xl: 22,
|
||||
xxl: 26,
|
||||
} as const;
|
||||
|
||||
export const FontWeight = {
|
||||
regular: "400",
|
||||
medium: "500",
|
||||
semibold: "600",
|
||||
bold: "700",
|
||||
} as const;
|
||||
Reference in New Issue
Block a user