React + AntDesign ile Dinamik Karanlık Tema
React + AntDesign ile Dinamik Karanlık Tema

React + AntDesign ile Dinamik Karanlık Tema

Tags
Web Dev
React.js
Node.js
Design
Published
January 3, 2023

AntDesign

Ant Design en popüler react ui araçlarından biridir. Bu kadar popüler olmasının en büyük sebebi de geniş bir araç kiti olması ve çeşitli gösterge panellerinin kolaylıkla projeye dahil edilmesi olarak düşünüyorum (antdesign-vision).
notion image
Not: Çok fazla uzatmıyorum çünkü antdesign ile alakalı ayrıca birkaç yazı yazmayı planlıyorum.

Problemimiz nedir?

Antdesign kendi komponentlerinde karanlık temayı bulunduran bir kit aslında. CSS stil dosyalarını Less stiline çeviriyor. React.js’de bunu yapmak için CSS dosyalarını derlemek ve ardından yapıya eklemek için gerekiyor. Bunun için de webpackten destek alıyoruz. Ancak bu işlem sonucunda da değiştiremeyeceğimiz anlamına geliyor.
 

Örnek Ufak Çözüm

Bu soruna karşı bir sürü kitaplık mevcut örneğin: react-app-rewire-antd-theme. Bu, less dosyasına doğrudan HTML'de değiştirilecek renkleri enjekte eder ve çalışma zamanında stilleri yeni değişkenlerle yeniden derlemek için window.modifyVars'ı kullanır. Bu, az sayıda değişkenle işe yarayabilir, ancak karanlık bir tema için yüzlerce değişken için bu mümkün değildir. Kullanıcının performansını öldürecektir.

Çözüm

JoseRFelix bu konuda birçok deneme yapmış ve sonunda yılıp kendi dark mode kitaplığını yapmış.
Projesine aşağıdan ulaşabilirsiniz 👇
En büyük sıkıntılar derleme süresi, kullanıcının bilgisayarını yorması ve yapılan değişiklikleri gösteremesiydi. Ancak çözüm sayesinde sistem hiç yorulmadan basit bir şekilde halloluyor.

Less Dosyalarmızı oluşturalım

Yapmamız gereken ilk şey, AntD stillerini içerecek olan Less stil sayfalarını oluşturmak. Bunu başarmak için, her tema için ihtiyacımız olan değişkenleri ve stilleri içe aktarmamız yeterlidir.

Temanın Dosya Yapısı

notion image
Dosya düzenimiz soldaki gibi olacaktır. Bir themes klasörü oluşturun ve içine aşağıdaki less dosyalarını ekleyin.
 
light tema için:
// light-theme.less @import '~antd/lib/style/color/colorPalette.less'; @import '~antd/dist/antd.less'; @import '~antd/lib/style/themes/default.less'; @primary-color: #00adb5; @border-radius-base: 4px;
dark tema için;
// dark-theme.less @import '~antd/lib/style/color/colorPalette.less'; @import '~antd/dist/antd.less'; @import '~antd/lib/style/themes/dark.less'; @primary-color: #00adb5; @border-radius-base: 4px; @component-background: #303030; @body-background: #303030; @popover-background: #303030; @border-color-base: #6f6c6c; @border-color-split: #424242; @table-header-sort-active-bg: #424242; @card-skeleton-bg: #424242; @skeleton-color: #424242; @table-header-sort-active-bg: #424242;

Gulp.js ile kontrol sende 💪

Tabi less dosyalarımızı yaptık ancak bunu derlemezsek hiçbir değişim göremeyiz. Webpack’ten yardım alabiliriz ancak en ufak değişiklikte bile yeniden derlemesi sistemi yorduğu için biz gulp kullanacağız. Gulp.js, tekrar eden işlerinizi tanımlamak ve çalıştırmak için kullanılır. Basit ve etkili bir javascript kütüphanesidir.
Dosyayı küçültmek, postcss kullanmak ve içe aktarmaları çözmek ve Gulp.js kurmak için aşağıdaki kodu çalıştırın (npm veya yarn hangisiniyle isterseniz kurun);
npm add -D gulp gulp-less gulp-postcss gulp-debug gulp-csso autoprefixer less-plugin-npm-import
Ve ana dizine bir gulpfile.js oluşturun:
const gulp = require('gulp') const gulpless = require('gulp-less') const postcss = require('gulp-postcss') const debug = require('gulp-debug') var csso = require('gulp-csso') const autoprefixer = require('autoprefixer') const NpmImportPlugin = require('less-plugin-npm-import') gulp.task('less', function () { const plugins = [autoprefixer()] return gulp .src('src/themes/*-theme.less') .pipe(debug({title: 'Less files:'})) .pipe( gulpless({ javascriptEnabled: true, plugins: [new NpmImportPlugin({prefix: '~'})], }), ) .pipe(postcss(plugins)) .pipe( csso({ debug: true, }), ) .pipe(gulp.dest('./public')) })
İşlemler bittikten sonra terminale npx gulp less yazdığınızda css dosyalarınız derlenecek ve otomatik olarak public klasörüne, css çıktısı eklenecektir.

