Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10,890 changes: 10,890 additions & 0 deletions assets/figma/variables.json

Large diffs are not rendered by default.

165 changes: 165 additions & 0 deletions scripts/generate_theme.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
#!/usr/bin/env node
// eslint-disable-next-line @typescript-eslint/no-var-requires
const fs = require('fs')

const json = fs.readFileSync('./assets/figma/variables.json')

const figmaVariables = JSON.parse(json)

const collections = figmaVariables.collections

const primitivesCollection = collections.find((collection) => collection.name === '_Primitives')
const colorsCollection = collections.find((collection) => collection.name === '1. Color modes')

const primitivesColors = primitivesCollection.modes
.find((mode) => mode.name === 'Style')
.variables.filter((variable) => variable.type === 'color')
.map((color) => ({ name: color.name, value: color.value }))

// colorMode could be either 'light' or 'dark'
const getModeColors = (colorMode) => {
const modeName = colorMode === 'light' ? 'Light mode' : 'Dark mode'
const modeColors = colorsCollection.modes.find((mode) => mode.name === modeName)?.variables
const colors = modeColors
.map((variable) => {
if (variable.isAlias) {
if (variable.value.collection === '_Primitives') {
const primitiveColor = primitivesColors.find(
(color) => color.name === variable.value.name
)
if (primitiveColor) {
return { name: variable.name, value: primitiveColor.value }
}
return null
} else {
const newColor = modeColors.find((color) => color.name === variable.value.name)
if (newColor) {
const primitiveColor = primitivesColors.find(
(color) => color.name === newColor.value.name
)
if (primitiveColor) {
return { name: variable.name, value: primitiveColor.value }
}
}
}
return null
} else if (!variable.isAlias) {
return { name: variable.name, value: variable.value }
} else return null
})
.filter(Boolean)

const colorsArray = colors.map((color) => {
return { [color.name.split('/').pop().split(' ').shift() || '']: color.value }
})

const colorsInMode = colorsArray.reduceRight((acc, color) => {
const [entries] = Object.entries(color)

const nestedKeys = entries[0].split('-')

const newValue = createNestedObject(nestedKeys, entries[1])

return mergeObjects(acc, newValue)
}, {})

const sortedColors = sortObject(colorsInMode)
return sortedColors
}

const light = getModeColors('light')
const dark = getModeColors('dark')

const primitivesColorsArray = primitivesColors.map((color) => {
return { [color.name.split('/').slice(1).join('-')]: color.value }
})

const primitives = primitivesColorsArray.reduceRight((acc, color) => {
const [entries] = Object.entries(color)

const colorName = entries[0].split('_')

const nestedKeys = colorName[0].split('-')
if (colorName[1]) {
nestedKeys.push(colorName[1])
}

const newValue = createNestedObject(nestedKeys, entries[1])

return mergeObjects(acc, newValue)
}, {})

// Export colors to file

const theme = {
darkMode: dark,
lightMode: light,
primitives: sortObject(primitives),
}

const objectString = `export const themeColors = ${JSON.stringify(theme, null, 2)}`

// Specify the file path
const filePath = './src/constants/colors.ts'

fs.writeFileSync(filePath, objectString, 'utf-8')

// Utils
function createNestedObject(keys, value) {
if (keys.length === 0) {
return value
}

const key = keys[0]
const remainingKeys = keys.slice(1)

const nestedObject = {}
nestedObject[key] = createNestedObject(remainingKeys, value)

return nestedObject
}

function mergeObjects(obj1, obj2) {
// Initialize the result object
const result = {}

// Loop through keys in obj1
for (const key in obj1) {
// If the key is present in both obj1 and obj2 and both values are objects
if (key in obj2 && typeof obj1[key] === 'object' && typeof obj2[key] === 'object') {
// Recursively merge the nested objects
result[key] = mergeObjects(obj1[key], obj2[key])
} else {
// Otherwise, prioritize the value from obj2
result[key] = obj2[key] !== undefined ? obj2[key] : obj1[key]
}
}

// Loop through keys in obj2
for (const key in obj2) {
// If the key is not present in obj1, add it to the result object
if (!(key in obj1)) {
result[key] = obj2[key]
}
}

return result
}

function sortObject(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj
}

if (Array.isArray(obj)) {
return obj.map(sortObject)
}

