Skip to content

Commit

Permalink
theme app
Browse files Browse the repository at this point in the history
  • Loading branch information
wiktorrudzki committed Jan 13, 2024
1 parent 832ebd9 commit 7d355ac
Show file tree
Hide file tree
Showing 19 changed files with 168 additions and 10 deletions.
1 change: 1 addition & 0 deletions %ProgramData%/Microsoft/Windows/UUS/State/_active.uusver
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1213.2310.20012.0
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ module.exports = {
'react-hooks/exhaustive-deps': 'warn',
'simple-import-sort/imports': 'warn',
'simple-import-sort/exports': 'warn',
indent: ['warn', 2],
indent: ['warn', 2, { SwitchCase: 1 }],
quotes: ['warn', 'single'],
semi: ['warn', 'always'],
},
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

# dependencies
node_modules/
yarn.lock

# Expo
.expo/
Expand Down
21 changes: 14 additions & 7 deletions App.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
import { globalStyles } from 'style';

import { PrimaryButton, SwitchTheme } from '@/components';
import { ThemeProvider } from '@/hooks';

const App = () => {
return (
<View style={styles.container}>
<Text>Open up App.tsx to start working on your app!</Text>
<StatusBar style="auto" />
</View>
<ThemeProvider>
<View style={styles.container}>
<Text>Open up App.tsx to start working on your app!</Text>
<StatusBar style="auto" />
<SwitchTheme />
<PrimaryButton onPress={() => {}} title="dasdsa" />
</View>
</ThemeProvider>
);
};

const styles = StyleSheet.create({
container: {
...globalStyles.horizontalFlex,
...globalStyles.centerFlex,
color: 'red',
height: '100%',
width: '100%',
backgroundColor: 'white',
alignItems: 'center',
justifyContent: 'center',
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@

`You should declare all reusable stylings there`

## Theming

![themed colors example](./readme/themedColors.png)

### Example of how do we declare colors for different themes

![usage of themes](./readme/themeUsage.png)

### Example of how do we use themes in component

## Form

### When we want to create form, we use external library called _react-hook-form_
Expand Down
9 changes: 9 additions & 0 deletions app.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@
},
"web": {
"favicon": "./assets/favicon.png"
},
"expo": {
"userInterfaceStyle": "automatic",
"ios": {
"userInterfaceStyle": "automatic"
},
"android": {
"userInterfaceStyle": "automatic"
}
}
}
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"lint": "eslint --ext .js,.jsx,.ts,.tsx"
},
"dependencies": {
"@react-native-async-storage/async-storage": "^1.21.0",
"@react-native/metro-config": "^0.73.3",
"expo": "~49.0.15",
"expo-status-bar": "~1.6.0",
Expand Down
Binary file added readme/themeUsage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added readme/themedColors.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file removed src/components/.placeholder
Empty file.
12 changes: 12 additions & 0 deletions src/components/SwitchTheme.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
import { Switch } from 'react-native';

import { useTheme } from '@/hooks';

const SwitchTheme = () => {
const { theme, switchTheme } = useTheme();

return <Switch value={theme === 'dark'} onChange={switchTheme} />;
};

export default SwitchTheme;
2 changes: 2 additions & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as PrimaryButton } from './PrimaryButton';
export { default as SwitchTheme } from './SwitchTheme';
Empty file removed src/hooks/.placeholder
Empty file.
1 change: 1 addition & 0 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './useTheme';
84 changes: 84 additions & 0 deletions src/hooks/useTheme.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import React, { useContext, useEffect, useState } from 'react';
import { useColorScheme } from 'react-native';
import { darkColors, lightColors } from 'style';

import { isTypeOfTheme, Theme, THEMES } from '@/types/theme';

type Props = {
children: React.ReactNode;
};

type Context = {
theme: Theme;
themedStyles: Record<string, string>;
switchTheme: () => void;
};

