RuleStack

Configs

Stacks

Compare

Diff

RuleStack

Configs

Stacks

Compare

Diff

Read API

RuleStack

Configs

Stacks

Compare

Diff

Read API

Configs/Cursor rules/ai-evals-course/isaac-fasthtml-workshop

Cursor rule

.cursor/rules/htmx.mdc

This rule is to help create interactive behavior with HTMX and fasthtml, which is the preferred approach

Cursor rules

Quality

54/100

Scores the file, not the repository.

Length

794 words

12 headings · 5 code blocks

Repository

69

— · pushed 363 days ago

Last changed

3 days ago

First indexed 3 days ago.
ai-evals-course/isaac-fasthtml-workshop/.cursor/rules/htmx.mdcRawGitHub
1---
2description: This rule is to help create interactive behavior with HTMX and fasthtml, which is the preferred approach
3globs:
4alwaysApply: false
5---
6To use HTMX with FastHTML you can pass the attributes to the HTML elements (e.g. `Button("Show", hx_get=my_route, hx_target='#my-target')`). Key things to keep in mind:
7 
8In FastHTML routes stringify to the route path so you can be pythonic instead of passing strings. For example if we have the following routes:
9 
10```python
11@rt
12def my_route(): return "Hello world"
13 
14@rt
15def my_second_route(my_arg:str): return my_arg
16```
17 
18In this example `Button("Show", hx_get=my_route)` would translate to `Button("Show", hx_get='/my_route')`.
19 
20For routes that have query or path parameters we can use the `to` method if it's not passed via a form. For example, `Button("Show", hx_get=my_second_route.to(my_arg="Goodbye"))` would translate to `Button("Show", hx_get='/my_second_route?my_arg=Goodbye')`.
21 
22`@rt` by default exposes routes as both a `GET` and a `POST`, which is almost always what I want.
23 
24## File Upload Example
25 
26```python
27from base64 import b64encode
28from fasthtml.common import *
29from monsterui.all import *
30 
31app, rt = fast_app(hdrs=Theme.blue.headers())
32 
33@rt
34def index():
35 inp = Card(
36 H3("Drag and drop images here"),
37 # HTMX for uploading multiple images
38 Input(type="file",name="images", multiple=True, required=True,
39 # Call the upload route on change
40 post=upload, hx_target="#image-list", hx_swap="afterbegin", hx_trigger="change",
41 # encoding for multipart
42 hx_encoding="multipart/form-data",accept="image/*"))
43 
44 return DivCentered(inp, H3("👇 Uploaded images 👇"), Div(id="image-list"))
45 
46async def ImageCard(image):
47 contents = await image.read()
48 # Create a base64 string
49 img_data = f"data:{image.content_type};base64,{b64encode(contents).decode()}"
50 # Create a card with the image
51 return Card(H4(image.filename), Img(src=img_data, alt=image.filename))
52 
53@rt
54async def upload(images: list[UploadFile]):
55 # Create a grid filled with 1 image card per image
56 return Grid(*[await ImageCard(image) for image in images])
57 
58serve()
59```
60 
61## Cascading DropDown Example
62 
63```python
64from fasthtml.common import *
65from monsterui.all import *
66from fasthtml import ft
67 
68app, rt = fast_app(hdrs=Theme.blue.headers())
69 
70chapters = ['ch1', 'ch2', 'ch3']
71lessons = {
72 'ch1': ['lesson1', 'lesson2', 'lesson3'],
73 'ch2': ['lesson4', 'lesson5', 'lesson6'],
74 'ch3': ['lesson7', 'lesson8', 'lesson9']}
75 
76def mk_opts(nm, cs):
77 return (
78 ft.Option(f'-- select {nm} --', disabled='', selected='', value=''),
79 *map(ft.Option, cs))
80 
81@rt
82def get_lessons(chapter: str):
83 return ft.Select(*mk_opts('lesson', lessons[chapter]), name='lesson')
84 
85@rt
86def index():
87 chapter_dropdown = ft.Select(
88 *mk_opts('chapter', chapters),
89 name='chapter',
90 hx_get=get_lessons, hx_target='#lessons',
91 label='Chapter:')
92 
93 return Container(
94 DivLAligned(FormLabel("Chapter:", for_="chapter"),chapter_dropdown),
95 DivLAligned(
96 FormLabel("Lesson:", for_="lesson"),
97 Div(id='lessons')),
98 cls='space-y-4')
99 
100serve()
101```
102 
103## Infinite Scroll Example
104 
105```python
106from fasthtml.common import *
107from monsterui.all import *
108import uuid
109 
110column_names = ('name', 'email', 'id')
111 
112def generate_contact(id: int) -> Dict[str, str]:
113 return {'name': 'Agent Smith',
114 'email': f'void{str(id)}@matrix.com',
115 'id': str(uuid.uuid4())
116 }
117 
118def generate_table_row(row_num: int) -> Tr:
119 contact = generate_contact(row_num)
120 return Tr(*[Td(contact[key]) for key in column_names])
121 
122def generate_table_part(part_num: int = 1, size: int = 20) -> Tuple[Tr]:
123 paginated = [generate_table_row((part_num - 1) * size + i) for i in range(size)]
124 paginated[-1].attrs.update({
125 'get': f'page?idx={part_num + 1}',
126 'hx-trigger': 'revealed',
127 'hx-swap': 'afterend'})
128 return tuple(paginated)
129 
130app, rt = fast_app(hdrs=Theme.blue.headers())
131 
132@rt
133def index():
134 return Titled('Infinite Scroll',
135 Div(Table(
136 Thead(Tr(*[Th(key) for key in column_names])),
137 Tbody(generate_table_part(1)))))
138 
139@rt
140def page(idx:int|None = 0):
141 return generate_table_part(idx)
142```
143 
144## Simple Todo App Example
145 
146```python
147# Database Model
148class Todo:
149 title: str
150 done: bool
151 due: date
152 id: int
153 
154# Sqlite Database connection with fastlite
155db = database('intermediate_todo.db')
156 
157# Create a connection to the database table todo.
158# Creates the table if it doesn't exist with columns id and title making id the primary key by default
159todos = db.create(Todo)
160 
161# Create a fasthtml app with the slate theme
162app, rt = fast_app(hdrs=Theme.slate.headers())
163 
164def tid(id): return f'todo-{id}'
165 
166# Render all the todos ordered by todo due date
167def mk_todo_list(): return Grid(*todos(order_by='due'), cols=1)
168 
169@app.delete
170async def delete_todo(id:int):
171 "Delete if it exists, if not someone else already deleted it so no action needed"
172 try: todos.delete(id)
173 except NotFoundError: pass
174 # Because there is no return, the todo will be swapped with None and removed from UI
175 
176# patch is a decorator that patches the __ft__ method of the Todo class
177# this is used to customize the html representation of the Todo object
178@patch
179def __ft__(self:Todo):
180 # Set color to red if the due date is passed
181 dd = datetime.strptime(self.due, '%Y-%m-%d').date()
182 due_date = Strong(dd.strftime('%Y-%m-%d'),style= "" if date.today() <= dd else "background-color: red;")
183 
184 # Action Buttons
185 _targets = {'hx_target':f'#{tid(self.id)}', 'hx_swap':'outerHTML'}
186 done = CheckboxX( hx_get =toggle_done.to(id=self.id).lstrip('/'), **_targets, checked=self.done),
187 delete = Button('delete', hx_delete=delete_todo.to(id=self.id).lstrip('/'), **_targets)
188 edit = Button('edit', hx_get =edit_todo .to(id=self.id).lstrip('/'), **_targets)
189
190 # Strike through todo if it is completed
191 style = Del if self.done else noop
192
193 return Card(DivLAligned(done,
194 style(Strong(self.title, target_id='current-todo')),
195 style(P(due_date,cls=TextPresets.muted_sm)),
196 edit,
197 delete),
198 id=tid(self.id))
199 
200@rt
201async def index():
202 "Main page of the app"
203 return Titled('Todo List',mk_todo_form(),Div(mk_todo_list(),id='todo-list'))
204 
205@rt
206async def upsert_todo(todo:Todo):
207 # Create/update a todo if there is content
208 if todo.title.strip(): todos.insert(todo,replace=True)
209 # Reload main page with updated database content
210 return mk_todo_list(),mk_todo_form()(hx_swap_oob='true',hx_target='#todo-input',hx_swap='outerHTML')
211 
212@rt
213async def toggle_done(id:int):
214 "Reverses done boolean in the database and returns the todo (rendered with __ft__)"
215 return todos.update(Todo(id=id, done=not todos[id].done))
216 
217 
218def mk_todo_form(todo=Todo(title=None, done=False, due=date.today(), id=None), btn_text="Add"):
219 """Create a form for todo creation/editing with optional pre-filled values"""
220 inputs = [Input(id='new-title', name='title',value=todo.title, placeholder='New Todo'),
221 Input(id='new-done', name='done', value=todo.done, hidden=True),
222 Input(id='new-due', name='due', value=todo.due)]
223 
224 # If there is an ID use it for editing existing row in db
225 if todo.id: inputs.append(Input(id='new-id', name='id', value=todo.id, hidden=True))
226
227 return Form(DivLAligned(
228 *inputs,
229 Button(btn_text, cls=ButtonT.primary, post=upsert_todo,hx_target='#todo-list', hx_swap='innerHTML')),
230 id='todo-input', cls='mb-6')
231 
232@rt
233async def edit_todo(id:int): return Card(mk_todo_form(todos.get(id), btn_text="Save"))
234 
235serve()
236```
237 
238 

