Як створювати та використовувати теми в Tamagui. Практичний приклад на основі todo-застосунку
Привіт! Мене звати Артем, я Fullstack-розробник. Для мене програмування — це не просто набір технологій і написання коду, а спосіб мислення.
Я вирішив написати цю статтю, тому що в інтернеті дуже мало інформації про роботу з темами в Tamagui. Ті, хто вже працював із цією бібліотекою, знають, що її документація не завжди є достатньо детальною. Тож я вирішив створити простий приклад — todo-застосунок з трьома темами.
Ця стаття призначена для людей, які вже мають налаштований проєкт з використанням Tamagui, але не знають, як створювати власні теми та ефективно працювати з ними.
Посилання на проєкт на GitHub. Інструкції щодо встановлення та запуску застосунка можна знайти в репозиторії.
Коротко про технології, які я використав:
- Expo
- TypeScript
- Redux Toolkit
- React Native MMKV
- Redux Persist
- Tamagui
- React Native Gesture Handler (для видалення задачі по свайпу)
Основи роботи з темами
Перш за все потрібно розуміти два ключових поняття: палітра (palette) і шаблон (template). Детальніше можна прочитати в офіційній документації Tamagui, але я поясню.
Палітра — це набір кольорів, який використовується в темі. Назви палітр можуть бути довільними. Приклад:
const darkPallete = [ «#111827», «#F9FAFB», «#10B981», «#9CA3AF», «#374151», «#4B5563», «#1F2937», «#10B981», ];
Шаблон — це об’єкт, де кожен колір палітри відповідає певній логічній назві (ключ в об’єкті шаблона), наприклад, background, primary, accent.
Значенням для цих назв є індекси кольорів з палітри. const baseTemplate = { background: 0, border: 5, buttonBg: 7, checkbox: 6, inputBorder: 4, text: 1, textAccent: 2, textMuted: 3, };
Налаштування тем у застосунку
Щоб теми працювали, треба огорнути весь проєкт у компонент TamaguiProvider і передати туди тему за замовчуванням та конфігурацію. Я використовую Redux Toolkit, тому створив окремий слайс для зберігання обраної теми, але можна використовувати будь-який стейт-менеджер — суть залишається тією ж.
theme-slice.ts
import { createSlice } from "@reduxjs/toolkit"; export interface ThemeState { theme: string; } const initialState: ThemeState = { theme: "light", }; export const themeSlice = createSlice({ initialState, name: "theme", reducers: { setTheme: (state, action) => { state.theme = action.payload; }, }, }); export const { setTheme } = themeSlice.actions; export default themeSlice.reducer;
tamagui-provider.tsx
import { ReactNode } from "react"; import { useSelector } from "@/store/hooks"; import tamaguiConfig from "@/tamagui.config"; import { TamaguiProvider as Tamagui } from "tamagui"; type TamaguiProviderProps = { children: ReactNode; }; export default function TamaguiProvider({ children }: TamaguiProviderProps) { const theme = useSelector((state) => state.theme.theme); return ( <Tamagui config={tamaguiConfig} defaultTheme={theme}> {children} </Tamagui> ); }
Як це працює:
- У файлі theme-builder.ts я визначив три палітри: темну, зелену та світлу. Усі вони використовують один шаблон.
theme-builder.ts
import { createThemeBuilder } from "@tamagui/theme-builder"; const palettes = { dark: [ "#111827", // background "#F9FAFB", // text "#10B981", // textAccent "#9CA3AF", // textMuted "#374151", // input border "#4B5563", // checkbox border "#1F2937", // checkbox background "#10B981", // button background ], green: [ "#D1FAE5", // background "#065F46", // text "#10B981", // textAccent "#6EE7B7", // textMuted "#A7F3D0", // input border "#A7F3D0", // checkbox border "#ECFDF5", // checkbox background "#10B981", // button background ], light: [ "#F9FAFB", // background "#111827", // text "#3B82F6", // textAccent "#6B7280", // textMuted "#E5E7EB", // input border "#D1D5DB", // checkbox border "#FFFFFF", // checkbox background "#3B82F6", // button background ], }; const templates = { base: { background: 0, border: 5, buttonBg: 7, checkbox: 6, inputBorder: 4, text: 1, textAccent: 2, textMuted: 3, }, };
- За допомогою функції createThemeBuilder я створив нову тему.
export const themes = createThemeBuilder() .addPalettes(palettes) .addTemplates(templates) .addThemes({ dark: { palette: "dark", template: "base", }, green: { palette: "green", template: "base", }, light: { palette: "light", template: "base", }, }) .build();
- Щоб збілдити тему, додав у package.json скрипт: «generate-themes»: «tamagui generate-themes ./theme-builder.ts ./theme-output.ts». Цей скрипт за допомогою @tamagui/cli генерує теми та зберігає їх у файл theme-output.ts.
Тепер потрібно додати створені нами теми в файл tamagui.config.ts, а саме в функцію createTamagui().
tamagui.config.ts
import { shorthands } from "@tamagui/shorthands"; import { createTamagui, createTokens } from "tamagui"; import { animations, tokens as defaultTokens, fonts, media, } from "@tamagui/config/v3"; import * as themes from "./theme-output"; const tokens = createTokens({ ...defaultTokens, }); const config = createTamagui({ animations, fonts, media, shorthands, themes, tokens, }); type Conf = typeof config; declare module "tamagui" { interface TamaguiCustomConfig extends Conf {} } export default config;
Як використовувати теми
В результаті ми отримуємо велику палітру, шаблон і три готові теми. Тепер їх можна застосовувати в компонентах, використовуючи, наприклад, змінну $background. Однак це не означає, що не можна прописати властивість як color="$background".
Це лише означає, що змінна буде братися на основі активної теми. Але вона залишається звичайним кольором, який можна використовувати в межах стилізації компонентів як завгодно.
<SafeArea> <AvoidKeyboardView> <YStack bg="$background" gap="$3" h="100%" padding="$3"> <ThemeSelect /> <H1 color="$textAccent">Tasks</H1> <H4 color="$text">Title:</H4> <Input bbw="$1" blw={0} borderColor="$inputBorder" brw={0} btw={0} color="$text" onChangeText={setTitle} placeholder="Pay utilities bill" placeholderTextColor="$textMuted" value={title} /> <Button bg="$buttonBg" color="$text" onPress={() => handleAdd(title)}> Add todo </Button> <TodoList /> </YStack> </AvoidKeyboardView> </SafeArea>
Щоб змінити тему, достатньо оновити значення теми у Redux Store, і всі кольори зміняться автоматично.
export default function ThemeSelect({ ...props }: XStackProps) { const dispatch = useDispatch(); const theme = useSelector((state) => state.theme.theme); return ( <XStack ai="center" gap="$5" jc="center" p="$3" {...props}> <ThemeSelectItem bg="$black4" isSelected={theme === "dark"} onPress={() => dispatch(setTheme("dark"))} /> <ThemeSelectItem bg="$green8Light" isSelected={theme === "green"} onPress={() => dispatch(setTheme("green"))} /> <ThemeSelectItem bg="$blue8Light" isSelected={theme === "light"} onPress={() => dispatch(setTheme("light"))} /> </XStack> );
Висновок
Отже, щоб створити тему в Tamagui, потрібно визначити палітру, шаблон, а потім збілдити тему, яку можна буде додати в tamagui.config ). Створення тем у Tamagui не є складним, але вимагає правильного розуміння базових концепцій і налаштувань. Сподіваюся, ця інформація стане вам корисною!
Якщо вам цікаво, я можу підготувати статтю про більш просунуте використання тем у Tamagui. До речі, я також планую записати відео англійською мовою про роботу з темами :)
Це моя перша стаття, тому судіть строго!
Дякую за увагу!
Немає коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів