1- import type { FC } from 'react' ;
1+ import type { FC , PropsWithChildren } from 'react' ;
22import reactElementToJSXString from 'react-element-to-jsx-string' ;
3+ import { FaMinus , FaPlus } from 'react-icons/fa' ;
34import { HiInformationCircle } from 'react-icons/hi' ;
45import { PrismLight as SyntaxHighlighter } from 'react-syntax-highlighter' ;
56import { dracula } from 'react-syntax-highlighter/dist/esm/styles/prism' ;
67import { Alert , Card , DarkThemeToggle } from '../../lib' ;
7- import { Flowbite } from '../../lib/components' ;
8- import type { CustomFlowbiteTheme } from '../../lib/components/Flowbite/FlowbiteTheme' ;
8+ import { Flowbite , Table } from '../../lib/components' ;
99
1010const ThemePage : FC = ( ) => {
11- const theme : CustomFlowbiteTheme = { alert : { color : { info : 'bg-primary' } } } ;
11+ return (
12+ < div className = "mx-auto max-w-4xl dark:text-white" >
13+ < h1 className = "mb-3 text-2xl font-bold" > Theme</ h1 >
14+ < Alert color = "warning" icon = { HiInformationCircle } >
15+ This feature is highly experimental. In the future, it could be deprecated or even suffer several changes.
16+ </ Alert >
17+ < CustomizeFlowbiteComponentsSection />
18+ < SwitchToDarkModeSection />
19+ < ReadTheThemeSection />
20+ </ div >
21+ ) ;
22+ } ;
1223
24+ const CustomizeFlowbiteComponentsSection : FC = ( ) => {
1325 return (
14- < div className = "mx-auto flex max-w-4xl flex-col gap-8 dark:text-white" >
15- < div className = "flex flex-col gap-2" >
16- < span className = "text-2xl font-bold" > Theme</ span >
17- < div className = "py-4" >
18- < Alert color = "yellow" icon = { HiInformationCircle } >
19- This feature is highly experimental. In the future, it could be deprecated or even suffer several changes.
20- </ Alert >
21- < p className = "mt-4" >
22- Sometimes you want to give your web application a little more personality and customize some aspects of
23- Flowbite. This is possible thanks to the support we offer for themes. To use our theme support, your
24- application needs to be surrounded by the Flowbite component, and you must tell this component which theme
25- you want to load for your application.
26- </ p >
27- </ div >
28- < Card >
29- < SyntaxHighlighter language = "tsx" style = { dracula } >
30- { reactElementToJSXString ( < Flowbite theme = { { theme } } > ...</ Flowbite > , {
31- showFunctions : true ,
32- functionValue : ( fn ) => fn . name ,
33- sortProps : false ,
34- useBooleanShorthandSyntax : false ,
35- useFragmentShortSyntax : false ,
36- } ) }
37- </ SyntaxHighlighter >
38- </ Card >
39- </ div >
40- < span className = "text-xl font-bold" > Switch to dark theme</ span >
41- < p >
26+ < section className = "mb-6" >
27+ < header >
28+ < h2 className = "my-3 text-xl font-bold" > Customize Flowbite components using Tailwind CSS</ h2 >
29+ </ header >
30+ < p className = "mb-3" >
31+ You want to customize Flowbite. Specifically, you would like to remove/add Tailwind CSS classes to one or more
32+ components.
33+ </ p >
34+ < p className = "mb-3" >
35+ You have a few options. They each have benefits and drawbacks, and you can combine them how you want.
36+ </ p >
37+ < FlowbiteCustomizationOptionsTable />
38+ < BenefitsAndDrawbacks />
39+ </ section >
40+ ) ;
41+ } ;
42+
43+ const FlowbiteCustomizationOptionsTable : FC = ( ) => {
44+ return (
45+ < Table >
46+ < Table . Head >
47+ < Table . HeadCell className = "w-64" > Option</ Table . HeadCell >
48+ < Table . HeadCell > Example</ Table . HeadCell >
49+ </ Table . Head >
50+ < Table . Body >
51+ < Table . Row >
52+ < Table . Cell > Custom theme</ Table . Cell >
53+ < Table . Cell >
54+ < SyntaxHighlighter language = "tsx" style = { dracula } >
55+ { `const theme: CustomFlowbiteTheme = {
56+ accordion: {
57+ root: {
58+ base: 'bg-primary',
59+ },
60+ },
61+ };
62+
63+ <Flowbite theme={{ theme }}>...</Flowbite>` }
64+ </ SyntaxHighlighter >
65+ </ Table . Cell >
66+ </ Table . Row >
67+ < Table . Row >
68+ < Table . Cell >
69+ Custom component with < strong > className={}</ strong >
70+ </ Table . Cell >
71+ < Table . Cell >
72+ < SyntaxHighlighter language = "tsx" style = { dracula } >
73+ { `<Accordion className="bg-primary">
74+ <Accordion.Title>My accordion</Accordion.Title>
75+ <Accordion.Content>Contains</Accordion.Content>
76+ </Accordion>` }
77+ </ SyntaxHighlighter >
78+ </ Table . Cell >
79+ </ Table . Row >
80+ < Table . Row >
81+ < Table . Cell >
82+ Custom component with < strong > theme={}</ strong >
83+ </ Table . Cell >
84+ < Table . Cell >
85+ < SyntaxHighlighter language = "tsx" style = { dracula } >
86+ { `const accordionTheme: CustomFlowbiteTheme = {
87+ accordion: {
88+ root: {
89+ base: 'bg-primary',
90+ },
91+ },
92+ }
93+
94+ <Accordion theme={{ accordionTheme }}>
95+ <Accordion.Title>My accordion</Accordion.Title>
96+ <Accordion.Content>Contains</Accordion.Content>
97+ </Accordion>` }
98+ </ SyntaxHighlighter >
99+ </ Table . Cell >
100+ </ Table . Row >
101+ </ Table . Body >
102+ </ Table >
103+ ) ;
104+ } ;
105+
106+ const BenefitsAndDrawbacks : FC = ( ) => {
107+ return (
108+ < div >
109+ < h3 className = "mt-6 mb-3 text-lg font-bold" >
110+ Benefits & drawbacks of < strong > custom themes</ strong >
111+ </ h3 >
112+ < ul className = "list-none [&>li]:mb-2" >
113+ < Benefit > You can customize every component, one time, in one place</ Benefit >
114+ < Benefit > Changes will apply to every usage of the component in your app</ Benefit >
115+ < Benefit >
116+ < span >
117+ You get the best performance
118+ < span >
119+ < span className = "sr-only" > See disclaimer</ span >
120+ < sup aria-hidden > *</ sup >
121+ </ span >
122+ compared to other options
123+ </ span >
124+ </ Benefit >
125+ < Drawback > Customizations can quickly become complex and hard to maintain in one large JSON file</ Drawback >
126+ </ ul >
127+ < h3 className = "mt-6 mb-3 text-lg font-bold" >
128+ Benefits & drawbacks of
129+ < strong > custom components with className={}</ strong >
130+ </ h3 >
131+ < ul className = "list-none [&>li]:mb-2" >
132+ < Benefit > You can customize with very little effort and code</ Benefit >
133+ < Benefit > You don't need to learn how to use the theme API</ Benefit >
134+ < Drawback >
135+ < span >
136+ Some components have nested elements, and you can't customize all of them with one
137+ < strong > className</ strong >
138+ </ span >
139+ </ Drawback >
140+ < Drawback >
141+ You need to customize every usage of a component individually, or create and remember to use a custom
142+ component of your own
143+ </ Drawback >
144+ </ ul >
145+ < h3 className = "mt-6 mb-3 text-lg font-bold" >
146+ Benefits & drawbacks of
147+ < strong > custom components with theme={}</ strong >
148+ </ h3 >
149+ < ul className = "mb-6 list-none [&>li]:mb-2" >
150+ < Benefit > You can customize one usage of a component that has nested elements</ Benefit >
151+ < Benefit >
152+ You can still create a custom component of your own to reuse the customizations rather than repeating them
153+ </ Benefit >
154+ < Drawback > You add further complexity and indirection to your app</ Drawback >
155+ < Drawback >
156+ < span >
157+ Your app will probably perform worse at scale
158+ < span >
159+ < span className = "sr-only" > See disclaimer</ span >
160+ < sup aria-hidden > *</ sup >
161+ </ span >
162+ </ span >
163+ </ Drawback >
164+ </ ul >
165+ < p className = "text-gray-700 dark:text-gray-400" >
166+ < strong >
167+ < span className = "sr-only" > Disclaimer:</ span >
168+ < span aria-hidden > *</ span >
169+ </ strong >
170+ We haven't tested performance at any scale. The < strong > theme={}</ strong > attribute merges the
171+ necessary part of the global theme with what is provided in the attribute, which is a deep object merge —
172+ and it isn't fast. It is safe to assume that < strong > theme={}</ strong > attribute will degrade
173+ performance with enough components using that technique. It is safe to assume performance won't degrade
174+ meaningfully at scale if you just use a global theme and/or < strong > className={}</ strong > attributes.
175+ </ p >
176+ </ div >
177+ ) ;
178+ } ;
179+
180+ const Benefit : FC < PropsWithChildren > = ( { children } ) => {
181+ return (
182+ < li className = "flex items-center gap-3 leading-4 text-green-700 dark:text-green-100" >
183+ < span >
184+ < FaPlus aria-hidden className = "w-6" />
185+ < span className = "sr-only" > Benefit:</ span >
186+ </ span >
187+ { children }
188+ </ li >
189+ ) ;
190+ } ;
191+
192+ const Drawback : FC < PropsWithChildren > = ( { children } ) => {
193+ return (
194+ < li className = "flex items-center gap-3 leading-4 text-red-700 dark:text-red-100" >
195+ < span >
196+ < FaMinus aria-hidden className = "w-6" />
197+ < span className = "sr-only" > Drawback:</ span >
198+ </ span >
199+ { children }
200+ </ li >
201+ ) ;
202+ } ;
203+
204+ const SwitchToDarkModeSection : FC = ( ) => {
205+ return (
206+ < section className = "mb-6" >
207+ < header >
208+ < h2 className = "mb-3 text-xl font-bold" > Switch to dark theme</ h2 >
209+ </ header >
210+ < p className = "mb-3" >
42211 Since the Flowbite component creates and context to manage the theme, it also enables your application to use
43- the < strong > DarkThemeToggle</ strong > component.
212+ the < strong > < DarkThemeToggle/> </ strong > component.
44213 </ p >
45214 < Card >
46215 < SyntaxHighlighter language = "tsx" style = { dracula } >
@@ -58,20 +227,29 @@ const ThemePage: FC = () => {
58227 ) }
59228 </ SyntaxHighlighter >
60229 </ Card >
61- < span className = "text-xl font-bold" > Get the theme</ span >
62- < p >
63- For more customizations, there is the possibility to get the theme with the < strong > useTheme</ strong > hook and
64- its mode with the < strong > useThemeMode</ strong > hook.
230+ </ section >
231+ ) ;
232+ } ;
233+
234+ const ReadTheThemeSection : FC = ( ) => {
235+ return (
236+ < section className = "mb-6" >
237+ < header >
238+ < h2 className = "mb-3 text-xl font-bold" > Read the theme</ h2 >
239+ </ header >
240+ < p className = "mb-3" >
241+ You can obtain active Tailwind CSS Classes in the theme via < strong > useTheme</ strong > as well as the status of
242+ light/dark mode via < strong > useThemeMode</ strong > .
65243 </ p >
66244 < Card >
67245 < SyntaxHighlighter language = "tsx" style = { dracula } >
68- const theme = useTheme().theme.button;
246+ { ` const theme = useTheme().theme.button; // -> { base: "..", color: { ... }, ... }` }
69247 </ SyntaxHighlighter >
70248 < SyntaxHighlighter language = "tsx" style = { dracula } >
71- const [mode, setMode, toggleMode] = useThemeMode(usePreferences);
249+ { ` const [mode, setMode, toggleMode] = useThemeMode(usePreferences); // -> ["light", ..]` }
72250 </ SyntaxHighlighter >
73251 </ Card >
74- </ div >
252+ </ section >
75253 ) ;
76254} ;
77255
0 commit comments