Sections

  • File Upload Example
  • Cascading DropDown Example
  • Infinite Scroll Example
  • Simple Todo App Example
  • Database Model
  • Sqlite Database connection with fastlite
  • Create a connection to the database table todo.
  • Creates the table if it doesn't exist with columns id and title making id the primary key by default
  • Create a fasthtml app with the slate theme
  • Render all the todos ordered by todo due date
  • patch is a decorator that patches the __ft__ method of the Todo class
  • this is used to customize the html representation of the Todo object

What it covers

database

Stack — with the evidence

react

(0.70)

fastapi

(0.70)

vite

(0.70)

javascript

(0.50)

python

(0.50)

Glob targeting

  • [object Object]

Format

Cursor rules

The most expressive format here. Many small .mdc files, each with frontmatter declaring when it should load, so a rule about migrations only enters context when a migration is open. Costs the most to maintain and only one editor reads it.

What the corpus says about it

Repository

Owner
ai-evals-course
Language
—
License
—
Archived
no

All configs in this repo

Also in ai-evals-course/isaac-fasthtml-workshop

Diff this repo’s formats

One repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?

The other instruction files in this repository
RepositoryFormatStackCoversScoreChanged
ai-evals-course/isaac-fasthtml-workshop.cursor/rules/fasthtml.mdc · 69Cursor rulesreactfastapi+3archtypesdatabaseui+281/1003 days ago
ai-evals-course/isaac-fasthtml-workshop.cursor/rules/fastapi-react-backend-rules.mdc · 69Cursor rulesreactfastapi+3lint-formatstyledependenciesdo-not40/1003 days ago
ai-evals-course/isaac-fasthtml-workshop.cursor/rules/fastapi-react-frontend-rules.mdc · 69Cursor rulesreactfastapi+3lint-formatstyledependenciesdo-not54/1003 days ago
ai-evals-course/isaac-fasthtml-workshop.cursor/rules/ui.mdc · 69Cursor rulesreactfastapi+3no sections16/1003 days ago
Diff against .cursor/rules/fasthtml.mdc Diff against .cursor/rules/fastapi-react-backend-rules.mdc Diff against .cursor/rules/fastapi-react-frontend-rules.mdc Diff against .cursor/rules/ui.mdc

