Як створювати та використовувати теми в Tamagui. Практичний приклад на основі todo-застосунку

💡 Усі статті, обговорення, новини про Front-end — в одному місці. Приєднуйтесь до Front-end спільноти!

Привіт! Мене звати Артем, я 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. До речі, я також планую записати відео англійською мовою про роботу з темами :)

Це моя перша стаття, тому судіть строго!
Дякую за увагу!

👍ПодобаєтьсяСподобалось4
До обраногоВ обраному1
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Підписатись на коментарі