from fasthtml.common import *
SemanticUI FastHTML Cards
Caution: I’ve learned better patterns since I wrote this. Leaving this here for posterity.
I pasted the code for Semantic UI’s group of button cards into HTML to XT and got:
Div(
Div(
Div('Elliot Fu', cls='header'),
Div('Elliot Fu is a film-maker from New York.', cls='description'),
Div(='content'
cls
),
Div(='add icon'),
I(cls'Add Friend',
='ui button'
cls
),='card'
cls
),
Div(
Div('Veronika Ossi', cls='header'),
Div('Veronika Ossi is a set designer living in New York who enjoys kittens, music, and partying.', cls='description'),
Div(='content'
cls
),
Div(='add icon'),
I(cls'Add Friend',
='ui button'
cls
),='card'
cls
),
Div(
Div('Jenny Hess', cls='header'),
Div('Jenny is a student studying Media Management at the New School', cls='description'),
Div(='content'
cls
),
Div(='add icon'),
I(cls'Add Friend',
='ui button'
cls
),='card'
cls
),='ui cards'
cls )
div class="ui cards">
<div class="card">
<div class="content">
<div class="header">Elliot Fu</div>
<div class="description">Elliot Fu is a film-maker from New York.</div>
<div>
</div class="ui button">
<i class="add icon"></i>
<
Add Frienddiv>
</div>
</div class="card">
<div class="content">
<div class="header">Veronika Ossi</div>
<div class="description">Veronika Ossi is a set designer living in New York who enjoys kittens, music, and partying.</div>
<div>
</div class="ui button">
<i class="add icon"></i>
<
Add Frienddiv>
</div>
</div class="card">
<div class="content">
<div class="header">Jenny Hess</div>
<div class="description">Jenny is a student studying Media Management at the New School</div>
<div>
</div class="ui button">
<i class="add icon"></i>
<
Add Frienddiv>
</div>
</div> </
Extracting the data into a Python list of tuples:
= [
cards_data 'Elliot Fu', 'Elliot Fu is a film-maker from New York.'),
('Veronika Ossi', 'Veronika Ossi is a set designer living in New York who enjoys kittens, music, and partying.'),
('Jenny Hess', 'Jenny is a student studying Media Management at the New School')
( ]
We could hardcode the Semantic UI tree structure in like this…
def Card(name, description):
return Div(
Div(='header'),
Div(name, cls='description'),
Div(description, cls='content'
cls
),
Div(='add icon'),
I(cls'Add Friend',
='ui button'
cls
),='card'
cls )
= [Card(name, description) for name, description in cards_data]
cards cards
[['div',
(['div',
(['div', ('Elliot Fu',), {'class': 'header'}],
['div',
('Elliot Fu is a film-maker from New York.',),
{'class': 'description'}]),
{'class': 'content'}],
['div',
(['i', (), {'class': 'add icon'}], 'Add Friend'),
{'class': 'ui button'}]),
{'class': 'card'}],
['div',
(['div',
(['div', ('Veronika Ossi',), {'class': 'header'}],
['div',
('Veronika Ossi is a set designer living in New York who enjoys kittens, music, and partying.',),
{'class': 'description'}]),
{'class': 'content'}],
['div',
(['i', (), {'class': 'add icon'}], 'Add Friend'),
{'class': 'ui button'}]),
{'class': 'card'}],
['div',
(['div',
(['div', ('Jenny Hess',), {'class': 'header'}],
['div',
('Jenny is a student studying Media Management at the New School',),
{'class': 'description'}]),
{'class': 'content'}],
['div',
(['i', (), {'class': 'add icon'}], 'Add Friend'),
{'class': 'ui button'}]),
{'class': 'card'}]]
= Div(*cards, cls='ui cards')
result result
div class="ui cards">
<div class="card">
<div class="content">
<div class="header">Elliot Fu</div>
<div class="description">Elliot Fu is a film-maker from New York.</div>
<div>
</div class="ui button">
<i class="add icon"></i>
<
Add Frienddiv>
</div>
</div class="card">
<div class="content">
<div class="header">Veronika Ossi</div>
<div class="description">Veronika Ossi is a set designer living in New York who enjoys kittens, music, and partying.</div>
<div>
</div class="ui button">
<i class="add icon"></i>
<
Add Frienddiv>
</div>
</div class="card">
<div class="content">
<div class="header">Jenny Hess</div>
<div class="description">Jenny is a student studying Media Management at the New School</div>
<div>
</div class="ui button">
<i class="add icon"></i>
<
Add Frienddiv>
</div>
</div> </
But it might be nice to separate card text/values from how it is rendered as an XT, and offer different rendering options
@dataclass
class Card():
str
title: str
image: str
description: # button_links: list of text, link pairs maybe
def __xt__(self, uiframework='semanticui'):
if uiframework == 'semanticui':
...elif uiframework == 'frankenui':
...elif uiframework == 'bootstrap':
...else:
raise ValueError(f"Unknown uiframework {uiframework}")
This would be hard to maintain, though. I feel like a system to allow devs to make their own CSS framework plugins for XT would be nice.
Daniel suggested using dataclasses like in his blog.
Claude 3.5 Sonnet suggested renderers for each framework could look like:
from typing import List, Tuple, Optional, Callable, Dict
# Global registry for renderers
str, Callable] = {}
renderer_registry: Dict[
def register_renderer(framework: str):
"""Decorator to register a renderer for a specific framework."""
def decorator(func: Callable):
= func
renderer_registry[framework] return func
return decorator
from dataclasses import dataclass
@dataclass
class Card:
str
title: str
description: str] = None
image: Optional[str, str]] = ()
button_links: List[Tuple[
def __xt__(self, uiframework='semanticui'):
if uiframework not in renderer_registry:
raise ValueError(f"No renderer registered for framework: {uiframework}")
return renderer_registry[uiframework](self)
@register_renderer('semanticui')
def render_semanticui(card: Card):
= [
content ='header'),
Div(card.title, cls='description')
Div(card.description, cls
]if card.image:
0, Div(Img(src=card.image, cls='ui image'), cls='image'))
content.insert(
= [
buttons =link, cls='ui button')
A(text, hreffor text, link in card.button_links
]
return Div(
*content, cls='content'),
Div(*buttons,
='ui card'
cls )
Let’s try rendering out a simple card with this
= Card('Hannah', 'Hannah is a girl who likes to dance.', image='hannah.jpg', button_links=[('Add Friend', '#')])
hannah_card hannah_card.__xt__()
div class="ui card">
<div class="content">
<div class="image">
<img src="hannah.jpg" class="ui image">
<div>
</div class="header">Hannah</div>
<div class="description">Hannah is a girl who likes to dance.</div>
<div>
</a href="#" class="ui button">Add Friend</a>
<div> </
Note: I’ve learned better patterns since I wrote this. Leaving this here for posterity.