Ver código fonte

Add vars and components for working with color_mode (#1132)

* `pc.color_mode`: a BaseVar that accesses colorMode on the frontend
* `pc.color_mode_cond`: a `pc.cond` wrapper that conditionally renders
  components or props based on the value of `color_mode`
* `pc.color_mode_icon`: by default "sun" if light mode, "moon" if dark mode
* `pc.color_mode_switch`: a Switch component where is_checked depends on the
  color_mode and changing the value calls toggle_color_mode
* `pc.color_mode_button`: a Button component that calls toggle_color_mode on click

The default template has been updated to include a color_mode_button with
color_mode_icon for toggling light/dark mode. The inline hover style has also
been updated to use color_mode_cond to show a different highlight color based
on the color_mode.
Masen Furer 1 ano atrás
pai
commit
aa2a1df201

+ 7 - 3
pynecone/.templates/apps/default/default.py

@@ -14,7 +14,8 @@ class State(pc.State):
 
 
 
 
 def index() -> pc.Component:
 def index() -> pc.Component:
-    return pc.center(
+    return pc.fragment(
+        pc.color_mode_button(pc.color_mode_icon(), float="right"),
         pc.vstack(
         pc.vstack(
             pc.heading("Welcome to Pynecone!", font_size="2em"),
             pc.heading("Welcome to Pynecone!", font_size="2em"),
             pc.box("Get started by editing ", pc.code(filename, font_size="1em")),
             pc.box("Get started by editing ", pc.code(filename, font_size="1em")),
@@ -25,13 +26,16 @@ def index() -> pc.Component:
                 padding="0.5em",
                 padding="0.5em",
                 border_radius="0.5em",
                 border_radius="0.5em",
                 _hover={
                 _hover={
-                    "color": "rgb(107,99,246)",
+                    "color": pc.color_mode_cond(
+                        light="rgb(107,99,246)",
+                        dark="rgb(179, 175, 255)",
+                    )
                 },
                 },
             ),
             ),
             spacing="1.5em",
             spacing="1.5em",
             font_size="2em",
             font_size="2em",
+            padding_top="10%",
         ),
         ),
-        padding_top="10%",
     )
     )
 
 
 
 

+ 1 - 0
pynecone/__init__.py

@@ -32,6 +32,7 @@ from .model import session as session
 from .route import route as route
 from .route import route as route
 from .state import ComputedVar as var
 from .state import ComputedVar as var
 from .state import State as State
 from .state import State as State
+from .style import color_mode as color_mode
 from .style import toggle_color_mode as toggle_color_mode
 from .style import toggle_color_mode as toggle_color_mode
 from .vars import Var as Var
 from .vars import Var as Var
 from .vars import cached_var as cached_var
 from .vars import cached_var as cached_var

+ 3 - 0
pynecone/components/__init__.py

@@ -238,3 +238,6 @@ text = Text.create
 script = ScriptTag.create
 script = ScriptTag.create
 aspect_ratio = AspectRatio.create
 aspect_ratio = AspectRatio.create
 kbd = KeyboardKey.create
 kbd = KeyboardKey.create
+color_mode_button = ColorModeButton.create
+color_mode_icon = ColorModeIcon.create
+color_mode_switch = ColorModeSwitch.create

+ 11 - 1
pynecone/components/forms/__init__.py

@@ -2,6 +2,12 @@
 
 
 from .button import Button, ButtonGroup
 from .button import Button, ButtonGroup
 from .checkbox import Checkbox, CheckboxGroup
 from .checkbox import Checkbox, CheckboxGroup
+from .colormodeswitch import (
+    ColorModeButton,
+    ColorModeIcon,
+    ColorModeSwitch,
+    color_mode_cond,
+)
 from .copytoclipboard import CopyToClipboard
 from .copytoclipboard import CopyToClipboard
 from .date_picker import DatePicker
 from .date_picker import DatePicker
 from .date_time_picker import DateTimePicker
 from .date_time_picker import DateTimePicker
@@ -34,4 +40,8 @@ from .switch import Switch
 from .textarea import TextArea
 from .textarea import TextArea
 from .upload import Upload
 from .upload import Upload
 
 
