Created
May 9, 2025 20:37
-
-
Save bpeterso2000/2ef45b8192f2e5eac07961e7d75ef951 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from fasthtml.common import * | |
from fastlite import Database, Model, Field | |
from dataclasses import dataclass, fields | |
from typing import Optional | |
import sqlite3 | |
# Initialize FastHTML app with Tailwind CSS for styling | |
app = FastHTML(hdrs=(picolink, Script(src="https://cdn.tailwindcss.com"))) | |
# Initialize FastLite database | |
db = Database("example.db") | |
# Example dataclass model for a "User" table | |
@dataclass | |
class User(Model): | |
id: Optional[int] = Field(default=None, primary_key=True) | |
name: str = Field() | |
email: str = Field() | |
# Create the table if it doesn't exist | |
db.create(User) | |
# DataGrid component | |
def DataGrid(model, db_table): | |
# Get field names from the dataclass (excluding primary key for form) | |
model_fields = [f.name for f in fields(model) if f.name != 'id'] | |
# Add button with UXWing add icon | |
add_btn = A( | |
Img(src="https://uxwing.com/wp-content/themes/uxwing/download/checkmark-cross/add-icon.svg", | |
cls="w-6 h-6 inline-block", alt="Add"), | |
" Add New", | |
href=f"/add/{model.__name__.lower()}", | |
cls="inline-flex items-center px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600" | |
) | |
# Table headers | |
headers = [Th(f.name.capitalize()) for f in fields(model)] + [Th("Actions")] | |
# Table rows | |
rows = [] | |
for record in db_table.all(): | |
row_cells = [Td(getattr(record, f)) for f in model_fields] | |
row_cells.append(Td(getattr(record, 'id'))) # Include ID for reference | |
# Edit and Delete buttons with UXWing icons | |
actions = Td( | |
A( | |
Img(src="https://uxwing.com/wp-content/themes/uxwing/download/editing-modification/edit-icon.svg", | |
cls="w-5 h-5 inline-block", alt="Edit"), | |
href=f"/edit/{model.__name__.lower()}/{record.id}", | |
cls="text-blue-500 hover:text-blue-700 mr-2" | |
), | |
A( | |
Img(src="https://uxwing.com/wp-content/themes/uxwing/download/checkmark-cross/delete-icon.svg", | |
cls="w-5 h-5 inline-block", alt="Delete"), | |
href=f"/delete/{model.__name__.lower()}/{record.id}", | |
cls="text-red-500 hover:text-red-700", | |
hx_delete=f"/delete/{model.__name__.lower()}/{record.id}", | |
hx_confirm="Are you sure you want to delete this record?", | |
hx_target="closest tr", | |
hx_swap="outerHTML" | |
) | |
) | |
rows.append(Tr(*row_cells, actions)) | |
# Return the complete table with add button | |
return Div( | |
add_btn, | |
Table( | |
Thead(*headers), | |
Tbody(*rows), | |
cls="min-w-full divide-y divide-gray-200 mt-4" | |
), | |
cls="p-4" | |
) | |
# Form component for Add/Edit | |
def ModelForm(model, record=None): | |
model_fields = [f.name for f in fields(model) if f.name != 'id'] | |
inputs = [ | |
Div( | |
Label(f.name.capitalize(), fr=f.name, cls="block text-sm font-medium text-gray-700"), | |
Input(name=f.name, value=getattr(record, f.name, ""), | |
cls="mt-1 block w-full border-gray-300 rounded-md shadow-sm") | |
) for f in model_fields | |
] | |
return Form( | |
*inputs, | |
Button("Save", type="submit", cls="mt-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"), | |
method="post", | |
action=f"/save/{model.__name__.lower()}/{getattr(record, 'id', '')}", | |
cls="space-y-4 max-w-md", | |
hx_post=f"/save/{model.__name__.lower()}/{getattr(record, 'id', '')}", | |
hx_target="#content", | |
hx_swap="innerHTML" | |
) | |
# Routes | |
@app.get("/") | |
def home(): | |
return Div( | |
H1("User Management", cls="text-2xl font-bold mb-4"), | |
DataGrid(User, db.t.users), | |
id="content", | |
cls="container mx-auto p-4" | |
) | |
@app.get("/add/{model_name}") | |
def add_form(model_name: str): | |
model = globals()[model_name.capitalize()] | |
return Div( | |
H2("Add New Record", cls="text-xl font-bold mb-4"), | |
ModelForm(model), | |
A("Back", href="/", cls="mt-4 inline-block text-blue-500 hover:underline"), | |
id="content", | |
cls="container mx-auto p-4" | |
) | |
@app.get("/edit/{model_name}/{id}") | |
def edit_form(model_name: str, id: int): | |
model = globals()[model_name.capitalize()] | |
record = db.t[model_name].get(id) | |
return Div( | |
H2("Edit Record", cls="text-xl font-bold mb-4"), | |
ModelForm(model, record), | |
A("Back", href="/", cls="mt-4 inline-block text-blue-500 hover:underline"), | |
id="content", | |
cls="container mx-auto p-4" | |
) | |
@app.post("/save/{model_name}/{id}") | |
def save(model_name: str, id: Optional[int], **kwargs): | |
model = globals()[model_name.capitalize()] | |
table = db.t[model_name] | |
if id: | |
table.update(kwargs, id=id) | |
else: | |
table.insert(kwargs) | |
return DataGrid(model, table) | |
@app.delete("/delete/{model_name}/{id}") | |
def delete(model_name: str, id: int): | |
table = db.t[model_name] | |
table.delete(id) | |
return "" | |
# Run the app | |
if __name__ == "__main__": | |
serve() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment