Skip to content

Add accordion component #94

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions docs/api_reference/api_reference.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,91 @@ def _card(i): return Card(H3(f'Card {i}'), P(f'Card {i} content'))
SliderNav,
title="Sliders")

# Accordions

def ex_accordion_1():
return Div(
H2("Multiple Open, No Animation Accordion"),
Accordion(
AccordionItem(
"Section 1",
P("Content for the first section."),
P("More content here."),
),
AccordionItem(
"Section 2",
P("Content for the second section."),
Label("A label inside!"),
li_kwargs={"id": "section-2"},
),
AccordionItem(
"Section 3 - The last one!", P("Content for the third section.")
),
multiple=False,
animation=True,
),
),

def ex_accordion_2():
return Div(
H2("Multiple Open, No Animation Accordion"),
Accordion(
AccordionItem(
"Section 1",
P("Content for the first section."),
P("More content here."),
open=True,
),
AccordionItem(
"Section 2",
P("Content for the second section."),
Label("A label inside!"),
li_kwargs={"id": "section-2"},
),
AccordionItem(
"Section 3 - The last one!", P("Content for the third section.")
),
multiple=True,
animation=True,
),
),

def ex_accordion_3():
return Div(
H2("Multiple Open, No Animation Accordion"),
Accordion(
AccordionItem(
"Section 1",
P("Content for the first section."),
P("More content here."),
),
AccordionItem(
"Section 2",
P("Content for the second section."),
Label("A label inside!"),
li_kwargs={"id": "section-2"},
),
AccordionItem(
"Section 3 - The last one!", P("Content for the third section.")
),
multiple=False,
animation=False,
),
),

docs_accordion_link = create_doc_section(
H1("Accordion"),
Div(id='accordion'), # for linking to in release post
P("A simple accordion with fluid collapsing and expanding animation where only a single Section can be exanded at any time."),
fn2code_string(ex_accordion_1),
P("An accordion with fluid collapsing and expanding animation where one section is already expanded at startup and where multiple section can be expanded at any time."),
fn2code_string(ex_accordion_2),
P("An accordion with no collapsing and expanding animation where only a single Section can be exanded at any time."),
fn2code_string(ex_accordion_3),
Accordion,
AccordionItem,
title="Accordion")

# Buttons

