Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions demo/demo/demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import reflex as rx

import reflex_ui as ui
from reflex_ui.blocks.lemcal import get_lemcal_script, lemcal_button, lemcal_calendar


class State(rx.State):
Expand Down Expand Up @@ -58,6 +59,12 @@ def index() -> rx.Component:
on_value_change=lambda value: rx.toast.success(f"Value: {value}"),
on_open_change=lambda value: rx.toast.success(f"Open: {value}"),
),
rx.el.h3("Lemcal Integration Demo", class_name="text-lg font-semibold mt-8 mb-4"),
lemcal_button(
ui.button("Book a Demo", variant="outline"),
class_name="mb-4",
),
lemcal_calendar(class_name="w-full max-w-md h-96 border rounded-lg"),
ui.theme_switcher(class_name="absolute top-4 right-4"),
class_name=ui.cn(
"flex flex-col gap-6 items-center justify-center h-screen", "bg-secondary-1"
Expand Down Expand Up @@ -85,6 +92,7 @@ def index() -> rx.Component:
href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400..700&display=swap",
rel="stylesheet",
),
get_lemcal_script(),
],
)
app.add_page(index)
1 change: 1 addition & 0 deletions reflex_ui/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"components.icons.hugeicon": ["hi", "icon"],
"components.icons.others": ["spinner"],
"utils.twmerge": ["cn"],
"blocks.lemcal": ["get_lemcal_script", "lemcal_button", "lemcal_calendar"],
}

getattr, __dir__, __all__ = lazy_loader.attach(
Expand Down
93 changes: 93 additions & 0 deletions reflex_ui/blocks/lemcal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
"""Lemcal booking integration for Reflex applications."""

from typing import Any

import reflex as rx

LEMCAL_SCRIPT_URL = "https://cdn.lemcal.com/lemcal-integrations.min.js"


def get_lemcal_script() -> rx.Component:
"""Generate Lemcal script component for a Reflex application.

Returns:
rx.Component: Script component needed for Lemcal integration
"""
return rx.el.script(
src=LEMCAL_SCRIPT_URL,
defer=True,
)


def lemcal_button(
child: rx.Component | None = None,
label: str = "Book a Demo",
class_name: str = "",
user_id: str = "usr_8tiwtJ8nEJaFj2qH9",
meeting_type: str = "met_ToQQ9dLZDYrEBv5qz",
**props: Any,
) -> rx.Component:
"""Reusable Lemcal embed button wrapper.

Wraps provided child (or a default button) in a div with the Lemcal
integration class and data attributes so that the external script can
attach the booking behavior.

Args:
child: Custom component to wrap (defaults to a button with label)
label: Default button text if no child provided
class_name: Additional CSS classes to apply
user_id: Lemcal user ID for booking integration
meeting_type: Lemcal meeting type ID for booking integration
**props: Additional props to pass to the wrapper div

Returns:
rx.Component: Lemcal button wrapper component
"""
content = child if child is not None else rx.el.button(label)
return rx.el.div(
content,
class_name=("lemcal-embed-button " + class_name).strip(),
custom_attrs={
"data-user": user_id,
"data-meeting-type": meeting_type,
},
**props,
)


def lemcal_calendar(
user_id: str = "usr_8tiwtJ8nEJaFj2qH9",
meeting_type: str = "met_ToQQ9dLZDYrEBv5qz",
class_name: str = "",
refresh_on_mount: bool = True,
**props: Any,
) -> rx.Component:
"""Lemcal booking calendar embed component.

Creates a div with the Lemcal calendar integration class and data attributes.
Optionally refreshes the Lemcal integration when the component mounts.

Args:
user_id: Lemcal user ID for booking integration
meeting_type: Lemcal meeting type ID for booking integration
class_name: Additional CSS classes to apply
refresh_on_mount: Whether to call window.lemcal.refresh() on mount
**props: Additional props to pass to the wrapper div

Returns:
rx.Component: Lemcal calendar embed component
"""
calendar_props = {
"class_name": ("lemcal-embed-booking-calendar " + class_name).strip(),
"custom_attrs": {
"data-user": user_id,
"data-meeting-type": meeting_type,
},
**props,
}

if refresh_on_mount:
calendar_props["on_mount"] = rx.call_function("window.lemcal.refresh")

return rx.el.div(**calendar_props)
22 changes: 22 additions & 0 deletions reflex_ui/blocks/lemcal.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""Lemcal booking integration for Reflex applications."""

from typing import Any

import reflex as rx

def get_lemcal_script() -> rx.Component: ...
def lemcal_button(
child: rx.Component | None = ...,
label: str = ...,
class_name: str = ...,
user_id: str = ...,
meeting_type: str = ...,
**props: Any,
) -> rx.Component: ...
def lemcal_calendar(
user_id: str = ...,
meeting_type: str = ...,
class_name: str = ...,
refresh_on_mount: bool = ...,
**props: Any,
) -> rx.Component: ...