From b8aa6758a75d4a9935cd991344f74f926b94b72b Mon Sep 17 00:00:00 2001 From: Ahmad Hakim Date: Thu, 25 Jun 2026 19:41:03 +0300 Subject: [PATCH 1/2] add: blocks --- app/pages/blocks.py | 71 +++++++++++++++++++++++++++++++++++++++++++++ app/pages/charts.py | 6 ++-- 2 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 app/pages/blocks.py diff --git a/app/pages/blocks.py b/app/pages/blocks.py new file mode 100644 index 0000000..c4a1d94 --- /dev/null +++ b/app/pages/blocks.py @@ -0,0 +1,71 @@ +import reflex as rx + +from app.examples.utils import block_card +from app.templates.layout import layout_decorator +from app.www.library.blocks.bar_chart_01 import bar_chart_01 +from app.www.library.blocks.bar_chart_02 import bar_chart_02 +from app.www.library.blocks.bar_chart_03 import bar_chart_03 +from app.www.library.blocks.line_chart_01 import line_chart_01 +from app.www.library.blocks.line_chart_02 import line_chart_02 +from app.www.library.blocks.line_chart_03 import line_chart_03 +from components.ui.button import button + +GRID_LAYOUT = " ".join( + [ + "grid grid-cols-1 lg:grid-cols-2", + "divide-y lg:divide-y-0", + "lg:divide-x", + "[&>div]:p-4 items-stretch", + "divide-input/60", + "border-x border-input/40", + ] +) + + +@layout_decorator( + title="Building Blocks for Dashboards", + description="Clean, modern building blocks for Reflex dashboards. Copy and paste into your apps. Open Source. Extensible.", + ctas=[ + rx.el.a( + button("Create Your Own", size="sm"), + href="/create", + ), + rx.el.a( + button("View Components", variant="secondary", size="sm"), + href="/components", + ), + ], +) +def blocks_page(): + return rx.el.div( + rx.el.div( + block_card(bar_chart_01)(), + block_card(bar_chart_02)(), + class_name=GRID_LAYOUT, + ), + rx.el.hr(class_name="border border-input/40"), + block_card(bar_chart_03)(), + rx.el.hr(class_name="border border-input/40"), + rx.el.div( + block_card(line_chart_01)(), + block_card(line_chart_02)(), + class_name=GRID_LAYOUT, + ), + block_card(line_chart_03)(), + # rx.el.div(barchart_v5(), class_name="w-full p-7"), + # rx.el.hr(class_name="border border-input/40"), + # rx.el.div( + # areachart_v9(), radar_v6(), scatterchart_v1(), class_name=GRID_LAYOUT + # ), + # rx.el.hr(class_name="border border-input/40"), + # rx.el.div(linechart_v7(), class_name="w-full p-7"), + # rx.el.hr(class_name="border border-input/40"), + # rx.el.div(linechart_v5(), barchart_v9(), piechart_v1(), class_name=GRID_LAYOUT), + # rx.el.hr(class_name="border border-input/40"), + class_name=" ".join( + [ + "max-w-[96rem] mx-auto px-0 md:px-8", + "py-6 space-y-10", + ] + ), + ) diff --git a/app/pages/charts.py b/app/pages/charts.py index 348d890..bf0762e 100644 --- a/app/pages/charts.py +++ b/app/pages/charts.py @@ -32,12 +32,12 @@ description="A collection of ready-to-use chart components built with Recharts. From basic charts to rich data displays, copy and paste into your apps.", ctas=[ rx.el.a( - button("Chart Themes", size="sm"), - href="/create", + button("Browse Charts", size="sm"), + href="/docs/charts/area-chart", ), rx.el.a( button("Documentation", variant="secondary", size="sm"), - href="/docs/charts/area-chart", + href="/docs/components/chart", ), ], ) From 0cb72353559d0f45c9da8cd0d50f842328f31e87 Mon Sep 17 00:00:00 2001 From: Ahmad Hakim Date: Fri, 26 Jun 2026 20:10:30 +0300 Subject: [PATCH 2/2] new: blocks --- app/examples/utils.py | 112 +- app/export.py | 13 + app/hooks.py | 2 + app/pages/blocks.py | 83 +- app/registry/components.py | 49 + app/templates/navbar.py | 8 +- app/www/library/blocks/area_chart_01.py | 118 ++ app/www/library/blocks/area_chart_02.py | 117 ++ app/www/library/blocks/bar_chart_01.py | 114 ++ app/www/library/blocks/bar_chart_02.py | 99 ++ app/www/library/blocks/bar_chart_03.py | 119 ++ app/www/library/blocks/bar_chart_04.py | 79 ++ app/www/library/blocks/kpi_card_01.py | 55 + app/www/library/blocks/kpi_card_02.py | 117 ++ app/www/library/blocks/line_chart_01.py | 148 +++ app/www/library/blocks/line_chart_02.py | 167 +++ app/www/library/blocks/line_chart_03.py | 198 ++++ app/www/library/blocks/line_chart_04.py | 106 ++ app/www/library/charts/area/v1.py | 2 +- app/www/library/charts/area/v10.py | 2 +- app/www/library/charts/area/v2.py | 2 +- app/www/library/charts/area/v3.py | 2 +- app/www/library/charts/area/v4.py | 2 +- app/www/library/charts/area/v5.py | 2 +- app/www/library/charts/area/v6.py | 2 +- app/www/library/charts/area/v7.py | 2 +- app/www/library/charts/area/v8.py | 2 +- app/www/library/charts/area/v9.py | 2 +- app/www/library/charts/bar/docex_4.py | 2 +- app/www/library/charts/bar/docex_5.py | 2 +- app/www/library/charts/bar/v1.py | 2 +- app/www/library/charts/bar/v10.py | 107 -- app/www/library/charts/bar/v2.py | 2 +- app/www/library/charts/bar/v3.py | 2 +- app/www/library/charts/bar/v4.py | 2 +- app/www/library/charts/bar/v5.py | 2 +- app/www/library/charts/bar/v6.py | 2 +- app/www/library/charts/bar/v7.py | 2 +- app/www/library/charts/bar/v8.py | 2 +- app/www/library/charts/bar/v9.py | 2 +- app/www/library/charts/chart_tooltip.py | 55 +- app/www/library/charts/line/v1.py | 2 +- app/www/library/charts/line/v2.py | 2 +- app/www/library/charts/line/v3.py | 2 +- app/www/library/charts/line/v4.py | 2 +- app/www/library/charts/line/v5.py | 2 +- app/www/library/charts/line/v6.py | 2 +- app/www/library/charts/line/v7.py | 2 +- app/www/library/charts/line/v8.py | 2 +- assets/docs/charts/area-chart.md | 75 +- assets/docs/charts/bar-chart.md | 197 +-- assets/docs/charts/line-chart.md | 71 +- assets/docs/components/chart.md | 63 +- assets/fuse/searchList.json | 1450 ----------------------- assets/social/blocks.webp | Bin 0 -> 23808 bytes components/charts/chart_tooltip.py | 55 +- components/icons/hugeicon.py | 68 +- components/utils/twmerge.py | 15 +- dev.sh | 46 - docs/charts/bar_chart.md | 8 - docs/components/chart.md | 4 +- llms.txt | 25 - pyproject.toml | 2 +- reflex.lock/bun.lock | 54 +- reflex.lock/package.json | 10 +- scripts/generate_preview_cards.py | 5 + uv.lock | 20 +- 67 files changed, 1970 insertions(+), 2122 deletions(-) create mode 100644 app/www/library/blocks/area_chart_01.py create mode 100644 app/www/library/blocks/area_chart_02.py create mode 100644 app/www/library/blocks/bar_chart_01.py create mode 100644 app/www/library/blocks/bar_chart_02.py create mode 100644 app/www/library/blocks/bar_chart_03.py create mode 100644 app/www/library/blocks/bar_chart_04.py create mode 100644 app/www/library/blocks/kpi_card_01.py create mode 100644 app/www/library/blocks/kpi_card_02.py create mode 100644 app/www/library/blocks/line_chart_01.py create mode 100644 app/www/library/blocks/line_chart_02.py create mode 100644 app/www/library/blocks/line_chart_03.py create mode 100644 app/www/library/blocks/line_chart_04.py delete mode 100644 app/www/library/charts/bar/v10.py create mode 100644 assets/social/blocks.webp delete mode 100755 dev.sh delete mode 100644 llms.txt diff --git a/app/examples/utils.py b/app/examples/utils.py index d3964ce..2a0f20e 100644 --- a/app/examples/utils.py +++ b/app/examples/utils.py @@ -2,7 +2,117 @@ import reflex as rx -from app.hooks import selected_component_category +from app.hooks import selected_blocks_category, selected_component_category +from app.www.wrapper import generate_component_id +from components.icons.hugeicon import hi +from components.ui.button import button +from components.ui.tooltip import tooltip + + +def open_in_reflex_build( + icon_light, + icon_dark, + tooltip_content: str, + href: str, + icon_size: str = "size-5", +): + return tooltip.provider( + tooltip.root( + tooltip.trigger( + render_=rx.el.a( + rx.el.image( + rx.color_mode_cond(icon_light, icon_dark), + class_name=icon_size, + ), + href=href, + target="_blank", + rel="noopener noreferrer", + ) + ), + tooltip.portal( + tooltip.positioner( + tooltip.popup( + rx.el.p(tooltip_content, class_name="!text-xs"), + class_name="rounded-radius p-2", + ), + side="top", + side_offset=8, + ), + ), + ), + delay=0, + ) + + +def block_card(func=None, *, label=""): + """ + Decorator wrapper to wrap blocks + """ + + if func is None: + return functools.partial(block_card, label=label) + + @functools.wraps(func) + def wrapper(*args, **kwargs): + inner_component = func(*args, **kwargs) + cmd = f"uv run buridan add {func.__qualname__}" + btn_id = generate_component_id() + return rx.el.div( + rx.el.div( + button( + hi("TerminalIcon", class_name="size-4 shrink-0"), + cmd, + variant="outline", + size="sm", + id=btn_id, + on_click=rx.call_script(f""" + const btn = document.getElementById({btn_id!r}); + navigator.clipboard.writeText({cmd!r}); + + const original = btn.innerText; + btn.innerText = "Copied!"; + + setTimeout(() => {{ + btn.innerText = original; + }}, 1000); + """), + class_name="min-w-3xs", + ), + rx.el.p("︲", class_name="text-muted-foreground/50 font-thin h-6"), + open_in_reflex_build( + icon_light="/svg/reflex/reflex_light.svg", + icon_dark="/svg/reflex/reflex_dark.svg", + tooltip_content="Open in Reflex Build", + href=f"https://build.reflex.dev/?prompt=Install and run pip install buridan-create and buridan init. Then run the following command: buridan add {func.__qualname__}", + ), + class_name="flex flex-row gap-x-2 items-center justify-end px-6 sm:px-2", + ), + rx.el.div( + inner_component, + class_name=" ".join( + [ + "break-inside-avoid", + "w-full h-full", + "p-7", + "flex flex-col", + ] + ), + ), + class_name=" ".join( + [ + "w-full flex flex-col", + "gap-y-2", + ] + ) + + rx.cond( + (selected_blocks_category.value == "all") + | (selected_blocks_category.value == label), + " flex", + " hidden", + ).to(str), + ) + + return wrapper def masonry_card(func=None, *, label="General"): diff --git a/app/export.py b/app/export.py index a32d4b7..2977f66 100644 --- a/app/export.py +++ b/app/export.py @@ -1,5 +1,6 @@ import reflex as rx +from app.pages.blocks import blocks_page from app.pages.charts import chart_page from app.pages.components import components_page from app.pages.landing import landing_page @@ -35,6 +36,18 @@ def export_site(app: rx.App): ), ) + app.add_page( + component=blocks_page(), + route="/blocks", + title="Building Blocks for Dashboards - buridan/ui", + meta=generate_site_meta_tags( + title="Blocks", + url="/blocks", + description="Clean, modern building blocks for Reflex dashboards. Copy and paste into your apps. Open Source. Extensible.", + social_card="blocks.webp", + ), + ) + app.add_page( component=components_page(), route="/components", diff --git a/app/hooks.py b/app/hooks.py index 2274dbe..fd692e5 100644 --- a/app/hooks.py +++ b/app/hooks.py @@ -46,6 +46,8 @@ "selected_component_category", "All" ) +selected_blocks_category = ClientStateVar.create("selected_blocks_category", "all") + search_items_cs = ClientStateVar.create( "search_items_cs", routes.GET_STARTED_URLS + routes.BASE_UI_COMPONENTS + routes.CHARTS_URLS, diff --git a/app/pages/blocks.py b/app/pages/blocks.py index c4a1d94..d686647 100644 --- a/app/pages/blocks.py +++ b/app/pages/blocks.py @@ -1,24 +1,34 @@ +from pathlib import Path + import reflex as rx from app.examples.utils import block_card +from app.hooks import selected_blocks_category from app.templates.layout import layout_decorator +from app.www.library.blocks.area_chart_01 import area_chart_01 +from app.www.library.blocks.area_chart_02 import area_chart_02 from app.www.library.blocks.bar_chart_01 import bar_chart_01 from app.www.library.blocks.bar_chart_02 import bar_chart_02 from app.www.library.blocks.bar_chart_03 import bar_chart_03 +from app.www.library.blocks.bar_chart_04 import bar_chart_04 +from app.www.library.blocks.kpi_card_01 import kpi_card_01 +from app.www.library.blocks.kpi_card_02 import kpi_card_02 from app.www.library.blocks.line_chart_01 import line_chart_01 from app.www.library.blocks.line_chart_02 import line_chart_02 from app.www.library.blocks.line_chart_03 import line_chart_03 -from components.ui.button import button +from app.www.library.blocks.line_chart_04 import line_chart_04 +from components.ui.button import BUTTON_VARIANTS, button + +BLOCKS = [ + {"name": "All", "value": "all"}, + {"name": "Bar Charts", "value": "bar"}, + {"name": "Line Charts", "value": "line"}, + {"name": "Area Charts", "value": "area"}, + {"name": "KPI Cards", "value": "kpi"}, +] -GRID_LAYOUT = " ".join( - [ - "grid grid-cols-1 lg:grid-cols-2", - "divide-y lg:divide-y-0", - "lg:divide-x", - "[&>div]:p-4 items-stretch", - "divide-input/60", - "border-x border-input/40", - ] +NUM_BLOCK_FILES = len( + [f for f in Path("app/www/library/blocks").iterdir() if f.is_file()] ) @@ -39,33 +49,40 @@ def blocks_page(): return rx.el.div( rx.el.div( - block_card(bar_chart_01)(), - block_card(bar_chart_02)(), - class_name=GRID_LAYOUT, - ), - rx.el.hr(class_name="border border-input/40"), - block_card(bar_chart_03)(), - rx.el.hr(class_name="border border-input/40"), - rx.el.div( - block_card(line_chart_01)(), - block_card(line_chart_02)(), - class_name=GRID_LAYOUT, + *[ + button( + item["name"], + size="sm", + on_click=selected_blocks_category.set_value(item["value"]), + class_name="transition-none " + + rx.cond( + selected_blocks_category.value == item["value"], + BUTTON_VARIANTS["variant"]["default"], + BUTTON_VARIANTS["variant"]["outline"], + ).to(str), + ) + for item in BLOCKS + ], + class_name="w-full max-w-7xl mx-auto flex flex-row flex-wrap gap-4 items-center justify-center sm:justify-start p-7", ), - block_card(line_chart_03)(), - # rx.el.div(barchart_v5(), class_name="w-full p-7"), - # rx.el.hr(class_name="border border-input/40"), - # rx.el.div( - # areachart_v9(), radar_v6(), scatterchart_v1(), class_name=GRID_LAYOUT - # ), - # rx.el.hr(class_name="border border-input/40"), - # rx.el.div(linechart_v7(), class_name="w-full p-7"), - # rx.el.hr(class_name="border border-input/40"), - # rx.el.div(linechart_v5(), barchart_v9(), piechart_v1(), class_name=GRID_LAYOUT), - # rx.el.hr(class_name="border border-input/40"), + block_card(func=bar_chart_01, label="bar")(), + block_card(func=bar_chart_02, label="bar")(), + block_card(func=bar_chart_03, label="bar")(), + block_card(func=bar_chart_04, label="bar")(), + block_card(func=line_chart_01, label="line")(), + block_card(func=line_chart_02, label="line")(), + block_card(func=line_chart_03, label="line")(), + block_card(func=line_chart_04, label="line")(), + block_card(func=area_chart_01, label="area")(), + block_card(func=area_chart_02, label="area")(), + block_card(func=kpi_card_01, label="kpi")(), + block_card(func=kpi_card_02, label="kpi")(), class_name=" ".join( [ - "max-w-[96rem] mx-auto px-0 md:px-8", + "w-full max-w-7xl mx-auto px-0", + "divide-y divide-input/90", "py-6 space-y-10", + "[&>*:first-child]:border-b-0", ] ), ) diff --git a/app/registry/components.py b/app/registry/components.py index 9ac2d43..ab432ea 100644 --- a/app/registry/components.py +++ b/app/registry/components.py @@ -169,4 +169,53 @@ "files": ["components/ui/typography.py"], "dependencies": [], }, + # --- UI Blocks --- + "bar_chart_01": { + "files": ["app/www/library/blocks/bar_chart_01.py"], + "dependencies": ["field", "checkbox", "card", "charts"], + }, + "bar_chart_02": { + "files": ["app/www/library/blocks/bar_chart_02.py"], + "dependencies": ["card", "charts"], + }, + "bar_chart_03": { + "files": ["app/www/library/blocks/bar_chart_03.py"], + "dependencies": ["card", "charts"], + }, + "bar_chart_04": { + "files": ["app/www/library/blocks/bar_chart_04.py"], + "dependencies": ["card", "charts"], + }, + "line_chart_01": { + "files": ["app/www/library/blocks/line_chart_01.py"], + "dependencies": ["card", "charts"], + }, + "line_chart_02": { + "files": ["app/www/library/blocks/line_chart_02.py"], + "dependencies": ["card", "charts"], + }, + "line_chart_03": { + "files": ["app/www/library/blocks/line_chart_03.py"], + "dependencies": ["card", "charts"], + }, + "line_chart_04": { + "files": ["app/www/library/blocks/line_chart_04.py"], + "dependencies": ["card", "charts"], + }, + "area_chart_01": { + "files": ["app/www/library/blocks/area_chart_01.py"], + "dependencies": ["card", "charts"], + }, + "area_chart_02": { + "files": ["app/www/library/blocks/area_chart_02.py"], + "dependencies": ["frame", "charts"], + }, + "kpi_card_01": { + "files": ["app/www/library/blocks/kpi_card_01.py"], + "dependencies": ["frame"], + }, + "kpi_card_02": { + "files": ["app/www/library/blocks/kpi_card_02.py"], + "dependencies": ["frame"], + }, } diff --git a/app/templates/navbar.py b/app/templates/navbar.py index f4137c0..c90a60a 100644 --- a/app/templates/navbar.py +++ b/app/templates/navbar.py @@ -12,6 +12,7 @@ {"name": "Home", "path": "/"}, {"name": "Docs", "path": "/docs/getting-started/introduction"}, {"name": "Components", "path": "/components"}, + {"name": "Blocks", "path": "/blocks"}, {"name": "Charts", "path": "/charts"}, {"name": "Create", "path": "/create"}, ] @@ -87,6 +88,8 @@ def site_github() -> rx.Component: label="GitHub", ), href="https://github.com/LineIndent/ui", + target="_blank", + rel="noopener noreferrer", class_name="no-underline", ) @@ -98,10 +101,7 @@ def navbar(with_create_page_cta: bool = False) -> rx.Component: separator(), site_github(), separator(), - rx.el.a( - button(hi("PlusSignIcon", class_name="size-4"), "New", size="sm"), - href="/create", - ), + rx.el.a(button("New Project", size="sm"), href="/create"), ] if with_create_page_cta: diff --git a/app/www/library/blocks/area_chart_01.py b/app/www/library/blocks/area_chart_01.py new file mode 100644 index 0000000..2f62d5a --- /dev/null +++ b/app/www/library/blocks/area_chart_01.py @@ -0,0 +1,118 @@ +import reflex as rx + +from components.charts.chart_tooltip import chart_tooltip, chart_tooltip_content +from components.ui.card import card + +data = [ + {"date": "Jan 23", "Actual costs": 42340, "Potential costs": 32330}, + {"date": "Feb 23", "Actual costs": 50120, "Potential costs": 40100}, + {"date": "Mar 23", "Actual costs": 45190, "Potential costs": 38240}, + {"date": "Apr 23", "Actual costs": 56420, "Potential costs": 31200}, + {"date": "May 23", "Actual costs": 40420, "Potential costs": 34900}, + {"date": "Jun 23", "Actual costs": 47010, "Potential costs": 36800}, + {"date": "Jul 23", "Actual costs": 47490, "Potential costs": 34560}, + {"date": "Aug 23", "Actual costs": 39610, "Potential costs": 31260}, + {"date": "Sep 23", "Actual costs": 45860, "Potential costs": 29240}, + {"date": "Oct 23", "Actual costs": 50910, "Potential costs": 31220}, + {"date": "Nov 23", "Actual costs": 49190, "Potential costs": 33020}, + {"date": "Dec 23", "Actual costs": 55190, "Potential costs": 36090}, +] + +summary = [ + ("Actual costs", "$540,690", "chart-1"), + ("Potential costs", "$422,300", "chart-2"), + ("Potential savings (%)", "-21.9%", None), + ("Potential savings ($)", "$118,390", None), +] + + +def _gradient(id_: str, color: str) -> rx.Component: + return rx.el.svg.linear_gradient( + rx.el.svg.stop(stop_color=f"var(--{color})", offset="5%", stop_opacity=0.2), + rx.el.svg.stop(stop_color=f"var(--{color})", offset="95%", stop_opacity=0.2), + x1=0, + x2=0, + y1=0, + y2=1, + id=id_, + ) + + +def _area(data_key: str, color: str) -> rx.Component: + return rx.recharts.area( + data_key=data_key, + fill=f"url(#{data_key.replace(' ', '_')})", + stroke=f"var(--{color})", + stroke_width=2, + is_animation_active=False, + active_dot={"fill": f"var(--{color})", "stroke": f"var(--{color})"}, + dot=False, + ) + + +def _chart(show_y_axis: bool) -> rx.Component: + return rx.recharts.area_chart( + rx.el.svg.defs( + _gradient("Actual_costs", "chart-1"), + _gradient("Potential_costs", "chart-2"), + ), + chart_tooltip(), + rx.recharts.cartesian_grid( + horizontal=True, vertical=False, class_name="opacity-50" + ), + rx.recharts.x_axis( + data_key="date", + tick_line=False, + axis_line=False, + interval="preserveStartEnd", + ), + rx.recharts.y_axis( + width=55, + tick_line=False, + axis_line=False, + hide=not show_y_axis, + ), + _area("Actual costs", "chart-1"), + _area("Potential costs", "chart-2"), + data=data, + width="100%", + height=288, + ) + + +def area_chart_01(): + return card.root( + card.header( + card.title("Actual costs vs. potential costs"), + card.description( + "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt." + ), + ), + card.content( + rx.el.ul( + *[ + rx.el.li( + rx.el.div( + rx.el.span( + class_name=f"w-1 h-6 shrink-0 rounded-sm bg-{color}" + ) + if color + else None, + rx.el.p(total, class_name="text-lg font-semibold"), + class_name="flex items-center gap-2", + ), + rx.el.p( + category, + class_name="text-sm text-muted-foreground " + + ("pl-3" if color else ""), + ), + ) + for category, total, color in summary + ], + class_name="grid grid-cols-2 lg:grid-cols-4 gap-6 mb-8", + ), + rx.el.div(_chart(show_y_axis=False), class_name="sm:hidden"), + rx.el.div(_chart(show_y_axis=True), class_name="hidden sm:block"), + ), + class_name=chart_tooltip_content([1, 2], "square") + " w-full p-0", + ) diff --git a/app/www/library/blocks/area_chart_02.py b/app/www/library/blocks/area_chart_02.py new file mode 100644 index 0000000..076d3bc --- /dev/null +++ b/app/www/library/blocks/area_chart_02.py @@ -0,0 +1,117 @@ +import reflex as rx + +from components.charts.chart_tooltip import chart_tooltip, chart_tooltip_content +from components.ui.card import card + +data = [ + {"date": "Jan 23", "Organic": 232, "Sponsored": 0}, + {"date": "Feb 23", "Organic": 241, "Sponsored": 0}, + {"date": "Mar 23", "Organic": 291, "Sponsored": 0}, + {"date": "Apr 23", "Organic": 101, "Sponsored": 0}, + {"date": "May 23", "Organic": 318, "Sponsored": 0}, + {"date": "Jun 23", "Organic": 205, "Sponsored": 0}, + {"date": "Jul 23", "Organic": 372, "Sponsored": 0}, + {"date": "Aug 23", "Organic": 341, "Sponsored": 0}, + {"date": "Sep 23", "Organic": 387, "Sponsored": 120}, + {"date": "Oct 23", "Organic": 220, "Sponsored": 0}, + {"date": "Nov 23", "Organic": 372, "Sponsored": 0}, + {"date": "Dec 23", "Organic": 321, "Sponsored": 0}, +] + +summary = [ + ("Organic", "3,273", "chart-1"), + ("Sponsored", "120", "chart-2"), +] + + +def _gradient(id_: str, color: str) -> rx.Component: + return rx.el.svg.linear_gradient( + rx.el.svg.stop(stop_color=f"var(--{color})", offset="5%", stop_opacity=0.2), + rx.el.svg.stop(stop_color=f"var(--{color})", offset="95%", stop_opacity=0.2), + x1=0, + x2=0, + y1=0, + y2=1, + id=id_, + ) + + +def _area(data_key: str, color: str) -> rx.Component: + return rx.recharts.area( + data_key=data_key, + fill=f"url(#{data_key})", + stroke=f"var(--{color})", + stroke_width=2, + is_animation_active=False, + dot=False, + active_dot={"fill": f"var(--{color})", "stroke": f"var(--{color})"}, + ) + + +def _chart(show_y_axis: bool, start_end_only: bool = False) -> rx.Component: + return rx.recharts.area_chart( + rx.el.svg.defs( + _gradient("Organic", "chart-1"), + _gradient("Sponsored", "chart-2"), + ), + chart_tooltip(), + rx.recharts.cartesian_grid( + horizontal=True, vertical=False, class_name="opacity-50" + ), + rx.recharts.x_axis( + data_key="date", + tick_line=False, + axis_line=False, + interval="preserveStartEnd", + tick_count=2 if start_end_only else None, + tick_size=15, + custom_attrs={"fontSize": "11px"}, + ), + rx.recharts.y_axis( + width=30, + tick_line=False, + axis_line=False, + tick_size=15, + custom_attrs={"fontSize": "11px"}, + hide=not show_y_axis, + ), + _area("Organic", "chart-1"), + _area("Sponsored", "chart-2"), + data=data, + width="100%", + height=220, + ) + + +def area_chart_02(): + return card.root( + card.header( + card.title("Follower metrics"), + card.description("More power? Upgrade to get more insights."), + ), + card.content( + rx.el.div( + _chart(show_y_axis=False, start_end_only=True), class_name="sm:hidden" + ), + rx.el.div( + _chart(show_y_axis=True, start_end_only=False), + class_name="hidden sm:block", + ), + rx.el.ul( + *[ + rx.el.li( + rx.el.div( + rx.el.span(class_name=f"h-0.5 w-3 bg-{color}"), + rx.el.span(label, class_name="text-sm"), + class_name="flex items-center gap-2", + ), + rx.el.span(value, class_name="text-sm font-medium"), + class_name="flex items-center justify-between py-2 border-b border-input last:border-0", + ) + for label, value, color in summary + ], + class_name="mt-4 w-full", + ), + ), + class_name=chart_tooltip_content([1, 2], "square") + " w-full p-0", + ) diff --git a/app/www/library/blocks/bar_chart_01.py b/app/www/library/blocks/bar_chart_01.py new file mode 100644 index 0000000..85aaf72 --- /dev/null +++ b/app/www/library/blocks/bar_chart_01.py @@ -0,0 +1,114 @@ +import reflex as rx +from reflex.experimental import ClientStateVar + +from components.charts.chart_tooltip import chart_tooltip, chart_tooltip_content +from components.ui.card import card +from components.ui.checkbox import checkbox +from components.ui.field import field + +ShowComparison = ClientStateVar.create("show_comparison", False) + +data = [ + {"date": "Jan 23", "This Year": 68560, "Last Year": 28560}, + {"date": "Feb 23", "This Year": 70320, "Last Year": 30320}, + {"date": "Mar 23", "This Year": 80233, "Last Year": 70233}, + {"date": "Apr 23", "This Year": 55123, "Last Year": 45123}, + {"date": "May 23", "This Year": 56000, "Last Year": 80600}, + {"date": "Jun 23", "This Year": 100000, "Last Year": 85390}, + {"date": "Jul 23", "This Year": 85390, "Last Year": 45340}, + {"date": "Aug 23", "This Year": 80100, "Last Year": 70120}, + {"date": "Sep 23", "This Year": 75090, "Last Year": 69450}, + {"date": "Oct 23", "This Year": 71080, "Last Year": 63345}, + {"date": "Nov 23", "This Year": 61210, "Last Year": 100330}, + {"date": "Dec 23", "This Year": 60143, "Last Year": 45321}, +] + + +def _chart(show_y_axis: bool) -> rx.Component: + return rx.recharts.bar_chart( + chart_tooltip(), + rx.recharts.cartesian_grid( + horizontal=True, vertical=False, class_name="opacity-50" + ), + rx.recharts.x_axis( + data_key="date", + tick_line=False, + axis_line=False, + tick_size=15, + custom_attrs={"fontSize": "11px"}, + interval="preserveStartEnd", + ), + rx.recharts.y_axis( + width=55, + tick_line=False, + axis_line=False, + tick_size=15, + custom_attrs={"fontSize": "11px"}, + hide=not show_y_axis, + ), + rx.recharts.bar( + data_key="This Year", + fill="var(--chart-1)", + is_animation_active=False, + max_bar_size=40, + ), + rx.cond( + ShowComparison.value, + rx.recharts.bar( + data_key="Last Year", + fill="var(--chart-2)", + is_animation_active=False, + max_bar_size=40, + ), + ), + data=data, + width="100%", + height=250, + ) + + +def bar_chart_01(): + return card.root( + card.header( + card.title("Sales overview"), + card.description( + "Lorem ipsum dolor sit amet, consetetur sadipscing elitr." + ), + ), + rx.el.div( + rx.cond( + ShowComparison.value, + rx.el.div( + rx.el.div(class_name="w-3 h-3 rounded-sm bg-chart-2"), + "Last Year", + class_name="text-sm flex flex-row gap-x-2 items-center", + ), + ), + rx.el.div( + rx.el.div(class_name="w-3 h-3 rounded-sm bg-chart-1"), + "This Year", + class_name="text-sm flex flex-row gap-x-2 items-center", + ), + class_name="flex flex-row gap-x-2 justify-end items-center", + ), + card.content( + # Mobile: no y-axis + rx.el.div(_chart(show_y_axis=False), class_name="sm:hidden"), + # Desktop: with y-axis + rx.el.div(_chart(show_y_axis=True), class_name="hidden sm:block"), + ), + card.footer( + field.root( + checkbox( + id="terms-checkbox-basic", + on_checked_change=ShowComparison.set_value(~ShowComparison.value), + ), + field.label( + "Show same period last year", + html_for="terms-checkbox-basic", + ), + orientation="horizontal", + ), + ), + class_name=chart_tooltip_content([1, 2], "square") + " w-full p-0", + ) diff --git a/app/www/library/blocks/bar_chart_02.py b/app/www/library/blocks/bar_chart_02.py new file mode 100644 index 0000000..8b8f64d --- /dev/null +++ b/app/www/library/blocks/bar_chart_02.py @@ -0,0 +1,99 @@ +import reflex as rx + +from components.charts.chart_tooltip import chart_tooltip, chart_tooltip_content +from components.ui.card import card + +data = [ + {"date": "Jan 23", "This Year": 68560, "Last Year": 28560}, + {"date": "Feb 23", "This Year": 70320, "Last Year": 30320}, + {"date": "Mar 23", "This Year": 80233, "Last Year": 70233}, + {"date": "Apr 23", "This Year": 55123, "Last Year": 45123}, + {"date": "May 23", "This Year": 56000, "Last Year": 80600}, + {"date": "Jun 23", "This Year": 100000, "Last Year": 85390}, + {"date": "Jul 23", "This Year": 85390, "Last Year": 45340}, + {"date": "Aug 23", "This Year": 80100, "Last Year": 70120}, + {"date": "Sep 23", "This Year": 75090, "Last Year": 69450}, + {"date": "Oct 23", "This Year": 71080, "Last Year": 63345}, + {"date": "Nov 23", "This Year": 61210, "Last Year": 100330}, + {"date": "Dec 23", "This Year": 60143, "Last Year": 45321}, +] + + +def _chart(show_y_axis: bool) -> rx.Component: + return rx.recharts.bar_chart( + chart_tooltip(), + rx.recharts.cartesian_grid( + horizontal=True, vertical=False, class_name="opacity-50" + ), + rx.recharts.x_axis( + data_key="date", + tick_line=False, + axis_line=False, + tick_size=15, + custom_attrs={"fontSize": "11px"}, + interval="preserveStartEnd", + ), + rx.recharts.y_axis( + width=50, + tick_line=False, + axis_line=False, + tick_size=15, + custom_attrs={"fontSize": "11px"}, + hide=not show_y_axis, + ), + rx.recharts.bar( + data_key="Last Year", + fill="var(--chart-2)", + is_animation_active=False, + ), + rx.recharts.bar( + data_key="This Year", + fill="var(--chart-1)", + is_animation_active=False, + ), + data=data, + width="100%", + height=300, + ) + + +def bar_chart_02(): + return card.root( + card.header( + card.title("Sales overview"), + card.description( + "Lorem ipsum dolor sit amet, consetetur sadipscing elitr." + ), + ), + rx.el.ul( + rx.el.li( + rx.el.div( + rx.el.div(class_name="w-3 h-3 rounded-sm bg-chart-1"), + rx.el.p("This year", class_name="text-sm text-muted-foreground"), + class_name="flex items-center gap-1.5", + ), + rx.el.div( + rx.el.p("$0.8M", class_name="mt-0.5 text-base font-semibold"), + rx.el.span( + "+16%", + class_name="rounded px-1.5 py-0.5 text-xs font-medium bg-muted text-muted-foreground", + ), + class_name="flex items-center gap-1.5", + ), + ), + rx.el.li( + rx.el.div( + rx.el.div(class_name="w-3 h-3 rounded-sm bg-chart-2"), + rx.el.p("Last year", class_name="text-sm text-muted-foreground"), + class_name="flex items-center gap-1.5", + ), + rx.el.p("$0.7M", class_name="mt-0.5 text-base font-semibold"), + ), + class_name="flex gap-10", + ), + card.content( + rx.el.div(_chart(show_y_axis=False), class_name="sm:hidden"), + rx.el.div(_chart(show_y_axis=True), class_name="hidden sm:block"), + ), + class_name=chart_tooltip_content([1, 2], "square") + " w-full p-0", + ) diff --git a/app/www/library/blocks/bar_chart_03.py b/app/www/library/blocks/bar_chart_03.py new file mode 100644 index 0000000..431586d --- /dev/null +++ b/app/www/library/blocks/bar_chart_03.py @@ -0,0 +1,119 @@ +import reflex as rx +from reflex.experimental import ClientStateVar + +from components.charts.chart_tooltip import chart_tooltip, chart_tooltip_content +from components.ui.card import card + +data = [ + {"date": "Jan 23", "Running": 167, "Cycling": 145}, + {"date": "Feb 23", "Running": 125, "Cycling": 110}, + {"date": "Mar 23", "Running": 156, "Cycling": 149}, + {"date": "Apr 23", "Running": 165, "Cycling": 112}, + {"date": "May 23", "Running": 153, "Cycling": 138}, + {"date": "Jun 23", "Running": 124, "Cycling": 145}, + {"date": "Jul 23", "Running": 164, "Cycling": 134}, + {"date": "Aug 23", "Running": 123, "Cycling": 110}, + {"date": "Sep 23", "Running": 132, "Cycling": 113}, + {"date": "Oct 23", "Running": 124, "Cycling": 129}, + {"date": "Nov 23", "Running": 149, "Cycling": 101}, + {"date": "Dec 23", "Running": 129, "Cycling": 109}, +] + +_running_avg = round(sum(d["Running"] for d in data) / len(data)) +_cycling_avg = round(sum(d["Cycling"] for d in data) / len(data)) +_overall_avg = round((_running_avg + _cycling_avg) / 2) + +ShowRunning = ClientStateVar.create("show_running", True) +ShowCycling = ClientStateVar.create("show_cycling", True) +AvgBPM = ClientStateVar.create("avg_bpm", _overall_avg) + + +def _legend_item(label: str, color: str, is_active: ClientStateVar) -> rx.Component: + return rx.el.button( + rx.el.div( + rx.el.span(class_name=f"size-3 rounded-sm {color}"), + rx.el.p(label, class_name="text-sm text-muted-foreground"), + class_name="flex items-center gap-1.5", + ), + on_click=is_active.set_value(~is_active.value), + class_name=rx.cond( + is_active.value, + "text-left opacity-100 cursor-pointer", + "text-left opacity-40 cursor-pointer", + ), + ) + + +def _chart(show_y_axis: bool) -> rx.Component: + return rx.recharts.bar_chart( + chart_tooltip(), + rx.recharts.cartesian_grid( + horizontal=True, vertical=False, class_name="opacity-50" + ), + rx.recharts.x_axis( + data_key="date", + tick_line=False, + axis_line=False, + tick_size=15, + custom_attrs={"fontSize": "11px"}, + interval="preserveStartEnd", + ), + rx.recharts.y_axis( + width=30, + tick_line=False, + axis_line=False, + tick_size=15, + custom_attrs={"fontSize": "11px"}, + hide=not show_y_axis, + ), + rx.recharts.bar( + data_key="Running", + fill="var(--chart-2)", + is_animation_active=False, + class_name=rx.cond(ShowRunning.value, "opacity-100", "opacity-50").to(str), + ), + rx.recharts.bar( + data_key="Cycling", + fill="var(--chart-3)", + is_animation_active=False, + class_name=rx.cond(ShowCycling.value, "opacity-100", "opacity-50").to(str), + ), + data=data, + width="100%", + height=300, + ) + + +def bar_chart_03(): + return card.root( + card.header( + card.title("Average BPM"), + rx.el.p( + rx.cond( + ShowRunning.value & ShowCycling.value, + str(_overall_avg), + rx.cond( + ShowRunning.value, + str(_running_avg), + rx.cond( + ShowCycling.value, + str(_cycling_avg), + "0", + ), + ), + ), + "bpm", + class_name="text-3xl font-bold", + ), + ), + rx.el.ul( + _legend_item("Running", "bg-chart-2", ShowRunning), + _legend_item("Cycling", "bg-chart-3", ShowCycling), + class_name="flex gap-10 items-center justify-end", + ), + card.content( + rx.el.div(_chart(show_y_axis=False), class_name="sm:hidden"), + rx.el.div(_chart(show_y_axis=True), class_name="hidden sm:block"), + ), + class_name=chart_tooltip_content([2, 3], "square") + " w-full p-0", + ) diff --git a/app/www/library/blocks/bar_chart_04.py b/app/www/library/blocks/bar_chart_04.py new file mode 100644 index 0000000..5af0506 --- /dev/null +++ b/app/www/library/blocks/bar_chart_04.py @@ -0,0 +1,79 @@ +import reflex as rx + +from components.charts.chart_tooltip import chart_tooltip, chart_tooltip_content +from components.ui.card import card + +data = [ + {"hour": "00:00", "temperature": 12.8}, + {"hour": "01:00", "temperature": 12.4}, + {"hour": "02:00", "temperature": 12.2}, + {"hour": "03:00", "temperature": 11.9}, + {"hour": "04:00", "temperature": 11.7}, + {"hour": "05:00", "temperature": 11.5}, + {"hour": "06:00", "temperature": 11.3}, + {"hour": "07:00", "temperature": 11.2}, + {"hour": "08:00", "temperature": 11.5}, + {"hour": "09:00", "temperature": 12.0}, + {"hour": "10:00", "temperature": 13.0}, + {"hour": "11:00", "temperature": 14.2}, + {"hour": "12:00", "temperature": 15.5}, + {"hour": "13:00", "temperature": 16.8}, + {"hour": "14:00", "temperature": 17.5}, + {"hour": "15:00", "temperature": 18.1}, + {"hour": "16:00", "temperature": 18.2}, + {"hour": "17:00", "temperature": 17.8}, + {"hour": "18:00", "temperature": 17.2}, + {"hour": "19:00", "temperature": 16.5}, + {"hour": "20:00", "temperature": 15.8}, + {"hour": "21:00", "temperature": 14.9}, + {"hour": "22:00", "temperature": 14.2}, + {"hour": "23:00", "temperature": 13.5}, +] + + +def _chart(show_y_axis: bool) -> rx.Component: + return rx.recharts.bar_chart( + rx.recharts.cartesian_grid( + horizontal=True, vertical=False, class_name="opacity-50" + ), + rx.recharts.x_axis( + data_key="hour", + tick_line=False, + axis_line=False, + interval="preserveStartEnd", + label={ + "value": "24H Temperature Readout (Zurich)", + "position": "insideBottom", + "offset": -5, + "style": {"fill": "var(--muted-foreground)", "fontSize": "12px"}, + }, + ), + rx.recharts.y_axis( + width=40, + tick_line=False, + axis_line=False, + hide=not show_y_axis, + ), + rx.recharts.bar( + data_key="temperature", + fill="var(--chart-1)", + is_animation_active=False, + ), + data=data, + width="100%", + height=300, + ) + + +def bar_chart_04(): + return card.root( + card.header( + card.title("Temperature"), + card.description("Zurich — 24 hour readout"), + ), + card.content( + rx.el.div(_chart(show_y_axis=False), class_name="sm:hidden"), + rx.el.div(_chart(show_y_axis=True), class_name="hidden sm:block"), + ), + class_name=chart_tooltip_content([1], "square") + " w-full p-0", + ) diff --git a/app/www/library/blocks/kpi_card_01.py b/app/www/library/blocks/kpi_card_01.py new file mode 100644 index 0000000..8806654 --- /dev/null +++ b/app/www/library/blocks/kpi_card_01.py @@ -0,0 +1,55 @@ +import reflex as rx + +from components.ui.card import card + +data = [ + { + "name": "Monthly active users", + "stat": "996", + "change": "+1.3%", + "color": "bg-chart-1", + }, + { + "name": "Monthly sessions", + "stat": "1,672", + "change": "+9.1%", + "color": "bg-chart-2", + }, + { + "name": "Monthly user growth", + "stat": "5.1%", + "change": "-4.8%", + "color": "bg-chart-3", + }, +] + + +def _kpi_card(name: str, stat: str, change: str, color: str) -> rx.Component: + is_positive = change.startswith("+") + return card.root( + rx.el.div( + rx.el.div(class_name=f"w-1 shrink-0 rounded {color}"), + rx.el.div( + rx.el.span(name, class_name="truncate text-sm text-muted-foreground"), + rx.el.span( + change, + class_name="text-sm font-medium " + + ("text-emerald-600" if is_positive else "text-red-600"), + ), + class_name="flex w-full items-center justify-between gap-3 truncate", + ), + class_name="flex gap-3", + ), + rx.el.div( + rx.el.p(stat, class_name="text-3xl font-semibold"), + class_name="mt-2 pl-4", + ), + class_name="w-full border border-input/80 rounded-2xl", + ) + + +def kpi_card_01(): + return rx.el.dl( + *[_kpi_card(**item) for item in data], + class_name="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3", + ) diff --git a/app/www/library/blocks/kpi_card_02.py b/app/www/library/blocks/kpi_card_02.py new file mode 100644 index 0000000..4522df6 --- /dev/null +++ b/app/www/library/blocks/kpi_card_02.py @@ -0,0 +1,117 @@ +import reflex as rx + +from components.charts.chart_tooltip import chart_tooltip, chart_tooltip_content +from components.ui.card import card + +data = [ + {"date": "Jan 23", "users": 234, "sessions": 1432, "churn": 5.2}, + {"date": "Feb 23", "users": 431, "sessions": 1032, "churn": 4.3}, + {"date": "Mar 23", "users": 543, "sessions": 1089, "churn": 5.1}, + {"date": "Apr 23", "users": 489, "sessions": 988, "churn": 5.4}, + {"date": "May 23", "users": 391, "sessions": 642, "churn": 5.5}, + {"date": "Jun 23", "users": 582, "sessions": 786, "churn": 4.8}, + {"date": "Jul 23", "users": 482, "sessions": 673, "churn": 4.5}, + {"date": "Aug 23", "users": 389, "sessions": 761, "churn": 0}, + {"date": "Sep 23", "users": 521, "sessions": 793, "churn": 0}, + {"date": "Oct 23", "users": 434, "sessions": 543, "churn": 0}, + {"date": "Nov 23", "users": 332, "sessions": 678, "churn": 0}, + {"date": "Dec 23", "users": 275, "sessions": 873, "churn": 0}, +] + +categories = [ + { + "name": "Monthly users", + "key": "users", + "color": 1, + "avg": round(sum(d["users"] for d in data) / len(data)), + "suffix": "", + }, + { + "name": "Monthly sessions", + "key": "sessions", + "color": 2, + "avg": round(sum(d["sessions"] for d in data) / len(data)), + "suffix": "", + }, + { + "name": "Monthly churn", + "key": "churn", + "color": 3, + "avg": round(sum(d["churn"] for d in data) / len(data), 1), + "suffix": "%", + }, +] + + +def _gradient(id_: str, color: int) -> rx.Component: + return rx.el.svg.linear_gradient( + rx.el.svg.stop( + stop_color=f"var(--chart-{color})", offset="5%", stop_opacity=0.2 + ), + rx.el.svg.stop( + stop_color=f"var(--chart-{color})", offset="95%", stop_opacity=0.2 + ), + x1=0, + x2=0, + y1=0, + y2=1, + id=id_, + ) + + +def _mini_chart(key: str, color: int) -> rx.Component: + return rx.recharts.area_chart( + chart_tooltip(label="hide"), + rx.el.svg.defs(_gradient(key, color)), + rx.recharts.x_axis( + data_key="date", + tick_line=False, + axis_line=False, + interval="preserveStartEnd", + custom_attrs={"fontSize": "10px"}, + ), + rx.recharts.y_axis(hide=True), + rx.recharts.area( + data_key=key, + fill=f"url(#{key})", + stroke=f"var(--chart-{color})", + stroke_width=2, + dot=False, + is_animation_active=False, + active_dot={"fill": "var(--chart-1)", "stroke": f"var(--chart-{color})"}, + ), + data=data, + width="100%", + height=100, + ) + + +def _kpi_mini_chart( + name: str, key: str, color: int, avg: float, suffix: str +) -> rx.Component: + return card.root( + card.content( + rx.el.p(name, class_name="text-sm text-muted-foreground"), + rx.el.div( + rx.el.span( + f"{avg:,}{suffix}", + class_name="text-xl font-semibold", + ), + rx.el.span( + "12-month avg", + class_name="text-sm text-muted-foreground", + ), + class_name="mt-1 flex items-baseline justify-between gap-2", + ), + _mini_chart(key, color), + ), + class_name=chart_tooltip_content([color], "square") + + " w-full px-4 pt-4 pb-0 border border-input/80 rounded-2xl", + ) + + +def kpi_card_02(): + return rx.el.dl( + *[_kpi_mini_chart(**item) for item in categories], + class_name="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3", + ) diff --git a/app/www/library/blocks/line_chart_01.py b/app/www/library/blocks/line_chart_01.py new file mode 100644 index 0000000..2a94c6e --- /dev/null +++ b/app/www/library/blocks/line_chart_01.py @@ -0,0 +1,148 @@ +import reflex as rx + +from components.charts.chart_tooltip import chart_tooltip, chart_tooltip_content +from components.ui.card import card + +data = [ + {"date": "Aug 01", "price": 21.2}, + {"date": "Aug 02", "price": 29.0}, + {"date": "Aug 03", "price": 48.5}, + {"date": "Aug 04", "price": 53.8}, + {"date": "Aug 05", "price": 57.7}, + {"date": "Aug 06", "price": 59.9}, + {"date": "Aug 07", "price": 41.4}, + {"date": "Aug 08", "price": 60.2}, + {"date": "Aug 09", "price": 62.8}, + {"date": "Aug 10", "price": 62.5}, + {"date": "Aug 11", "price": 63.6}, + {"date": "Aug 12", "price": 64.4}, + {"date": "Aug 13", "price": 65.1}, + {"date": "Aug 14", "price": 66.4}, + {"date": "Aug 15", "price": 71.6}, + {"date": "Aug 16", "price": 79.5}, + {"date": "Aug 17", "price": 102.8}, + {"date": "Aug 18", "price": 103.2}, + {"date": "Aug 19", "price": 105.4}, + {"date": "Aug 20", "price": 110.9}, + {"date": "Aug 21", "price": 67.7}, + {"date": "Aug 22", "price": 69.8}, + {"date": "Aug 23", "price": 79.5}, + {"date": "Aug 24", "price": 90.0}, + {"date": "Aug 25", "price": 91.2}, + {"date": "Aug 26", "price": 95.1}, + {"date": "Aug 27", "price": 99.8}, + {"date": "Aug 28", "price": 100.6}, + {"date": "Aug 29", "price": 102.8}, + {"date": "Aug 30", "price": 100.5}, + {"date": "Aug 31", "price": 111.6}, + {"date": "Sep 01", "price": 123.2}, + {"date": "Sep 02", "price": 125.8}, + {"date": "Sep 03", "price": 120.4}, + {"date": "Sep 04", "price": 121.9}, + {"date": "Sep 05", "price": 124.5}, + {"date": "Sep 06", "price": 127.7}, + {"date": "Sep 07", "price": 129.2}, + {"date": "Sep 08", "price": 130.8}, + {"date": "Sep 09", "price": 134.4}, + {"date": "Sep 10", "price": 136.0}, + {"date": "Sep 11", "price": 137.5}, + {"date": "Sep 12", "price": 131.1}, + {"date": "Sep 13", "price": 128.6}, + {"date": "Sep 14", "price": 124.2}, + {"date": "Sep 15", "price": 120.8}, + {"date": "Sep 16", "price": 118.3}, + {"date": "Sep 17", "price": 101.9}, + {"date": "Sep 18", "price": 121.5}, + {"date": "Sep 19", "price": 129.1}, + {"date": "Sep 20", "price": 131.6}, + {"date": "Sep 21", "price": 141.2}, + {"date": "Sep 22", "price": 142.8}, + {"date": "Sep 23", "price": 143.3}, + {"date": "Sep 24", "price": 149.9}, + {"date": "Sep 25", "price": 159.5}, + {"date": "Sep 26", "price": 173.3}, +] + +summary = [ + ("Open", "$153.56"), + ("High", "$154.78"), + ("Volume", "$48.14M"), + ("Low", "$179.12"), + ("Close", "$173.34"), + ("Market Cap", "$1.58B"), +] + + +def _summary_list(items: list[tuple[str, str]]) -> rx.Component: + return rx.el.ul( + *[ + rx.el.li( + rx.el.span(label, class_name="text-sm text-muted-foreground truncate"), + rx.el.span(value, class_name="text-sm font-medium"), + class_name="flex items-center justify-between gap-4 py-1.5 border-b border-input last:border-0", + ) + for label, value in items + ], + class_name="w-full", + ) + + +def _chart(show_y_axis: bool) -> rx.Component: + return rx.recharts.line_chart( + chart_tooltip(), + rx.recharts.cartesian_grid( + horizontal=True, vertical=False, class_name="opacity-50" + ), + rx.recharts.x_axis( + data_key="date", + tick_line=False, + axis_line=False, + tick_size=15, + custom_attrs={"fontSize": "11px"}, + interval="preserveStartEnd", + ), + rx.recharts.y_axis( + width=30, + tick_line=False, + axis_line=False, + tick_size=15, + custom_attrs={"fontSize": "12px"}, + hide=not show_y_axis, + ), + rx.recharts.line( + data_key="price", + stroke="var(--chart-1)", + stroke_width=2, + dot=False, + is_animation_active=False, + active_dot={"fill": "var(--chart-1)", "stroke": "var(--chart-1)"}, + ), + data=data, + width="100%", + height=250, + ) + + +def line_chart_01(): + return card.root( + card.header( + rx.el.p("Amazon, Inc. (AMZN)", class_name="text-sm text-muted-foreground"), + rx.el.p("$173.30", class_name="mt-1 text-3xl font-semibold"), + rx.el.p( + rx.el.span("+$9.30 (8.6%)", class_name="text-emerald-600 font-medium"), + " ", + rx.el.span("Past 24 hours", class_name="text-muted-foreground"), + class_name="mt-1 text-sm", + ), + ), + card.content( + rx.el.div(_chart(show_y_axis=False), class_name="sm:hidden"), + rx.el.div(_chart(show_y_axis=True), class_name="hidden sm:block"), + rx.el.div( + _summary_list(summary[:3]), + _summary_list(summary[3:]), + class_name="mt-4 flex items-start gap-6", + ), + ), + class_name=chart_tooltip_content([1], "square") + " w-full p-0", + ) diff --git a/app/www/library/blocks/line_chart_02.py b/app/www/library/blocks/line_chart_02.py new file mode 100644 index 0000000..77d31dc --- /dev/null +++ b/app/www/library/blocks/line_chart_02.py @@ -0,0 +1,167 @@ +import reflex as rx + +from components.charts.chart_tooltip import chart_tooltip, chart_tooltip_content +from components.ui.card import card + +data = [ + {"date": "Jan 23", "Munich": 42340, "Zurich": 22320, "Vienna": 12410}, + {"date": "Feb 23", "Munich": 50120, "Zurich": 32310, "Vienna": 10300}, + {"date": "Mar 23", "Munich": 45190, "Zurich": 23450, "Vienna": 10900}, + {"date": "Apr 23", "Munich": 56420, "Zurich": 13400, "Vienna": 7900}, + {"date": "May 23", "Munich": 40420, "Zurich": 16400, "Vienna": 12310}, + {"date": "Jun 23", "Munich": 47010, "Zurich": 18350, "Vienna": 10250}, + {"date": "Jul 23", "Munich": 47490, "Zurich": 19950, "Vienna": 12650}, + {"date": "Aug 23", "Munich": 39610, "Zurich": 10910, "Vienna": 4650}, + {"date": "Sep 23", "Munich": 45860, "Zurich": 24740, "Vienna": 12650}, + {"date": "Oct 23", "Munich": 50910, "Zurich": 15740, "Vienna": 10430}, + {"date": "Nov 23", "Munich": 4919, "Zurich": 2874, "Vienna": 2081}, + {"date": "Dec 23", "Munich": 5519, "Zurich": 2274, "Vienna": 1479}, +] + + +summary = [ + { + "location": "Munich", + "address": "Maximilianstrasse", + "color": "-chart-1", + "type": "Flagship", + "total": "$460.2K", + "change": "+0.7%", + "change_type": "positive", + }, + { + "location": "Zurich", + "address": "Bahnhofstrasse", + "color": "-chart-2", + "type": "In-Store", + "total": "$237.3K", + "change": "-1.2%", + "change_type": "negative", + }, + { + "location": "Vienna", + "address": "Stephansplatz", + "color": "-chart-3", + "type": "In-Store", + "total": "$118.2K", + "change": "+4.6%", + "change_type": "positive", + }, +] + + +def _chart(show_y_axis: bool) -> rx.Component: + return rx.recharts.line_chart( + chart_tooltip(), + rx.recharts.cartesian_grid( + horizontal=True, + vertical=False, + class_name="opacity-50", + ), + rx.recharts.x_axis( + data_key="date", + tick_line=False, + axis_line=False, + tick_size=15, + interval="preserveStartEnd", + custom_attrs={"fontSize": "11px"}, + ), + rx.recharts.y_axis( + width=50, + tick_line=False, + axis_line=False, + tick_size=15, + custom_attrs={"fontSize": "12px"}, + hide=not show_y_axis, + ), + rx.recharts.line( + data_key="Munich", + stroke="var(--chart-1)", + stroke_width=2, + dot=False, + is_animation_active=False, + active_dot={"fill": "var(--chart-1)", "stroke": "var(--chart-1)"}, + ), + rx.recharts.line( + data_key="Zurich", + stroke="var(--chart-2)", + stroke_width=2, + dot=False, + is_animation_active=False, + active_dot={"fill": "var(--chart-2)", "stroke": "var(--chart-2)"}, + ), + rx.recharts.line( + data_key="Vienna", + stroke="var(--chart-3)", + stroke_width=2, + dot=False, + is_animation_active=False, + active_dot={"fill": "var(--chart-3)", "stroke": "var(--chart-3)"}, + ), + data=data, + width="100%", + height=270, + ) + + +def _summary_item(item: dict) -> rx.Component: + is_positive = item["change_type"] == "positive" + + return rx.el.div( + rx.el.div( + rx.el.div( + class_name=f"size-3 rounded-sm bg{item['color']}", + ), + rx.el.div( + rx.el.p( + item["location"], + class_name="text-sm font-medium", + ), + rx.el.span( + item["type"], + class_name="rounded bg-muted px-1.5 py-0.5 text-xs", + ), + class_name="flex items-center gap-2", + ), + class_name="flex items-center gap-2", + ), + rx.el.div( + rx.el.span( + item["address"], + class_name="text-xs text-muted-foreground", + ), + ), + rx.el.div( + rx.el.p( + item["change"], + class_name=( + "text-sm font-medium " + + ("text-emerald-600" if is_positive else "text-red-600") + ), + ), + rx.el.span( + item["total"], + class_name="text-xs text-muted-foreground", + ), + class_name="text-right", + ), + class_name="flex items-center justify-between py-2 border-b border-input last:border-0", + ) + + +def line_chart_02(): + return card.root( + card.header( + rx.el.p("Revenue", class_name="text-sm text-muted-foreground"), + rx.el.p("$815,700", class_name="text-3xl font-semibold"), + ), + card.content( + rx.el.div(_chart(show_y_axis=True), class_name="hidden sm:block"), + rx.el.div(_chart(show_y_axis=False), class_name="sm:hidden"), + rx.el.div( + *[_summary_item(item) for item in summary], + class_name="mt-4 flex flex-col", + ), + ), + class_name=chart_tooltip_content([1, 2, 3], "line") + " w-full p-0", + ) diff --git a/app/www/library/blocks/line_chart_03.py b/app/www/library/blocks/line_chart_03.py new file mode 100644 index 0000000..17cf82f --- /dev/null +++ b/app/www/library/blocks/line_chart_03.py @@ -0,0 +1,198 @@ +import reflex as rx + +from components.charts.chart_tooltip import ( + chart_tooltip, + chart_tooltip_content, +) +from components.ui.card import card + +data = [ + {"date": "Aug 01", "Market Index": 44.1, "Portfolio": 79.2}, + {"date": "Aug 02", "Market Index": 49.1, "Portfolio": 89.1}, + {"date": "Aug 03", "Market Index": 61.2, "Portfolio": 91.7}, + {"date": "Aug 04", "Market Index": 49.7, "Portfolio": 74.4}, + {"date": "Aug 05", "Market Index": 71.1, "Portfolio": 95.3}, + {"date": "Aug 06", "Market Index": 75.3, "Portfolio": 99.4}, + {"date": "Aug 07", "Market Index": 74.1, "Portfolio": 101.2}, + {"date": "Aug 08", "Market Index": 78.4, "Portfolio": 102.2}, + {"date": "Aug 09", "Market Index": 81.1, "Portfolio": 103.6}, + {"date": "Aug 10", "Market Index": 82.6, "Portfolio": 104.4}, + {"date": "Aug 11", "Market Index": 89.3, "Portfolio": 106.3}, + {"date": "Aug 12", "Market Index": 79.3, "Portfolio": 109.5}, + {"date": "Aug 13", "Market Index": 78.6, "Portfolio": 110.4}, + {"date": "Aug 14", "Market Index": 73.8, "Portfolio": 113.5}, + {"date": "Aug 15", "Market Index": 69.7, "Portfolio": 114.1}, + {"date": "Aug 16", "Market Index": 62.6, "Portfolio": 121.4}, + {"date": "Aug 17", "Market Index": 59.3, "Portfolio": 120.4}, + {"date": "Aug 18", "Market Index": 57.1, "Portfolio": 110.7}, + {"date": "Aug 19", "Market Index": 55.1, "Portfolio": 118.8}, + {"date": "Aug 20", "Market Index": 54.3, "Portfolio": 123.1}, + {"date": "Aug 21", "Market Index": 53.2, "Portfolio": 110.2}, + {"date": "Aug 22", "Market Index": 49.4, "Portfolio": 101.2}, + {"date": "Aug 23", "Market Index": 48.1, "Portfolio": 99.2}, + {"date": "Aug 24", "Market Index": 27.1, "Portfolio": 105.8}, + {"date": "Aug 25", "Market Index": 21.0, "Portfolio": 109.4}, + {"date": "Aug 26", "Market Index": 21.3, "Portfolio": 110.1}, + {"date": "Aug 27", "Market Index": 21.8, "Portfolio": 119.6}, + {"date": "Aug 28", "Market Index": 29.4, "Portfolio": 121.3}, + {"date": "Aug 29", "Market Index": 32.4, "Portfolio": 129.1}, + {"date": "Aug 30", "Market Index": 37.1, "Portfolio": 134.5}, + {"date": "Aug 31", "Market Index": 41.3, "Portfolio": 144.2}, + {"date": "Sep 01", "Market Index": 48.1, "Portfolio": 145.1}, + {"date": "Sep 02", "Market Index": 51.3, "Portfolio": 142.5}, + {"date": "Sep 03", "Market Index": 52.8, "Portfolio": 140.9}, + {"date": "Sep 04", "Market Index": 54.4, "Portfolio": 138.7}, + {"date": "Sep 05", "Market Index": 57.1, "Portfolio": 135.2}, + {"date": "Sep 06", "Market Index": 67.9, "Portfolio": 136.2}, + {"date": "Sep 07", "Market Index": 78.8, "Portfolio": 136.2}, + {"date": "Sep 08", "Market Index": 89.2, "Portfolio": 146.2}, + {"date": "Sep 09", "Market Index": 99.2, "Portfolio": 145.2}, + {"date": "Sep 10", "Market Index": 101.2, "Portfolio": 141.8}, + {"date": "Sep 11", "Market Index": 104.2, "Portfolio": 132.2}, + {"date": "Sep 12", "Market Index": 109.8, "Portfolio": 129.2}, + {"date": "Sep 13", "Market Index": 110.4, "Portfolio": 120.3}, + {"date": "Sep 14", "Market Index": 111.3, "Portfolio": 123.4}, + {"date": "Sep 15", "Market Index": 114.3, "Portfolio": 137.4}, + {"date": "Sep 16", "Market Index": 105.1, "Portfolio": 130.1}, + {"date": "Sep 17", "Market Index": 89.3, "Portfolio": 131.8}, + {"date": "Sep 18", "Market Index": 102.1, "Portfolio": 149.4}, + {"date": "Sep 19", "Market Index": 101.7, "Portfolio": 149.3}, + {"date": "Sep 20", "Market Index": 121.3, "Portfolio": 153.2}, + {"date": "Sep 21", "Market Index": 132.5, "Portfolio": 157.2}, + {"date": "Sep 22", "Market Index": 121.4, "Portfolio": 139.1}, + {"date": "Sep 23", "Market Index": 100.1, "Portfolio": 120.2}, + {"date": "Sep 24", "Market Index": 89.1, "Portfolio": 119.1}, + {"date": "Sep 25", "Market Index": 97.1, "Portfolio": 112.2}, + {"date": "Sep 26", "Market Index": 109.4, "Portfolio": 129.1}, +] + + +summary = [ + ("Portfolio value", "$37,081.89"), + ("Invested", "$19,698.65"), + ("Cashflow", "$20,033.74"), + ("Price gain", "+$15,012.39"), + ("Realized", "+$177.4"), + ("Dividends (gross)", "+$490.97"), +] + + +def _chart(show_y_axis: bool) -> rx.Component: + return rx.recharts.line_chart( + chart_tooltip(), + rx.recharts.cartesian_grid( + horizontal=True, + vertical=False, + class_name="opacity-50", + ), + rx.recharts.x_axis( + data_key="date", + tick_line=False, + axis_line=False, + tick_size=15, + custom_attrs={"fontSize": "11px"}, + interval="preserveStartEnd", + ), + rx.recharts.y_axis( + width=30, + tick_line=False, + axis_line=False, + tick_size=15, + custom_attrs={"fontSize": "11px"}, + hide=not show_y_axis, + ), + rx.recharts.line( + data_key="Portfolio", + stroke="var(--chart-1)", + stroke_width=2, + dot=False, + is_animation_active=False, + active_dot={"fill": "var(--chart-1)", "stroke": "var(--chart-1)"}, + ), + rx.recharts.line( + data_key="Market Index", + stroke="var(--chart-2)", + stroke_width=2, + dot=False, + is_animation_active=False, + active_dot={"fill": "var(--chart-2)", "stroke": "var(--chart-2)"}, + ), + data=data, + width="100%", + height=280, + ) + + +def _summary_list(items): + return rx.el.ul( + *[ + rx.el.li( + rx.el.span( + label, + class_name="text-sm text-muted-foreground", + ), + rx.el.span( + value, + class_name=( + "text-sm font-medium " + if not value.startswith("+") + else "text-sm font-medium text-emerald-600" + ), + ), + class_name=( + "flex items-center justify-between " + "gap-4 py-1.5 border-b border-input " + "last:border-0" + ), + ) + for label, value in items + ], + class_name="w-full", + ) + + +def line_chart_03(): + return card.root( + card.header( + rx.el.p( + "Portfolio performance", + class_name="text-sm text-muted-foreground", + ), + rx.el.p( + "$37,081.89", + class_name="mt-1 text-3xl font-semibold", + ), + rx.el.p( + rx.el.span( + "+$430.90 (4.1%)", + class_name="text-emerald-600 font-medium", + ), + " ", + rx.el.span( + "Past 24 hours", + class_name="text-muted-foreground", + ), + class_name="mt-1 text-sm", + ), + ), + card.content( + rx.el.div( + _chart(show_y_axis=False), + class_name="sm:hidden", + ), + rx.el.div( + _chart(show_y_axis=True), + class_name="hidden sm:block", + ), + rx.el.p( + "Portfolio summary", + class_name="mt-6 mb-3 text-sm font-medium", + ), + rx.el.div( + _summary_list(summary[:3]), + _summary_list(summary[3:]), + class_name="flex gap-8", + ), + ), + class_name=(chart_tooltip_content([1, 2], "square") + " w-full p-0"), + ) diff --git a/app/www/library/blocks/line_chart_04.py b/app/www/library/blocks/line_chart_04.py new file mode 100644 index 0000000..48b34b1 --- /dev/null +++ b/app/www/library/blocks/line_chart_04.py @@ -0,0 +1,106 @@ +import reflex as rx + +from components.charts.chart_tooltip import chart_tooltip, chart_tooltip_content +from components.ui.card import card + +data = [ + {"date": "Jan 23", "SolarPanels": 2890, "Inverters": 2338}, + {"date": "Feb 23", "SolarPanels": 2756, "Inverters": 2103}, + {"date": "Mar 23", "SolarPanels": 3322, "Inverters": 2194}, + {"date": "Apr 23", "SolarPanels": 3470, "Inverters": 2108}, + {"date": "May 23", "SolarPanels": 3475, "Inverters": 1812}, + {"date": "Jun 23", "SolarPanels": 3129, "Inverters": 1726}, + {"date": "Jul 23", "SolarPanels": 3490, "Inverters": 1982}, + {"date": "Aug 23", "SolarPanels": 2903, "Inverters": 2012}, + {"date": "Sep 23", "SolarPanels": 2643, "Inverters": 2342}, + {"date": "Oct 23", "SolarPanels": 2837, "Inverters": 2473}, + {"date": "Nov 23", "SolarPanels": 2954, "Inverters": 3848}, + {"date": "Dec 23", "SolarPanels": 3239, "Inverters": 3736}, +] + + +def _chart(show_y_axis: bool) -> rx.Component: + return rx.recharts.line_chart( + chart_tooltip(), + rx.recharts.cartesian_grid( + horizontal=True, vertical=False, class_name="opacity-50" + ), + rx.recharts.x_axis( + data_key="date", + tick_line=False, + axis_line=False, + tick_size=15, + custom_attrs={"fontSize": "11px"}, + interval="preserveStartEnd", + ), + rx.recharts.y_axis( + width=40, + tick_line=False, + axis_line=False, + tick_size=15, + custom_attrs={"fontSize": "11px"}, + hide=not show_y_axis, + ), + rx.recharts.line( + data_key="SolarPanels", + stroke="var(--chart-1)", + dot=False, + is_animation_active=False, + active_dot={"fill": "var(--chart-1)", "stroke": "var(--chart-1)"}, + ), + rx.recharts.line( + data_key="Inverters", + stroke="var(--chart-2)", + stroke_width=2, + dot=False, + is_animation_active=False, + active_dot={"fill": "var(--chart-2)", "stroke": "var(--chart-2)"}, + ), + data=data, + width="100%", + height=270, + ) + + +def line_chart_04(): + return card.root( + card.header( + card.title("Solar & Inverters"), + card.description("Monthly spend category — Jan to Dec 23"), + ), + card.content( + rx.el.div( + # Y-axis label rotated on the left + rx.el.p( + "Spend Category", + class_name="-rotate-90 text-xs text-muted-foreground whitespace-nowrap self-center h-fit w-[1rem]", + ), + # Chart + rx.el.div( + rx.el.div(_chart(show_y_axis=False), class_name="sm:hidden"), + rx.el.div(_chart(show_y_axis=True), class_name="hidden sm:block"), + class_name="flex flex-col flex-1 min-w-0", + ), + class_name="flex flex-row gap-2 w-full", + ), + # X-axis label + rx.el.p( + "Month", + class_name="text-xs text-muted-foreground text-center mt-1", + ), + # Legend + rx.el.div( + *[ + rx.el.div( + rx.el.span(class_name=f"w-3 h-0.5 bg-chart-{i}"), + rx.el.span(label, class_name="text-sm text-muted-foreground"), + class_name="flex items-center gap-2", + ) + for i, label in enumerate(["SolarPanels", "Inverters"], 1) + ], + class_name="mt-4 flex items-center justify-center gap-6", + ), + class_name="relative", + ), + class_name=chart_tooltip_content([1, 2], "line") + " w-full p-0", + ) diff --git a/app/www/library/charts/area/v1.py b/app/www/library/charts/area/v1.py index 396e34d..9073394 100644 --- a/app/www/library/charts/area/v1.py +++ b/app/www/library/charts/area/v1.py @@ -64,5 +64,5 @@ def areachart_v1(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "border") + " w-full p-0", + class_name=chart_tooltip_content([1], "border") + " w-full p-0", ) diff --git a/app/www/library/charts/area/v10.py b/app/www/library/charts/area/v10.py index 1395aba..118fb8d 100644 --- a/app/www/library/charts/area/v10.py +++ b/app/www/library/charts/area/v10.py @@ -104,5 +104,5 @@ def areachart_v10(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(2, "square") + " w-full p-0", + class_name=chart_tooltip_content([1, 2], "square") + " w-full p-0", ) diff --git a/app/www/library/charts/area/v2.py b/app/www/library/charts/area/v2.py index 9adb3e2..f205e84 100644 --- a/app/www/library/charts/area/v2.py +++ b/app/www/library/charts/area/v2.py @@ -63,5 +63,5 @@ def areachart_v2(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "square") + " w-full p-0", + class_name=chart_tooltip_content([1], "square") + " w-full p-0", ) diff --git a/app/www/library/charts/area/v3.py b/app/www/library/charts/area/v3.py index b9900c0..51217d6 100644 --- a/app/www/library/charts/area/v3.py +++ b/app/www/library/charts/area/v3.py @@ -63,5 +63,5 @@ def areachart_v3(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "square") + " w-full p-0", + class_name=chart_tooltip_content([1], "square") + " w-full p-0", ) diff --git a/app/www/library/charts/area/v4.py b/app/www/library/charts/area/v4.py index 44f9cfc..b275eee 100644 --- a/app/www/library/charts/area/v4.py +++ b/app/www/library/charts/area/v4.py @@ -71,5 +71,5 @@ def areachart_v4(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(2, "square") + " w-full p-0", + class_name=chart_tooltip_content([1, 2], "square") + " w-full p-0", ) diff --git a/app/www/library/charts/area/v5.py b/app/www/library/charts/area/v5.py index bdd0817..edfb879 100644 --- a/app/www/library/charts/area/v5.py +++ b/app/www/library/charts/area/v5.py @@ -113,5 +113,5 @@ def area(data_key: str, color: str): class_name="py-4 px-4 flex w-full flex justify-center gap-8", ), ), - class_name=chart_tooltip_content(2, "square") + " w-full p-0", + class_name=chart_tooltip_content([1, 2], "square") + " w-full p-0", ) diff --git a/app/www/library/charts/area/v6.py b/app/www/library/charts/area/v6.py index 5bda8fe..c156269 100644 --- a/app/www/library/charts/area/v6.py +++ b/app/www/library/charts/area/v6.py @@ -72,5 +72,5 @@ def areachart_v6(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(2, "square") + " w-full p-0", + class_name=chart_tooltip_content([1, 2], "square") + " w-full p-0", ) diff --git a/app/www/library/charts/area/v7.py b/app/www/library/charts/area/v7.py index 9c6ab8d..2a9f995 100644 --- a/app/www/library/charts/area/v7.py +++ b/app/www/library/charts/area/v7.py @@ -79,5 +79,5 @@ def areachart_v7(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(2, "square") + " w-full p-0", + class_name=chart_tooltip_content([1, 2], "square") + " w-full p-0", ) diff --git a/app/www/library/charts/area/v8.py b/app/www/library/charts/area/v8.py index 166d50d..d717f15 100644 --- a/app/www/library/charts/area/v8.py +++ b/app/www/library/charts/area/v8.py @@ -109,5 +109,5 @@ def create_gradient(var_name): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(2, "square") + " w-full p-0", + class_name=chart_tooltip_content([1, 2], "square") + " w-full p-0", ) diff --git a/app/www/library/charts/area/v9.py b/app/www/library/charts/area/v9.py index 05475b8..9527097 100644 --- a/app/www/library/charts/area/v9.py +++ b/app/www/library/charts/area/v9.py @@ -80,5 +80,5 @@ def gradient(id_: str, color: str): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "square") + " w-full p-0", + class_name=chart_tooltip_content([1], "square") + " w-full p-0", ) diff --git a/app/www/library/charts/bar/docex_4.py b/app/www/library/charts/bar/docex_4.py index ba729b2..0113306 100644 --- a/app/www/library/charts/bar/docex_4.py +++ b/app/www/library/charts/bar/docex_4.py @@ -42,5 +42,5 @@ def chart_example_with_custom_tooltip(): data=data, width="100%", height=250, - class_name=chart_tooltip_content(2, "square"), + class_name=chart_tooltip_content([1, 2], "square"), ) diff --git a/app/www/library/charts/bar/docex_5.py b/app/www/library/charts/bar/docex_5.py index 1671009..00c8ada 100644 --- a/app/www/library/charts/bar/docex_5.py +++ b/app/www/library/charts/bar/docex_5.py @@ -43,7 +43,7 @@ def chart_example_with_custom_legends(): data=data, width="100%", height=250, - class_name=chart_tooltip_content(2, "square"), + class_name=chart_tooltip_content([1, 2], "square"), ), rx.el.div( rx.foreach( diff --git a/app/www/library/charts/bar/v1.py b/app/www/library/charts/bar/v1.py index 98ed5ec..c74a958 100644 --- a/app/www/library/charts/bar/v1.py +++ b/app/www/library/charts/bar/v1.py @@ -68,5 +68,5 @@ def barchart_v1(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(2, "square") + " w-full p-0", + class_name=chart_tooltip_content([1, 2], "square") + " w-full p-0", ) diff --git a/app/www/library/charts/bar/v10.py b/app/www/library/charts/bar/v10.py deleted file mode 100644 index 351105f..0000000 --- a/app/www/library/charts/bar/v10.py +++ /dev/null @@ -1,107 +0,0 @@ -import reflex as rx - -from components.charts.chart_tooltip import chart_tooltip, chart_tooltip_content -from components.ui.card import card - -sport_data = [ - {"date": "Jan 23", "Running": 167, "Cycling": 145}, - {"date": "Feb 23", "Running": 125, "Cycling": 110}, - {"date": "Mar 23", "Running": 156, "Cycling": 149}, - {"date": "Apr 23", "Running": 165, "Cycling": 112}, - {"date": "May 23", "Running": 153, "Cycling": 138}, - {"date": "Jun 23", "Running": 124, "Cycling": 145}, - {"date": "Jul 23", "Running": 164, "Cycling": 134}, -] - -activities = ["Running", "Cycling"] -chart_colors = ["var(--chart-1)", "var(--chart-2)"] - - -def create_alternating_chart(active_key: str): - return rx.recharts.bar_chart( - chart_tooltip(), - rx.recharts.cartesian_grid( - horizontal=True, vertical=False, class_name="opacity-30" - ), - *[ - rx.recharts.bar( - is_animation_active=False, - radius=4, - data_key=key, - fill=color, - custom_attrs={"opacity": rx.cond(key == active_key, "0.25", "1")}, - ) - for key, color in zip(activities, chart_colors) - ], - rx.recharts.x_axis( - data_key="date", - axis_line=False, - tick_size=10, - tick_line=False, - custom_attrs={"fontSize": "12px"}, - interval="preserveStartEnd", - ), - data=sport_data, - width="100%", - height=250, - ) - - -def barchart_v10(): - - return card.root( - card.header( - rx.hstack( - rx.el.div( - card.title("Sport Activities"), - card.description("Running vs Cycling load"), - class_name="flex flex-col gap-y-1.5", - ), - rx.tabs.root( - rx.tabs.list( - *[ - rx.tabs.trigger( - rx.text(activity, class_name="text-xs font-semibold"), - value=str(i + 1), - ) - for i, activity in enumerate(activities) - ] - ), - default_value="1", - ), - align="center", - justify="between", - width="100%", - ), - ), - card.content( - rx.tabs.root( - *[ - rx.tabs.content( - create_alternating_chart(active), - value=str(i + 1), - ) - for i, active in enumerate(activities) - ], - default_value="1", - width="100%", - ), - ), - card.footer( - rx.el.div( - rx.el.div( - rx.el.div( - "Trending up by 5.2% this month ", - class_name="flex items-center gap-2 leading-none font-medium", - ), - rx.el.div( - "January - June 2024", - class_name="flex items-center gap-2 leading-none text-muted-foreground", - ), - class_name="grid gap-2", - ), - class_name="flex w-full items-start gap-2 text-sm", - ) - ), - class_name=chart_tooltip_content(2, "square") + " w-full p-0", - ) diff --git a/app/www/library/charts/bar/v2.py b/app/www/library/charts/bar/v2.py index 848592c..57d3e84 100644 --- a/app/www/library/charts/bar/v2.py +++ b/app/www/library/charts/bar/v2.py @@ -60,5 +60,5 @@ def barchart_v2(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "square") + " w-full p-0", + class_name=chart_tooltip_content([1], "square") + " w-full p-0", ) diff --git a/app/www/library/charts/bar/v3.py b/app/www/library/charts/bar/v3.py index 29e8952..fd28887 100644 --- a/app/www/library/charts/bar/v3.py +++ b/app/www/library/charts/bar/v3.py @@ -71,5 +71,5 @@ def barchart_v3(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(2, "square") + " w-full p-0", + class_name=chart_tooltip_content([1, 2], "square") + " w-full p-0", ) diff --git a/app/www/library/charts/bar/v4.py b/app/www/library/charts/bar/v4.py index c387f37..f64d366 100644 --- a/app/www/library/charts/bar/v4.py +++ b/app/www/library/charts/bar/v4.py @@ -68,5 +68,5 @@ def barchart_v4(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "square") + " w-full p-0", + class_name=chart_tooltip_content([1], "square") + " w-full p-0", ) diff --git a/app/www/library/charts/bar/v5.py b/app/www/library/charts/bar/v5.py index 27b4b41..6d6cee6 100644 --- a/app/www/library/charts/bar/v5.py +++ b/app/www/library/charts/bar/v5.py @@ -114,5 +114,5 @@ def barchart_v5(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "square") + " w-full p-0", + class_name=chart_tooltip_content([1], "square") + " w-full p-0", ) diff --git a/app/www/library/charts/bar/v6.py b/app/www/library/charts/bar/v6.py index 5c0808d..86c4f9a 100644 --- a/app/www/library/charts/bar/v6.py +++ b/app/www/library/charts/bar/v6.py @@ -73,5 +73,5 @@ def barchart_v6(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "square") + " w-full p-0", + class_name=chart_tooltip_content([1], "square") + " w-full p-0", ) diff --git a/app/www/library/charts/bar/v7.py b/app/www/library/charts/bar/v7.py index d0cd167..2040dc6 100644 --- a/app/www/library/charts/bar/v7.py +++ b/app/www/library/charts/bar/v7.py @@ -59,5 +59,5 @@ def barchart_v7(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "square") + " w-full p-0", + class_name=chart_tooltip_content([1], "square") + " w-full p-0", ) diff --git a/app/www/library/charts/bar/v8.py b/app/www/library/charts/bar/v8.py index 10afc3f..ee05fdf 100644 --- a/app/www/library/charts/bar/v8.py +++ b/app/www/library/charts/bar/v8.py @@ -130,5 +130,5 @@ def barchart_v8(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(2, "square") + " w-full p-0", + class_name=chart_tooltip_content([1, 2], "square") + " w-full p-0", ) diff --git a/app/www/library/charts/bar/v9.py b/app/www/library/charts/bar/v9.py index e6d9f41..986d796 100644 --- a/app/www/library/charts/bar/v9.py +++ b/app/www/library/charts/bar/v9.py @@ -89,5 +89,5 @@ def barchart_v9(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(3, "square") + " w-full p-0", + class_name=chart_tooltip_content([1, 2, 3], "square") + " w-full p-0", ) diff --git a/app/www/library/charts/chart_tooltip.py b/app/www/library/charts/chart_tooltip.py index 14ed716..891739b 100644 --- a/app/www/library/charts/chart_tooltip.py +++ b/app/www/library/charts/chart_tooltip.py @@ -64,53 +64,48 @@ def __call__( class _ChartTooltipContent: - def __call__(self, num_series: int, swatch: Swatch = "square") -> str: + def __call__(self, chart_colors: list[int], swatch: Swatch = "square") -> str: base = """ [&_.recharts-tooltip-item-name]:!text-muted-foreground [&_.recharts-tooltip-item-separator]:!w-full - [&_.recharts-tooltip-item]:!w-[8rem] + [&_.recharts-tooltip-item]:!min-w-[8rem] [&_.recharts-tooltip-item]:!flex [&_.recharts-tooltip-item]:!items-center [&_.recharts-tooltip-item]:!gap-2 """ if swatch == "border": - base += """ - [&_.recharts-tooltip-label]:!border-l-3 - [&_.recharts-tooltip-label]:!border-[var(--chart-1)] + # Single vertical left border on the tooltip label using first color + first_color = chart_colors[0] + base += f""" + [&_.recharts-tooltip-label]:!border-l-2 + [&_.recharts-tooltip-label]:!border-[var(--chart-{first_color})] [&_.recharts-tooltip-label]:!pl-2 [&_.recharts-tooltip-label]:!py-0 """ + return base lines = [] - - for i in range(1, num_series + 1): - idx = str(i) - - if swatch == "border": + for i, color_idx in enumerate(chart_colors, 1): + if swatch == "line": lines.append(f""" - [&_.recharts-default-tooltip]:!py-2 !flex !flex-col !gap-y-0 - [&_.recharts-tooltip-item:nth-child({idx})]:!border-l-3 - [&_.recharts-tooltip-item:nth-child({idx})]:!border-[var(--chart-{idx})] - [&_.recharts-tooltip-item:nth-child({idx})]:!pl-2 - [&_.recharts-tooltip-item:nth-child({idx})]:!py-0 + [&_.recharts-tooltip-item:nth-child({i})]:before:!content-[''] + [&_.recharts-tooltip-item:nth-child({i})]:before:!w-3 + [&_.recharts-tooltip-item:nth-child({i})]:before:!h-0.5 + [&_.recharts-tooltip-item:nth-child({i})]:before:!rounded-full + [&_.recharts-tooltip-item:nth-child({i})]:before:!flex-shrink-0 + [&_.recharts-tooltip-item:nth-child({i})]:before:!bg-[var(--chart-{color_idx})] + [&_.recharts-tooltip-item:nth-child({i})]:before:!block """) - else: - width = "!w-3" if swatch == "square" else "!w-8" - shrink = ( - f"[&_.recharts-tooltip-item:nth-child({idx})]:before:!flex-shrink-0" - if swatch == "square" - else "" - ) - + else: # square lines.append(f""" - [&_.recharts-tooltip-item:nth-child({idx})]:before:!content-[''] - [&_.recharts-tooltip-item:nth-child({idx})]:before:{width} - {shrink} - [&_.recharts-tooltip-item:nth-child({idx})]:before:!h-3 - [&_.recharts-tooltip-item:nth-child({idx})]:before:!rounded-sm - [&_.recharts-tooltip-item:nth-child({idx})]:before:!bg-[var(--chart-{idx})] - [&_.recharts-tooltip-item:nth-child({idx})]:before:!block + [&_.recharts-tooltip-item:nth-child({i})]:before:!content-[''] + [&_.recharts-tooltip-item:nth-child({i})]:before:!w-3 + [&_.recharts-tooltip-item:nth-child({i})]:before:!h-3 + [&_.recharts-tooltip-item:nth-child({i})]:before:!rounded-sm + [&_.recharts-tooltip-item:nth-child({i})]:before:!flex-shrink-0 + [&_.recharts-tooltip-item:nth-child({i})]:before:!bg-[var(--chart-{color_idx})] + [&_.recharts-tooltip-item:nth-child({i})]:before:!block """) return base + "\n".join(lines) diff --git a/app/www/library/charts/line/v1.py b/app/www/library/charts/line/v1.py index bd5fb9e..4bf11f1 100644 --- a/app/www/library/charts/line/v1.py +++ b/app/www/library/charts/line/v1.py @@ -63,5 +63,5 @@ def linechart_v1(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "square") + " w-full p-0", + class_name=chart_tooltip_content([1], "square") + " w-full p-0", ) diff --git a/app/www/library/charts/line/v2.py b/app/www/library/charts/line/v2.py index 67f33a7..6443b80 100644 --- a/app/www/library/charts/line/v2.py +++ b/app/www/library/charts/line/v2.py @@ -63,5 +63,5 @@ def linechart_v2(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "square") + " w-full p-0", + class_name=chart_tooltip_content([1], "square") + " w-full p-0", ) diff --git a/app/www/library/charts/line/v3.py b/app/www/library/charts/line/v3.py index e5f5fe8..be0425c 100644 --- a/app/www/library/charts/line/v3.py +++ b/app/www/library/charts/line/v3.py @@ -69,5 +69,5 @@ def linechart_v3(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "square") + " w-full p-0", + class_name=chart_tooltip_content([1], "square") + " w-full p-0", ) diff --git a/app/www/library/charts/line/v4.py b/app/www/library/charts/line/v4.py index 067e4fe..41c3fe2 100644 --- a/app/www/library/charts/line/v4.py +++ b/app/www/library/charts/line/v4.py @@ -71,5 +71,5 @@ def linechart_v4(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(2, "square") + " w-full p-0", + class_name=chart_tooltip_content([1, 2], "square") + " w-full p-0", ) diff --git a/app/www/library/charts/line/v5.py b/app/www/library/charts/line/v5.py index 675e416..53ecf36 100644 --- a/app/www/library/charts/line/v5.py +++ b/app/www/library/charts/line/v5.py @@ -62,5 +62,5 @@ def linechart_v5(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "square") + " w-full p-0", + class_name=chart_tooltip_content([1], "square") + " w-full p-0", ) diff --git a/app/www/library/charts/line/v6.py b/app/www/library/charts/line/v6.py index 69f7010..319c6a6 100644 --- a/app/www/library/charts/line/v6.py +++ b/app/www/library/charts/line/v6.py @@ -55,5 +55,5 @@ def linechart_v6(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "square") + " w-full p-0", + class_name=chart_tooltip_content([1], "square") + " w-full p-0", ) diff --git a/app/www/library/charts/line/v7.py b/app/www/library/charts/line/v7.py index adb35ae..2f7dbc7 100644 --- a/app/www/library/charts/line/v7.py +++ b/app/www/library/charts/line/v7.py @@ -124,5 +124,5 @@ def linechart_v7(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "line") + " w-full p-0", + class_name=chart_tooltip_content([1], "line") + " w-full p-0", ) diff --git a/app/www/library/charts/line/v8.py b/app/www/library/charts/line/v8.py index 37a139f..3514cb5 100644 --- a/app/www/library/charts/line/v8.py +++ b/app/www/library/charts/line/v8.py @@ -95,5 +95,5 @@ def linechart_v8(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(2, "square") + " w-full p-0", + class_name=chart_tooltip_content([1, 2], "square") + " w-full p-0", ) diff --git a/assets/docs/charts/area-chart.md b/assets/docs/charts/area-chart.md index 35995a1..f6295a3 100644 --- a/assets/docs/charts/area-chart.md +++ b/assets/docs/charts/area-chart.md @@ -75,53 +75,48 @@ class _ChartTooltip: class _ChartTooltipContent: - def __call__(self, num_series: int, swatch: Swatch = "square") -> str: + def __call__(self, chart_colors: list[int], swatch: Swatch = "square") -> str: base = """ [&_.recharts-tooltip-item-name]:!text-muted-foreground [&_.recharts-tooltip-item-separator]:!w-full - [&_.recharts-tooltip-item]:!w-[8rem] + [&_.recharts-tooltip-item]:!min-w-[8rem] [&_.recharts-tooltip-item]:!flex [&_.recharts-tooltip-item]:!items-center [&_.recharts-tooltip-item]:!gap-2 """ if swatch == "border": - base += """ - [&_.recharts-tooltip-label]:!border-l-3 - [&_.recharts-tooltip-label]:!border-[var(--chart-1)] + # Single vertical left border on the tooltip label using first color + first_color = chart_colors[0] + base += f""" + [&_.recharts-tooltip-label]:!border-l-2 + [&_.recharts-tooltip-label]:!border-[var(--chart-{first_color})] [&_.recharts-tooltip-label]:!pl-2 [&_.recharts-tooltip-label]:!py-0 """ + return base lines = [] - - for i in range(1, num_series + 1): - idx = str(i) - - if swatch == "border": + for i, color_idx in enumerate(chart_colors, 1): + if swatch == "line": lines.append(f""" - [&_.recharts-default-tooltip]:!py-2 !flex !flex-col !gap-y-0 - [&_.recharts-tooltip-item:nth-child({idx})]:!border-l-3 - [&_.recharts-tooltip-item:nth-child({idx})]:!border-[var(--chart-{idx})] - [&_.recharts-tooltip-item:nth-child({idx})]:!pl-2 - [&_.recharts-tooltip-item:nth-child({idx})]:!py-0 + [&_.recharts-tooltip-item:nth-child({i})]:before:!content-[''] + [&_.recharts-tooltip-item:nth-child({i})]:before:!w-3 + [&_.recharts-tooltip-item:nth-child({i})]:before:!h-0.5 + [&_.recharts-tooltip-item:nth-child({i})]:before:!rounded-full + [&_.recharts-tooltip-item:nth-child({i})]:before:!flex-shrink-0 + [&_.recharts-tooltip-item:nth-child({i})]:before:!bg-[var(--chart-{color_idx})] + [&_.recharts-tooltip-item:nth-child({i})]:before:!block """) - else: - width = "!w-3" if swatch == "square" else "!w-8" - shrink = ( - f"[&_.recharts-tooltip-item:nth-child({idx})]:before:!flex-shrink-0" - if swatch == "square" - else "" - ) - + else: # square lines.append(f""" - [&_.recharts-tooltip-item:nth-child({idx})]:before:!content-[''] - [&_.recharts-tooltip-item:nth-child({idx})]:before:{width} - {shrink} - [&_.recharts-tooltip-item:nth-child({idx})]:before:!h-3 - [&_.recharts-tooltip-item:nth-child({idx})]:before:!rounded-sm - [&_.recharts-tooltip-item:nth-child({idx})]:before:!bg-[var(--chart-{idx})] - [&_.recharts-tooltip-item:nth-child({idx})]:before:!block + [&_.recharts-tooltip-item:nth-child({i})]:before:!content-[''] + [&_.recharts-tooltip-item:nth-child({i})]:before:!w-3 + [&_.recharts-tooltip-item:nth-child({i})]:before:!h-3 + [&_.recharts-tooltip-item:nth-child({i})]:before:!rounded-sm + [&_.recharts-tooltip-item:nth-child({i})]:before:!flex-shrink-0 + [&_.recharts-tooltip-item:nth-child({i})]:before:!bg-[var(--chart-{color_idx})] + [&_.recharts-tooltip-item:nth-child({i})]:before:!block """) return base + "\n".join(lines) @@ -189,7 +184,7 @@ def areachart_v1(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "border") + " w-full p-0", + class_name=chart_tooltip_content([1], "border") + " w-full p-0", ) ``` @@ -248,7 +243,7 @@ def areachart_v2(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "square") + " w-full p-0", + class_name=chart_tooltip_content([1], "square") + " w-full p-0", ) ``` @@ -307,7 +302,7 @@ def areachart_v3(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "square") + " w-full p-0", + class_name=chart_tooltip_content([1], "square") + " w-full p-0", ) ``` @@ -374,7 +369,7 @@ def areachart_v4(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(2, "square") + " w-full p-0", + class_name=chart_tooltip_content([1, 2], "square") + " w-full p-0", ) ``` @@ -488,7 +483,7 @@ def areachart_v5(): class_name="py-4 px-4 flex w-full flex justify-center gap-8", ), ), - class_name=chart_tooltip_content(2, "square") + " w-full p-0", + class_name=chart_tooltip_content([1, 2], "square") + " w-full p-0", ) ``` @@ -556,7 +551,7 @@ def areachart_v6(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(2, "square") + " w-full p-0", + class_name=chart_tooltip_content([1, 2], "square") + " w-full p-0", ) ``` @@ -631,7 +626,7 @@ def areachart_v7(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(2, "square") + " w-full p-0", + class_name=chart_tooltip_content([1, 2], "square") + " w-full p-0", ) ``` @@ -736,7 +731,7 @@ def areachart_v8(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(2, "square") + " w-full p-0", + class_name=chart_tooltip_content([1, 2], "square") + " w-full p-0", ) ``` @@ -812,7 +807,7 @@ def areachart_v9(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "square") + " w-full p-0", + class_name=chart_tooltip_content([1], "square") + " w-full p-0", ) ``` @@ -912,7 +907,7 @@ def areachart_v10(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(2, "square") + " w-full p-0", + class_name=chart_tooltip_content([1, 2], "square") + " w-full p-0", ) ``` diff --git a/assets/docs/charts/bar-chart.md b/assets/docs/charts/bar-chart.md index 3c3e3e1..68dfe3f 100644 --- a/assets/docs/charts/bar-chart.md +++ b/assets/docs/charts/bar-chart.md @@ -76,53 +76,48 @@ class _ChartTooltip: class _ChartTooltipContent: - def __call__(self, num_series: int, swatch: Swatch = "square") -> str: + def __call__(self, chart_colors: list[int], swatch: Swatch = "square") -> str: base = """ [&_.recharts-tooltip-item-name]:!text-muted-foreground [&_.recharts-tooltip-item-separator]:!w-full - [&_.recharts-tooltip-item]:!w-[8rem] + [&_.recharts-tooltip-item]:!min-w-[8rem] [&_.recharts-tooltip-item]:!flex [&_.recharts-tooltip-item]:!items-center [&_.recharts-tooltip-item]:!gap-2 """ if swatch == "border": - base += """ - [&_.recharts-tooltip-label]:!border-l-3 - [&_.recharts-tooltip-label]:!border-[var(--chart-1)] + # Single vertical left border on the tooltip label using first color + first_color = chart_colors[0] + base += f""" + [&_.recharts-tooltip-label]:!border-l-2 + [&_.recharts-tooltip-label]:!border-[var(--chart-{first_color})] [&_.recharts-tooltip-label]:!pl-2 [&_.recharts-tooltip-label]:!py-0 """ + return base lines = [] - - for i in range(1, num_series + 1): - idx = str(i) - - if swatch == "border": + for i, color_idx in enumerate(chart_colors, 1): + if swatch == "line": lines.append(f""" - [&_.recharts-default-tooltip]:!py-2 !flex !flex-col !gap-y-0 - [&_.recharts-tooltip-item:nth-child({idx})]:!border-l-3 - [&_.recharts-tooltip-item:nth-child({idx})]:!border-[var(--chart-{idx})] - [&_.recharts-tooltip-item:nth-child({idx})]:!pl-2 - [&_.recharts-tooltip-item:nth-child({idx})]:!py-0 + [&_.recharts-tooltip-item:nth-child({i})]:before:!content-[''] + [&_.recharts-tooltip-item:nth-child({i})]:before:!w-3 + [&_.recharts-tooltip-item:nth-child({i})]:before:!h-0.5 + [&_.recharts-tooltip-item:nth-child({i})]:before:!rounded-full + [&_.recharts-tooltip-item:nth-child({i})]:before:!flex-shrink-0 + [&_.recharts-tooltip-item:nth-child({i})]:before:!bg-[var(--chart-{color_idx})] + [&_.recharts-tooltip-item:nth-child({i})]:before:!block """) - else: - width = "!w-3" if swatch == "square" else "!w-8" - shrink = ( - f"[&_.recharts-tooltip-item:nth-child({idx})]:before:!flex-shrink-0" - if swatch == "square" - else "" - ) - + else: # square lines.append(f""" - [&_.recharts-tooltip-item:nth-child({idx})]:before:!content-[''] - [&_.recharts-tooltip-item:nth-child({idx})]:before:{width} - {shrink} - [&_.recharts-tooltip-item:nth-child({idx})]:before:!h-3 - [&_.recharts-tooltip-item:nth-child({idx})]:before:!rounded-sm - [&_.recharts-tooltip-item:nth-child({idx})]:before:!bg-[var(--chart-{idx})] - [&_.recharts-tooltip-item:nth-child({idx})]:before:!block + [&_.recharts-tooltip-item:nth-child({i})]:before:!content-[''] + [&_.recharts-tooltip-item:nth-child({i})]:before:!w-3 + [&_.recharts-tooltip-item:nth-child({i})]:before:!h-3 + [&_.recharts-tooltip-item:nth-child({i})]:before:!rounded-sm + [&_.recharts-tooltip-item:nth-child({i})]:before:!flex-shrink-0 + [&_.recharts-tooltip-item:nth-child({i})]:before:!bg-[var(--chart-{color_idx})] + [&_.recharts-tooltip-item:nth-child({i})]:before:!block """) return base + "\n".join(lines) @@ -194,7 +189,7 @@ def barchart_v1(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(2, "square") + " w-full p-0", + class_name=chart_tooltip_content([1, 2], "square") + " w-full p-0", ) ``` @@ -250,7 +245,7 @@ def barchart_v2(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "square") + " w-full p-0", + class_name=chart_tooltip_content([1], "square") + " w-full p-0", ) ``` @@ -317,7 +312,7 @@ def barchart_v3(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(2, "square") + " w-full p-0", + class_name=chart_tooltip_content([1, 2], "square") + " w-full p-0", ) ``` @@ -381,7 +376,7 @@ def barchart_v4(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "square") + " w-full p-0", + class_name=chart_tooltip_content([1], "square") + " w-full p-0", ) ``` @@ -498,7 +493,7 @@ def barchart_v5(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "square") + " w-full p-0", + class_name=chart_tooltip_content([1], "square") + " w-full p-0", ) ``` @@ -559,7 +554,7 @@ def barchart_v6(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "square") + " w-full p-0", + class_name=chart_tooltip_content([1], "square") + " w-full p-0", ) ``` @@ -615,68 +610,7 @@ def barchart_v7(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "square") + " w-full p-0", - ) -``` - - -## Custom Tabs -Customize and format your x and y axes for improved presentation. - -```python -def barchart_v8(): - - return card.root( - card.header( - rx.hstack( - rx.el.div( - card.title("Online Transactions"), - card.description("Global revenue distributions"), - class_name="flex flex-col gap-y-1.5", - ), - rx.tabs.root( - rx.tabs.list( - rx.tabs.trigger( - rx.text("Europe", class_name="text-xs font-semibold"), - value="1", - ), - rx.tabs.trigger( - rx.text("Asia", class_name="text-xs font-semibold"), - value="2", - ), - ), - default_value="1", - id="transactions-tabs", - ), - align="center", - justify="between", - width="100%", - ), - ), - card.content( - rx.tabs.root( - rx.tabs.content(create_chart(EUROPE), value="1"), - rx.tabs.content(create_chart(ASIA), value="2"), - default_value="1", - ), - ), - card.footer( - rx.el.div( - rx.el.div( - rx.el.div( - "Trending up by 5.2% this month ", - class_name="flex items-center gap-2 leading-none font-medium", - ), - rx.el.div( - "January - June 2024", - class_name="flex items-center gap-2 leading-none text-muted-foreground", - ), - class_name="grid gap-2", - ), - class_name="flex w-full items-start gap-2 text-sm", - ) - ), - class_name=chart_tooltip_content(2, "square") + " w-full p-0", + class_name=chart_tooltip_content([1], "square") + " w-full p-0", ) ``` @@ -762,72 +696,7 @@ def barchart_v9(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(3, "square") + " w-full p-0", - ) -``` - - -## Alternating Colors -Apply gradient fills to your bars for a modern, polished look. - -```python -def barchart_v10(): - - return card.root( - card.header( - rx.hstack( - rx.el.div( - card.title("Sport Activities"), - card.description("Running vs Cycling load"), - class_name="flex flex-col gap-y-1.5", - ), - rx.tabs.root( - rx.tabs.list( - *[ - rx.tabs.trigger( - rx.text(activity, class_name="text-xs font-semibold"), - value=str(i + 1), - ) - for i, activity in enumerate(activities) - ] - ), - default_value="1", - ), - align="center", - justify="between", - width="100%", - ), - ), - card.content( - rx.tabs.root( - *[ - rx.tabs.content( - create_alternating_chart(active), - value=str(i + 1), - ) - for i, active in enumerate(activities) - ], - default_value="1", - width="100%", - ), - ), - card.footer( - rx.el.div( - rx.el.div( - rx.el.div( - "Trending up by 5.2% this month ", - class_name="flex items-center gap-2 leading-none font-medium", - ), - rx.el.div( - "January - June 2024", - class_name="flex items-center gap-2 leading-none text-muted-foreground", - ), - class_name="grid gap-2", - ), - class_name="flex w-full items-start gap-2 text-sm", - ) - ), - class_name=chart_tooltip_content(2, "square") + " w-full p-0", + class_name=chart_tooltip_content([1, 2, 3], "square") + " w-full p-0", ) ``` diff --git a/assets/docs/charts/line-chart.md b/assets/docs/charts/line-chart.md index 81678d4..e862d75 100644 --- a/assets/docs/charts/line-chart.md +++ b/assets/docs/charts/line-chart.md @@ -75,53 +75,48 @@ class _ChartTooltip: class _ChartTooltipContent: - def __call__(self, num_series: int, swatch: Swatch = "square") -> str: + def __call__(self, chart_colors: list[int], swatch: Swatch = "square") -> str: base = """ [&_.recharts-tooltip-item-name]:!text-muted-foreground [&_.recharts-tooltip-item-separator]:!w-full - [&_.recharts-tooltip-item]:!w-[8rem] + [&_.recharts-tooltip-item]:!min-w-[8rem] [&_.recharts-tooltip-item]:!flex [&_.recharts-tooltip-item]:!items-center [&_.recharts-tooltip-item]:!gap-2 """ if swatch == "border": - base += """ - [&_.recharts-tooltip-label]:!border-l-3 - [&_.recharts-tooltip-label]:!border-[var(--chart-1)] + # Single vertical left border on the tooltip label using first color + first_color = chart_colors[0] + base += f""" + [&_.recharts-tooltip-label]:!border-l-2 + [&_.recharts-tooltip-label]:!border-[var(--chart-{first_color})] [&_.recharts-tooltip-label]:!pl-2 [&_.recharts-tooltip-label]:!py-0 """ + return base lines = [] - - for i in range(1, num_series + 1): - idx = str(i) - - if swatch == "border": + for i, color_idx in enumerate(chart_colors, 1): + if swatch == "line": lines.append(f""" - [&_.recharts-default-tooltip]:!py-2 !flex !flex-col !gap-y-0 - [&_.recharts-tooltip-item:nth-child({idx})]:!border-l-3 - [&_.recharts-tooltip-item:nth-child({idx})]:!border-[var(--chart-{idx})] - [&_.recharts-tooltip-item:nth-child({idx})]:!pl-2 - [&_.recharts-tooltip-item:nth-child({idx})]:!py-0 + [&_.recharts-tooltip-item:nth-child({i})]:before:!content-[''] + [&_.recharts-tooltip-item:nth-child({i})]:before:!w-3 + [&_.recharts-tooltip-item:nth-child({i})]:before:!h-0.5 + [&_.recharts-tooltip-item:nth-child({i})]:before:!rounded-full + [&_.recharts-tooltip-item:nth-child({i})]:before:!flex-shrink-0 + [&_.recharts-tooltip-item:nth-child({i})]:before:!bg-[var(--chart-{color_idx})] + [&_.recharts-tooltip-item:nth-child({i})]:before:!block """) - else: - width = "!w-3" if swatch == "square" else "!w-8" - shrink = ( - f"[&_.recharts-tooltip-item:nth-child({idx})]:before:!flex-shrink-0" - if swatch == "square" - else "" - ) - + else: # square lines.append(f""" - [&_.recharts-tooltip-item:nth-child({idx})]:before:!content-[''] - [&_.recharts-tooltip-item:nth-child({idx})]:before:{width} - {shrink} - [&_.recharts-tooltip-item:nth-child({idx})]:before:!h-3 - [&_.recharts-tooltip-item:nth-child({idx})]:before:!rounded-sm - [&_.recharts-tooltip-item:nth-child({idx})]:before:!bg-[var(--chart-{idx})] - [&_.recharts-tooltip-item:nth-child({idx})]:before:!block + [&_.recharts-tooltip-item:nth-child({i})]:before:!content-[''] + [&_.recharts-tooltip-item:nth-child({i})]:before:!w-3 + [&_.recharts-tooltip-item:nth-child({i})]:before:!h-3 + [&_.recharts-tooltip-item:nth-child({i})]:before:!rounded-sm + [&_.recharts-tooltip-item:nth-child({i})]:before:!flex-shrink-0 + [&_.recharts-tooltip-item:nth-child({i})]:before:!bg-[var(--chart-{color_idx})] + [&_.recharts-tooltip-item:nth-child({i})]:before:!block """) return base + "\n".join(lines) @@ -188,7 +183,7 @@ def linechart_v1(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "square") + " w-full p-0", + class_name=chart_tooltip_content([1], "square") + " w-full p-0", ) ``` @@ -247,7 +242,7 @@ def linechart_v2(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "square") + " w-full p-0", + class_name=chart_tooltip_content([1], "square") + " w-full p-0", ) ``` @@ -312,7 +307,7 @@ def linechart_v3(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "square") + " w-full p-0", + class_name=chart_tooltip_content([1], "square") + " w-full p-0", ) ``` @@ -379,7 +374,7 @@ def linechart_v4(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(2, "square") + " w-full p-0", + class_name=chart_tooltip_content([1, 2], "square") + " w-full p-0", ) ``` @@ -438,7 +433,7 @@ def linechart_v5(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "square") + " w-full p-0", + class_name=chart_tooltip_content([1], "square") + " w-full p-0", ) ``` @@ -490,7 +485,7 @@ def linechart_v6(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "square") + " w-full p-0", + class_name=chart_tooltip_content([1], "square") + " w-full p-0", ) ``` @@ -617,7 +612,7 @@ def linechart_v7(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(1, "line") + " w-full p-0", + class_name=chart_tooltip_content([1], "line") + " w-full p-0", ) ``` @@ -708,7 +703,7 @@ def linechart_v8(): class_name="flex w-full items-start gap-2 text-sm", ) ), - class_name=chart_tooltip_content(2, "square") + " w-full p-0", + class_name=chart_tooltip_content([1, 2], "square") + " w-full p-0", ) ``` diff --git a/assets/docs/components/chart.md b/assets/docs/components/chart.md index 145d0ba..b996576 100644 --- a/assets/docs/components/chart.md +++ b/assets/docs/components/chart.md @@ -107,53 +107,48 @@ class _ChartTooltip: class _ChartTooltipContent: - def __call__(self, num_series: int, swatch: Swatch = "square") -> str: + def __call__(self, chart_colors: list[int], swatch: Swatch = "square") -> str: base = """ [&_.recharts-tooltip-item-name]:!text-muted-foreground [&_.recharts-tooltip-item-separator]:!w-full - [&_.recharts-tooltip-item]:!w-[8rem] + [&_.recharts-tooltip-item]:!min-w-[8rem] [&_.recharts-tooltip-item]:!flex [&_.recharts-tooltip-item]:!items-center [&_.recharts-tooltip-item]:!gap-2 """ if swatch == "border": - base += """ - [&_.recharts-tooltip-label]:!border-l-3 - [&_.recharts-tooltip-label]:!border-[var(--chart-1)] + # Single vertical left border on the tooltip label using first color + first_color = chart_colors[0] + base += f""" + [&_.recharts-tooltip-label]:!border-l-2 + [&_.recharts-tooltip-label]:!border-[var(--chart-{first_color})] [&_.recharts-tooltip-label]:!pl-2 [&_.recharts-tooltip-label]:!py-0 """ + return base lines = [] - - for i in range(1, num_series + 1): - idx = str(i) - - if swatch == "border": + for i, color_idx in enumerate(chart_colors, 1): + if swatch == "line": lines.append(f""" - [&_.recharts-default-tooltip]:!py-2 !flex !flex-col !gap-y-0 - [&_.recharts-tooltip-item:nth-child({idx})]:!border-l-3 - [&_.recharts-tooltip-item:nth-child({idx})]:!border-[var(--chart-{idx})] - [&_.recharts-tooltip-item:nth-child({idx})]:!pl-2 - [&_.recharts-tooltip-item:nth-child({idx})]:!py-0 + [&_.recharts-tooltip-item:nth-child({i})]:before:!content-[''] + [&_.recharts-tooltip-item:nth-child({i})]:before:!w-3 + [&_.recharts-tooltip-item:nth-child({i})]:before:!h-0.5 + [&_.recharts-tooltip-item:nth-child({i})]:before:!rounded-full + [&_.recharts-tooltip-item:nth-child({i})]:before:!flex-shrink-0 + [&_.recharts-tooltip-item:nth-child({i})]:before:!bg-[var(--chart-{color_idx})] + [&_.recharts-tooltip-item:nth-child({i})]:before:!block """) - else: - width = "!w-3" if swatch == "square" else "!w-8" - shrink = ( - f"[&_.recharts-tooltip-item:nth-child({idx})]:before:!flex-shrink-0" - if swatch == "square" - else "" - ) - + else: # square lines.append(f""" - [&_.recharts-tooltip-item:nth-child({idx})]:before:!content-[''] - [&_.recharts-tooltip-item:nth-child({idx})]:before:{width} - {shrink} - [&_.recharts-tooltip-item:nth-child({idx})]:before:!h-3 - [&_.recharts-tooltip-item:nth-child({idx})]:before:!rounded-sm - [&_.recharts-tooltip-item:nth-child({idx})]:before:!bg-[var(--chart-{idx})] - [&_.recharts-tooltip-item:nth-child({idx})]:before:!block + [&_.recharts-tooltip-item:nth-child({i})]:before:!content-[''] + [&_.recharts-tooltip-item:nth-child({i})]:before:!w-3 + [&_.recharts-tooltip-item:nth-child({i})]:before:!h-3 + [&_.recharts-tooltip-item:nth-child({i})]:before:!rounded-sm + [&_.recharts-tooltip-item:nth-child({i})]:before:!flex-shrink-0 + [&_.recharts-tooltip-item:nth-child({i})]:before:!bg-[var(--chart-{color_idx})] + [&_.recharts-tooltip-item:nth-child({i})]:before:!block """) return base + "\n".join(lines) @@ -323,7 +318,7 @@ rx.recharts.bar_chart( data=data, width="100%", height=250, - class_name=chart_tooltip_content(2, "square"), + class_name=chart_tooltip_content([1, 2], "square"), ) ``` @@ -359,7 +354,7 @@ def chart_example_with_custom_tooltip(): data=data, width="100%", height=250, - class_name=chart_tooltip_content(2, "square"), + class_name=chart_tooltip_content([1, 2], "square"), ) ``` @@ -422,7 +417,7 @@ def chart_example_with_custom_legends(): data=data, width="100%", height=250, - class_name=chart_tooltip_content(2, "square"), + class_name=chart_tooltip_content([1, 2], "square"), ), rx.el.div( rx.foreach( @@ -516,7 +511,7 @@ Use the following props to customize the tooltip. | Prop | Type | Default | Description | | :--- | :--- | :--- | :--- | -| `num_series` | `int` | — | Number of data series in the chart. Must match the number of `rx.recharts.bar` / `line` / `area` components. | +| `chart_colors` | `list[int]` | — | Number of data series in the chart. Must match the number of `rx.recharts.bar` / `line` / `area` components. | | `swatch` | `"square" \| "line" \| "border"` | `"square"` | Indicator style per item. `square` = small filled box, `line` = wide pill, `border` = left accent line per series using `--chart-{i}`. | >**chart_tooltip_content()** returns a string of Tailwind classes and must be passed to the **chart component's** class_name, not to **chart_tooltip()**. diff --git a/assets/fuse/searchList.json b/assets/fuse/searchList.json index 33a3261..e76db1a 100644 --- a/assets/fuse/searchList.json +++ b/assets/fuse/searchList.json @@ -243,1455 +243,5 @@ "section": "Charts", "title": "Scatter Chart", "url": "docs/charts/scatter-chart" - }, - { - "section": "Reflex / Advanced Onboarding", - "title": "Code Structure", - "url": "https://reflex.dev/docs/advanced-onboarding/code-structure/" - }, - { - "section": "Reflex / Advanced Onboarding", - "title": "Configuration", - "url": "https://reflex.dev/docs/advanced-onboarding/configuration/" - }, - { - "section": "Reflex / Advanced Onboarding", - "title": "How Reflex Works", - "url": "https://reflex.dev/docs/advanced-onboarding/how-reflex-works/" - }, - { - "section": "Reflex / Ai Builder", - "title": "Apis", - "url": "https://reflex.dev/docs/ai-builder/apis/" - }, - { - "section": "Reflex / Ai Builder / App Lifecycle", - "title": "Copy App", - "url": "https://reflex.dev/docs/ai-builder/app-lifecycle/copy-app/" - }, - { - "section": "Reflex / Ai Builder / App Lifecycle", - "title": "Deploy App", - "url": "https://reflex.dev/docs/ai-builder/app-lifecycle/deploy-app/" - }, - { - "section": "Reflex / Ai Builder / App Lifecycle", - "title": "Download App", - "url": "https://reflex.dev/docs/ai-builder/app-lifecycle/download-app/" - }, - { - "section": "Reflex / Ai Builder / App Lifecycle", - "title": "Fork App", - "url": "https://reflex.dev/docs/ai-builder/app-lifecycle/fork-app/" - }, - { - "section": "Reflex / Ai Builder / App Lifecycle", - "title": "General", - "url": "https://reflex.dev/docs/ai-builder/app-lifecycle/general/" - }, - { - "section": "Reflex / Ai Builder / App Lifecycle", - "title": "Share App", - "url": "https://reflex.dev/docs/ai-builder/app-lifecycle/share-app/" - }, - { - "section": "Reflex / Ai Builder / Features", - "title": "Automated Testing", - "url": "https://reflex.dev/docs/ai-builder/features/automated-testing/" - }, - { - "section": "Reflex / Ai Builder / Features", - "title": "Connect To Github", - "url": "https://reflex.dev/docs/ai-builder/features/connect-to-github/" - }, - { - "section": "Reflex / Ai Builder / Features", - "title": "Customization", - "url": "https://reflex.dev/docs/ai-builder/features/customization/" - }, - { - "section": "Reflex / Ai Builder / Features", - "title": "Editor Modes", - "url": "https://reflex.dev/docs/ai-builder/features/editor-modes/" - }, - { - "section": "Reflex / Ai Builder / Features", - "title": "File Tree", - "url": "https://reflex.dev/docs/ai-builder/features/file-tree/" - }, - { - "section": "Reflex / Ai Builder / Features", - "title": "Ide", - "url": "https://reflex.dev/docs/ai-builder/features/ide/" - }, - { - "section": "Reflex / Ai Builder / Features", - "title": "Image As Prompt", - "url": "https://reflex.dev/docs/ai-builder/features/image-as-prompt/" - }, - { - "section": "Reflex / Ai Builder / Features", - "title": "Installing External Packages", - "url": "https://reflex.dev/docs/ai-builder/features/installing-external-packages/" - }, - { - "section": "Reflex / Ai Builder / Features", - "title": "Integration Shortcut", - "url": "https://reflex.dev/docs/ai-builder/features/integration-shortcut/" - }, - { - "section": "Reflex / Ai Builder / Features", - "title": "Knowledge", - "url": "https://reflex.dev/docs/ai-builder/features/knowledge/" - }, - { - "section": "Reflex / Ai Builder / Features", - "title": "Restore Checkpoint", - "url": "https://reflex.dev/docs/ai-builder/features/restore-checkpoint/" - }, - { - "section": "Reflex / Ai Builder / Features", - "title": "Secrets", - "url": "https://reflex.dev/docs/ai-builder/features/secrets/" - }, - { - "section": "Reflex / Ai Builder", - "title": "Figma", - "url": "https://reflex.dev/docs/ai-builder/figma/" - }, - { - "section": "Reflex / Ai Builder", - "title": "Files", - "url": "https://reflex.dev/docs/ai-builder/files/" - }, - { - "section": "Reflex / Ai Builder", - "title": "Images", - "url": "https://reflex.dev/docs/ai-builder/images/" - }, - { - "section": "Reflex / Ai Builder / Integrations", - "title": "Agents Md", - "url": "https://reflex.dev/docs/ai-builder/integrations/agents-md/" - }, - { - "section": "Reflex / Ai Builder / Integrations", - "title": "Ai Onboarding", - "url": "https://reflex.dev/docs/ai-builder/integrations/ai-onboarding/" - }, - { - "section": "Reflex / Ai Builder / Integrations", - "title": "Mcp Installation", - "url": "https://reflex.dev/docs/ai-builder/integrations/mcp-installation/" - }, - { - "section": "Reflex / Ai Builder / Integrations", - "title": "Mcp Overview", - "url": "https://reflex.dev/docs/ai-builder/integrations/mcp-overview/" - }, - { - "section": "Reflex / Ai Builder / Integrations", - "title": "Overview", - "url": "https://reflex.dev/docs/ai-builder/integrations/overview/" - }, - { - "section": "Reflex / Ai Builder / Integrations", - "title": "Skills", - "url": "https://reflex.dev/docs/ai-builder/integrations/skills/" - }, - { - "section": "Reflex / Ai Builder / Overview", - "title": "Best Practices", - "url": "https://reflex.dev/docs/ai-builder/overview/best-practices/" - }, - { - "section": "Reflex / Ai Builder / Overview", - "title": "Templates", - "url": "https://reflex.dev/docs/ai-builder/overview/templates/" - }, - { - "section": "Reflex / Ai Builder / Overview", - "title": "Tutorial", - "url": "https://reflex.dev/docs/ai-builder/overview/tutorial/" - }, - { - "section": "Reflex / Ai Builder / Overview", - "title": "What Is Reflex Build", - "url": "https://reflex.dev/docs/ai-builder/overview/what-is-reflex-build/" - }, - { - "section": "Reflex / Ai Builder", - "title": "Python Libraries", - "url": "https://reflex.dev/docs/ai-builder/python-libraries/" - }, - { - "section": "Reflex / Ai Builder", - "title": "Urls", - "url": "https://reflex.dev/docs/ai-builder/urls/" - }, - { - "section": "Reflex / Ai Builder", - "title": "Webhooks", - "url": "https://reflex.dev/docs/ai-builder/webhooks/" - }, - { - "section": "Reflex / Api-Reference", - "title": "Browser Javascript", - "url": "https://reflex.dev/docs/api-reference/browser-javascript/" - }, - { - "section": "Reflex / Api-Reference", - "title": "Browser Storage", - "url": "https://reflex.dev/docs/api-reference/browser-storage/" - }, - { - "section": "Reflex / Api-Reference", - "title": "Cli", - "url": "https://reflex.dev/docs/api-reference/cli/" - }, - { - "section": "Reflex / Api-Reference", - "title": "Event Triggers", - "url": "https://reflex.dev/docs/api-reference/event-triggers/" - }, - { - "section": "Reflex / Api-Reference", - "title": "Plugins", - "url": "https://reflex.dev/docs/api-reference/plugins/" - }, - { - "section": "Reflex / Api-Reference", - "title": "Special Events", - "url": "https://reflex.dev/docs/api-reference/special-events/" - }, - { - "section": "Reflex / Api-Reference", - "title": "Telemetry", - "url": "https://reflex.dev/docs/api-reference/telemetry/" - }, - { - "section": "Reflex / Api-Reference", - "title": "Utils", - "url": "https://reflex.dev/docs/api-reference/utils/" - }, - { - "section": "Reflex / Api-Reference", - "title": "Var System", - "url": "https://reflex.dev/docs/api-reference/var-system/" - }, - { - "section": "Reflex / Api-Routes", - "title": "Overview", - "url": "https://reflex.dev/docs/api-routes/overview/" - }, - { - "section": "Reflex / App", - "title": "Claude", - "url": "https://reflex.dev/docs/app/CLAUDE/" - }, - { - "section": "Reflex / App", - "title": "Readme", - "url": "https://reflex.dev/docs/app/README/" - }, - { - "section": "Reflex / Assets", - "title": "Overview", - "url": "https://reflex.dev/docs/assets/overview/" - }, - { - "section": "Reflex / Assets", - "title": "Upload And Download Files", - "url": "https://reflex.dev/docs/assets/upload-and-download-files/" - }, - { - "section": "Reflex / Authentication", - "title": "Authentication Overview", - "url": "https://reflex.dev/docs/authentication/authentication-overview/" - }, - { - "section": "Reflex / Client Storage", - "title": "Overview", - "url": "https://reflex.dev/docs/client-storage/overview/" - }, - { - "section": "Reflex / Components", - "title": "Conditional Rendering", - "url": "https://reflex.dev/docs/components/conditional-rendering/" - }, - { - "section": "Reflex / Components", - "title": "Html To Reflex", - "url": "https://reflex.dev/docs/components/html-to-reflex/" - }, - { - "section": "Reflex / Components", - "title": "Props", - "url": "https://reflex.dev/docs/components/props/" - }, - { - "section": "Reflex / Components", - "title": "Rendering Iterables", - "url": "https://reflex.dev/docs/components/rendering-iterables/" - }, - { - "section": "Reflex / Custom-Components", - "title": "Command Reference", - "url": "https://reflex.dev/docs/custom-components/command-reference/" - }, - { - "section": "Reflex / Custom-Components", - "title": "Overview", - "url": "https://reflex.dev/docs/custom-components/overview/" - }, - { - "section": "Reflex / Custom-Components", - "title": "Prerequisites For Publishing", - "url": "https://reflex.dev/docs/custom-components/prerequisites-for-publishing/" - }, - { - "section": "Reflex / Database", - "title": "Overview", - "url": "https://reflex.dev/docs/database/overview/" - }, - { - "section": "Reflex / Database", - "title": "Queries", - "url": "https://reflex.dev/docs/database/queries/" - }, - { - "section": "Reflex / Database", - "title": "Relationships", - "url": "https://reflex.dev/docs/database/relationships/" - }, - { - "section": "Reflex / Database", - "title": "Tables", - "url": "https://reflex.dev/docs/database/tables/" - }, - { - "section": "Reflex / Enterprise", - "title": "Ag Chart", - "url": "https://reflex.dev/docs/enterprise/ag-chart/" - }, - { - "section": "Reflex / Enterprise / Ag Grid", - "title": "Aligned Grids", - "url": "https://reflex.dev/docs/enterprise/ag-grid/aligned-grids/" - }, - { - "section": "Reflex / Enterprise / Ag Grid", - "title": "Cell Selection", - "url": "https://reflex.dev/docs/enterprise/ag-grid/cell-selection/" - }, - { - "section": "Reflex / Enterprise / Ag Grid", - "title": "Column Defs", - "url": "https://reflex.dev/docs/enterprise/ag-grid/column-defs/" - }, - { - "section": "Reflex / Enterprise / Ag Grid", - "title": "Index", - "url": "https://reflex.dev/docs/enterprise/ag-grid/index/" - }, - { - "section": "Reflex / Enterprise / Ag Grid", - "title": "Model Wrapper", - "url": "https://reflex.dev/docs/enterprise/ag-grid/model-wrapper/" - }, - { - "section": "Reflex / Enterprise / Ag Grid", - "title": "Pivot Mode", - "url": "https://reflex.dev/docs/enterprise/ag-grid/pivot-mode/" - }, - { - "section": "Reflex / Enterprise / Ag Grid", - "title": "Theme", - "url": "https://reflex.dev/docs/enterprise/ag-grid/theme/" - }, - { - "section": "Reflex / Enterprise / Ag Grid", - "title": "Value Transformers", - "url": "https://reflex.dev/docs/enterprise/ag-grid/value-transformers/" - }, - { - "section": "Reflex / Enterprise", - "title": "Built With Reflex", - "url": "https://reflex.dev/docs/enterprise/built-with-reflex/" - }, - { - "section": "Reflex / Enterprise", - "title": "Components", - "url": "https://reflex.dev/docs/enterprise/components/" - }, - { - "section": "Reflex / Enterprise", - "title": "Drag And Drop", - "url": "https://reflex.dev/docs/enterprise/drag-and-drop/" - }, - { - "section": "Reflex / Enterprise", - "title": "Event Handler Api", - "url": "https://reflex.dev/docs/enterprise/event-handler-api/" - }, - { - "section": "Reflex / Enterprise / Mantine", - "title": "Autocomplete", - "url": "https://reflex.dev/docs/enterprise/mantine/autocomplete/" - }, - { - "section": "Reflex / Enterprise / Mantine", - "title": "Collapse", - "url": "https://reflex.dev/docs/enterprise/mantine/collapse/" - }, - { - "section": "Reflex / Enterprise / Mantine", - "title": "Combobox", - "url": "https://reflex.dev/docs/enterprise/mantine/combobox/" - }, - { - "section": "Reflex / Enterprise / Mantine", - "title": "Index", - "url": "https://reflex.dev/docs/enterprise/mantine/index/" - }, - { - "section": "Reflex / Enterprise / Mantine", - "title": "Json Input", - "url": "https://reflex.dev/docs/enterprise/mantine/json-input/" - }, - { - "section": "Reflex / Enterprise / Mantine", - "title": "Loading Overlay", - "url": "https://reflex.dev/docs/enterprise/mantine/loading-overlay/" - }, - { - "section": "Reflex / Enterprise / Mantine", - "title": "Multi Select", - "url": "https://reflex.dev/docs/enterprise/mantine/multi-select/" - }, - { - "section": "Reflex / Enterprise / Mantine", - "title": "Number Formatter", - "url": "https://reflex.dev/docs/enterprise/mantine/number-formatter/" - }, - { - "section": "Reflex / Enterprise / Mantine", - "title": "Pill", - "url": "https://reflex.dev/docs/enterprise/mantine/pill/" - }, - { - "section": "Reflex / Enterprise / Mantine", - "title": "Ring Progress", - "url": "https://reflex.dev/docs/enterprise/mantine/ring-progress/" - }, - { - "section": "Reflex / Enterprise / Mantine", - "title": "Semi Circle Progress", - "url": "https://reflex.dev/docs/enterprise/mantine/semi-circle-progress/" - }, - { - "section": "Reflex / Enterprise / Mantine", - "title": "Spoiler", - "url": "https://reflex.dev/docs/enterprise/mantine/spoiler/" - }, - { - "section": "Reflex / Enterprise / Mantine", - "title": "Tags Input", - "url": "https://reflex.dev/docs/enterprise/mantine/tags-input/" - }, - { - "section": "Reflex / Enterprise / Mantine", - "title": "Timeline", - "url": "https://reflex.dev/docs/enterprise/mantine/timeline/" - }, - { - "section": "Reflex / Enterprise / Mantine", - "title": "Tree", - "url": "https://reflex.dev/docs/enterprise/mantine/tree/" - }, - { - "section": "Reflex / Enterprise / Map", - "title": "Index", - "url": "https://reflex.dev/docs/enterprise/map/index/" - }, - { - "section": "Reflex / Enterprise", - "title": "Overview", - "url": "https://reflex.dev/docs/enterprise/overview/" - }, - { - "section": "Reflex / Enterprise / React Flow", - "title": "Basic Flow", - "url": "https://reflex.dev/docs/enterprise/react-flow/basic-flow/" - }, - { - "section": "Reflex / Enterprise / React Flow", - "title": "Components", - "url": "https://reflex.dev/docs/enterprise/react-flow/components/" - }, - { - "section": "Reflex / Enterprise / React Flow", - "title": "Edges", - "url": "https://reflex.dev/docs/enterprise/react-flow/edges/" - }, - { - "section": "Reflex / Enterprise / React Flow", - "title": "Examples", - "url": "https://reflex.dev/docs/enterprise/react-flow/examples/" - }, - { - "section": "Reflex / Enterprise / React Flow", - "title": "Hooks", - "url": "https://reflex.dev/docs/enterprise/react-flow/hooks/" - }, - { - "section": "Reflex / Enterprise / React Flow", - "title": "Interactivity", - "url": "https://reflex.dev/docs/enterprise/react-flow/interactivity/" - }, - { - "section": "Reflex / Enterprise / React Flow", - "title": "Nodes", - "url": "https://reflex.dev/docs/enterprise/react-flow/nodes/" - }, - { - "section": "Reflex / Enterprise / React Flow", - "title": "Overview", - "url": "https://reflex.dev/docs/enterprise/react-flow/overview/" - }, - { - "section": "Reflex / Enterprise / React Flow", - "title": "Theming", - "url": "https://reflex.dev/docs/enterprise/react-flow/theming/" - }, - { - "section": "Reflex / Enterprise / React Flow", - "title": "Utils", - "url": "https://reflex.dev/docs/enterprise/react-flow/utils/" - }, - { - "section": "Reflex / Enterprise", - "title": "Single Port Proxy", - "url": "https://reflex.dev/docs/enterprise/single-port-proxy/" - }, - { - "section": "Reflex / Events", - "title": "Background Events", - "url": "https://reflex.dev/docs/events/background-events/" - }, - { - "section": "Reflex / Events", - "title": "Chaining Events", - "url": "https://reflex.dev/docs/events/chaining-events/" - }, - { - "section": "Reflex / Events", - "title": "Decentralized Event Handlers", - "url": "https://reflex.dev/docs/events/decentralized-event-handlers/" - }, - { - "section": "Reflex / Events", - "title": "Event Actions", - "url": "https://reflex.dev/docs/events/event-actions/" - }, - { - "section": "Reflex / Events", - "title": "Event Arguments", - "url": "https://reflex.dev/docs/events/event-arguments/" - }, - { - "section": "Reflex / Events", - "title": "Events Overview", - "url": "https://reflex.dev/docs/events/events-overview/" - }, - { - "section": "Reflex / Events", - "title": "Page Load Events", - "url": "https://reflex.dev/docs/events/page-load-events/" - }, - { - "section": "Reflex / Events", - "title": "Special Events", - "url": "https://reflex.dev/docs/events/special-events/" - }, - { - "section": "Reflex / Events", - "title": "Yield Events", - "url": "https://reflex.dev/docs/events/yield-events/" - }, - { - "section": "Reflex / Getting Started", - "title": "Basics", - "url": "https://reflex.dev/docs/getting-started/basics/" - }, - { - "section": "Reflex / Getting Started", - "title": "Chatapp Tutorial", - "url": "https://reflex.dev/docs/getting-started/chatapp-tutorial/" - }, - { - "section": "Reflex / Getting Started", - "title": "Dashboard Tutorial", - "url": "https://reflex.dev/docs/getting-started/dashboard-tutorial/" - }, - { - "section": "Reflex / Getting Started", - "title": "Installation", - "url": "https://reflex.dev/docs/getting-started/installation/" - }, - { - "section": "Reflex / Getting Started", - "title": "Introduction", - "url": "https://reflex.dev/docs/getting-started/introduction/" - }, - { - "section": "Reflex / Getting Started", - "title": "Project Structure", - "url": "https://reflex.dev/docs/getting-started/project-structure/" - }, - { - "section": "Reflex / Hosting", - "title": "Adding Members", - "url": "https://reflex.dev/docs/hosting/adding-members/" - }, - { - "section": "Reflex / Hosting", - "title": "App Management", - "url": "https://reflex.dev/docs/hosting/app-management/" - }, - { - "section": "Reflex / Hosting", - "title": "Billing", - "url": "https://reflex.dev/docs/hosting/billing/" - }, - { - "section": "Reflex / Hosting", - "title": "Bring Your Own Cloud", - "url": "https://reflex.dev/docs/hosting/bring-your-own-cloud/" - }, - { - "section": "Reflex / Hosting", - "title": "Compute", - "url": "https://reflex.dev/docs/hosting/compute/" - }, - { - "section": "Reflex / Hosting", - "title": "Config File", - "url": "https://reflex.dev/docs/hosting/config-file/" - }, - { - "section": "Reflex / Hosting", - "title": "Custom Domains", - "url": "https://reflex.dev/docs/hosting/custom-domains/" - }, - { - "section": "Reflex / Hosting", - "title": "Databricks", - "url": "https://reflex.dev/docs/hosting/databricks/" - }, - { - "section": "Reflex / Hosting", - "title": "Deploy Quick Start", - "url": "https://reflex.dev/docs/hosting/deploy-quick-start/" - }, - { - "section": "Reflex / Hosting", - "title": "Deploy To Gcp", - "url": "https://reflex.dev/docs/hosting/deploy-to-gcp/" - }, - { - "section": "Reflex / Hosting", - "title": "Deploy With Github Actions", - "url": "https://reflex.dev/docs/hosting/deploy-with-github-actions/" - }, - { - "section": "Reflex / Hosting", - "title": "Logs", - "url": "https://reflex.dev/docs/hosting/logs/" - }, - { - "section": "Reflex / Hosting", - "title": "Machine Types", - "url": "https://reflex.dev/docs/hosting/machine-types/" - }, - { - "section": "Reflex / Hosting", - "title": "Regions", - "url": "https://reflex.dev/docs/hosting/regions/" - }, - { - "section": "Reflex / Hosting", - "title": "Secrets Environment Vars", - "url": "https://reflex.dev/docs/hosting/secrets-environment-vars/" - }, - { - "section": "Reflex / Hosting", - "title": "Security Scan", - "url": "https://reflex.dev/docs/hosting/security-scan/" - }, - { - "section": "Reflex / Hosting", - "title": "Self Hosting", - "url": "https://reflex.dev/docs/hosting/self-hosting/" - }, - { - "section": "Reflex / Hosting", - "title": "Tokens", - "url": "https://reflex.dev/docs/hosting/tokens/" - }, - { - "section": "Reflex / Library / Data-Display", - "title": "Avatar", - "url": "https://reflex.dev/docs/library/data-display/avatar/" - }, - { - "section": "Reflex / Library / Data-Display", - "title": "Badge", - "url": "https://reflex.dev/docs/library/data-display/badge/" - }, - { - "section": "Reflex / Library / Data-Display", - "title": "Callout Ll", - "url": "https://reflex.dev/docs/library/data-display/callout-ll/" - }, - { - "section": "Reflex / Library / Data-Display", - "title": "Callout", - "url": "https://reflex.dev/docs/library/data-display/callout/" - }, - { - "section": "Reflex / Library / Data-Display", - "title": "Code Block", - "url": "https://reflex.dev/docs/library/data-display/code-block/" - }, - { - "section": "Reflex / Library / Data-Display", - "title": "Data List", - "url": "https://reflex.dev/docs/library/data-display/data-list/" - }, - { - "section": "Reflex / Library / Data-Display", - "title": "Icon", - "url": "https://reflex.dev/docs/library/data-display/icon/" - }, - { - "section": "Reflex / Library / Data-Display", - "title": "List", - "url": "https://reflex.dev/docs/library/data-display/list/" - }, - { - "section": "Reflex / Library / Data-Display", - "title": "Moment", - "url": "https://reflex.dev/docs/library/data-display/moment/" - }, - { - "section": "Reflex / Library / Data-Display", - "title": "Progress", - "url": "https://reflex.dev/docs/library/data-display/progress/" - }, - { - "section": "Reflex / Library / Data-Display", - "title": "Scroll Area", - "url": "https://reflex.dev/docs/library/data-display/scroll-area/" - }, - { - "section": "Reflex / Library / Data-Display", - "title": "Spinner", - "url": "https://reflex.dev/docs/library/data-display/spinner/" - }, - { - "section": "Reflex / Library / Disclosure", - "title": "Accordion", - "url": "https://reflex.dev/docs/library/disclosure/accordion/" - }, - { - "section": "Reflex / Library / Disclosure", - "title": "Segmented Control", - "url": "https://reflex.dev/docs/library/disclosure/segmented-control/" - }, - { - "section": "Reflex / Library / Disclosure", - "title": "Tabs", - "url": "https://reflex.dev/docs/library/disclosure/tabs/" - }, - { - "section": "Reflex / Library / Dynamic-Rendering", - "title": "Auto Scroll", - "url": "https://reflex.dev/docs/library/dynamic-rendering/auto-scroll/" - }, - { - "section": "Reflex / Library / Dynamic-Rendering", - "title": "Cond", - "url": "https://reflex.dev/docs/library/dynamic-rendering/cond/" - }, - { - "section": "Reflex / Library / Dynamic-Rendering", - "title": "Foreach", - "url": "https://reflex.dev/docs/library/dynamic-rendering/foreach/" - }, - { - "section": "Reflex / Library / Dynamic-Rendering", - "title": "Match", - "url": "https://reflex.dev/docs/library/dynamic-rendering/match/" - }, - { - "section": "Reflex / Library / Forms", - "title": "Button", - "url": "https://reflex.dev/docs/library/forms/button/" - }, - { - "section": "Reflex / Library / Forms", - "title": "Checkbox", - "url": "https://reflex.dev/docs/library/forms/checkbox/" - }, - { - "section": "Reflex / Library / Forms", - "title": "Form Ll", - "url": "https://reflex.dev/docs/library/forms/form-ll/" - }, - { - "section": "Reflex / Library / Forms", - "title": "Form", - "url": "https://reflex.dev/docs/library/forms/form/" - }, - { - "section": "Reflex / Library / Forms", - "title": "Input Ll", - "url": "https://reflex.dev/docs/library/forms/input-ll/" - }, - { - "section": "Reflex / Library / Forms", - "title": "Input", - "url": "https://reflex.dev/docs/library/forms/input/" - }, - { - "section": "Reflex / Library / Forms", - "title": "Radio Group", - "url": "https://reflex.dev/docs/library/forms/radio-group/" - }, - { - "section": "Reflex / Library / Forms", - "title": "Select Ll", - "url": "https://reflex.dev/docs/library/forms/select-ll/" - }, - { - "section": "Reflex / Library / Forms", - "title": "Select", - "url": "https://reflex.dev/docs/library/forms/select/" - }, - { - "section": "Reflex / Library / Forms", - "title": "Slider", - "url": "https://reflex.dev/docs/library/forms/slider/" - }, - { - "section": "Reflex / Library / Forms", - "title": "Switch", - "url": "https://reflex.dev/docs/library/forms/switch/" - }, - { - "section": "Reflex / Library / Forms", - "title": "Text Area", - "url": "https://reflex.dev/docs/library/forms/text-area/" - }, - { - "section": "Reflex / Library / Forms", - "title": "Upload", - "url": "https://reflex.dev/docs/library/forms/upload/" - }, - { - "section": "Reflex / Library / Graphing", - "title": "Areachart", - "url": "https://reflex.dev/docs/library/graphing/charts/areachart/" - }, - { - "section": "Reflex / Library / Graphing", - "title": "Barchart", - "url": "https://reflex.dev/docs/library/graphing/charts/barchart/" - }, - { - "section": "Reflex / Library / Graphing", - "title": "Composedchart", - "url": "https://reflex.dev/docs/library/graphing/charts/composedchart/" - }, - { - "section": "Reflex / Library / Graphing", - "title": "Errorbar", - "url": "https://reflex.dev/docs/library/graphing/charts/errorbar/" - }, - { - "section": "Reflex / Library / Graphing", - "title": "Funnelchart", - "url": "https://reflex.dev/docs/library/graphing/charts/funnelchart/" - }, - { - "section": "Reflex / Library / Graphing", - "title": "Linechart", - "url": "https://reflex.dev/docs/library/graphing/charts/linechart/" - }, - { - "section": "Reflex / Library / Graphing", - "title": "Piechart", - "url": "https://reflex.dev/docs/library/graphing/charts/piechart/" - }, - { - "section": "Reflex / Library / Graphing", - "title": "Radarchart", - "url": "https://reflex.dev/docs/library/graphing/charts/radarchart/" - }, - { - "section": "Reflex / Library / Graphing", - "title": "Radialbarchart", - "url": "https://reflex.dev/docs/library/graphing/charts/radialbarchart/" - }, - { - "section": "Reflex / Library / Graphing", - "title": "Scatterchart", - "url": "https://reflex.dev/docs/library/graphing/charts/scatterchart/" - }, - { - "section": "Reflex / Library / Graphing", - "title": "Axis", - "url": "https://reflex.dev/docs/library/graphing/general/axis/" - }, - { - "section": "Reflex / Library / Graphing", - "title": "Brush", - "url": "https://reflex.dev/docs/library/graphing/general/brush/" - }, - { - "section": "Reflex / Library / Graphing", - "title": "Cartesiangrid", - "url": "https://reflex.dev/docs/library/graphing/general/cartesiangrid/" - }, - { - "section": "Reflex / Library / Graphing", - "title": "Label", - "url": "https://reflex.dev/docs/library/graphing/general/label/" - }, - { - "section": "Reflex / Library / Graphing", - "title": "Legend", - "url": "https://reflex.dev/docs/library/graphing/general/legend/" - }, - { - "section": "Reflex / Library / Graphing", - "title": "Reference", - "url": "https://reflex.dev/docs/library/graphing/general/reference/" - }, - { - "section": "Reflex / Library / Graphing", - "title": "Tooltip", - "url": "https://reflex.dev/docs/library/graphing/general/tooltip/" - }, - { - "section": "Reflex / Library / Graphing", - "title": "Plotly", - "url": "https://reflex.dev/docs/library/graphing/other-charts/plotly/" - }, - { - "section": "Reflex / Library / Graphing", - "title": "Pyplot", - "url": "https://reflex.dev/docs/library/graphing/other-charts/pyplot/" - }, - { - "section": "Reflex / Library / Html", - "title": "Forms", - "url": "https://reflex.dev/docs/library/html/forms/" - }, - { - "section": "Reflex / Library / Html", - "title": "Html", - "url": "https://reflex.dev/docs/library/html/html/" - }, - { - "section": "Reflex / Library / Html", - "title": "Layout", - "url": "https://reflex.dev/docs/library/html/layout/" - }, - { - "section": "Reflex / Library / Html", - "title": "Media", - "url": "https://reflex.dev/docs/library/html/media/" - }, - { - "section": "Reflex / Library / Html", - "title": "Svg", - "url": "https://reflex.dev/docs/library/html/svg/" - }, - { - "section": "Reflex / Library / Html", - "title": "Tables", - "url": "https://reflex.dev/docs/library/html/tables/" - }, - { - "section": "Reflex / Library / Html", - "title": "Text", - "url": "https://reflex.dev/docs/library/html/text/" - }, - { - "section": "Reflex / Library / Layout", - "title": "Aspect Ratio", - "url": "https://reflex.dev/docs/library/layout/aspect-ratio/" - }, - { - "section": "Reflex / Library / Layout", - "title": "Box", - "url": "https://reflex.dev/docs/library/layout/box/" - }, - { - "section": "Reflex / Library / Layout", - "title": "Card", - "url": "https://reflex.dev/docs/library/layout/card/" - }, - { - "section": "Reflex / Library / Layout", - "title": "Center", - "url": "https://reflex.dev/docs/library/layout/center/" - }, - { - "section": "Reflex / Library / Layout", - "title": "Container", - "url": "https://reflex.dev/docs/library/layout/container/" - }, - { - "section": "Reflex / Library / Layout", - "title": "Flex", - "url": "https://reflex.dev/docs/library/layout/flex/" - }, - { - "section": "Reflex / Library / Layout", - "title": "Fragment", - "url": "https://reflex.dev/docs/library/layout/fragment/" - }, - { - "section": "Reflex / Library / Layout", - "title": "Grid", - "url": "https://reflex.dev/docs/library/layout/grid/" - }, - { - "section": "Reflex / Library / Layout", - "title": "Inset", - "url": "https://reflex.dev/docs/library/layout/inset/" - }, - { - "section": "Reflex / Library / Layout", - "title": "Section", - "url": "https://reflex.dev/docs/library/layout/section/" - }, - { - "section": "Reflex / Library / Layout", - "title": "Separator", - "url": "https://reflex.dev/docs/library/layout/separator/" - }, - { - "section": "Reflex / Library / Layout", - "title": "Spacer", - "url": "https://reflex.dev/docs/library/layout/spacer/" - }, - { - "section": "Reflex / Library / Layout", - "title": "Stack", - "url": "https://reflex.dev/docs/library/layout/stack/" - }, - { - "section": "Reflex / Library / Media", - "title": "Audio", - "url": "https://reflex.dev/docs/library/media/audio/" - }, - { - "section": "Reflex / Library / Media", - "title": "Image", - "url": "https://reflex.dev/docs/library/media/image/" - }, - { - "section": "Reflex / Library / Media", - "title": "Video", - "url": "https://reflex.dev/docs/library/media/video/" - }, - { - "section": "Reflex / Library / Other", - "title": "Clipboard", - "url": "https://reflex.dev/docs/library/other/clipboard/" - }, - { - "section": "Reflex / Library / Other", - "title": "Html Embed", - "url": "https://reflex.dev/docs/library/other/html-embed/" - }, - { - "section": "Reflex / Library / Other", - "title": "Memo", - "url": "https://reflex.dev/docs/library/other/memo/" - }, - { - "section": "Reflex / Library / Other", - "title": "Script", - "url": "https://reflex.dev/docs/library/other/script/" - }, - { - "section": "Reflex / Library / Other", - "title": "Skeleton", - "url": "https://reflex.dev/docs/library/other/skeleton/" - }, - { - "section": "Reflex / Library / Other", - "title": "Theme", - "url": "https://reflex.dev/docs/library/other/theme/" - }, - { - "section": "Reflex / Library / Overlay", - "title": "Alert Dialog", - "url": "https://reflex.dev/docs/library/overlay/alert-dialog/" - }, - { - "section": "Reflex / Library / Overlay", - "title": "Context Menu", - "url": "https://reflex.dev/docs/library/overlay/context-menu/" - }, - { - "section": "Reflex / Library / Overlay", - "title": "Dialog", - "url": "https://reflex.dev/docs/library/overlay/dialog/" - }, - { - "section": "Reflex / Library / Overlay", - "title": "Drawer", - "url": "https://reflex.dev/docs/library/overlay/drawer/" - }, - { - "section": "Reflex / Library / Overlay", - "title": "Dropdown Menu", - "url": "https://reflex.dev/docs/library/overlay/dropdown-menu/" - }, - { - "section": "Reflex / Library / Overlay", - "title": "Hover Card", - "url": "https://reflex.dev/docs/library/overlay/hover-card/" - }, - { - "section": "Reflex / Library / Overlay", - "title": "Popover", - "url": "https://reflex.dev/docs/library/overlay/popover/" - }, - { - "section": "Reflex / Library / Overlay", - "title": "Toast", - "url": "https://reflex.dev/docs/library/overlay/toast/" - }, - { - "section": "Reflex / Library / Overlay", - "title": "Tooltip", - "url": "https://reflex.dev/docs/library/overlay/tooltip/" - }, - { - "section": "Reflex / Library / Tables-And-Data-Grids", - "title": "Data Editor", - "url": "https://reflex.dev/docs/library/tables-and-data-grids/data-editor/" - }, - { - "section": "Reflex / Library / Tables-And-Data-Grids", - "title": "Data Table", - "url": "https://reflex.dev/docs/library/tables-and-data-grids/data-table/" - }, - { - "section": "Reflex / Library / Tables-And-Data-Grids", - "title": "Table", - "url": "https://reflex.dev/docs/library/tables-and-data-grids/table/" - }, - { - "section": "Reflex / Library / Typography", - "title": "Blockquote", - "url": "https://reflex.dev/docs/library/typography/blockquote/" - }, - { - "section": "Reflex / Library / Typography", - "title": "Code", - "url": "https://reflex.dev/docs/library/typography/code/" - }, - { - "section": "Reflex / Library / Typography", - "title": "Em", - "url": "https://reflex.dev/docs/library/typography/em/" - }, - { - "section": "Reflex / Library / Typography", - "title": "Heading", - "url": "https://reflex.dev/docs/library/typography/heading/" - }, - { - "section": "Reflex / Library / Typography", - "title": "Kbd", - "url": "https://reflex.dev/docs/library/typography/kbd/" - }, - { - "section": "Reflex / Library / Typography", - "title": "Link", - "url": "https://reflex.dev/docs/library/typography/link/" - }, - { - "section": "Reflex / Library / Typography", - "title": "Markdown", - "url": "https://reflex.dev/docs/library/typography/markdown/" - }, - { - "section": "Reflex / Library / Typography", - "title": "Quote", - "url": "https://reflex.dev/docs/library/typography/quote/" - }, - { - "section": "Reflex / Library / Typography", - "title": "Strong", - "url": "https://reflex.dev/docs/library/typography/strong/" - }, - { - "section": "Reflex / Library / Typography", - "title": "Text", - "url": "https://reflex.dev/docs/library/typography/text/" - }, - { - "section": "Reflex / Package", - "title": "Readme", - "url": "https://reflex.dev/docs/package/README/" - }, - { - "section": "Reflex / Pages", - "title": "Dynamic Routing", - "url": "https://reflex.dev/docs/pages/dynamic-routing/" - }, - { - "section": "Reflex / Pages", - "title": "Overview", - "url": "https://reflex.dev/docs/pages/overview/" - }, - { - "section": "Reflex / Recipes / Auth", - "title": "Login Form", - "url": "https://reflex.dev/docs/recipes/auth/login-form/" - }, - { - "section": "Reflex / Recipes / Auth", - "title": "Signup Form", - "url": "https://reflex.dev/docs/recipes/auth/signup-form/" - }, - { - "section": "Reflex / Recipes / Content", - "title": "Forms", - "url": "https://reflex.dev/docs/recipes/content/forms/" - }, - { - "section": "Reflex / Recipes / Content", - "title": "Grid", - "url": "https://reflex.dev/docs/recipes/content/grid/" - }, - { - "section": "Reflex / Recipes / Content", - "title": "Multi Column Row", - "url": "https://reflex.dev/docs/recipes/content/multi-column-row/" - }, - { - "section": "Reflex / Recipes / Content", - "title": "Stats", - "url": "https://reflex.dev/docs/recipes/content/stats/" - }, - { - "section": "Reflex / Recipes / Content", - "title": "Top Banner", - "url": "https://reflex.dev/docs/recipes/content/top-banner/" - }, - { - "section": "Reflex / Recipes / Layout", - "title": "Footer", - "url": "https://reflex.dev/docs/recipes/layout/footer/" - }, - { - "section": "Reflex / Recipes / Layout", - "title": "Navbar", - "url": "https://reflex.dev/docs/recipes/layout/navbar/" - }, - { - "section": "Reflex / Recipes / Layout", - "title": "Sidebar", - "url": "https://reflex.dev/docs/recipes/layout/sidebar/" - }, - { - "section": "Reflex / Recipes / Others", - "title": "Checkboxes", - "url": "https://reflex.dev/docs/recipes/others/checkboxes/" - }, - { - "section": "Reflex / Recipes / Others", - "title": "Chips", - "url": "https://reflex.dev/docs/recipes/others/chips/" - }, - { - "section": "Reflex / Recipes / Others", - "title": "Dark Mode Toggle", - "url": "https://reflex.dev/docs/recipes/others/dark-mode-toggle/" - }, - { - "section": "Reflex / Recipes / Others", - "title": "Pricing Cards", - "url": "https://reflex.dev/docs/recipes/others/pricing-cards/" - }, - { - "section": "Reflex / Recipes / Others", - "title": "Speed Dial", - "url": "https://reflex.dev/docs/recipes/others/speed-dial/" - }, - { - "section": "Reflex / State", - "title": "Overview", - "url": "https://reflex.dev/docs/state/overview/" - }, - { - "section": "Reflex / State Structure", - "title": "Component State", - "url": "https://reflex.dev/docs/state-structure/component-state/" - }, - { - "section": "Reflex / State Structure", - "title": "Mixins", - "url": "https://reflex.dev/docs/state-structure/mixins/" - }, - { - "section": "Reflex / State Structure", - "title": "Overview", - "url": "https://reflex.dev/docs/state-structure/overview/" - }, - { - "section": "Reflex / State Structure", - "title": "Shared State", - "url": "https://reflex.dev/docs/state-structure/shared-state/" - }, - { - "section": "Reflex / Styling", - "title": "Common Props", - "url": "https://reflex.dev/docs/styling/common-props/" - }, - { - "section": "Reflex / Styling", - "title": "Custom Stylesheets", - "url": "https://reflex.dev/docs/styling/custom-stylesheets/" - }, - { - "section": "Reflex / Styling", - "title": "Layout", - "url": "https://reflex.dev/docs/styling/layout/" - }, - { - "section": "Reflex / Styling", - "title": "Overview", - "url": "https://reflex.dev/docs/styling/overview/" - }, - { - "section": "Reflex / Styling", - "title": "Responsive", - "url": "https://reflex.dev/docs/styling/responsive/" - }, - { - "section": "Reflex / Styling", - "title": "Tailwind", - "url": "https://reflex.dev/docs/styling/tailwind/" - }, - { - "section": "Reflex / Styling", - "title": "Theming", - "url": "https://reflex.dev/docs/styling/theming/" - }, - { - "section": "Reflex / Ui", - "title": "Overview", - "url": "https://reflex.dev/docs/ui/overview/" - }, - { - "section": "Reflex / Utility Methods", - "title": "Exception Handlers", - "url": "https://reflex.dev/docs/utility-methods/exception-handlers/" - }, - { - "section": "Reflex / Utility Methods", - "title": "Lifespan Tasks", - "url": "https://reflex.dev/docs/utility-methods/lifespan-tasks/" - }, - { - "section": "Reflex / Utility Methods", - "title": "Other Methods", - "url": "https://reflex.dev/docs/utility-methods/other-methods/" - }, - { - "section": "Reflex / Utility Methods", - "title": "Router Attributes", - "url": "https://reflex.dev/docs/utility-methods/router-attributes/" - }, - { - "section": "Reflex / Vars", - "title": "Base Vars", - "url": "https://reflex.dev/docs/vars/base-vars/" - }, - { - "section": "Reflex / Vars", - "title": "Computed Vars", - "url": "https://reflex.dev/docs/vars/computed-vars/" - }, - { - "section": "Reflex / Vars", - "title": "Custom Vars", - "url": "https://reflex.dev/docs/vars/custom-vars/" - }, - { - "section": "Reflex / Vars", - "title": "Var Operations", - "url": "https://reflex.dev/docs/vars/var-operations/" - }, - { - "section": "Reflex / Wrapping-React", - "title": "Custom Code And Hooks", - "url": "https://reflex.dev/docs/wrapping-react/custom-code-and-hooks/" - }, - { - "section": "Reflex / Wrapping-React", - "title": "Example", - "url": "https://reflex.dev/docs/wrapping-react/example/" - }, - { - "section": "Reflex / Wrapping-React", - "title": "Imports And Styles", - "url": "https://reflex.dev/docs/wrapping-react/imports-and-styles/" - }, - { - "section": "Reflex / Wrapping-React", - "title": "Library And Tags", - "url": "https://reflex.dev/docs/wrapping-react/library-and-tags/" - }, - { - "section": "Reflex / Wrapping-React", - "title": "Local Packages", - "url": "https://reflex.dev/docs/wrapping-react/local-packages/" - }, - { - "section": "Reflex / Wrapping-React", - "title": "More Wrapping Examples", - "url": "https://reflex.dev/docs/wrapping-react/more-wrapping-examples/" - }, - { - "section": "Reflex / Wrapping-React", - "title": "Overview", - "url": "https://reflex.dev/docs/wrapping-react/overview/" - }, - { - "section": "Reflex / Wrapping-React", - "title": "Props", - "url": "https://reflex.dev/docs/wrapping-react/props/" - }, - { - "section": "Reflex / Wrapping-React", - "title": "Serializers", - "url": "https://reflex.dev/docs/wrapping-react/serializers/" - }, - { - "section": "Reflex / Wrapping-React", - "title": "Step By Step", - "url": "https://reflex.dev/docs/wrapping-react/step-by-step/" } ] \ No newline at end of file diff --git a/assets/social/blocks.webp b/assets/social/blocks.webp new file mode 100644 index 0000000000000000000000000000000000000000..ac1d7de67985e407c617583ce8272e2f2d60382d GIT binary patch literal 23808 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 literal 0 HcmV?d00001 diff --git a/components/charts/chart_tooltip.py b/components/charts/chart_tooltip.py index 14ed716..891739b 100644 --- a/components/charts/chart_tooltip.py +++ b/components/charts/chart_tooltip.py @@ -64,53 +64,48 @@ def __call__( class _ChartTooltipContent: - def __call__(self, num_series: int, swatch: Swatch = "square") -> str: + def __call__(self, chart_colors: list[int], swatch: Swatch = "square") -> str: base = """ [&_.recharts-tooltip-item-name]:!text-muted-foreground [&_.recharts-tooltip-item-separator]:!w-full - [&_.recharts-tooltip-item]:!w-[8rem] + [&_.recharts-tooltip-item]:!min-w-[8rem] [&_.recharts-tooltip-item]:!flex [&_.recharts-tooltip-item]:!items-center [&_.recharts-tooltip-item]:!gap-2 """ if swatch == "border": - base += """ - [&_.recharts-tooltip-label]:!border-l-3 - [&_.recharts-tooltip-label]:!border-[var(--chart-1)] + # Single vertical left border on the tooltip label using first color + first_color = chart_colors[0] + base += f""" + [&_.recharts-tooltip-label]:!border-l-2 + [&_.recharts-tooltip-label]:!border-[var(--chart-{first_color})] [&_.recharts-tooltip-label]:!pl-2 [&_.recharts-tooltip-label]:!py-0 """ + return base lines = [] - - for i in range(1, num_series + 1): - idx = str(i) - - if swatch == "border": + for i, color_idx in enumerate(chart_colors, 1): + if swatch == "line": lines.append(f""" - [&_.recharts-default-tooltip]:!py-2 !flex !flex-col !gap-y-0 - [&_.recharts-tooltip-item:nth-child({idx})]:!border-l-3 - [&_.recharts-tooltip-item:nth-child({idx})]:!border-[var(--chart-{idx})] - [&_.recharts-tooltip-item:nth-child({idx})]:!pl-2 - [&_.recharts-tooltip-item:nth-child({idx})]:!py-0 + [&_.recharts-tooltip-item:nth-child({i})]:before:!content-[''] + [&_.recharts-tooltip-item:nth-child({i})]:before:!w-3 + [&_.recharts-tooltip-item:nth-child({i})]:before:!h-0.5 + [&_.recharts-tooltip-item:nth-child({i})]:before:!rounded-full + [&_.recharts-tooltip-item:nth-child({i})]:before:!flex-shrink-0 + [&_.recharts-tooltip-item:nth-child({i})]:before:!bg-[var(--chart-{color_idx})] + [&_.recharts-tooltip-item:nth-child({i})]:before:!block """) - else: - width = "!w-3" if swatch == "square" else "!w-8" - shrink = ( - f"[&_.recharts-tooltip-item:nth-child({idx})]:before:!flex-shrink-0" - if swatch == "square" - else "" - ) - + else: # square lines.append(f""" - [&_.recharts-tooltip-item:nth-child({idx})]:before:!content-[''] - [&_.recharts-tooltip-item:nth-child({idx})]:before:{width} - {shrink} - [&_.recharts-tooltip-item:nth-child({idx})]:before:!h-3 - [&_.recharts-tooltip-item:nth-child({idx})]:before:!rounded-sm - [&_.recharts-tooltip-item:nth-child({idx})]:before:!bg-[var(--chart-{idx})] - [&_.recharts-tooltip-item:nth-child({idx})]:before:!block + [&_.recharts-tooltip-item:nth-child({i})]:before:!content-[''] + [&_.recharts-tooltip-item:nth-child({i})]:before:!w-3 + [&_.recharts-tooltip-item:nth-child({i})]:before:!h-3 + [&_.recharts-tooltip-item:nth-child({i})]:before:!rounded-sm + [&_.recharts-tooltip-item:nth-child({i})]:before:!flex-shrink-0 + [&_.recharts-tooltip-item:nth-child({i})]:before:!bg-[var(--chart-{color_idx})] + [&_.recharts-tooltip-item:nth-child({i})]:before:!block """) return base + "\n".join(lines) diff --git a/components/icons/hugeicon.py b/components/icons/hugeicon.py index bd1514a..73f0752 100644 --- a/components/icons/hugeicon.py +++ b/components/icons/hugeicon.py @@ -3,60 +3,70 @@ from reflex.components.component import Component from reflex.utils.imports import ImportVar from reflex.vars.base import Var, VarData +from reflex_components_internal.components.component import CoreComponent -from ..ui.component import CoreComponent +REACT_LIBRARY = "@hugeicons/react@1.1.6" +CORE_ICONS_LIBRARY = "@hugeicons/core-free-icons@4.2.1" class HugeIcon(CoreComponent): - """A HugeIcon component.""" - - library = "@hugeicons/react@1.1.1" + """A HugeIcon component using HugeiconsIcon from @hugeicons/react.""" + library = REACT_LIBRARY tag = "HugeiconsIcon" - # The main icon to display + # Main icon icon: Var[str] - # Alternative icon for states/interactions + # Alternative icon alt_icon: Var[str | None] - # Whether to show the alternative icon + # Toggle alt icon show_alt: Var[bool] - # The size of the icon in pixels - size: Var[int] = Var.create(16) + # Size (px or css value) + size: Var[int | str] = Var.create(16) - # The stroke width of the icon - stroke_width: Var[float] = Var.create(2) + # Colors + color: Var[str] + primary_color: Var[str] + secondary_color: Var[str] - @classmethod - def create(cls, *children, **props) -> Component: - """Initialize the Icon component. + # Stroke options + stroke_width: Var[float] = Var.create(1.5) + absolute_stroke_width: Var[bool] - Args: - *children: The positional arguments - **props: The keyword arguments + # Multicolor option + disable_secondary_opacity: Var[bool] - Returns: - The created component. + @classmethod + def create(cls, *children, **props) -> Component: + """Create icon component.""" - """ + # Support: + # hi("HomeIcon") if children and isinstance(children[0], str) and "icon" not in props: props["icon"] = children[0] children = children[1:] - for prop in ["icon", "alt_icon"]: - if prop in props and isinstance(props[prop], str): - icon_name = props[prop] + + # Convert icon strings into import-backed Vars + for prop in ("icon", "alt_icon"): + value = props.get(prop) + + if isinstance(value, str): props[prop] = Var( - icon_name, + value, _var_data=VarData( - imports={ - "@hugeicons/core-free-icons@1.1.0": ImportVar(tag=icon_name) - } + imports={CORE_ICONS_LIBRARY: [ImportVar(tag=value)]} ), ) - stroke_width = props.pop("stroke_width", 2) - cls.set_class_name(f"[&_path]:stroke-[{stroke_width}]", props) + + stroke_width = props.get("stroke_width", 1.5) + + cls.set_class_name( + f"[&_path]:stroke-[{stroke_width}]", + props, + ) return super().create(*children, **props) diff --git a/components/utils/twmerge.py b/components/utils/twmerge.py index 3bec61d..688f59a 100644 --- a/components/utils/twmerge.py +++ b/components/utils/twmerge.py @@ -4,6 +4,11 @@ from reflex.vars import FunctionVar, Var from reflex.vars.base import VarData +CN = Var( + "cn", + _var_data=VarData(imports={"clsx-for-tailwind@1.0.0": ImportVar(tag="cn")}), +).to(FunctionVar) + def cn( *classes: Var | str | tuple | list | None, @@ -17,12 +22,4 @@ def cn( Var: A Var representing the merged classes string. """ - return ( - Var( - "cn", - _var_data=VarData(imports={"clsx-for-tailwind": ImportVar(tag="cn")}), - ) - .to(FunctionVar) - .call(*classes) - .to(str) - ) + return CN.call(*classes).to(str) diff --git a/dev.sh b/dev.sh deleted file mode 100755 index da53fd5..0000000 --- a/dev.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash -# dev.sh - Helper script for Buridan UI development -# Usage: -# ./dev.sh page getting-started/introduction components/button -# ./dev.sh off -# ./dev.sh list - -# Function to list available pages by scanning the docs directory -list_pages() { - echo "Available pages (slugs):" - # Find all markdown files, remove 'docs/' prefix and '.md' suffix, - # and replace underscores with hyphens to create the page slug. - find docs -name "*.md" | sed 's_docs/\(.*\)\.md_\1_' | sed 's/_/-/g' | sort -} - -MODE=$1 -shift - -case $MODE in - list) - list_pages - exit 0 - ;; - page) - if [ -z "$1" ]; then - echo "Error: No pages specified for 'page' mode." - echo "Usage: ./dev.sh page ..." - exit 1 - fi - export BURIDAN_DEV_MODE=true - export BURIDAN_DEV_PAGES=$(echo "$@" | tr ' ' ',') - echo "Development mode: Loading only specified pages - ${BURIDAN_DEV_PAGES}" - ;; - off) - unset BURIDAN_DEV_MODE - unset BURIDAN_DEV_PAGES - echo "Development mode: Disabled (loading all pages)" - ;; - *) - echo "Invalid mode. Use: page, list, or off" - exit 1 - ;; -esac - -# Run Reflex -uv run reflex run diff --git a/docs/charts/bar_chart.md b/docs/charts/bar_chart.md index c222f72..3af2635 100644 --- a/docs/charts/bar_chart.md +++ b/docs/charts/bar_chart.md @@ -44,14 +44,6 @@ Add a built-in legend for clarity when displaying multiple series. Create a fully custom legend layout using Reflex components. --DEMO(barchart_v7)-- -## Custom Tabs -Customize and format your x and y axes for improved presentation. ---DEMO(barchart_v8)-- - ## Custom Legends Show how the chart adapts across different screen sizes and layouts. --DEMO(barchart_v9)-- - -## Alternating Colors -Apply gradient fills to your bars for a modern, polished look. ---DEMO(barchart_v10)-- diff --git a/docs/components/chart.md b/docs/components/chart.md index 0689493..6d1e036 100644 --- a/docs/components/chart.md +++ b/docs/components/chart.md @@ -117,7 +117,7 @@ rx.recharts.bar_chart( data=data, width="100%", height=250, - class_name=chart_tooltip_content(2, "square"), + class_name=chart_tooltip_content([1, 2], "square"), ) ``` @@ -224,7 +224,7 @@ Use the following props to customize the tooltip. | Prop | Type | Default | Description | | :--- | :--- | :--- | :--- | -| `num_series` | `int` | — | Number of data series in the chart. Must match the number of `rx.recharts.bar` / `line` / `area` components. | +| `chart_colors` | `list[int]` | — | Number of data series in the chart. Must match the number of `rx.recharts.bar` / `line` / `area` components. | | `swatch` | `"square" \| "line" \| "border"` | `"square"` | Indicator style per item. `square` = small filled box, `line` = wide pill, `border` = left accent line per series using `--chart-{i}`. | >**chart_tooltip_content()** returns a string of Tailwind classes and must be passed to the **chart component's** class_name, not to **chart_tooltip()**. diff --git a/llms.txt b/llms.txt deleted file mode 100644 index bf4c24a..0000000 --- a/llms.txt +++ /dev/null @@ -1,25 +0,0 @@ -# buridan/ui - -Composable, themeable components designed for Reflex. Built with Python and modern OKLCH colors. - -## AI Expert Instructions -Any AI agent interacting with this repository or helping a user build an app with Buridan UI MUST follow these rules: - -- **Always use the CLI**: Use `buridan add ` to add components. Do NOT copy code blocks manually unless specifically requested for reference. The CLI handles dependency resolution (e.g., `twmerge`, `base_ui`, `CoreComponent`). -- **Imports**: Components live in `components/ui/` in the user's project. Icons live in `components/icons/`. -- **Theming**: Use the OKLCH variables in `assets/globals.css`. Prefer semantic names like `bg-background` and `text-primary`. -- **Patterns**: Use the `@layout_decorator` for page structures and `ClientStateVar` for client-side state management. - -## Documentation -- [Introduction](https://buridan-ui.reflex.run/docs/getting-started/introduction) -- [Installation](https://buridan-ui.reflex.run/docs/getting-started/installation) -- [CLI Reference](https://buridan-ui.reflex.run/docs/getting-started/cli) -- [Theming Guide](https://buridan-ui.reflex.run/docs/getting-started/theming) -- [AI Support](https://buridan-ui.reflex.run/docs/getting-started/ai-support) - -## Components -- [Accordion](https://buridan-ui.reflex.run/docs/components/accordion) -- [Button](https://buridan-ui.reflex.run/docs/components/button) -- [Dialog](https://buridan-ui.reflex.run/docs/components/dialog) -- [Select](https://buridan-ui.reflex.run/docs/components/select) -- (And 25+ more...) diff --git a/pyproject.toml b/pyproject.toml index fe16579..776eae5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ version = "0.1.8" description = "CLI to initialize Buridan UI design system in Reflex apps" requires-python = ">=3.11" dependencies = [ - "reflex==0.9.2", + "reflex==0.9.6", "reflex-hosting-cli>=0.1.67", "reflex-components-internal", "pillow>=12.2.0", diff --git a/reflex.lock/bun.lock b/reflex.lock/bun.lock index e837f5d..5905c0f 100644 --- a/reflex.lock/bun.lock +++ b/reflex.lock/bun.lock @@ -4,12 +4,12 @@ "": { "name": "reflex", "dependencies": { - "@base-ui/react": "1.5.0", - "@hugeicons/core-free-icons": "1.1.0", - "@hugeicons/react": "1.1.1", + "@base-ui/react": "1.6.0", + "@hugeicons/core-free-icons": "4.2.1", + "@hugeicons/react": "1.1.6", "@radix-ui/themes": "3.3.0", "@react-router/node": "7.15.0", - "clsx-for-tailwind": "^1.0.0", + "clsx-for-tailwind": "1.0.0", "isbot": "5.1.40", "lucide-react": "1.14.0", "react": "19.2.6", @@ -41,7 +41,7 @@ "tailwind-scrollbar": "^4.0.2", "tailwindcss": "4.3.0", "tailwindcss-animate": "^1.0.7", - "vite": "8.0.12", + "vite": "8.0.16", }, }, }, @@ -109,9 +109,9 @@ "@babel/types": ["@babel/types@7.29.7", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA=="], - "@base-ui/react": ["@base-ui/react@1.5.0", "", { "dependencies": { "@babel/runtime": "^7.29.2", "@base-ui/utils": "0.2.9", "@floating-ui/react-dom": "^2.1.8", "@floating-ui/utils": "^0.2.11", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "@date-fns/tz": "^1.2.0", "@types/react": "^17 || ^18 || ^19", "date-fns": "^4.0.0", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@date-fns/tz", "@types/react", "date-fns"] }, "sha512-z1gSAlced1yY+iM+mHDEtIkD8UI3Ebs52MuBPxvV6f5hRutk+xvCH/wuB7hDqDzK9JG5FoMz5nhrqtSs1wjt1A=="], + "@base-ui/react": ["@base-ui/react@1.6.0", "", { "dependencies": { "@babel/runtime": "^7.29.2", "@base-ui/utils": "0.3.1", "@floating-ui/react-dom": "^2.1.8", "@floating-ui/utils": "^0.2.11", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "@date-fns/tz": "^1.2.0", "@types/react": "^17 || ^18 || ^19", "date-fns": "^4.0.0", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@date-fns/tz", "@types/react", "date-fns"] }, "sha512-/jzjTWJYXhRFO45Bev9lc3cHbmjzCMpUqbMZ2AgKy/z25mY9B6shGSNcXcjQar9n5doM0KYW1W8fcFv2jZBuMw=="], - "@base-ui/utils": ["@base-ui/utils@0.2.9", "", { "dependencies": { "@babel/runtime": "^7.29.2", "@floating-ui/utils": "^0.2.11", "reselect": "^5.1.1", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "@types/react": "^17 || ^18 || ^19", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@types/react"] }, "sha512-x/PDDCYzoqPpjrdyb3VcyylTI2IjUXEtYDGi5foh7KsnmNJIIaVwA2GLgDH1dps1GgXiJbA60hM+AyuTfQzIvw=="], + "@base-ui/utils": ["@base-ui/utils@0.3.1", "", { "dependencies": { "@babel/runtime": "^7.29.2", "@floating-ui/utils": "^0.2.11", "reselect": "^5.2.0", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "@types/react": "^17 || ^18 || ^19", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@types/react"] }, "sha512-gFFiltORVmW/N6IILTGxizP3PBpVpysqML1ALY5Vk0mH+7faVkCknOU31goYHN5Aoek2dkjxva1XOD2Ce9WuIg=="], "@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="], @@ -201,9 +201,9 @@ "@floating-ui/utils": ["@floating-ui/utils@0.2.11", "", {}, "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg=="], - "@hugeicons/core-free-icons": ["@hugeicons/core-free-icons@1.1.0", "", {}, "sha512-xLLQcIiLKvazXjjhnO2qZ/piOo9yxAFQ5A67XP+HNpvFrO5hVEGv1qebHSHPK1tbSST9dZF3fhH4AfdyumqJsg=="], + "@hugeicons/core-free-icons": ["@hugeicons/core-free-icons@4.2.1", "", {}, "sha512-75jYZKYyA9VwS35YRmmGUGzFedbY+Fl0Vxx5FzXR2CGDlIhNRumFeVqaaKoClf2MeYEJwPAVMEL9RwCYtOgnSw=="], - "@hugeicons/react": ["@hugeicons/react@1.1.1", "", { "peerDependencies": { "react": ">=16.0.0" } }, "sha512-BAbFVtx0XZ/yF2poPLFn0N9Ji6ebV/MpI5+WRqooFp3smQDwpL+72m+BBs4KAM5djgWUpg12weyc5SJtTsOwsw=="], + "@hugeicons/react": ["@hugeicons/react@1.1.6", "", { "peerDependencies": { "react": ">=16.0.0" } }, "sha512-c2LhXJMAW5wN1pC/smBXG0YPqUON6ceR/ZdXHCjEI9KvB+hjtqYjmzIxok5hAQOeXGz0WtORgCQMzqewFKAZwg=="], "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], @@ -219,7 +219,7 @@ "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.4", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow=="], - "@oxc-project/types": ["@oxc-project/types@0.129.0", "", {}, "sha512-3oz8m3FGdr2nDXVqmFUw7jolKliC4MoyXYIG2c7gpjBnzUWQpUGIYcXYKxTdTi+N2jusvt610ckTMkxdwHkYEg=="], + "@oxc-project/types": ["@oxc-project/types@0.133.0", "", {}, "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA=="], "@radix-ui/colors": ["@radix-ui/colors@3.0.0", "", {}, "sha512-FUOsGBkHrYJwCSEtWRCIfQbZG7q1e6DgxCIOe1SUQzDe/7rXXeA47s8yCn6fuTNQAj1Zq4oTFi9Yjp3wzElcxg=="], @@ -355,35 +355,35 @@ "@remix-run/node-fetch-server": ["@remix-run/node-fetch-server@0.13.3", "", {}, "sha512-UfjOXed/DQteaM5VyTfqTeGpHwyL2J5aoRGY6cydip4tt1ehNNeSwuXCC7AEGE0RWBs/7bgKxYkL/B/+UDe4AA=="], - "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0", "", { "os": "android", "cpu": "arm64" }, "sha512-TWMZnRLMe63C2Lhyicviu7ZHaU4kxa6PS3rofvc9GmcvptzNN11BcfQ4Sl7MwTOsisQoa2keB/EBdNCAnUo8vA=="], + "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.3", "", { "os": "android", "cpu": "arm64" }, "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw=="], - "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-6XcD+8k0gPVItNagEw78/qqcBDwKcwDYS8V2hRmVsfUSIrd8cWe/CBvRDI5toqFyPfj+FJr6t8U6Xj2P2prEew=="], + "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA=="], - "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-iN/tWVXRQDWvmZlKdceP1Dwug9GDpEymhb9p4xnEe6zvCg5lFmzVljl+1qR1NVx3yfGpr2Na+CuLmv5IU8uzfQ=="], + "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg=="], - "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-jjQMDvvwSOuhOwMszD/klSOjyWMM3zI64hWTj9KT5x4MxRbZAf+7vLQ6qouRhtsLVFHr3f0ILaJAfgENPiQdAQ=="], + "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g=="], - "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.0", "", { "os": "linux", "cpu": "arm" }, "sha512-d//Dtg2x6/m3mbV64yUGNnDGNZaDGRpDLLNGerHQUVObuNaIQaaDp25yUiqGXtHEXX+NP2d0wAlmKgpYgIAJ2A=="], + "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.3", "", { "os": "linux", "cpu": "arm" }, "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw=="], - "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-n7Ofp0mx+aB2cC+Sdy5YtMnXtY9lchnHbY+3Yt0uq9JsWQExf4f5Whu0tK0R8Jdc9S6RchTHjIFY7uc92puOVQ=="], + "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw=="], - "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-EIVjy2cgd7uuMMo94FVkBp7F6DhcZAUwNURkSG3RwUmvAXR6s0ISxM81U+IydcZByPG0pZIHsf1b6kTxoFDgJA=="], + "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q=="], - "@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.0.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-JEwwOPcwTLAcpDQlqSmjEmfs63xJnSiUNIGvLcDLUHCWK4XowpS/7c7tUsUH6uT/ct6bMUTdXKfI8967FYj6mg=="], + "@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.0.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg=="], - "@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.0.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-0wjCFhLrihtAubnT9iA0N++0pSV0z5Hg7tNGdNJ4RFaINceHadoF+kiFGyY1qSSNVIAZtLotG8Ju1bgDPkjnFA=="], + "@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.0.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg=="], - "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.0", "", { "os": "linux", "cpu": "x64" }, "sha512-Dfn7iak9BcMMePxcoJfpSbWqnEyrp/dRF63/8qW/eHBdOZov6x5aShLLEYGYdIeSJ6vMLK/XCVB+lGIxm41bQA=="], + "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.3", "", { "os": "linux", "cpu": "x64" }, "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg=="], - "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.0", "", { "os": "linux", "cpu": "x64" }, "sha512-5/utzzDmD/pD/bmuaUcbTf/sZYy0aztwIVlfpoW1fTjCZ0BaPOMVWGZL1zvgxyi7ZIVYWlxKONHmSbHuiOh8Jw=="], + "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.3", "", { "os": "linux", "cpu": "x64" }, "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow=="], - "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.0", "", { "os": "none", "cpu": "arm64" }, "sha512-ouJs8VcUomfLfpbUECqFMRqdV4x6aeAK3MA4m6vTrJJjKyWTV5KnxZx7Jd9G+GlDaQQxubcba00x16OyJ1meig=="], + "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.3", "", { "os": "none", "cpu": "arm64" }, "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg=="], - "@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.0", "", { "dependencies": { "@emnapi/core": "1.10.0", "@emnapi/runtime": "1.10.0", "@napi-rs/wasm-runtime": "^1.1.4" }, "cpu": "none" }, "sha512-E+oHKGiDA+lsKMmFtffDDw91EryDT7uJocrIuCHqhm6bCTM6xFK+3gaCkYOHfPwQr0cCNarSM2xaELoQDz9jJg=="], + "@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.3", "", { "dependencies": { "@emnapi/core": "1.10.0", "@emnapi/runtime": "1.10.0", "@napi-rs/wasm-runtime": "^1.1.4" }, "cpu": "none" }, "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg=="], - "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-yYK02n8Rngo+gbm1y6G0+7jk1sJ/2Wt7K0me0Y7k/ErBpyf+LJ2gFpqWVTcRV1rUepBlQRmpgWkTQCiiwrK0Ow=="], + "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g=="], - "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.0", "", { "os": "win32", "cpu": "x64" }, "sha512-14bpChMahXRRXiTwahSl+zzHPW6qQTXtkMuJBFlbo+pqSAews2d4BdCSHfrJ/MBsCZtpmTafsY+1QhBzitcmdg=="], + "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.3", "", { "os": "win32", "cpu": "x64" }, "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA=="], "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0", "", {}, "sha512-aKs/3GSWyV0mrhNmt/96/Z3yczC3yvrzYATCiCXQebBsGyYzjNdUphRVLeJQ67ySKVXRfMxt2lm12pmXvbPFQQ=="], @@ -987,7 +987,7 @@ "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], - "rolldown": ["rolldown@1.0.0", "", { "dependencies": { "@oxc-project/types": "=0.129.0", "@rolldown/pluginutils": "1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0", "@rolldown/binding-darwin-arm64": "1.0.0", "@rolldown/binding-darwin-x64": "1.0.0", "@rolldown/binding-freebsd-x64": "1.0.0", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0", "@rolldown/binding-linux-arm64-gnu": "1.0.0", "@rolldown/binding-linux-arm64-musl": "1.0.0", "@rolldown/binding-linux-ppc64-gnu": "1.0.0", "@rolldown/binding-linux-s390x-gnu": "1.0.0", "@rolldown/binding-linux-x64-gnu": "1.0.0", "@rolldown/binding-linux-x64-musl": "1.0.0", "@rolldown/binding-openharmony-arm64": "1.0.0", "@rolldown/binding-wasm32-wasi": "1.0.0", "@rolldown/binding-win32-arm64-msvc": "1.0.0", "@rolldown/binding-win32-x64-msvc": "1.0.0" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-yD986aXDESFGS95spT1LAv0jssywP4npMEjmMHyN2/5+eE8qQJUype2AaKkRiLgBgyD0LFlubwAht7VmY8rGoA=="], + "rolldown": ["rolldown@1.0.3", "", { "dependencies": { "@oxc-project/types": "=0.133.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.3", "@rolldown/binding-darwin-arm64": "1.0.3", "@rolldown/binding-darwin-x64": "1.0.3", "@rolldown/binding-freebsd-x64": "1.0.3", "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", "@rolldown/binding-linux-arm64-gnu": "1.0.3", "@rolldown/binding-linux-arm64-musl": "1.0.3", "@rolldown/binding-linux-ppc64-gnu": "1.0.3", "@rolldown/binding-linux-s390x-gnu": "1.0.3", "@rolldown/binding-linux-x64-gnu": "1.0.3", "@rolldown/binding-linux-x64-musl": "1.0.3", "@rolldown/binding-openharmony-arm64": "1.0.3", "@rolldown/binding-wasm32-wasi": "1.0.3", "@rolldown/binding-win32-arm64-msvc": "1.0.3", "@rolldown/binding-win32-x64-msvc": "1.0.3" }, "bin": { "rolldown": "./bin/cli.mjs" } }, "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g=="], "rollup": ["rollup@4.61.1", "", { "dependencies": { "@types/estree": "1.0.9" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.61.1", "@rollup/rollup-android-arm64": "4.61.1", "@rollup/rollup-darwin-arm64": "4.61.1", "@rollup/rollup-darwin-x64": "4.61.1", "@rollup/rollup-freebsd-arm64": "4.61.1", "@rollup/rollup-freebsd-x64": "4.61.1", "@rollup/rollup-linux-arm-gnueabihf": "4.61.1", "@rollup/rollup-linux-arm-musleabihf": "4.61.1", "@rollup/rollup-linux-arm64-gnu": "4.61.1", "@rollup/rollup-linux-arm64-musl": "4.61.1", "@rollup/rollup-linux-loong64-gnu": "4.61.1", "@rollup/rollup-linux-loong64-musl": "4.61.1", "@rollup/rollup-linux-ppc64-gnu": "4.61.1", "@rollup/rollup-linux-ppc64-musl": "4.61.1", "@rollup/rollup-linux-riscv64-gnu": "4.61.1", "@rollup/rollup-linux-riscv64-musl": "4.61.1", "@rollup/rollup-linux-s390x-gnu": "4.61.1", "@rollup/rollup-linux-x64-gnu": "4.61.1", "@rollup/rollup-linux-x64-musl": "4.61.1", "@rollup/rollup-openbsd-x64": "4.61.1", "@rollup/rollup-openharmony-arm64": "4.61.1", "@rollup/rollup-win32-arm64-msvc": "4.61.1", "@rollup/rollup-win32-ia32-msvc": "4.61.1", "@rollup/rollup-win32-x64-gnu": "4.61.1", "@rollup/rollup-win32-x64-msvc": "4.61.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-I4KW6iuRpuu2uHBLraZ1wNZe0DP7lnRha+VJ9tNaYVaVgKhW0aI3h4RYnoRPeql0flHm/Co55b7snEDcOfOJrA=="], @@ -1077,7 +1077,7 @@ "victory-vendor": ["victory-vendor@37.3.6", "", { "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", "@types/d3-interpolate": "^3.0.1", "@types/d3-scale": "^4.0.2", "@types/d3-shape": "^3.1.0", "@types/d3-time": "^3.0.0", "@types/d3-timer": "^3.0.0", "d3-array": "^3.1.6", "d3-ease": "^3.0.1", "d3-interpolate": "^3.0.1", "d3-scale": "^4.0.2", "d3-shape": "^3.1.0", "d3-time": "^3.0.0", "d3-timer": "^3.0.1" } }, "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ=="], - "vite": ["vite@8.0.12", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.14", "rolldown": "1.0.0", "tinyglobby": "^0.2.16" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.1.18", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w2dDofOWv2QB09ZITZBsvKTVAlYvPR4IAmrY/v0ir9KvLs0xybR7i48wxhM1/oyBWO34wPns+bPGw5ZrZqDpZg=="], + "vite": ["vite@8.0.16", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.15", "rolldown": "1.0.3", "tinyglobby": "^0.2.17" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.1.18", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw=="], "vite-node": ["vite-node@3.2.4", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.1", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg=="], diff --git a/reflex.lock/package.json b/reflex.lock/package.json index 2b2deb5..1455b88 100644 --- a/reflex.lock/package.json +++ b/reflex.lock/package.json @@ -6,12 +6,12 @@ "export": "react-router build" }, "dependencies": { - "@base-ui/react": "1.5.0", - "@hugeicons/core-free-icons": "1.1.0", - "@hugeicons/react": "1.1.1", + "@base-ui/react": "1.6.0", + "@hugeicons/core-free-icons": "4.2.1", + "@hugeicons/react": "1.1.6", "@radix-ui/themes": "3.3.0", "@react-router/node": "7.15.0", - "clsx-for-tailwind": "^1.0.0", + "clsx-for-tailwind": "1.0.0", "isbot": "5.1.40", "lucide-react": "1.14.0", "react": "19.2.6", @@ -43,7 +43,7 @@ "tailwind-scrollbar": "^4.0.2", "tailwindcss": "4.3.0", "tailwindcss-animate": "^1.0.7", - "vite": "8.0.12" + "vite": "8.0.16" }, "overrides": { "cookie": "1.1.1" diff --git a/scripts/generate_preview_cards.py b/scripts/generate_preview_cards.py index 67cd207..d297c6f 100644 --- a/scripts/generate_preview_cards.py +++ b/scripts/generate_preview_cards.py @@ -40,6 +40,11 @@ "title": "Buridan UI", "description": "Composable, themeable components designed for Reflex. Extend, override, and ship without fighting the framework. Open source.", }, + { + "route": "blocks", + "title": "Blocks", + "description": "Clean, modern building blocks for Reflex dashboards. Copy and paste into your apps. Open Source. Extensible.", + }, ] diff --git a/uv.lock b/uv.lock index bf20514..e2f5da9 100644 --- a/uv.lock +++ b/uv.lock @@ -65,7 +65,7 @@ requires-dist = [ { name = "pytest", specifier = ">=9.1.1" }, { name = "pyyaml", specifier = ">=6.0.3" }, { name = "questionary", specifier = ">=2.1.1" }, - { name = "reflex", specifier = "==0.9.2" }, + { name = "reflex", specifier = "==0.9.6" }, { name = "reflex-components-internal" }, { name = "reflex-hosting-cli", specifier = ">=0.1.67" }, ] @@ -658,7 +658,7 @@ wheels = [ [[package]] name = "reflex" -version = "0.9.2" +version = "0.9.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, @@ -688,14 +688,14 @@ dependencies = [ { name = "typing-extensions" }, { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1d/f8/2666c0abc46125e6fbe903c99e22f6ebf82e17691a66142c4a87bdf4c1ae/reflex-0.9.2.tar.gz", hash = "sha256:640571d0276c152c04b95dfe7df805c45f8d0cd891ff33fa4b7506a75c6aef70", size = 375290, upload-time = "2026-05-06T23:55:23.778Z" } +sdist = { url = "https://files.pythonhosted.org/packages/29/74/409e0107937be71b241b37abb70798c95ff8e55c307d8d83a6e4049ef2fb/reflex-0.9.6.tar.gz", hash = "sha256:987f6a92e4fca6ddcb8b6771805fd012b65ef85ac9cc61445e698376e708bca6", size = 395060, upload-time = "2026-06-25T22:26:08.747Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/51/76/bb8e1db199a3fc82c84fa699fb46fbdbce566e6f115446846d37b9ba2e54/reflex-0.9.2-py3-none-any.whl", hash = "sha256:7fdd58c721eb848c13e669525c556bf7a034d646b387b894ce6db4e24d75e803", size = 629365, upload-time = "2026-05-06T23:55:22.374Z" }, + { url = "https://files.pythonhosted.org/packages/2d/e2/bdcc28289caa84106d856975713873f7f41e3ec8715b58ab04dc54fa4e6f/reflex-0.9.6-py3-none-any.whl", hash = "sha256:302702e8708aa4549758c277995726029606deea5f41e68150ff9c02b79fdb96", size = 649586, upload-time = "2026-06-25T22:26:07.433Z" }, ] [[package]] name = "reflex-base" -version = "0.9.2" +version = "0.9.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "packaging" }, @@ -704,9 +704,9 @@ dependencies = [ { name = "rich" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/15/18/ff2a0279fee2b742a21ae4fa76a0625a252f30e50c6fb0ef34e0007f7c45/reflex_base-0.9.2.tar.gz", hash = "sha256:55faa61c01165e53f337853ec4df437934c9a9429b46dd12664628b84b6c7d49", size = 217750, upload-time = "2026-05-06T23:55:12.127Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d9/94/344ac7b4d237eb8a88fc3e19db68e3b80c7d73db063a3c002fe7a78bfa75/reflex_base-0.9.6.tar.gz", hash = "sha256:f5774f68dc97ef80e7b5e517a96ffa1229fc5be0922a89965646b94764d24d13", size = 262179, upload-time = "2026-06-25T22:25:54.854Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/18/9b/b1feef05334a24adb633b9d6507807ca2b24ac6169fe25a5daee26b79f93/reflex_base-0.9.2-py3-none-any.whl", hash = "sha256:fed2fd1ae2e4e958958fda08422fd1ffdae828c950989b4aa522dacdb5760a51", size = 258737, upload-time = "2026-05-06T23:55:13.292Z" }, + { url = "https://files.pythonhosted.org/packages/df/27/ada069408424f107f8e9cfd82771ae3cbfd8ee72e36e6482ae40fdbec613/reflex_base-0.9.6-py3-none-any.whl", hash = "sha256:d88d8feb5bd21f3f08f3cba8a56b95aa64ce6651d60067058f5e10617a7c2774", size = 303778, upload-time = "2026-06-25T22:25:53.633Z" }, ] [[package]] @@ -726,7 +726,7 @@ wheels = [ [[package]] name = "reflex-components-core" -version = "0.9.4" +version = "0.9.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "python-multipart" }, @@ -736,9 +736,9 @@ dependencies = [ { name = "starlette" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7a/cf/5b0896e5929df1619c0119c5c56f0cf548df33585b7ad3db78dd886230d4/reflex_components_core-0.9.4.tar.gz", hash = "sha256:5973ca0520510246f613d12ed8ff99998323da23d88e5240b5c873fac696a041", size = 104166, upload-time = "2026-06-04T01:44:16.252Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/34/c6cb7e0198115582fbbd50061eb1e24069c91b0dcf4861f6e5c6c34bd743/reflex_components_core-0.9.5.tar.gz", hash = "sha256:e95f9d39c1785293c7b0ff0e81d410b24441bfe9d59f86c440a14fbb72d8fd61", size = 107438, upload-time = "2026-06-10T20:23:15.051Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/f2/f8936a7ca2a4efea48c3e5fc938138ca0f093ea88b6ea9908431eb96ec46/reflex_components_core-0.9.4-py3-none-any.whl", hash = "sha256:111bdc2ed0a1f60cd22f2cf0300daca5987031e1446d2caf784be63a6fe0e5a4", size = 173818, upload-time = "2026-06-04T01:44:17.318Z" }, + { url = "https://files.pythonhosted.org/packages/8c/23/ecc22652481bd1b462de7ca4bebac1f08c965293f13b9c29eb22519ebb47/reflex_components_core-0.9.5-py3-none-any.whl", hash = "sha256:478c7d04b8e2adc60905254810a04c61935352686e9a3dfe22ddd07ff4010bf5", size = 176321, upload-time = "2026-06-10T20:23:16.024Z" }, ] [[package]]