const ThemeContext = React.createContext<Context | undefined>(undefined);

const getThemedStyles = (theme: Theme): Record<string, string> => {
switch (theme) {
case 'dark':
return darkColors;
case 'light':
return lightColors;
default:
return lightColors;
}
};

export const ThemeProvider = ({ children }: Props) => {
const colorScheme = useColorScheme();

const [theme, setTheme] = useState<Theme>(
isTypeOfTheme(colorScheme) ? colorScheme : THEMES[0],
);

const switchTheme = () => {
const newTheme = theme === 'dark' ? 'light' : 'dark';

setTheme(newTheme);

AsyncStorage.setItem('theme', newTheme);
};

useEffect(() => {
// Load saved theme from storage
console.log('xd');
const getTheme = async () => {
try {
const savedTheme = await AsyncStorage.getItem('theme');
if (savedTheme && isTypeOfTheme(savedTheme)) {
setTheme(savedTheme);
}
} catch (error) {
// TODO - log error to db?
}
};

getTheme();
}, []);

const themedStyles = getThemedStyles(theme);

const value: Context = {
theme,
themedStyles,
switchTheme,
};

return (
<ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>
);
};

export const useTheme = () => {
const context = useContext(ThemeContext);

if (!context) {
throw new Error('use Theme must be used within provider');
}

return context;
};
Empty file removed src/types/.placeholder
Empty file.
5 changes: 5 additions & 0 deletions src/types/theme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const THEMES = ['light', 'dark'] as const;
export type Theme = (typeof THEMES)[number];

export const isTypeOfTheme = (value: any): value is Theme =>
THEMES.includes(value);
10 changes: 8 additions & 2 deletions style.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { StyleSheet } from 'react-native';

const globalStyles = StyleSheet.create({
export const globalStyles = StyleSheet.create({
verticalFlex: {
display: 'flex',
flexDirection: 'column',
Expand All @@ -14,4 +14,10 @@ const globalStyles = StyleSheet.create({
},
});

export { globalStyles };
export const darkColors = {
primary: 'blue',
};

export const lightColors = {
primary: 'green',
};
19 changes: 19 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1787,6 +1787,13 @@
resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.0.tgz#7d8dacb7fdef0e4387caf7396cbd77f179867d06"
integrity sha512-Zwq5OCzuwJC2jwqmpEQt7Ds1DTi6BWSwoGkbb1n9pO3hzb35BoJELx7c0T23iDkBGkh2e7tvOtjF3tr3OaQHDQ==

"@react-native-async-storage/async-storage@^1.21.0":
version "1.21.0"
resolved "https://registry.yarnpkg.com/@react-native-async-storage/async-storage/-/async-storage-1.21.0.tgz#d7e370028e228ab84637016ceeb495878b7a44c8"
integrity sha512-JL0w36KuFHFCvnbOXRekqVAUplmOyT/OuCQkogo6X98MtpSaJOKEAeZnYO8JB0U/RIEixZaGI5px73YbRm/oag==
dependencies:
merge-options "^3.0.4"

"@react-native-community/[email protected]":
version "11.3.7"
resolved "https://registry.yarnpkg.com/@react-native-community/cli-clean/-/cli-clean-11.3.7.tgz#cb4c2f225f78593412c2d191b55b8570f409a48f"
Expand Down Expand Up @@ -5980,6 +5987,11 @@ is-path-inside@^3.0.2, is-path-inside@^3.0.3:
resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==

is-plain-obj@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287"
integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==

is-plain-obj@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7"
Expand Down Expand Up @@ -6712,6 +6724,13 @@ [email protected]:
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==

merge-options@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/merge-options/-/merge-options-3.0.4.tgz#84709c2aa2a4b24c1981f66c179fe5565cc6dbb7"
integrity sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==
dependencies:
is-plain-obj "^2.1.0"

merge-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
Expand Down

0 comments on commit 7d355ac

Please sign in to comment.