const sorted = {}
Object.keys(obj)
.sort()
.forEach((key) => {
sorted[key] = sortObject(obj[key])
})
return sorted
}
2 changes: 1 addition & 1 deletion src/components/AppLoading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export const AppLoading: FC<PropsWithChildren> = ({ children }) => {
<View style={styles.container} onLayout={onLayoutRootView}>
{isLoading ? null : children}
{isLoading || isDelayLoading ? (
<AbsoluteFullFill bg="white">
<AbsoluteFullFill bg="fg.white">
<Center flex={1}>
<Loader type="bubbles" />
</Center>
Expand Down
8 changes: 4 additions & 4 deletions src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,20 @@ export const Header = ({ options, ...rest }: NativeStackHeaderProps) => {
})

return (
<Column bg="white">
<Row bg="white" zIndex={3} justifyContent="space-between" alignItems="center">
<Column bg="fg.white">
<Row bg="fg.white" zIndex={3} justifyContent="space-between" alignItems="center">
<Box ml={4} width={24}>
{router.canGoBack() && (
<Touchable onPress={router.back}>
<Icon name="arrow-left-line" size={24} color="text" />
<Icon name="arrow-left-line" size={24} color="text.brand.primary" />
</Touchable>
)}
</Box>
{options.title ? (
<>
<Box height={logoHeight} />
<Row ml={8} flex={1}>
<Text.H4Bold numberOfLines={1} color="text">
<Text.H4Bold numberOfLines={1} color="text.brand.primary">
{options.title}
</Text.H4Bold>
</Row>
Expand Down
4 changes: 1 addition & 3 deletions src/components/LanguagePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,11 @@ import { Touchable, TouchableProps } from './atoms/Touchables/Touchable'
import { Menu } from './organisms/Menu'
import languages from '../../assets/languages.json'

import { useColorScheme } from '~contexts'
import { useCallback, useTranslation, useTheme } from '~hooks'

export const LanguagePicker: React.FC = () => {
const { size } = useTheme()

const { colorScheme } = useColorScheme()
const { i18n } = useTranslation()
const language = i18n?.language?.slice?.(0, 2).toUpperCase() as keyof typeof languages
const isOpen = useSharedValue(false)
Expand All @@ -33,7 +31,7 @@ export const LanguagePicker: React.FC = () => {
icon: { height: size['8'], justifyContent: 'center' },
})

const iconColor = colorScheme === 'light' ? 'black' : 'white'
const iconColor = 'text.brand.primary'

const renderTrigger = useCallback(
(
Expand Down
4 changes: 2 additions & 2 deletions src/components/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ export const Modal = ({
<SafeAreaView
style={[
styles.modal,
{ backgroundColor: colors.modalBackground },
{ backgroundColor: colors.alpha.black[30] },
additionalWrapperStyle,
]}
>
<ScrollableComponent
style={styles.scroll}
contentContainerStyle={[styles.scrollContent, { background: colors.transparent }]}
contentContainerStyle={[styles.scrollContent, { background: colors.bg.overlay }]}
showsVerticalScrollIndicator={false}
>
<TouchableWithoutFeedback>{children}</TouchableWithoutFeedback>
Expand Down
14 changes: 7 additions & 7 deletions src/components/atoms/Button/Button.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { StyleSheet } from 'react-native'

import { Button } from '.'

import { _appTheme } from '~constants'
import { theme } from '~constants'
import { cleanup, render, fireEvent, act } from '~utils/testUtils'

afterEach(cleanup)
Expand All @@ -16,7 +16,7 @@ describe('Button', () => {
const { getByTestId } = render(<Button.Primary title="Button" />)
expect(getByTestId('baseButton').props.style).toStrictEqual({
alignItems: 'center',
backgroundColor: _appTheme.colors.primary,
backgroundColor: theme.light.colors.button.primary.bg,
borderColor: 'transparent',
borderRadius: 4,
borderWidth: undefined,
Expand All @@ -32,7 +32,7 @@ describe('Button', () => {
const { getByTestId } = render(<Button.Secondary title="Button" />)
expect(getByTestId('baseButton').props.style).toStrictEqual({
alignItems: 'center',
backgroundColor: _appTheme.colors.secondary,
backgroundColor: theme.light.colors.button.secondary.bg,
borderColor: 'transparent',
borderRadius: 4,
borderWidth: undefined,
Expand All @@ -48,8 +48,8 @@ describe('Button', () => {
const { getByTestId } = render(<Button.Outline title="Button" />)
expect(getByTestId('baseButton').props.style).toStrictEqual({
alignItems: 'center',
backgroundColor: 'transparent',
borderColor: _appTheme.colors.primary,
backgroundColor: theme.light.colors.button.tertiary.fg,
borderColor: theme.light.colors.border.primary,
borderRadius: 4,
borderWidth: StyleSheet.hairlineWidth,
flexDirection: 'row',
Expand All @@ -64,7 +64,7 @@ describe('Button', () => {
const { getByTestId } = render(<Button.Ghost title="Button" />)
expect(getByTestId('baseButton').props.style).toStrictEqual({
alignItems: 'center',
backgroundColor: 'transparent',
backgroundColor: theme.light.colors.button.tertiary.fg,
borderColor: 'transparent',
borderRadius: 4,
borderWidth: undefined,
Expand All @@ -80,7 +80,7 @@ describe('Button', () => {
const { getByTestId } = render(<Button.Link title="Button" />)
expect(getByTestId('baseButton').props.style).toStrictEqual({
alignItems: 'center',
backgroundColor: 'transparent',
backgroundColor: theme.light.colors.button.tertiary.fg,
borderColor: 'transparent',
borderRadius: 4,
borderWidth: undefined,
Expand Down
Loading