Similar configs

Same format, overlapping stack, ranked by quality.

Same format, overlapping stack, ranked by quality
RepositoryFormatStackCoversScoreChanged
TechSquidTV/Hermes.cursor/rules/10-hermes-api.mdc · 45Cursor rulestypescriptpytest+15testlint-formatstylearch+5100/1003 days ago
dodgecfr/combatfilms-webapp.cursor/rules/frontend.mdc · 0Cursor rulestypescriptturborepo+15setuptestlint-formatstyle+799/1003 days ago
markstev/mark-starter.cursor/rules/frontend.mdc · 0Cursor rulestypescriptturborepo+14setuptestlint-formatstyle+699/1003 days ago
deifos/clipmira-subtitles.cursor/rules/frontend.mdc · 1Cursor rulestypescriptnextjs+5setuptestlint-formatstyle+799/1003 days ago
Allymahmoud/case-intake-platform.cursor/rules/frontend.mdc · 0Cursor rulestypescriptturborepo+13setuptestlint-formatstyle+799/1003 days ago
TechSquidTV/Hermes.cursor/rules/20-hermes-api-tests.mdc · 45Cursor rulestypescriptpytest+15teststyletesting-strategysecurity+397/1003 days ago
langflow-ai/langflow.cursor/rules/docs_development.mdc · 153kCursor rulespythonnode+16setupbuildtestlint-format+797/1003 days ago
skillrecordings/egghead-next.cursor/rules/project-update-rules.mdc · 1.4kCursor rulestypescriptnode+14buildtestlint-formatstyle+796/1003 days ago
RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack