pull/2/head
Anthony RICHARD 5 months ago
parent e75f292a02
commit 69d00a5135

753
.gitignore vendored

@ -10,5 +10,756 @@ npm-debug.*
*.orig.*
web-build/
# macOS
# Created by https://www.toptal.com/developers/gitignore/api/rider,visualstudio,reactnative,macos
# Edit at https://www.toptal.com/developers/gitignore?templates=rider,visualstudio,reactnative,macos
### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### macOS Patch ###
# iCloud generated files
*.icloud
### ReactNative ###
# React Native Stack Base
.expo
__generated__
### ReactNative.Node Stack ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
### ReactNative.macOS Stack ###
# General
# Icon must end with two \r
# Thumbnails
# Files that might appear in the root of a volume
# Directories potentially created on remote AFP share
### ReactNative.Android Stack ###
# Gradle files
.gradle/
build/
# Local configuration file (sdk path, etc)
local.properties
# Log/OS Files
# Android Studio generated files and folders
captures/
.externalNativeBuild/
.cxx/
*.apk
output.json
# IntelliJ
*.iml
.idea/
misc.xml
deploymentTargetDropDown.xml
render.experimental.xml
# Keystore files
*.jks
*.keystore
# Google Services (e.g. APIs or Firebase)
google-services.json
# Android Profiling
*.hprof
### ReactNative.Xcode Stack ###
## User settings
xcuserdata/
## Xcode 8 and earlier
*.xcscmblueprint
*.xccheckout
### ReactNative.Buck Stack ###
buck-out/
.buckconfig.local
.buckd/
.buckversion
.fakebuckversion
### ReactNative.Gradle Stack ###
.gradle
**/build/
!src/**/build/
# Ignore Gradle GUI config
gradle-app.setting
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar
# Avoid ignore Gradle wrappper properties
!gradle-wrapper.properties
# Cache of project
.gradletasknamecache
# Eclipse Gradle plugin generated files
# Eclipse Core
.project
# JDT-specific (Eclipse Java Development Tools)
.classpath
### ReactNative.Linux Stack ###
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
### Rider ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### VisualStudio ###
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.tlog
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
*.vbp
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
*.dsw
*.dsp
# Visual Studio 6 technical files
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# Visual Studio History (VSHistory) files
.vshistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
# Local History for Visual Studio Code
.history/
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
# JetBrains Rider
*.sln.iml
### VisualStudio Patch ###
# Additional files built by Visual Studio
# End of https://www.toptal.com/developers/gitignore/api/rider,visualstudio,reactnative,macos
idea/

@ -0,0 +1 @@
legacy-peer-deps=true

@ -0,0 +1,45 @@
import { Tabs } from 'expo-router';
import React from 'react';
import { Platform } from 'react-native';
import { HapticTab } from '@/components/HapticTab';
import { IconSymbol } from '@/components/ui/IconSymbol';
import TabBarBackground from '@/components/ui/TabBarBackground';
import { Colors } from '@/constants/Colors';
import { useColorScheme } from '@/hooks/useColorScheme';
export default function TabLayout() {
const colorScheme = useColorScheme();
return (
<Tabs
screenOptions={{
tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint,
headerShown: false,
tabBarButton: HapticTab,
tabBarBackground: TabBarBackground,
tabBarStyle: Platform.select({
ios: {
// Use a transparent background on iOS to show the blur effect
position: 'absolute',
},
default: {},
}),
}}>
<Tabs.Screen
name="index"
options={{
title: 'Home',
tabBarIcon: ({ color }) => <IconSymbol size={28} name="house.fill" color={color} />,
}}
/>
<Tabs.Screen
name="explore"
options={{
title: 'Explore',
tabBarIcon: ({ color }) => <IconSymbol size={28} name="paperplane.fill" color={color} />,
}}
/>
</Tabs>
);
}