def ex_buttons():
Expand Down
2 changes: 2 additions & 0 deletions monsterui/_modidx.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
'monsterui.franken.AT._generate_next_value_': ( 'franken.html#at._generate_next_value_',
'monsterui/franken.py'),
'monsterui.franken.Abbr': ('franken.html#abbr', 'monsterui/franken.py'),
'monsterui.franken.Accordion': ('franken.html#accordion', 'monsterui/franken.py'),
'monsterui.franken.AccordionItem': ('franken.html#accordionitem', 'monsterui/franken.py'),
'monsterui.franken.Address': ('franken.html#address', 'monsterui/franken.py'),
'monsterui.franken.Article': ('franken.html#article', 'monsterui/franken.py'),
'monsterui.franken.ArticleMeta': ('franken.html#articlemeta', 'monsterui/franken.py'),
Expand Down
59 changes: 59 additions & 0 deletions monsterui/franken.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
__all__ = ['franken_class_map', 'TextT', 'TextPresets', 'CodeSpan', 'CodeBlock', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'Subtitle',
'Q', 'Em', 'Strong', 'I', 'Small', 'Mark', 'Del', 'Ins', 'Sub', 'Sup', 'Blockquote', 'Caption', 'Cite',
'Time', 'Address', 'Abbr', 'Dfn', 'Kbd', 'Samp', 'Var', 'Figure', 'Details', 'Summary', 'Data', 'Meter', 'S',

'U', 'Output', 'PicSumImg', 'ButtonT', 'Button', 'ContainerT', 'BackgroundT', 'Container', 'Titled',
'DividerT', 'Divider', 'DividerSplit', 'DividerLine', 'Article', 'ArticleTitle', 'ArticleMeta', 'SectionT',
'Section', 'Form', 'Fieldset', 'Legend', 'Input', 'Radio', 'CheckboxX', 'Range', 'TextArea', 'Switch',
Expand Down Expand Up @@ -389,6 +390,64 @@ def PicSumImg(h:int=200, # Height in pixels
url = f"{url}{'?' if not grayscale else '&'}blur={max(1,min(10,blur))}"
return fh.Img(src=url, loading="lazy", **kwargs)

# %% ../nbs/02_franken.ipynb
def AccordionItem(title: Union[str, FT], # Content for the accordion item title
*c: FT, # Content to display when the item is open
cls: Union[str, Enum, tuple] = (), # Additional classes for the outer `Li` container
title_cls: Union[str, Enum, tuple] = ('flex justify-between items-center w-full',), # Additional classes for the title `A` tag
content_cls: Union[str, Enum, tuple] = (), # Additional classes for the content `Div`
open: bool = False, # Whether this item should be open by default
li_kwargs: Optional[Dict] = None, # Additional attributes for the outer `Li` tag
a_kwargs: Optional[Dict] = None, # Additional attributes for the title `A` tag
div_kwargs: Optional[Dict] = None # Additional attributes for the content `Div` tag
) -> FT: # Li(A(title, Span(Icon, Icon)), Div(content))
"Creates a single item for use within an Accordion component, handling title, content, and open state."
li_attrs, a_attrs, div_attrs = li_kwargs or {}, a_kwargs or {}, div_kwargs or {}
li_classes = ['group', stringify(cls)]
if open: li_classes.append('uk-open')
final_li_cls = stringify(li_classes)
combined_title_cls = stringify(('uk-accordion-title', stringify(title_cls)))
content_classes = stringify(('uk-accordion-content', stringify(content_cls)))
if 'href' not in a_attrs: a_attrs['href'] = '#'
icon_container = Span(
UkIcon("chevron-down", cls="block group-[.uk-open]:hidden h-5 w-5"),
UkIcon("chevron-up", cls="hidden group-[.uk-open]:block h-5 w-5")
)
return fh.Li(
fh.A(title, icon_container, cls=combined_title_cls, **a_attrs),
fh.Div(*c, cls=content_classes, **div_attrs),
cls=final_li_cls,
**li_attrs
)

# %% ../nbs/02_franken.ipynb
def Accordion(*c: AccordionItem, # One or more `AccordionItem` components
cls: Union[str, Enum, tuple] = (), # Additional classes for the container (`Ul` or `Div`)
multiple: Optional[bool] = None, # Allow multiple items to be open simultaneously (UIkit option)
collapsible: Optional[bool] = None, # Allow all items to be closed (UIkit option, default True)
animation: Optional[bool] = None, # Enable/disable animation (UIkit option, default True)
duration: Optional[int] = None, # Animation duration in ms (UIkit option, default 200)
active: Optional[int] = None, # Index (0-based) of the item to be open by default (UIkit option)
transition: Optional[str] = None, # Animation transition timing function (UIkit option, e.g., 'ease-out')
tag: str = 'ul', # HTML tag for the container ('ul' or 'div')
**kwargs # Additional attributes for the container tag (e.g., id)
) -> FT: # Ul(*items...) or Div(*items...)
"""
Creates a styled Accordion container using accordion component.
"""
opts = []
if multiple is not None: opts.append(f"multiple: {str(multiple).lower()}")
if collapsible is not None: opts.append(f"collapsible: {str(collapsible).lower()}")
if animation is not None: opts.append(f"animation: {str(animation).lower()}")
if duration is not None: opts.append(f"duration: {duration}")
if active is not None: opts.append(f"active: {active}")
if transition is not None: opts.append(f"transition: {transition}")
uk_attr_val = "; ".join(opts) if opts else ""
kwargs['uk-accordion'] = uk_attr_val
container_tag = fh.Ul if tag.lower() == 'ul' else fh.Div
final_cls = stringify(cls)
return container_tag(*c, cls=final_cls, **kwargs)

# %% ../nbs/02_franken.ipynb
class ButtonT(VEnum):
"Options for styling Buttons"
Expand Down
82 changes: 82 additions & 0 deletions nbs/02_franken.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,88 @@
" return fh.Img(src=url, loading=\"lazy\", **kwargs)"
]
},
{
"cell_type": "markdown",
"id": "caf685b3",
"metadata": {},
"source": [
"## Accordion"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d672f295",
"metadata": {},
"outputs": [],
"source": [
"#| export\n",
"def AccordionItem(title: Union[str, FT], # Content for the accordion item title\n",
" *c: FT, # Content to display when the item is open\n",
" cls: Union[str, Enum, tuple] = (), # Additional classes for the outer `Li` container\n",
" title_cls: Union[str, Enum, tuple] = ('flex justify-between items-center w-full',), # Additional classes for the title `A` tag\n",
" content_cls: Union[str, Enum, tuple] = (), # Additional classes for the content `Div`\n",
" open: bool = False, # Whether this item should be open by default\n",
" li_kwargs: Optional[Dict] = None, # Additional attributes for the outer `Li` tag\n",
" a_kwargs: Optional[Dict] = None, # Additional attributes for the title `A` tag\n",
" div_kwargs: Optional[Dict] = None # Additional attributes for the content `Div` tag\n",
" ) -> FT: # Li(A(title, Span(Icon, Icon)), Div(content))\n",
" \"Creates a single item for use within an Accordion component, handling title, content, and open state.\"\n",
" li_attrs, a_attrs, div_attrs = li_kwargs or {}, a_kwargs or {}, div_kwargs or {}\n",
" li_classes = ['group', stringify(cls)]\n",
" if open: li_classes.append('uk-open')\n",
" final_li_cls = stringify(li_classes)\n",
" combined_title_cls = stringify(('uk-accordion-title', stringify(title_cls)))\n",
" content_classes = stringify(('uk-accordion-content', stringify(content_cls)))\n",
" if 'href' not in a_attrs: a_attrs['href'] = '#'\n",
" icon_container = Span(\n",
" UkIcon(\"chevron-down\", cls=\"block group-[.uk-open]:hidden h-5 w-5\"),\n",
" UkIcon(\"chevron-up\", cls=\"hidden group-[.uk-open]:block h-5 w-5\")\n",
" )\n",
" return fh.Li(\n",
" fh.A(title, icon_container, cls=combined_title_cls, **a_attrs),\n",
" fh.Div(*c, cls=content_classes, **div_attrs),\n",
" cls=final_li_cls,\n",
" **li_attrs\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a19bf8be",
"metadata": {},
"outputs": [],
"source": [
"#| export\n",
"def Accordion(*c: AccordionItem, # One or more `AccordionItem` components\n",
" cls: Union[str, Enum, tuple] = (), # Additional classes for the container (`Ul` or `Div`)\n",
" multiple: Optional[bool] = None, # Allow multiple items to be open simultaneously (UIkit option)\n",
" collapsible: Optional[bool] = None, # Allow all items to be closed (UIkit option, default True)\n",
" animation: Optional[bool] = None, # Enable/disable animation (UIkit option, default True)\n",
" duration: Optional[int] = None, # Animation duration in ms (UIkit option, default 200)\n",
" active: Optional[int] = None, # Index (0-based) of the item to be open by default (UIkit option)\n",
" transition: Optional[str] = None, # Animation transition timing function (UIkit option, e.g., 'ease-out')\n",
" tag: str = 'ul', # HTML tag for the container ('ul' or 'div')\n",
" **kwargs # Additional attributes for the container tag (e.g., id)\n",
" ) -> FT: # Ul(*items...) or Div(*items...)\n",
" \"\"\"\n",
" Creates a styled Accordion container using accordion component.\n",
" \"\"\"\n",
" opts = []\n",
" if multiple is not None: opts.append(f\"multiple: {str(multiple).lower()}\")\n",
" if collapsible is not None: opts.append(f\"collapsible: {str(collapsible).lower()}\")\n",
" if animation is not None: opts.append(f\"animation: {str(animation).lower()}\")\n",
" if duration is not None: opts.append(f\"duration: {duration}\")\n",
" if active is not None: opts.append(f\"active: {active}\")\n",
" if transition is not None: opts.append(f\"transition: {transition}\")\n",
" uk_attr_val = \"; \".join(opts) if opts else \"\"\n",
" kwargs['uk-accordion'] = uk_attr_val\n",
" container_tag = fh.Ul if tag.lower() == 'ul' else fh.Div\n",
" final_cls = stringify(cls)\n",
" return container_tag(*c, cls=final_cls, **kwargs)"
]
},
{
"cell_type": "markdown",
"id": "d818104f",
Expand Down