Temalar Arası Geçiş

JoseRFelix hazırladığı npm paketini yüklemek için terminale alttaki kodu çalıştırın.
 
npm i react-css-theme-switcher
 
Ardından index.js bulunan kısımda ThemeSwitcherProvider ile sarmalarız.Bu ayar ile mevcut ayarlarınız index dosyasında kalacak ve saklanacaktır.

Peki Kalıcı Temayı Nasıl sağlayacağız?

Burada bir ufak sorunu nasıl çözdüğümü anlatmam gerekiyor. React kullanırken temanın karanlık veya aydınlık olduğunu useState kullanarak tutabilirsiniz. Ancak kullanıcı F5 yaptığında bu değişiklik gidecektir. Temanın default değeri olan aydınlık (light-theme.css) stil dosyası aktif olacaktır. Bu can sıkıcı durum aslında 👉 localStorage ile basitçe çözülebilir. Bu sayede kişi tarayıcıdan bile çıksa tema kalıcı olarak kullanıcı tarafında çerez olarak tutulacaktır. Dosya yapılanmasına geçersek;
index.js:
import React from "react"; import ReactDOM from "react-dom"; import "./index.css"; import App from "./App"; import { ThemeSwitcherProvider } from "react-css-theme-switcher"; const themes = { dark: `${process.env.PUBLIC_URL}/dark-theme.css`, light: `${process.env.PUBLIC_URL}/light-theme.css`, }; if (!localStorage.getItem("theme")) { localStorage.setItem("theme", "dark"); } ReactDOM.render( <React.StrictMode> <ThemeSwitcherProvider themeMap={themes} defaultTheme={localStorage.getItem("theme")} insertionPoint={document.getElementById("inject-styles-here")} > <App /> </ThemeSwitcherProvider> </React.StrictMode>, document.getElementById("root") );
getItem”theme”.. kısmında yazdığımız kod ile var olan temanın değerini almaya yoksa setItem ile temanın değerini ekliyoruz. defaultTheme kısmında ise setItem yaptığımız temayı geri getiriyoruz.
App.js:
import React from "react"; import { useThemeSwitcher } from "react-css-theme-switcher"; import "./App.css"; import SwitchButton from "./components/switchButton"; function App() { const { currentTheme } = useThemeSwitcher(); return ( <div className="main fade-in"> <h1>The current theme is {currentTheme}</h1> <SwitchButton /> </div> ); } export default App;
Temayı değiştirmek için kullandığımız switch için direk komponent yazdım. direk SwitchButton kısmını ekleyerek projenizde çalıştırabilirsiniz.
SwitchButton.jsx:
import { Switch } from "antd"; import React from "react"; import { useThemeSwitcher } from "react-css-theme-switcher"; import darkLogo from "../themes/dark-icon.svg"; import lightLogo from "../themes/light-icon.svg"; export default function SwitchButton() { const { switcher, status, themes } = useThemeSwitcher(); const toggleTheme = (isChecked) => { switcher({ theme: isChecked ? themes.dark : themes.light }); if (isChecked) { localStorage.setItem("theme", "dark"); } else { localStorage.setItem("theme", "light"); } }; if (status === "loading") { return null; } return ( <Switch size="large" checked={localStorage.getItem("theme") === "dark" ? true : false} onChange={toggleTheme} checkedChildren={<img id="lightLogo" src={lightLogo} alt="light" />} unCheckedChildren={<img id="darkLogo" src={darkLogo} alt="dark" />} /> ); }
 

Sonuç

notion image
Evet yazımız burada son burada son bulurken projenin Github kodunu da paylaşalım. Bu sayede takıldığınız yerde oradan kontrol edebilirsiniz. 👉 antd-dynamic-theme-switch
Okuduğunuz için teşekkür ederim. Unutmadan demo linkini de alta ekliyorum oradan da test edebilirsiniz. 👇
💡
Demo 🥳