@ -1,4 +1,3 @@
import Ionicons from '@expo/vector-icons/Ionicons';
import { StyleSheet, Image, Platform } from 'react-native';
import { Collapsible } from '@/components/Collapsible';
@ -6,12 +5,20 @@ import { ExternalLink } from '@/components/ExternalLink';
import ParallaxScrollView from '@/components/ParallaxScrollView';
import { ThemedText } from '@/components/ThemedText';
import { ThemedView } from '@/components/ThemedView';
import { IconSymbol } from '@/components/ui/IconSymbol';
export default function TabTwoScreen() {
return (
<ParallaxScrollView
headerBackgroundColor={{ light: '#D0D0D0', dark: '#353636' }}
headerImage={<Ionicons size={310} name="code-slash" style={styles.headerImage} />}>
headerImage={
<IconSymbol
size={310}
color="#808080"
name="chevron.left.forwardslash.chevron.right"
style={styles.headerImage}
/>
}>
<ThemedView style={styles.titleContainer}>
<ThemedText type="title">Explore</ThemedText>
</ThemedView>
@ -72,8 +79,8 @@ export default function TabTwoScreen() {
<ThemedText>
This template includes an example of an animated component. The{' '}
<ThemedText type="defaultSemiBold">components/HelloWave.tsx</ThemedText> component uses
the powerful <ThemedText type="defaultSemiBold">react-native-reanimated</ThemedText> library
to create a waving hand animation.
the powerful <ThemedText type="defaultSemiBold">react-native-reanimated</ThemedText>{' '}
library to create a waving hand animation.
</ThemedText>
{Platform.select({
ios: (

@ -25,7 +25,11 @@ export default function HomeScreen() {
Edit <ThemedText type="defaultSemiBold">app/(tabs)/index.tsx</ThemedText> to see changes.
Press{' '}
<ThemedText type="defaultSemiBold">
{Platform.select({ ios: 'cmd + d', android: 'cmd + m' })}
{Platform.select({
ios: 'cmd + d',
android: 'cmd + m',
web: 'F12'
})}
</ThemedText>{' '}
to open developer tools.
</ThemedText>

@ -0,0 +1,39 @@
import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native';
import { useFonts } from 'expo-font';
import { Stack } from 'expo-router';
import * as SplashScreen from 'expo-splash-screen';
import { StatusBar } from 'expo-status-bar';
import { useEffect } from 'react';
import 'react-native-reanimated';
import { useColorScheme } from '@/hooks/useColorScheme';
// Prevent the splash screen from auto-hiding before asset loading is complete.
SplashScreen.preventAutoHideAsync();
export default function RootLayout() {
const colorScheme = useColorScheme();
const [loaded] = useFonts({
SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),
});
useEffect(() => {
if (loaded) {
SplashScreen.hideAsync();
}
}, [loaded]);
if (!loaded) {
return null;
}
return (
<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
<Stack>
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
<Stack.Screen name="+not-found" />
</Stack>
<StatusBar style="auto" />
</ThemeProvider>
);
}

@ -1,10 +1,11 @@
import Ionicons from '@expo/vector-icons/Ionicons';
import { PropsWithChildren, useState } from 'react';
import { StyleSheet, TouchableOpacity, useColorScheme } from 'react-native';
import { StyleSheet, TouchableOpacity } from 'react-native';
import { ThemedText } from '@/components/ThemedText';
import { ThemedView } from '@/components/ThemedView';
import { IconSymbol } from '@/components/ui/IconSymbol';
import { Colors } from '@/constants/Colors';
import { useColorScheme } from '@/hooks/useColorScheme';
export function Collapsible({ children, title }: PropsWithChildren & { title: string }) {
const [isOpen, setIsOpen] = useState(false);
@ -16,11 +17,14 @@ export function Collapsible({ children, title }: PropsWithChildren & { title: st
style={styles.heading}
onPress={() => setIsOpen((value) => !value)}
activeOpacity={0.8}>
<Ionicons
name={isOpen ? 'chevron-down' : 'chevron-forward-outline'}
<IconSymbol
name="chevron.right"
size={18}
weight="medium"
color={theme === 'light' ? Colors.light.icon : Colors.dark.icon}
style={{ transform: [{ rotate: isOpen ? '90deg' : '0deg' }] }}
/>
<ThemedText type="defaultSemiBold">{title}</ThemedText>
</TouchableOpacity>
{isOpen && <ThemedView style={styles.content}>{children}</ThemedView>}

@ -0,0 +1,18 @@
import { BottomTabBarButtonProps } from '@react-navigation/bottom-tabs';
import { PlatformPressable } from '@react-navigation/elements';
import * as Haptics from 'expo-haptics';
export function HapticTab(props: BottomTabBarButtonProps) {
return (
<PlatformPressable
{...props}
onPressIn={(ev) => {
if (process.env.EXPO_OS === 'ios') {
// Add a soft haptic feedback when pressing down on the tabs.
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
}
props.onPressIn?.(ev);
}}
/>
);
}

@ -1,3 +1,4 @@
import { useEffect } from 'react';
import { StyleSheet } from 'react-native';
import Animated, {
useSharedValue,
@ -12,10 +13,12 @@ import { ThemedText } from '@/components/ThemedText';
export function HelloWave() {
const rotationAnimation = useSharedValue(0);
rotationAnimation.value = withRepeat(
withSequence(withTiming(25, { duration: 150 }), withTiming(0, { duration: 150 })),
4 // Run the animation 4 times
);
useEffect(() => {
rotationAnimation.value = withRepeat(
withSequence(withTiming(25, { duration: 150 }), withTiming(0, { duration: 150 })),
4 // Run the animation 4 times
);
}, []);
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ rotate: `${rotationAnimation.value}deg` }],

@ -1,5 +1,5 @@
import type { PropsWithChildren, ReactElement } from 'react';
import { StyleSheet, useColorScheme } from 'react-native';
import { StyleSheet } from 'react-native';
import Animated, {
interpolate,
useAnimatedRef,
@ -8,6 +8,8 @@ import Animated, {
} from 'react-native-reanimated';
import { ThemedView } from '@/components/ThemedView';
import { useBottomTabOverflow } from '@/components/ui/TabBarBackground';
import { useColorScheme } from '@/hooks/useColorScheme';
const HEADER_HEIGHT = 250;
@ -24,7 +26,7 @@ export default function ParallaxScrollView({
const colorScheme = useColorScheme() ?? 'light';
const scrollRef = useAnimatedRef<Animated.ScrollView>();
const scrollOffset = useScrollViewOffset(scrollRef);
const bottom = useBottomTabOverflow();
const headerAnimatedStyle = useAnimatedStyle(() => {
return {
transform: [
@ -44,7 +46,11 @@ export default function ParallaxScrollView({
return (
<ThemedView style={styles.container}>
<Animated.ScrollView ref={scrollRef} scrollEventThrottle={16}>
<Animated.ScrollView
ref={scrollRef}
scrollEventThrottle={16}
scrollIndicatorInsets={{ bottom }}
contentContainerStyle={{ paddingBottom: bottom }}>
<Animated.View
style={[
styles.header,
@ -64,7 +70,7 @@ const styles = StyleSheet.create({
flex: 1,
},
header: {
height: 250,
height: HEADER_HEIGHT,
overflow: 'hidden',
},
content: {

@ -0,0 +1,32 @@
import { SymbolView, SymbolViewProps, SymbolWeight } from 'expo-symbols';
import { StyleProp, ViewStyle } from 'react-native';
export function IconSymbol({
name,
size = 24,
color,
style,
weight = 'regular',
}: {
name: SymbolViewProps['name'];
size?: number;
color: string;
style?: StyleProp<ViewStyle>;
weight?: SymbolWeight;
}) {
return (
<SymbolView
weight={weight}
tintColor={color}
resizeMode="scaleAspectFit"
name={name}
style={[
{
width: size,
height: size,
},
style,
]}
/>
);
}

@ -0,0 +1,43 @@
// This file is a fallback for using MaterialIcons on Android and web.
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
import { SymbolWeight } from 'expo-symbols';
import React from 'react';
import { OpaqueColorValue, StyleProp, ViewStyle } from 'react-native';
// Add your SFSymbol to MaterialIcons mappings here.
const MAPPING = {
// See MaterialIcons here: https://icons.expo.fyi
// See SF Symbols in the SF Symbols app on Mac.
'house.fill': 'home',
'paperplane.fill': 'send',
'chevron.left.forwardslash.chevron.right': 'code',
'chevron.right': 'chevron-right',
} as Partial<
Record<
import('expo-symbols').SymbolViewProps['name'],
React.ComponentProps<typeof MaterialIcons>['name']
>
>;
export type IconSymbolName = keyof typeof MAPPING;
/**
* An icon component that uses native SFSymbols on iOS, and MaterialIcons on Android and web. This ensures a consistent look across platforms, and optimal resource usage.
*
* Icon `name`s are based on SFSymbols and require manual mapping to MaterialIcons.
*/
export function IconSymbol({
name,
size = 24,
color,
style,
}: {
name: IconSymbolName;
size?: number;
color: string | OpaqueColorValue;
style?: StyleProp<ViewStyle>;
weight?: SymbolWeight;
}) {
return <MaterialIcons color={color} size={size} name={MAPPING[name]} style={style} />;
}

@ -0,0 +1,22 @@
import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs';
import { BlurView } from 'expo-blur';
import { StyleSheet } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
export default function BlurTabBarBackground() {
return (
<BlurView
// System chrome material automatically adapts to the system's theme
// and matches the native tab bar appearance on iOS.
tint="systemChromeMaterial"
intensity={100}
style={StyleSheet.absoluteFill}
/>
);
}
export function useBottomTabOverflow() {
const tabHeight = useBottomTabBarHeight();
const { bottom } = useSafeAreaInsets();
return tabHeight - bottom;
}

@ -0,0 +1,6 @@
// This is a shim for web and Android where the tab bar is generally opaque.
export default undefined;
export function useBottomTabOverflow() {
return 0;
}

@ -0,0 +1,21 @@
import { useEffect, useState } from 'react';
import { useColorScheme as useRNColorScheme } from 'react-native';
/**
* To support static rendering, this value needs to be re-calculated on the client side for web
*/
export function useColorScheme() {
const [hasHydrated, setHasHydrated] = useState(false);
useEffect(() => {
setHasHydrated(true);
}, []);
const colorScheme = useRNColorScheme();
if (hasHydrated) {
return colorScheme;
}
return 'light';
}

@ -3,9 +3,8 @@
* https://docs.expo.dev/guides/color-schemes/
*/
import { useColorScheme } from 'react-native';
import { Colors } from '@/constants/Colors';
import { useColorScheme } from '@/hooks/useColorScheme';
export function useThemeColor(
props: { light?: string; dark?: string },

@ -0,0 +1,84 @@
#!/usr/bin/env node
/**
* This script is used to reset the project to a blank state.
* It moves the /app, /components, /hooks, /scripts, and /constants directories to /app-example and creates a new /app directory with an index.tsx and _layout.tsx file.
* You can remove the `reset-project` script from package.json and safely delete this file after running it.
*/
const fs = require("fs");
const path = require("path");
const root = process.cwd();
const oldDirs = ["app", "components", "hooks", "constants", "scripts"];
const newDir = "app-example";
const newAppDir = "app";
const newDirPath = path.join(root, newDir);
const indexContent = `import { Text, View } from "react-native";
export default function Index() {
return (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
}}
>
<Text>Edit app/index.tsx to edit this screen.</Text>
</View>
);
}
`;
const layoutContent = `import { Stack } from "expo-router";
export default function RootLayout() {
return <Stack />;
}
`;
const moveDirectories = async () => {
try {
// Create the app-example directory
await fs.promises.mkdir(newDirPath, { recursive: true });
console.log(`📁 /${newDir} directory created.`);
// Move old directories to new app-example directory
for (const dir of oldDirs) {
const oldDirPath = path.join(root, dir);
const newDirPath = path.join(root, newDir, dir);
if (fs.existsSync(oldDirPath)) {
await fs.promises.rename(oldDirPath, newDirPath);
console.log(`➡️ /${dir} moved to /${newDir}/${dir}.`);
} else {
console.log(`➡️ /${dir} does not exist, skipping.`);
}
}
// Create new /app directory
const newAppDirPath = path.join(root, newAppDir);
await fs.promises.mkdir(newAppDirPath, { recursive: true });
console.log("\n📁 New /app directory created.");
// Create index.tsx
const indexPath = path.join(newAppDirPath, "index.tsx");
await fs.promises.writeFile(indexPath, indexContent);
console.log("📄 app/index.tsx created.");
// Create _layout.tsx
const layoutPath = path.join(newAppDirPath, "_layout.tsx");
await fs.promises.writeFile(layoutPath, layoutContent);
console.log("📄 app/_layout.tsx created.");
console.log("\n✅ Project reset complete. Next steps:");
console.log(
"1. Run `npx expo start` to start a development server.\n2. Edit app/index.tsx to edit the main screen.\n3. Delete the /app-example directory when you're done referencing it."
);
} catch (error) {
console.error(`Error during script execution: ${error}`);
}
};
moveDirectories();

@ -1,17 +1,13 @@
{
"expo": {
"name": "Optifit-App",
"slug": "Optifit-App",
"name": "Optifit",
"slug": "Optifit",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/images/icon.png",
"scheme": "myapp",
"userInterfaceStyle": "automatic",
"splash": {
"image": "./assets/images/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"newArchEnabled": true,
"ios": {
"supportsTablet": true
},
@ -27,7 +23,16 @@
"favicon": "./assets/images/favicon.png"
},
"plugins": [
"expo-router"
"expo-router",
[
"expo-splash-screen",
{
"image": "./assets/images/splash-icon.png",
"imageWidth": 200,
"resizeMode": "contain",
"backgroundColor": "#ffffff"
}
]
],
"experiments": {
"typedRoutes": true

@ -1,37 +0,0 @@
import { Tabs } from 'expo-router';
import React from 'react';
import { TabBarIcon } from '@/components/navigation/TabBarIcon';
import { Colors } from '@/constants/Colors';
import { useColorScheme } from '@/hooks/useColorScheme';
export default function TabLayout() {
const colorScheme = useColorScheme();
return (
<Tabs
screenOptions={{
tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint,
headerShown: false,
}}>
<Tabs.Screen
name="index"
options={{
title: 'Home',
tabBarIcon: ({ color, focused }) => (
<TabBarIcon name={focused ? 'home' : 'home-outline'} color={color} />
),
}}
/>
<Tabs.Screen
name="explore"
options={{
title: 'Explore',
tabBarIcon: ({ color, focused }) => (
<TabBarIcon name={focused ? 'code-slash' : 'code-slash-outline'} color={color} />
),
}}
/>
</Tabs>
);
}

@ -1,39 +0,0 @@
import { ScrollViewStyleReset } from 'expo-router/html';
import { type PropsWithChildren } from 'react';
/**
* 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 }: PropsWithChildren) {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
{/*
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;
}
}`;

@ -1,37 +1,12 @@
import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native';
import { useFonts } from 'expo-font';
import { Stack } from 'expo-router';
import * as SplashScreen from 'expo-splash-screen';
import { useEffect } from 'react';
import 'react-native-reanimated';
import { Stack } from "expo-router";
import { useColorScheme } from '@/hooks/useColorScheme';
// Prevent the splash screen from auto-hiding before asset loading is complete.
SplashScreen.preventAutoHideAsync();
import "../global.css";
import { GluestackUIProvider } from "./src/components/ui/gluestack-ui-provider";
export default function RootLayout() {
const colorScheme = useColorScheme();
const [loaded] = useFonts({
SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),
});
useEffect(() => {
if (loaded) {
SplashScreen.hideAsync();
}
}, [loaded]);
if (!loaded) {
return null;
}
return (
<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
<Stack>
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
<Stack.Screen name="+not-found" />
</Stack>
</ThemeProvider>
<GluestackUIProvider>
<Stack />
</GluestackUIProvider>
);
}

@ -0,0 +1,9 @@
import { Text, View } from "react-native";
export default function Index() {
return (
<View>
<Text>Edit app/index.tsx to edit this screen.</Text>
</View>
);
}

@ -0,0 +1,434 @@
'use client';
import React from 'react';
import { createButton } from '@gluestack-ui/button';
import { tva } from '@gluestack-ui/nativewind-utils/tva';
import {
withStyleContext,
useStyleContext,
} from '@gluestack-ui/nativewind-utils/withStyleContext';
import { cssInterop } from 'nativewind';
import { ActivityIndicator, Pressable, Text, View } from 'react-native';
import type { VariantProps } from '@gluestack-ui/nativewind-utils';
import { PrimitiveIcon, UIIcon } from '@gluestack-ui/icon';
const SCOPE = 'BUTTON';
const Root = withStyleContext(Pressable, SCOPE);
const UIButton = createButton({
Root: Root,
Text,
Group: View,
Spinner: ActivityIndicator,
Icon: UIIcon,
});
cssInterop(PrimitiveIcon, {
className: {
target: 'style',
nativeStyleToProp: {
height: true,
width: true,
fill: true,
color: 'classNameColor',
stroke: true,
},
},
});
const buttonStyle = tva({
base: 'group/button rounded bg-primary-500 flex-row items-center justify-center data-[focus-visible=true]:web:outline-none data-[focus-visible=true]:web:ring-2 data-[disabled=true]:opacity-40 gap-2',
variants: {
action: {
primary:
'bg-primary-500 data-[hover=true]:bg-primary-600 data-[active=true]:bg-primary-700 border-primary-300 data-[hover=true]:border-primary-400 data-[active=true]:border-primary-500 data-[focus-visible=true]:web:ring-indicator-info',
secondary:
'bg-secondary-500 border-secondary-300 data-[hover=true]:bg-secondary-600 data-[hover=true]:border-secondary-400 data-[active=true]:bg-secondary-700 data-[active=true]:border-secondary-700 data-[focus-visible=true]:web:ring-indicator-info',
positive:
'bg-success-500 border-success-300 data-[hover=true]:bg-success-600 data-[hover=true]:border-success-400 data-[active=true]:bg-success-700 data-[active=true]:border-success-500 data-[focus-visible=true]:web:ring-indicator-info',
negative:
'bg-error-500 border-error-300 data-[hover=true]:bg-error-600 data-[hover=true]:border-error-400 data-[active=true]:bg-error-700 data-[active=true]:border-error-500 data-[focus-visible=true]:web:ring-indicator-info',
default:
'bg-transparent data-[hover=true]:bg-background-50 data-[active=true]:bg-transparent',
},
variant: {
link: 'px-0',
outline:
'bg-transparent border data-[hover=true]:bg-background-50 data-[active=true]:bg-transparent',
solid: '',
},
size: {
xs: 'px-3.5 h-8',
sm: 'px-4 h-9',
md: 'px-5 h-10',
lg: 'px-6 h-11',
xl: 'px-7 h-12',
},
},
compoundVariants: [
{
action: 'primary',
variant: 'link',
class:
'px-0 bg-transparent data-[hover=true]:bg-transparent data-[active=true]:bg-transparent',
},
{
action: 'secondary',
variant: 'link',
class:
'px-0 bg-transparent data-[hover=true]:bg-transparent data-[active=true]:bg-transparent',
},
{
action: 'positive',
variant: 'link',
class:
'px-0 bg-transparent data-[hover=true]:bg-transparent data-[active=true]:bg-transparent',
},
{
action: 'negative',
variant: 'link',
class:
'px-0 bg-transparent data-[hover=true]:bg-transparent data-[active=true]:bg-transparent',
},
{
action: 'primary',
variant: 'outline',
class:
'bg-transparent data-[hover=true]:bg-background-50 data-[active=true]:bg-transparent',
},
{
action: 'secondary',
variant: 'outline',
class:
'bg-transparent data-[hover=true]:bg-background-50 data-[active=true]:bg-transparent',
},
{
action: 'positive',
variant: 'outline',
class:
'bg-transparent data-[hover=true]:bg-background-50 data-[active=true]:bg-transparent',
},
{
action: 'negative',
variant: 'outline',
class:
'bg-transparent data-[hover=true]:bg-background-50 data-[active=true]:bg-transparent',
},
],
});
const buttonTextStyle = tva({
base: 'text-typography-0 font-semibold web:select-none',
parentVariants: {
action: {
primary:
'text-primary-600 data-[hover=true]:text-primary-600 data-[active=true]:text-primary-700',
secondary:
'text-typography-500 data-[hover=true]:text-typography-600 data-[active=true]:text-typography-700',
positive:
'text-success-600 data-[hover=true]:text-success-600 data-[active=true]:text-success-700',
negative:
'text-error-600 data-[hover=true]:text-error-600 data-[active=true]:text-error-700',
},
variant: {
link: 'data-[hover=true]:underline data-[active=true]:underline',
outline: '',
solid:
'text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0',
},
size: {
xs: 'text-xs',
sm: 'text-sm',
md: 'text-base',
lg: 'text-lg',
xl: 'text-xl',
},
},
parentCompoundVariants: [
{
variant: 'solid',
action: 'primary',
class:
'text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0',
},
{
variant: 'solid',
action: 'secondary',
class:
'text-typography-800 data-[hover=true]:text-typography-800 data-[active=true]:text-typography-800',
},
{
variant: 'solid',
action: 'positive',
class:
'text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0',
},
{
variant: 'solid',
action: 'negative',
class:
'text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0',
},
{
variant: 'outline',
action: 'primary',
class:
'text-primary-500 data-[hover=true]:text-primary-500 data-[active=true]:text-primary-500',
},
{
variant: 'outline',
action: 'secondary',
class:
'text-typography-500 data-[hover=true]:text-primary-600 data-[active=true]:text-typography-700',
},
{
variant: 'outline',
action: 'positive',
class:
'text-primary-500 data-[hover=true]:text-primary-500 data-[active=true]:text-primary-500',
},
{
variant: 'outline',
action: 'negative',
class:
'text-primary-500 data-[hover=true]:text-primary-500 data-[active=true]:text-primary-500',
},
],
});
const buttonIconStyle = tva({
base: 'fill-none',
parentVariants: {
variant: {
link: 'data-[hover=true]:underline data-[active=true]:underline',
outline: '',
solid:
'text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0',
},
size: {
xs: 'h-3.5 w-3.5',
sm: 'h-4 w-4',
md: 'h-[18px] w-[18px]',
lg: 'h-[18px] w-[18px]',
xl: 'h-5 w-5',
},
action: {
primary:
'text-primary-600 data-[hover=true]:text-primary-600 data-[active=true]:text-primary-700',
secondary:
'text-typography-500 data-[hover=true]:text-typography-600 data-[active=true]:text-typography-700',
positive:
'text-success-600 data-[hover=true]:text-success-600 data-[active=true]:text-success-700',
negative:
'text-error-600 data-[hover=true]:text-error-600 data-[active=true]:text-error-700',
},
},
parentCompoundVariants: [
{
variant: 'solid',
action: 'primary',
class:
'text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0',
},
{
variant: 'solid',
action: 'secondary',
class:
'text-typography-800 data-[hover=true]:text-typography-800 data-[active=true]:text-typography-800',
},
{
variant: 'solid',
action: 'positive',
class:
'text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0',
},
{
variant: 'solid',
action: 'negative',
class:
'text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0',
},
],
});
const buttonGroupStyle = tva({
base: '',
variants: {
space: {
'xs': 'gap-1',
'sm': 'gap-2',
'md': 'gap-3',
'lg': 'gap-4',
'xl': 'gap-5',
'2xl': 'gap-6',
'3xl': 'gap-7',
'4xl': 'gap-8',
},
isAttached: {
true: 'gap-0',
},
flexDirection: {
'row': 'flex-row',
'column': 'flex-col',
'row-reverse': 'flex-row-reverse',
'column-reverse': 'flex-col-reverse',
},
},
});
type IButtonProps = Omit<
React.ComponentPropsWithoutRef<typeof UIButton>,
'context'
> &
VariantProps<typeof buttonStyle> & { className?: string };
const Button = React.forwardRef<
React.ElementRef<typeof UIButton>,
IButtonProps
>(
(
{ className, variant = 'solid', size = 'md', action = 'primary', ...props },
ref
) => {
return (
<UIButton
ref={ref}
{...props}
className={buttonStyle({ variant, size, action, class: className })}
context={{ variant, size, action }}
/>
);
}
);
type IButtonTextProps = React.ComponentPropsWithoutRef<typeof UIButton.Text> &
VariantProps<typeof buttonTextStyle> & { className?: string };
const ButtonText = React.forwardRef<
React.ElementRef<typeof UIButton.Text>,
IButtonTextProps
>(({ className, variant, size, action, ...props }, ref) => {
const {
variant: parentVariant,
size: parentSize,
action: parentAction,
} = useStyleContext(SCOPE);
return (
<UIButton.Text
ref={ref}
{...props}
className={buttonTextStyle({
parentVariants: {
variant: parentVariant,
size: parentSize,
action: parentAction,
},
variant,
size,
action,
class: className,
})}
/>
);
});
const ButtonSpinner = UIButton.Spinner;
type IButtonIcon = React.ComponentPropsWithoutRef<typeof UIButton.Icon> &
VariantProps<typeof buttonIconStyle> & {
className?: string | undefined;
as?: React.ElementType;
height?: number;
width?: number;
};
const ButtonIcon = React.forwardRef<
React.ElementRef<typeof UIButton.Icon>,
IButtonIcon
>(({ className, size, ...props }, ref) => {
const {
variant: parentVariant,
size: parentSize,
action: parentAction,
} = useStyleContext(SCOPE);
if (typeof size === 'number') {
return (
<UIButton.Icon
ref={ref}
{...props}
className={buttonIconStyle({ class: className })}
size={size}
/>
);
} else if (
(props.height !== undefined || props.width !== undefined) &&
size === undefined
) {
return (
<UIButton.Icon
ref={ref}
{...props}
className={buttonIconStyle({ class: className })}
/>
);
}
return (
<UIButton.Icon
{...props}
className={buttonIconStyle({
parentVariants: {
size: parentSize,
variant: parentVariant,
action: parentAction,
},
size,
class: className,
})}
ref={ref}
/>
);
});
type IButtonGroupProps = React.ComponentPropsWithoutRef<typeof UIButton.Group> &
VariantProps<typeof buttonGroupStyle>;
const ButtonGroup = React.forwardRef<
React.ElementRef<typeof UIButton.Group>,
IButtonGroupProps
>(
(
{
className,
space = 'md',
isAttached = false,
flexDirection = 'column',
...props
},
ref
) => {
return (
<UIButton.Group
className={buttonGroupStyle({
class: className,
space,
isAttached,
flexDirection,
})}
{...props}
ref={ref}
/>
);
}
);
Button.displayName = 'Button';
ButtonText.displayName = 'ButtonText';
ButtonSpinner.displayName = 'ButtonSpinner';
ButtonIcon.displayName = 'ButtonIcon';
ButtonGroup.displayName = 'ButtonGroup';
export { Button, ButtonText, ButtonSpinner, ButtonIcon, ButtonGroup };

@ -0,0 +1,309 @@
"use client";
import { vars } from "nativewind";
export const config = {
light: vars({
"--color-primary-0": "179 179 179",
"--color-primary-50": "153 153 153",
"--color-primary-100": "128 128 128",
"--color-primary-200": "115 115 115",
"--color-primary-300": "102 102 102",
"--color-primary-400": "82 82 82",
"--color-primary-500": "51 51 51",
"--color-primary-600": "41 41 41",
"--color-primary-700": "31 31 31",
"--color-primary-800": "13 13 13",
"--color-primary-900": "10 10 10",
"--color-primary-950": "8 8 8",
/* Secondary */
"--color-secondary-0": "253 253 253",
"--color-secondary-50": "251 251 251",
"--color-secondary-100": "246 246 246",
"--color-secondary-200": "242 242 242",
"--color-secondary-300": "237 237 237",
"--color-secondary-400": "230 230 231",
"--color-secondary-500": "217 217 219",
"--color-secondary-600": "198 199 199",
"--color-secondary-700": "189 189 189",
"--color-secondary-800": "177 177 177",
"--color-secondary-900": "165 164 164",
"--color-secondary-950": "157 157 157",
/* Tertiary */
"--color-tertiary-0": "255 250 245",
"--color-tertiary-50": "255 242 229",
"--color-tertiary-100": "255 233 213",
"--color-tertiary-200": "254 209 170",
"--color-tertiary-300": "253 180 116",
"--color-tertiary-400": "251 157 75",
"--color-tertiary-500": "231 129 40",
"--color-tertiary-600": "215 117 31",
"--color-tertiary-700": "180 98 26",
"--color-tertiary-800": "130 73 23",
"--color-tertiary-900": "108 61 19",
"--color-tertiary-950": "84 49 18",
/* Error */
"--color-error-0": "254 233 233",
"--color-error-50": "254 226 226",
"--color-error-100": "254 202 202",
"--color-error-200": "252 165 165",
"--color-error-300": "248 113 113",
"--color-error-400": "239 68 68",
"--color-error-500": "230 53 53",
"--color-error-600": "220 38 38",
"--color-error-700": "185 28 28",
"--color-error-800": "153 27 27",
"--color-error-900": "127 29 29",
"--color-error-950": "83 19 19",
/* Success */
"--color-success-0": "228 255 244",
"--color-success-50": "202 255 232",
"--color-success-100": "162 241 192",
"--color-success-200": "132 211 162",
"--color-success-300": "102 181 132",
"--color-success-400": "72 151 102",
"--color-success-500": "52 131 82",
"--color-success-600": "42 121 72",
"--color-success-700": "32 111 62",
"--color-success-800": "22 101 52",
"--color-success-900": "20 83 45",
"--color-success-950": "27 50 36",
/* Warning */
"--color-warning-0": "255 249 245",
"--color-warning-50": "255 244 236",
"--color-warning-100": "255 231 213",
"--color-warning-200": "254 205 170",
"--color-warning-300": "253 173 116",
"--color-warning-400": "251 149 75",
"--color-warning-500": "231 120 40",
"--color-warning-600": "215 108 31",
"--color-warning-700": "180 90 26",
"--color-warning-800": "130 68 23",
"--color-warning-900": "108 56 19",
"--color-warning-950": "84 45 18",
/* Info */
"--color-info-0": "236 248 254",
"--color-info-50": "199 235 252",
"--color-info-100": "162 221 250",
"--color-info-200": "124 207 248",
"--color-info-300": "87 194 246",
"--color-info-400": "50 180 244",
"--color-info-500": "13 166 242",
"--color-info-600": "11 141 205",
"--color-info-700": "9 115 168",
"--color-info-800": "7 90 131",
"--color-info-900": "5 64 93",
"--color-info-950": "3 38 56",
/* Typography */
"--color-typography-0": "254 254 255",
"--color-typography-50": "245 245 245",
"--color-typography-100": "229 229 229",
"--color-typography-200": "219 219 220",
"--color-typography-300": "212 212 212",
"--color-typography-400": "163 163 163",
"--color-typography-500": "140 140 140",
"--color-typography-600": "115 115 115",
"--color-typography-700": "82 82 82",
"--color-typography-800": "64 64 64",
"--color-typography-900": "38 38 39",
"--color-typography-950": "23 23 23",
/* Outline */
"--color-outline-0": "253 254 254",
"--color-outline-50": "243 243 243",
"--color-outline-100": "230 230 230",
"--color-outline-200": "221 220 219",
"--color-outline-300": "211 211 211",
"--color-outline-400": "165 163 163",
"--color-outline-500": "140 141 141",
"--color-outline-600": "115 116 116",
"--color-outline-700": "83 82 82",
"--color-outline-800": "65 65 65",
"--color-outline-900": "39 38 36",
"--color-outline-950": "26 23 23",
/* Background */
"--color-background-0": "255 255 255",
"--color-background-50": "246 246 246",
"--color-background-100": "242 241 241",
"--color-background-200": "220 219 219",
"--color-background-300": "213 212 212",
"--color-background-400": "162 163 163",
"--color-background-500": "142 142 142",
"--color-background-600": "116 116 116",
"--color-background-700": "83 82 82",
"--color-background-800": "65 64 64",
"--color-background-900": "39 38 37",
"--color-background-950": "18 18 18",
/* Background Special */
"--color-background-error": "254 241 241",
"--color-background-warning": "255 243 234",
"--color-background-success": "237 252 242",
"--color-background-muted": "247 248 247",
"--color-background-info": "235 248 254",
/* Focus Ring Indicator */
"--color-indicator-primary": "55 55 55",
"--color-indicator-info": "83 153 236",
"--color-indicator-error": "185 28 28",
}),
dark: vars({
"--color-primary-0": "166 166 166",
"--color-primary-50": "175 175 175",
"--color-primary-100": "186 186 186",
"--color-primary-200": "197 197 197",
"--color-primary-300": "212 212 212",
"--color-primary-400": "221 221 221",
"--color-primary-500": "230 230 230",
"--color-primary-600": "240 240 240",
"--color-primary-700": "250 250 250",
"--color-primary-800": "253 253 253",
"--color-primary-900": "254 249 249",
"--color-primary-950": "253 252 252",
/* Secondary */
"--color-secondary-0": "20 20 20",
"--color-secondary-50": "23 23 23",
"--color-secondary-100": "31 31 31",
"--color-secondary-200": "39 39 39",
"--color-secondary-300": "44 44 44",
"--color-secondary-400": "56 57 57",
"--color-secondary-500": "63 64 64",
"--color-secondary-600": "86 86 86",
"--color-secondary-700": "110 110 110",
"--color-secondary-800": "135 135 135",
"--color-secondary-900": "150 150 150",
"--color-secondary-950": "164 164 164",
/* Tertiary */
"--color-tertiary-0": "84 49 18",
"--color-tertiary-50": "108 61 19",
"--color-tertiary-100": "130 73 23",
"--color-tertiary-200": "180 98 26",
"--color-tertiary-300": "215 117 31",
"--color-tertiary-400": "231 129 40",
"--color-tertiary-500": "251 157 75",
"--color-tertiary-600": "253 180 116",
"--color-tertiary-700": "254 209 170",
"--color-tertiary-800": "255 233 213",
"--color-tertiary-900": "255 242 229",
"--color-tertiary-950": "255 250 245",
/* Error */
"--color-error-0": "83 19 19",
"--color-error-50": "127 29 29",
"--color-error-100": "153 27 27",
"--color-error-200": "185 28 28",
"--color-error-300": "220 38 38",
"--color-error-400": "230 53 53",
"--color-error-500": "239 68 68",
"--color-error-600": "249 97 96",
"--color-error-700": "229 91 90",
"--color-error-800": "254 202 202",
"--color-error-900": "254 226 226",
"--color-error-950": "254 233 233",
/* Success */
"--color-success-0": "27 50 36",
"--color-success-50": "20 83 45",
"--color-success-100": "22 101 52",
"--color-success-200": "32 111 62",
"--color-success-300": "42 121 72",
"--color-success-400": "52 131 82",
"--color-success-500": "72 151 102",
"--color-success-600": "102 181 132",
"--color-success-700": "132 211 162",
"--color-success-800": "162 241 192",
"--color-success-900": "202 255 232",
"--color-success-950": "228 255 244",
/* Warning */
"--color-warning-0": "84 45 18",
"--color-warning-50": "108 56 19",
"--color-warning-100": "130 68 23",
"--color-warning-200": "180 90 26",
"--color-warning-300": "215 108 31",
"--color-warning-400": "231 120 40",
"--color-warning-500": "251 149 75",
"--color-warning-600": "253 173 116",
"--color-warning-700": "254 205 170",
"--color-warning-800": "255 231 213",
"--color-warning-900": "255 244 237",
"--color-warning-950": "255 249 245",
/* Info */
"--color-info-0": "3 38 56",
"--color-info-50": "5 64 93",
"--color-info-100": "7 90 131",
"--color-info-200": "9 115 168",
"--color-info-300": "11 141 205",
"--color-info-400": "13 166 242",
"--color-info-500": "50 180 244",
"--color-info-600": "87 194 246",
"--color-info-700": "124 207 248",
"--color-info-800": "162 221 250",
"--color-info-900": "199 235 252",
"--color-info-950": "236 248 254",
/* Typography */
"--color-typography-0": "23 23 23",
"--color-typography-50": "38 38 39",
"--color-typography-100": "64 64 64",
"--color-typography-200": "82 82 82",
"--color-typography-300": "115 115 115",
"--color-typography-400": "140 140 140",
"--color-typography-500": "163 163 163",
"--color-typography-600": "212 212 212",
"--color-typography-700": "219 219 220",
"--color-typography-800": "229 229 229",
"--color-typography-900": "245 245 245",
"--color-typography-950": "254 254 255",
/* Outline */
"--color-outline-0": "26 23 23",
"--color-outline-50": "39 38 36",
"--color-outline-100": "65 65 65",
"--color-outline-200": "83 82 82",
"--color-outline-300": "115 116 116",
"--color-outline-400": "140 141 141",
"--color-outline-500": "165 163 163",
"--color-outline-600": "211 211 211",
"--color-outline-700": "221 220 219",
"--color-outline-800": "230 230 230",
"--color-outline-900": "243 243 243",
"--color-outline-950": "253 254 254",
/* Background */
"--color-background-0": "18 18 18",
"--color-background-50": "39 38 37",
"--color-background-100": "65 64 64",
"--color-background-200": "83 82 82",
"--color-background-300": "116 116 116",
"--color-background-400": "142 142 142",
"--color-background-500": "162 163 163",
"--color-background-600": "213 212 212",
"--color-background-700": "229 228 228",
"--color-background-800": "242 241 241",
"--color-background-900": "246 246 246",
"--color-background-950": "255 255 255",
/* Background Special */
"--color-background-error": "66 43 43",
"--color-background-warning": "65 47 35",
"--color-background-success": "28 43 33",
"--color-background-muted": "51 51 51",
"--color-background-info": "26 40 46",
/* Focus Ring Indicator */
"--color-indicator-primary": "247 247 247",
"--color-indicator-info": "161 199 245",
"--color-indicator-error": "232 70 69",
}),
};

@ -0,0 +1,48 @@
import React from "react";
import { config } from "./config";
import { ColorSchemeName, useColorScheme, View, ViewProps } from "react-native";
import { OverlayProvider } from "@gluestack-ui/overlay";
import { ToastProvider } from "@gluestack-ui/toast";
import { colorScheme as colorSchemeNW } from "nativewind";
type ModeType = "light" | "dark" | "system";
const getColorSchemeName = (
colorScheme: ColorSchemeName,
mode: ModeType
): "light" | "dark" => {
if (mode === "system") {
return colorScheme ?? "light";
}
return mode;
};
export function GluestackUIProvider({
mode = "light",
...props
}: {
mode?: "light" | "dark" | "system";
children?: React.ReactNode;
style?: ViewProps["style"];
}) {
const colorScheme = useColorScheme();
const colorSchemeName = getColorSchemeName(colorScheme, mode);
colorSchemeNW.set(mode);
return (
<View
style={[
config[colorSchemeName],
// eslint-disable-next-line react-native/no-inline-styles
{ flex: 1, height: "100%", width: "100%" },
props.style,
]}
>
<OverlayProvider>
<ToastProvider>{props.children}</ToastProvider>
</OverlayProvider>
</View>
);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

@ -1,6 +1,9 @@
module.exports = function (api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
presets: [
["babel-preset-expo", { jsxImportSource: "nativewind" }],
"nativewind/babel",
],
};
};

@ -1,9 +0,0 @@
// You can explore the built-in icon families and icons on the web at https://icons.expo.fyi/
import Ionicons from '@expo/vector-icons/Ionicons';
import { type IconProps } from '@expo/vector-icons/build/createIconSet';
import { type ComponentProps } from 'react';
export function TabBarIcon({ style, ...rest }: IconProps<ComponentProps<typeof Ionicons>['name']>) {
return <Ionicons size={28} style={[{ marginBottom: -3 }, style]} {...rest} />;
}

3
expo-env.d.ts vendored

@ -0,0 +1,3 @@
/// <reference types="expo/types" />
// NOTE: This file should not be edited and should be in your git ignore

@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

@ -1,8 +0,0 @@
// NOTE: The default React Native styling doesn't support server rendering.
// Server rendered styles should not change between the first render of the HTML
// and the first render on the client. Typically, web developers will use CSS media queries
// to render different styles on the client and server, these aren't directly supported in React Native
// but can be achieved using a styling library like Nativewind.
export function useColorScheme() {
return 'light';
}

@ -0,0 +1,6 @@
const { getDefaultConfig } = require("expo/metro-config");
const { withNativeWind } = require("nativewind/metro");
const config = getDefaultConfig(__dirname);
module.exports = withNativeWind(config, { input: "./global.css" });

@ -0,0 +1 @@
/// <reference types="nativewind/types" />

18719
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -1,5 +1,5 @@
{
"name": "optifit-app",
"name": "optifit",
"main": "expo-router/entry",
"version": "1.0.0",
"scripts": {
@ -16,34 +16,47 @@
},
"dependencies": {
"@expo/vector-icons": "^14.0.2",
"@react-navigation/native": "^6.0.2",
"expo": "~51.0.28",
"expo-constants": "~16.0.2",
"expo-font": "~12.0.9",
"expo-linking": "~6.3.1",
"expo-router": "~3.5.23",
"expo-splash-screen": "~0.27.5",
"expo-status-bar": "~1.12.1",
"expo-system-ui": "~3.0.7",
"expo-web-browser": "~13.0.3",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-native": "0.74.5",
"react-native-gesture-handler": "~2.16.1",
"react-native-reanimated": "~3.10.1",
"react-native-safe-area-context": "4.10.5",
"react-native-screens": "3.31.1",
"react-native-web": "~0.19.10"
"@gluestack-ui/button": "^1.0.8",
"@gluestack-ui/icon": "^0.1.25",
"@gluestack-ui/nativewind-utils": "^1.0.26",
"@gluestack-ui/overlay": "^0.1.16",
"@gluestack-ui/toast": "^1.0.8",
"@react-navigation/bottom-tabs": "^7.2.0",
"@react-navigation/native": "^7.0.14",
"expo": "~52.0.24",
"expo-blur": "~14.0.1",
"expo-constants": "~17.0.3",
"expo-font": "~13.0.2",
"expo-haptics": "~14.0.0",
"expo-linking": "~7.0.3",
"expo-router": "~4.0.16",
"expo-splash-screen": "~0.29.19",
"expo-status-bar": "~2.0.0",
"expo-symbols": "~0.2.0",
"expo-system-ui": "~4.0.6",
"expo-web-browser": "~14.0.1",
"nativewind": "^4.1.23",
"react": "18.3.1",
"react-dom": "18.3.1",
"react-native": "0.76.5",
"react-native-gesture-handler": "~2.20.2",
"react-native-reanimated": "~3.16.1",
"react-native-safe-area-context": "^4.12.0",
"react-native-screens": "~4.4.0",
"react-native-svg": "^15.11.0",
"react-native-web": "~0.19.13",
"react-native-webview": "13.12.5",
"tailwindcss": "^3.4.17"
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@babel/core": "^7.25.2",
"@types/jest": "^29.5.12",
"@types/react": "~18.2.45",
"@types/react-test-renderer": "^18.0.7",
"@types/react": "~18.3.12",
"@types/react-test-renderer": "^18.3.0",
"jest": "^29.2.1",
"jest-expo": "~51.0.3",
"react-test-renderer": "18.2.0",
"typescript": "~5.3.3"
"jest-expo": "~52.0.2",
"react-test-renderer": "18.3.1",
"typescript": "^5.3.3"
},
"private": true
}

@ -1,73 +0,0 @@
#!/usr/bin/env node
/**
* This script is used to reset the project to a blank state.
* It moves the /app directory to /app-example and creates a new /app directory with an index.tsx and _layout.tsx file.
* You can remove the `reset-project` script from package.json and safely delete this file after running it.
*/
const fs = require('fs');
const path = require('path');
const root = process.cwd();
const oldDirPath = path.join(root, 'app');
const newDirPath = path.join(root, 'app-example');
const newAppDirPath = path.join(root, 'app');
const indexContent = `import { Text, View } from "react-native";
export default function Index() {
return (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
}}
>
<Text>Edit app/index.tsx to edit this screen.</Text>
</View>
);
}
`;
const layoutContent = `import { Stack } from "expo-router";
export default function RootLayout() {
return (
<Stack>
<Stack.Screen name="index" />
</Stack>
);
}
`;
fs.rename(oldDirPath, newDirPath, (error) => {
if (error) {
return console.error(`Error renaming directory: ${error}`);
}
console.log('/app moved to /app-example.');
fs.mkdir(newAppDirPath, { recursive: true }, (error) => {
if (error) {
return console.error(`Error creating new app directory: ${error}`);
}
console.log('New /app directory created.');
const indexPath = path.join(newAppDirPath, 'index.tsx');
fs.writeFile(indexPath, indexContent, (error) => {
if (error) {
return console.error(`Error creating index.tsx: ${error}`);
}
console.log('app/index.tsx created.');
const layoutPath = path.join(newAppDirPath, '_layout.tsx');
fs.writeFile(layoutPath, layoutContent, (error) => {
if (error) {
return console.error(`Error creating _layout.tsx: ${error}`);
}
console.log('app/_layout.tsx created.');
});
});
});
});

@ -0,0 +1,192 @@
import gluestackPlugin from "@gluestack-ui/nativewind-utils/tailwind-plugin";
/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: process.env.DARK_MODE ? process.env.DARK_MODE : "media",
content: ["./app/**/*.{html,js,jsx,ts,tsx}"],
presets: [require("nativewind/preset")],
theme: {
extend: {
colors: {
primary: {
0: "rgb(var(--color-primary-0)/<alpha-value>)",
50: "rgb(var(--color-primary-50)/<alpha-value>)",
100: "rgb(var(--color-primary-100)/<alpha-value>)",
200: "rgb(var(--color-primary-200)/<alpha-value>)",
300: "rgb(var(--color-primary-300)/<alpha-value>)",
400: "rgb(var(--color-primary-400)/<alpha-value>)",
500: "rgb(var(--color-primary-500)/<alpha-value>)",
600: "rgb(var(--color-primary-600)/<alpha-value>)",
700: "rgb(var(--color-primary-700)/<alpha-value>)",
800: "rgb(var(--color-primary-800)/<alpha-value>)",
900: "rgb(var(--color-primary-900)/<alpha-value>)",
950: "rgb(var(--color-primary-950)/<alpha-value>)",
},
secondary: {
0: "rgb(var(--color-secondary-0)/<alpha-value>)",
50: "rgb(var(--color-secondary-50)/<alpha-value>)",
100: "rgb(var(--color-secondary-100)/<alpha-value>)",
200: "rgb(var(--color-secondary-200)/<alpha-value>)",
300: "rgb(var(--color-secondary-300)/<alpha-value>)",
400: "rgb(var(--color-secondary-400)/<alpha-value>)",
500: "rgb(var(--color-secondary-500)/<alpha-value>)",
600: "rgb(var(--color-secondary-600)/<alpha-value>)",
700: "rgb(var(--color-secondary-700)/<alpha-value>)",
800: "rgb(var(--color-secondary-800)/<alpha-value>)",
900: "rgb(var(--color-secondary-900)/<alpha-value>)",
950: "rgb(var(--color-secondary-950)/<alpha-value>)",
},
tertiary: {
50: "rgb(var(--color-tertiary-50)/<alpha-value>)",
100: "rgb(var(--color-tertiary-100)/<alpha-value>)",
200: "rgb(var(--color-tertiary-200)/<alpha-value>)",
300: "rgb(var(--color-tertiary-300)/<alpha-value>)",
400: "rgb(var(--color-tertiary-400)/<alpha-value>)",
500: "rgb(var(--color-tertiary-500)/<alpha-value>)",
600: "rgb(var(--color-tertiary-600)/<alpha-value>)",
700: "rgb(var(--color-tertiary-700)/<alpha-value>)",
800: "rgb(var(--color-tertiary-800)/<alpha-value>)",
900: "rgb(var(--color-tertiary-900)/<alpha-value>)",
950: "rgb(var(--color-tertiary-950)/<alpha-value>)",
},
error: {
0: "rgb(var(--color-error-0)/<alpha-value>)",
50: "rgb(var(--color-error-50)/<alpha-value>)",
100: "rgb(var(--color-error-100)/<alpha-value>)",
200: "rgb(var(--color-error-200)/<alpha-value>)",
300: "rgb(var(--color-error-300)/<alpha-value>)",
400: "rgb(var(--color-error-400)/<alpha-value>)",
500: "rgb(var(--color-error-500)/<alpha-value>)",
600: "rgb(var(--color-error-600)/<alpha-value>)",
700: "rgb(var(--color-error-700)/<alpha-value>)",
800: "rgb(var(--color-error-800)/<alpha-value>)",
900: "rgb(var(--color-error-900)/<alpha-value>)",
950: "rgb(var(--color-error-950)/<alpha-value>)",
},
success: {
0: "rgb(var(--color-success-0)/<alpha-value>)",
50: "rgb(var(--color-success-50)/<alpha-value>)",
100: "rgb(var(--color-success-100)/<alpha-value>)",
200: "rgb(var(--color-success-200)/<alpha-value>)",
300: "rgb(var(--color-success-300)/<alpha-value>)",
400: "rgb(var(--color-success-400)/<alpha-value>)",
500: "rgb(var(--color-success-500)/<alpha-value>)",
600: "rgb(var(--color-success-600)/<alpha-value>)",
700: "rgb(var(--color-success-700)/<alpha-value>)",
800: "rgb(var(--color-success-800)/<alpha-value>)",
900: "rgb(var(--color-success-900)/<alpha-value>)",
950: "rgb(var(--color-success-950)/<alpha-value>)",
},
warning: {
0: "rgb(var(--color-warning-0)/<alpha-value>)",
50: "rgb(var(--color-warning-50)/<alpha-value>)",
100: "rgb(var(--color-warning-100)/<alpha-value>)",
200: "rgb(var(--color-warning-200)/<alpha-value>)",
300: "rgb(var(--color-warning-300)/<alpha-value>)",
400: "rgb(var(--color-warning-400)/<alpha-value>)",
500: "rgb(var(--color-warning-500)/<alpha-value>)",
600: "rgb(var(--color-warning-600)/<alpha-value>)",
700: "rgb(var(--color-warning-700)/<alpha-value>)",
800: "rgb(var(--color-warning-800)/<alpha-value>)",
900: "rgb(var(--color-warning-900)/<alpha-value>)",
950: "rgb(var(--color-warning-950)/<alpha-value>)",
},
info: {
0: "rgb(var(--color-info-0)/<alpha-value>)",
50: "rgb(var(--color-info-50)/<alpha-value>)",
100: "rgb(var(--color-info-100)/<alpha-value>)",
200: "rgb(var(--color-info-200)/<alpha-value>)",
300: "rgb(var(--color-info-300)/<alpha-value>)",
400: "rgb(var(--color-info-400)/<alpha-value>)",
500: "rgb(var(--color-info-500)/<alpha-value>)",
600: "rgb(var(--color-info-600)/<alpha-value>)",
700: "rgb(var(--color-info-700)/<alpha-value>)",
800: "rgb(var(--color-info-800)/<alpha-value>)",
900: "rgb(var(--color-info-900)/<alpha-value>)",
950: "rgb(var(--color-info-950)/<alpha-value>)",
},
typography: {
0: "rgb(var(--color-typography-0)/<alpha-value>)",
50: "rgb(var(--color-typography-50)/<alpha-value>)",
100: "rgb(var(--color-typography-100)/<alpha-value>)",
200: "rgb(var(--color-typography-200)/<alpha-value>)",
300: "rgb(var(--color-typography-300)/<alpha-value>)",
400: "rgb(var(--color-typography-400)/<alpha-value>)",
500: "rgb(var(--color-typography-500)/<alpha-value>)",
600: "rgb(var(--color-typography-600)/<alpha-value>)",
700: "rgb(var(--color-typography-700)/<alpha-value>)",
800: "rgb(var(--color-typography-800)/<alpha-value>)",
900: "rgb(var(--color-typography-900)/<alpha-value>)",
950: "rgb(var(--color-typography-950)/<alpha-value>)",
white: "#FFFFFF",
gray: "#D4D4D4",
black: "#181718",
},
outline: {
0: "rgb(var(--color-outline-0)/<alpha-value>)",
50: "rgb(var(--color-outline-50)/<alpha-value>)",
100: "rgb(var(--color-outline-100)/<alpha-value>)",
200: "rgb(var(--color-outline-200)/<alpha-value>)",
300: "rgb(var(--color-outline-300)/<alpha-value>)",
400: "rgb(var(--color-outline-400)/<alpha-value>)",
500: "rgb(var(--color-outline-500)/<alpha-value>)",
600: "rgb(var(--color-outline-600)/<alpha-value>)",
700: "rgb(var(--color-outline-700)/<alpha-value>)",
800: "rgb(var(--color-outline-800)/<alpha-value>)",
900: "rgb(var(--color-outline-900)/<alpha-value>)",
950: "rgb(var(--color-outline-950)/<alpha-value>)",
},
background: {
0: "rgb(var(--color-background-0)/<alpha-value>)",
50: "rgb(var(--color-background-50)/<alpha-value>)",
100: "rgb(var(--color-background-100)/<alpha-value>)",
200: "rgb(var(--color-background-200)/<alpha-value>)",
300: "rgb(var(--color-background-300)/<alpha-value>)",
400: "rgb(var(--color-background-400)/<alpha-value>)",
500: "rgb(var(--color-background-500)/<alpha-value>)",
600: "rgb(var(--color-background-600)/<alpha-value>)",
700: "rgb(var(--color-background-700)/<alpha-value>)",
800: "rgb(var(--color-background-800)/<alpha-value>)",
900: "rgb(var(--color-background-900)/<alpha-value>)",
950: "rgb(var(--color-background-950)/<alpha-value>)",
error: "rgb(var(--color-background-error)/<alpha-value>)",
warning: "rgb(var(--color-background-warning)/<alpha-value>)",
muted: "rgb(var(--color-background-muted)/<alpha-value>)",
success: "rgb(var(--color-background-success)/<alpha-value>)",
info: "rgb(var(--color-background-info)/<alpha-value>)",
light: "#FBFBFB",
dark: "#181719",
},
indicator: {
primary: "rgb(var(--color-indicator-primary)/<alpha-value>)",
info: "rgb(var(--color-indicator-info)/<alpha-value>)",
error: "rgb(var(--color-indicator-error)/<alpha-value>)",
},
},
fontFamily: {
heading: undefined,
body: undefined,
mono: undefined,
roboto: ["Roboto", "sans-serif"],
},
fontWeight: {
extrablack: "950",
},
fontSize: {
"2xs": "10px",
},
boxShadow: {
"hard-1": "-2px 2px 8px 0px rgba(38, 38, 38, 0.20)",
"hard-2": "0px 3px 10px 0px rgba(38, 38, 38, 0.20)",
"hard-3": "2px 2px 8px 0px rgba(38, 38, 38, 0.20)",
"hard-4": "0px -3px 10px 0px rgba(38, 38, 38, 0.20)",
"hard-5": "0px 2px 10px 0px rgba(38, 38, 38, 0.10)",
"soft-1": "0px 0px 10px rgba(38, 38, 38, 0.1)",
"soft-2": "0px 0px 20px rgba(38, 38, 38, 0.2)",
"soft-3": "0px 0px 30px rgba(38, 38, 38, 0.1)",
"soft-4": "0px 0px 40px rgba(38, 38, 38, 0.1)",
},
},
},
plugins: [gluestackPlugin],
};

@ -3,15 +3,14 @@
"compilerOptions": {
"strict": true,
"paths": {
"@/*": [
"./*"
]
"@/*": ["./*"]
}
},
"include": [
"**/*.ts",
"**/*.tsx",
".expo/types/**/*.ts",
"expo-env.d.ts"
"expo-env.d.ts",
"nativewind-env.d.ts"
]
}

Loading…
Cancel
Save