React Context API ve Tailwind CSS ile Dark Mode Nasıl Yapılır?
Dark mode, artık neredeyse tüm servislerde mevcut. İlk başta gerçekten nasıl yapacağımı bilmiyordum. Kullanılacak paketler olduğundan eminim ama kendim yapmak istiyordum.
Daha sonra Josh Comeau'un bu makalesine rastladım: The Quest for the Perfect Dark Mode. Kafamda iki şey netleşmiş oldu: CSS değişkenleri ve prefers-color-scheme.
Bu yazıda, bir Gatsby ve Tailwind CSS projesinde karanlık modun nasıl uygulanacağıyla ilgili sürecimde size yol göstereceğim.
CSS değişkenlerini ekleme
Öncelikle ana css dosyamızdaki tüm css değişkenlerimizi tanımlayalım.
Örneğin bu websiteyi ele alalım, hem arka plan hem de metinler için üç renk mevcut: primary, secondary, ve accent. Renkler tasarımınıza göre değişecektir.
Daha sonra, .light
ve .dark
classlarını ekleyin ve her bir değişken için renkleri tanımlayın. Ardından, sayfanız için varsayılan bir tema uygulamak için :root içerisinde @apply yönergesini tanımlayın.
index.css
:root {@apply .light;}.dark {--color-bg-primary: #2d3748;--color-bg-secondary: #283141;--color-text-primary: #f7fafc;--color-text-secondary: #e2e8f0;--color-text-accent: #81e6d9;}.light {--color-bg-primary: #ffffff;--color-bg-secondary: #edf2f7;--color-text-primary: #2d3748;--color-text-secondary: #4a5568;--color-text-accent: #2b6cb0;}@import 'tailwindcss/base';@import 'tailwindcss/components';@import 'tailwindcss/utilities';
Tailwind CSS'e Müdahele Etme
Oluşturduğumuz css değişkenlerini kullanabilmek için Tailwind CSS'e müdahele etmemiz gerekiyor.
tailwind.config.js
module.exports = {theme: {extend: {backgroundColor: {primary: 'var(--color-bg-primary)',secondary: 'var(--color-bg-secondary)',},textColor: {accent: 'var(--color-text-accent)',primary: 'var(--color-text-primary)',secondary: 'var(--color-text-secondary)',},},},}
Tailwind'in config.js dosyasında yaptığımız bu değişiklik ile özel classlarımız Tailwind'e dahil olacak.
Toggle Ekleme
Kullanıcıya toggle butonu verebilmek için gerekli React fonksiyonumuzu ekleyelim.
Varsayılan Temayı Alma
themeContext.jsx
const getInitialTheme = _ => {if (typeof window !== 'undefined' &&window.localStorage) {const storedPrefs =window.localStorage.getItem('color-theme')if (typeof storedPrefs === 'string') {return storedPrefs}const userMedia =window.matchMedia('(prefers-color-scheme: dark)')if (userMedia.matches) {return 'dark'}}// Varsayılan olarak açık tema isterseniz burayı 'light' olarak değiştirin.return 'dark'}
Burada önce localStorage
içerisinde bir değerimiz olup olmadığını kontrol ediyoruz. Eğer yoksa kullanıcının tarayıcısının prefers-color-scheme
sorgusunu kullanarak açık veya koyu tema tercih edip etmediğini kontrol ediyoruz.
Context Oluşturma
Her bileşende desteği manuel olarak aşağı aktarmak zorunda kalmadan tema verilerimizi iletmek için Context API'i kullanıyoruz.
Context'imiz aşağıdakileri yapmalı:
- Tema için bir state oluşturmak daha önce yazdığımız
getInitialTheme
fonksiyonuna göndermek. - CSS :root içinde
.dark
veya.light
class'ını uygulayacak ve uygulanan değerilocalStorage
'e kaydedecekrawSetTheme
adında başka bir fonksiyon oluşturarak. theme
değeri değiştiğinderawSetTheme
'i çağıracak.
themeContext.jsx
export const ThemeContext = createContext()export const ThemeProvider = ({ initialTheme, children }) => {const [theme, setTheme] = useState(getInitialTheme)const rawSetTheme = theme => {const root = window.document.documentElementconst isDark = theme === 'dark'root.classList.remove(isDark ? 'light' : 'dark')root.classList.add(theme)localStorage.setItem('color-theme', theme)}if (initialTheme) {rawSetTheme(initialTheme)}React.useEffect(_ => {rawSetTheme(theme)},[theme])return (<ThemeContext.Provider value={{ theme, setTheme }}> {children} </ThemeContext.Provider>)}
Context Provider Kullanma
Componentlerin oluşturduğumuz ThemeProvider
context'ini kullanması için onu Higher Order Component (HOC) yapalım.
layout.jsx
import { ThemeProvider } from './themeContext'const Layout = ({ children }) => {return (<ThemeProvider> <Header /> <main>{children}</main> </ThemeProvider>)}
Toggle Fonksiyonlarını Ekleme
Context'imiz hazır olduğuna göre artık toggle'ımıza fonksiyon ekleyebiliriz.
theme
vesetTheme
içinThemeContext
'i kullanma.theme
dark
'a eşitle checkboxchecked
'ı true olarak ayarlama.onChange
eventındasetTheme
'i çalıştırma.
toggle.jsx
export const Toggle = () => {const { theme, setTheme } = useContext(ThemeContext)function isDark() {return theme === 'dark'}function toggleTheme(e) {setTheme(e.target.checked ? 'dark' : 'light')}return (<label> <input type="checkbox" checked={isDark()} onChange={e => toggleTheme(e)} /> Dark Mode </label>)}
İşte Bu Kadar!
Artık toggle'ımız Componentlerden bağımsız olarak çalışıyor.
Dark Mode Tasarımı
Gördüğünüz üzere bu websitesinde karanlık mod için çok fazla fonksiyon yok, eğer karmaşık uygulamanızın arayüzünü karanlık moda çevirmek istiyorsanız aşağıdaki makaleye göz atabilirsiniz.