-__all__ = [f for f in dir() if f[0].isupper()]  # type: ignore
+helpers = [
+    "color_mode_cond",
+]
+
+__all__ = [f for f in dir() if f[0].isupper()] + helpers  # type: ignore

+ 116 - 0
pynecone/components/forms/colormodeswitch.py

@@ -0,0 +1,116 @@
+"""A switch component for toggling color_mode.
+
+To style components based on color mode, use style props with `color_mode_cond`:
+
+```
+pc.text(
+    "Hover over me",
+    _hover={
+        "background": pc.color_mode_cond(
+            light="var(--chakra-colors-gray-200)",
+            dark="var(--chakra-colors-gray-700)",
+        ),
+    },
+)
+```
+"""
+from __future__ import annotations
+
+from typing import Any
+
+from pynecone.components.component import Component
+from pynecone.components.layout.cond import Cond, cond
+from pynecone.components.media.icon import Icon
+from pynecone.style import color_mode, toggle_color_mode
+from pynecone.vars import BaseVar
+
+from .button import Button
+from .switch import Switch
+
+DEFAULT_COLOR_MODE = "light"
+DEFAULT_LIGHT_ICON = Icon.create(tag="sun")
+DEFAULT_DARK_ICON = Icon.create(tag="moon")
+
+
+def color_mode_cond(light: Any, dark: Any = None) -> BaseVar | Component:
+    """Create a component or Prop based on color_mode.
+
+    Args:
+        light: The component or prop to render if color_mode is default
+        dark: The component or prop to render if color_mode is non-default
+
+    Returns:
+        The conditional component or prop.
+    """
+    return cond(
+        color_mode == DEFAULT_COLOR_MODE,
+        light,
+        dark,
+    )
+
+
+class ColorModeIcon(Cond):
+    """Displays the current color mode as an icon."""
+
+    @classmethod
+    def create(
+        cls,
+        light_component: Component | None = None,
+        dark_component: Component | None = None,
+    ):
+        """Create an icon component based on color_mode.
+
+        Args:
+            light_component: the component to display when color mode is default
+            dark_component: the component to display when color mode is dark (non-default)
+
+        Returns:
+            The conditionally rendered component
+        """
+        return color_mode_cond(
+            light=light_component or DEFAULT_LIGHT_ICON,
+            dark=dark_component or DEFAULT_DARK_ICON,
+        )
+
+
+class ColorModeSwitch(Switch):
+    """Switch for toggling chakra light / dark mode via toggle_color_mode."""
+
+    @classmethod
+    def create(cls, *children, **props):
+        """Create a switch component bound to color_mode.
+
+        Args:
+            *children: The children of the component.
+            **props: The props to pass to the component.
+
+        Returns:
+            The switch component.
+        """
+        return Switch.create(
+            *children,
+            is_checked=color_mode != DEFAULT_COLOR_MODE,
+            on_change=toggle_color_mode,
+            **props,
+        )
+
+
+class ColorModeButton(Button):
+    """Button for toggling chakra light / dark mode via toggle_color_mode."""
+
+    @classmethod
+    def create(cls, *children, **props):
+        """Create a button component that calls toggle_color_mode on click.
+
+        Args:
+            *children: The children of the component.
+            **props: The props to pass to the component.
+
+        Returns:
+            The switch component.
+        """
+        return Button.create(
+            *children,
+            on_click=toggle_color_mode,
+            **props,
+        )

+ 1 - 0
pynecone/style.py

@@ -7,6 +7,7 @@ from pynecone.event import EventChain
 from pynecone.utils import format
 from pynecone.utils import format
 from pynecone.vars import BaseVar, Var
 from pynecone.vars import BaseVar, Var
 
 
+color_mode = BaseVar(name=constants.COLOR_MODE, type_="str")
 toggle_color_mode = BaseVar(name=constants.TOGGLE_COLOR_MODE, type_=EventChain)
 toggle_color_mode = BaseVar(name=constants.TOGGLE_COLOR_MODE, type_=EventChain)