diff --git a/demo/components_list.py b/demo/components_list.py index 8132fca1..41a653c5 100644 --- a/demo/components_list.py +++ b/demo/components_list.py @@ -268,6 +268,14 @@ class Delivery(BaseModel): ], class_name='border-top mt-3 pt-1', ), + c.Div( + components=[ + c.Heading(text='DarkMode', level=2), + c.Markdown(text='`DarkMode` can be used to toggle dark mode on and off.'), + c.DarkMode(), + ], + class_name='border-top mt-3 pt-1', + ), c.Div( components=[ c.Heading(text='Custom', level=2), diff --git a/demo/main.py b/demo/main.py index 0ce0b167..370651c8 100644 --- a/demo/main.py +++ b/demo/main.py @@ -36,6 +36,7 @@ def api_index() -> list[AnyComponent]: * `Image` - example [here](/components#image) * `Iframe` - example [here](/components#iframe) * `Video` - example [here](/components#video) +* `DarkMode` — example [here](/components#darkmode) * `Toast` - example [here](/components#toast) * `Table` — See [cities table](/table/cities) and [users table](/table/users) * `Pagination` — See the bottom of the [cities table](/table/cities) diff --git a/docs/api/python_components.md b/docs/api/python_components.md index 1d8b5663..081e530f 100644 --- a/docs/api/python_components.md +++ b/docs/api/python_components.md @@ -28,6 +28,7 @@ - Error - Spinner - Toast + - DarkMode - Custom - Table - Pagination diff --git a/src/npm-fastui-bootstrap/src/DarkMode.tsx b/src/npm-fastui-bootstrap/src/DarkMode.tsx new file mode 100644 index 00000000..746e55c0 --- /dev/null +++ b/src/npm-fastui-bootstrap/src/DarkMode.tsx @@ -0,0 +1,48 @@ +import { FC, useEffect, useState } from 'react' +import { models, useClassName } from 'fastui' + +export const DarkMode: FC = (props) => { + const [darkMode, setDarkMode] = useState(() => { + const localData = localStorage.getItem('fastui-dark-mode') + return localData ? JSON.parse(localData) : false + }) + + useEffect(() => { + localStorage.setItem('fastui-dark-mode', JSON.stringify(darkMode)) + document.documentElement.setAttribute('data-bs-theme', darkMode ? 'dark' : 'light') + }, [darkMode]) + + const handleDarkMode = (darkMode: boolean) => { + document.documentElement.setAttribute('data-bs-theme', darkMode ? 'dark' : 'light') + setDarkMode(darkMode) + } + + return ( + handleDarkMode(!darkMode)}> + {darkMode ? ( + + + + + ) : ( + + + + )} + + ) +} diff --git a/src/npm-fastui-bootstrap/src/index.tsx b/src/npm-fastui-bootstrap/src/index.tsx index 3341cb6a..46dfe9a8 100644 --- a/src/npm-fastui-bootstrap/src/index.tsx +++ b/src/npm-fastui-bootstrap/src/index.tsx @@ -5,6 +5,7 @@ import type { ClassNameGenerator, CustomRender, models } from 'fastui' import { Modal } from './modal' import { Navbar } from './navbar' import { Pagination } from './pagination' +import { DarkMode } from './DarkMode' import { Footer } from './footer' import { Toast } from './toast' @@ -19,6 +20,8 @@ export const customRender: CustomRender = (props) => { return () => case 'Pagination': return () => + case 'DarkMode': + return () => case 'Toast': return () => } diff --git a/src/npm-fastui/src/components/DarkMode.tsx b/src/npm-fastui/src/components/DarkMode.tsx new file mode 100644 index 00000000..636403c3 --- /dev/null +++ b/src/npm-fastui/src/components/DarkMode.tsx @@ -0,0 +1,7 @@ +import { FC } from 'react' + +import { DarkMode } from '../models' + +export const DarkModeComp: FC = (props: DarkMode) => { + return <>`${props.type} are not implemented by pure FastUI, implement a component for 'DarkModeProps'.` +} diff --git a/src/npm-fastui/src/components/index.tsx b/src/npm-fastui/src/components/index.tsx index d82b5754..d354b5ff 100644 --- a/src/npm-fastui/src/components/index.tsx +++ b/src/npm-fastui/src/components/index.tsx @@ -41,6 +41,7 @@ import { FireEventComp } from './FireEvent' import { ErrorComp } from './error' import { SpinnerComp } from './spinner' import { CustomComp } from './Custom' +import { DarkModeComp } from './DarkMode' import { ToastComp } from './toast' // TODO some better way to export components @@ -67,6 +68,7 @@ export { PaginationComp, DetailsComp, DisplayComp, + DarkModeComp, JsonComp, FooterComp, ServerLoadComp, @@ -168,6 +170,8 @@ export const AnyComp: FC = (props) => { return case 'Custom': return + case 'DarkMode': + return case 'Toast': return default: diff --git a/src/npm-fastui/src/models.d.ts b/src/npm-fastui/src/models.d.ts index 91fc18ad..1e718bfd 100644 --- a/src/npm-fastui/src/models.d.ts +++ b/src/npm-fastui/src/models.d.ts @@ -28,6 +28,7 @@ export type FastProps = | Error | Spinner | Custom + | DarkMode | Table | Pagination | Display @@ -339,6 +340,13 @@ export interface Custom { className?: ClassName type: 'Custom' } +/** + * DarkMode component + */ +export interface DarkMode { + className?: ClassName + type: 'DarkMode' +} /** * Table component. */ diff --git a/src/python-fastui/fastui/components/__init__.py b/src/python-fastui/fastui/components/__init__.py index f74fafc2..4b25213e 100644 --- a/src/python-fastui/fastui/components/__init__.py +++ b/src/python-fastui/fastui/components/__init__.py @@ -50,6 +50,7 @@ 'Spinner', 'Toast', 'Custom', + 'DarkMode', # then we include components from other files 'Table', 'Pagination', @@ -597,6 +598,13 @@ class Custom(BaseModel, extra='forbid'): """The type of the component. Always 'Custom'.""" +class DarkMode(BaseModel, extra='forbid'): + """DarkMode component""" + + class_name: _class_name.ClassNameField = None + type: _t.Literal['DarkMode'] = 'DarkMode' + + AnyComponent = _te.Annotated[ _t.Union[ Text, @@ -622,6 +630,7 @@ class Custom(BaseModel, extra='forbid'): Error, Spinner, Custom, + DarkMode, Table, Pagination, Display,