feat: initial project setup with implementation plan

- Add PLAN.md with 40-step checklist across 10 phases
- Add CLAUDE.md with project-specific instructions
- Set up nix flake with FastHTML/MonsterUI dependencies
- Create Python package skeleton (src/animaltrack)
- Vendor FastHTML and MonsterUI documentation
- Add Docker build configuration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-27 17:37:16 +00:00
parent 852107794b
commit c0b939627b
61 changed files with 18076 additions and 0 deletions

View File

@@ -0,0 +1,733 @@
# Forms and User Inputs API Reference
### Example Form
This form was live coded in a 5 minute video here
See Source
See Output
### Emergency Contact Form
Please fill out the form completely
First Name
Last Name
Email
Phone
### Relationship to patient
Parent
Sibling
Friend
Spouse
Significant Other
Relative
Child
Other
Address
Address Line 2
City
State
Zip
Submit Form
[code]
def ex_form():
relationship = ["Parent",'Sibling', "Friend", "Spouse", "Significant Other", "Relative", "Child", "Other"]
return Div(cls='space-y-4')(
DivCentered(
H3("Emergency Contact Form"),
P("Please fill out the form completely", cls=TextPresets.muted_sm)),
Form(cls='space-y-4')(
Grid(LabelInput("First Name",id='fn'), LabelInput("Last Name",id='ln')),
Grid(LabelInput("Email", id='em'), LabelInput("Phone", id='ph')),
H3("Relationship to patient"),
Grid(*[LabelCheckboxX(o) for o in relationship], cols=4, cls='space-y-3'),
LabelInput("Address", id='ad'),
LabelInput("Address Line 2", id='ad2'),
Grid(LabelInput("City", id='ct'), LabelInput("State", id='st')),
LabelInput("Zip", id='zp'),
DivCentered(Button("Submit Form", cls=ButtonT.primary))))
[/code]
See Source
See Output
Upload Button!
Upload Zone
[code]
def ex_upload():
return Div(Upload("Upload Button!", id='upload1'),
UploadZone(DivCentered(Span("Upload Zone"), UkIcon("upload")), id='upload2'),
cls='space-y-4')
[/code]
### FormLabel
Source
[code]
FormLabel(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]
> A Label with default styling
**Params**
* `c` contents of FormLabel tag (often text)
* `cls` Classes in addition to FormLabel styling
* `kwargs`
**Returns:** Label(..., cls='uk-form-label')
See Source
See Output
Form Label
[code]
def ex_formlabel():
return FormLabel("Form Label")
[/code]
### Input
Source
[code]
Input(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]
> An Input with default styling
**Params**
* `c` contents of Input tag (often nothing)
* `cls` Classes in addition to Input styling
* `kwargs`
**Returns:** Input(..., cls='uk-input')
See Source
See Output
Input
[code]
def ex_input():
return Div(
Input(placeholder="Enter text"),
LabelInput(label="Input", id='myid'))
[/code]
### LabelInput
Source
[code]
LabelInput(label: str | fastcore.xml.FT, lbl_cls='', input_cls='', cls='space-y-2', id='', **kwargs) -> fastcore.xml.FT
[/code]
> A `FormLabel` and `Input` pair that provides default spacing and links/names them based on id
**Params**
* `label` FormLabel content (often text)
* `lbl_cls` Additional classes for `FormLabel`
* `input_cls` Additional classes for `Input`
* `cls` Classes on container (default is `'space-y-2'` to prevent scrunched up form elements)
* `id` id for `FormLabel` and `Input` (`id`, `name` and `for` attributes are set to this value)
* `kwargs`
**Returns:** Div(cls='space-y-2')(`FormLabel`, `Input`)
### LabelCheckboxX
Source
[code]
LabelCheckboxX(label: str | fastcore.xml.FT, lbl_cls='', input_cls='', container=functools.partial(<function ft at 0x7526ec1c9580>, 'div', void_=False), cls='flex items-center space-x-2', id='', **kwargs) -> fastcore.xml.FT
[/code]
> A FormLabel and CheckboxX pair that provides default spacing and links/names them based on id
**Params**
* `label` FormLabel content (often text)
* `lbl_cls` Additional classes for `FormLabel`
* `input_cls` Additional classes for `CheckboxX`
* `container` Container to wrap label and input in (default is Div)
* `cls` Classes on container (default is 'flex items-center space-x-2')
* `id` id for `FormLabel` and `CheckboxX` (`id`, `name` and `for` attributes are set to this value)
* `kwargs`
**Returns:** Div(cls='flex items-center space-x-2')(`FormLabel`, `CheckboxX`)
### LabelSwitch
Source
[code]
LabelSwitch(label: str | fastcore.xml.FT, lbl_cls='', input_cls='', cls='space-x-2', id='', *, container=functools.partial(<function ft at 0x7526ec1c9580>, 'div', void_=False)) -> fastcore.xml.FT
[/code]
> **Params**
* `label` FormLabel content (often text)
* `lbl_cls` Additional classes for `FormLabel`
* `input_cls` Additional classes for `Switch`
* `container` Container to wrap label and input in (default is Div)
* `cls` Classes on container (default is `'space-x-2'` to prevent scrunched up form elements)
* `id` id for `FormLabel` and `Switch` (`id`, `name` and `for` attributes are set to this value)
**Returns:** Div(cls='space-y-2')(`FormLabel`, `Switch`)
### LabelRange
Source
[code]
LabelRange(label: str | fastcore.xml.FT, lbl_cls='', input_cls='', cls='space-y-6', id='', value='', min=None, max=None, step=None, label_range=True, *, container=functools.partial(<function ft at 0x7526ec1c9580>, 'div', void_=False)) -> fastcore.xml.FT
[/code]
> A FormLabel and Range pair that provides default spacing and links/names them based on id
**Params**
* `label` FormLabel content (often text)
* `lbl_cls` Additional classes for `FormLabel`
* `input_cls` Additional classes for `Range`
* `container` Container to wrap label and input in (default is Div)
* `cls` Classes on container (default is `'space-y-2'` to prevent scrunched up form elements)
* `id` id for `FormLabel` and `Range` (`id`, `name` and `for` attributes are set to this value)
* `value` Value for the range input
* `min` Minimum value
* `max` Maximum value
* `step` Step size
* `label_range` Whether to show the range value label (label for the `Range` component)
**Returns:** Div(cls='space-y-2')(`FormLabel`, `Range`)
### LabelTextArea
Source
[code]
LabelTextArea(label: str | fastcore.xml.FT, value='', lbl_cls='', input_cls='', cls='space-y-2', id='', **kwargs) -> fastcore.xml.FT
[/code]
> **Params**
* `label` FormLabel content (often text)
* `value` Value for the textarea
* `lbl_cls` Additional classes for `FormLabel`
* `input_cls` Additional classes for `TextArea`
* `cls` Classes on container (default is `'space-y-2'` to prevent scrunched up form elements)
* `id` id for `FormLabel` and `TextArea` (`id`, `name` and `for` attributes are set to this value)
* `kwargs`
**Returns:** Div(cls='space-y-2')(`FormLabel`, `TextArea`)
### LabelRadio
Source
[code]
LabelRadio(label: str | fastcore.xml.FT, lbl_cls='', input_cls='', container=functools.partial(<function ft at 0x7526ec1c9580>, 'div', void_=False), cls='flex items-center space-x-2', id='', **kwargs) -> fastcore.xml.FT
[/code]
> A FormLabel and Radio pair that provides default spacing and links/names them based on id
**Params**
* `label` FormLabel content (often text)
* `lbl_cls` Additional classes for `FormLabel`
* `input_cls` Additional classes for `Radio`
* `container` Container to wrap label and input in (default is Div)
* `cls` Classes on container (default is 'flex items-center space-x-2')
* `id` id for `FormLabel` and `Radio` (`id`, `name` and `for` attributes are set to this value)
* `kwargs`
**Returns:** Div(cls='flex items-center space-x-2')(`FormLabel`, `Radio`)
### LabelSelect
Source
[code]
LabelSelect(*option, label=(), lbl_cls=(), inp_cls=(), cls=('space-y-2',), id='', name='', placeholder='', searchable=False, select_kwargs=None, **kwargs)
[/code]
> A FormLabel and Select pair that provides default spacing and links/names them based on id
**Params**
* `option` Options for the select dropdown (can use `Options` helper function to create)
* `label` String or FT component for the label
* `lbl_cls` Additional classes for the label
* `inp_cls` Additional classes for the select input
* `cls` Classes for the outer div
* `id` ID for the select input
* `name` Name attribute for the select input
* `placeholder` Placeholder text for the select input
* `searchable` Whether the select should be searchable
* `select_kwargs` Additional Arguments passed to Select
* `kwargs`
### Progress
Source
[code]
Progress(*c, cls=(), value='', max='100', **kwargs) -> fastcore.xml.FT
[/code]
> Creates a progress bar
**Params**
* `c` Components to put in the progress bar (often nothing)
* `cls` Additional classes on the progress bar
* `value` Value of the progress bar
* `max` Max value of the progress bar (defaults to 100 for percentage)
* `kwargs`
**Returns:** Progress(..., cls='uk-progress')
See Source
See Output
[code]
def ex_progress():
return Progress(value=20, max=100)
[/code]
### Radio
Source
[code]
Radio(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]
> A Radio with default styling
**Params**
* `c` contents of Radio tag (often nothing)
* `cls` Classes in addition to Radio styling
* `kwargs`
**Returns:** Input(..., cls='uk-radio', type='radio')
See Source
See Output
Radio
[code]
def ex_radio():
return Div(
Radio(name="radio-group", id="radio1"),
LabelRadio(label="Radio", id='radio1',cls='flex items-center space-x-4'))
[/code]
### CheckboxX
Source
[code]
CheckboxX(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]
> A Checkbox with default styling
**Params**
* `c` contents of CheckboxX tag (often nothing)
* `cls` Classes in addition to CheckboxX styling
* `kwargs`
**Returns:** Input(..., cls='uk-checkbox', type='checkbox')
See Source
See Output
Checkbox
[code]
def ex_checkbox():
return Div(
CheckboxX(),
LabelCheckboxX(label="Checkbox", id='checkbox1'))
[/code]
### Range
Source
[code]
Range(*c, value='', label=True, min=None, max=None, step=None, cls=(), **kwargs) -> fastcore.xml.FT
[/code]
> A Range with default styling
**Params**
* `c` contents of Range tag (often nothing)
* `value`
* `label`
* `min`
* `max`
* `step`
* `cls` Classes in addition to Range styling
* `kwargs`
**Returns:** Input(..., cls='uk-range', type='range')
See Source
See Output
Basic Range
Range with Label
Multiple Values
Custom Range
[code]
def ex_range():
return Div(
Range(),
Range(label='kg', value="25,75", min=20, max=75),
LabelRange('Basic Range', value='50', min=0, max=100, step=1),
LabelRange('Range with Label', value='75', min=0, max=100, step=5, label_range=True),
LabelRange('Multiple Values', value='25,75', min=0, max=100, step=5, label_range=True),
LabelRange('Custom Range', value='500', min=0, max=1000, step=100, label_range=True)
)
[/code]
### Switch
Source
[code]
Switch(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]
> A Switch with default styling
**Params**
* `c` contents of Switch tag (often nothing)
* `cls` Classes in addition to Switch styling
* `kwargs`
**Returns:** Input(..., cls='uk-toggle-switch uk-toggle-switch-primary min-w-9', type='checkbox')
See Source
See Output
Switch
[code]
def ex_switch():
return Div(
Switch(id="switch"),
LabelSwitch(label="Switch", id='switch'))
[/code]
### TextArea
Source
[code]
TextArea(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]
> A Textarea with default styling
**Params**
* `c` contents of TextArea tag (often text)
* `cls` Classes in addition to TextArea styling
* `kwargs`
**Returns:** TextArea(..., cls='uk-textarea')
See Source
See Output
TextArea
[code]
def ex_textarea():
return Div(
TextArea(placeholder="Enter multiple lines of text"),
LabelTextArea(label="TextArea", id='myid'))
[/code]
### Select
Source
[code]
Select(*option, inp_cls=(), cls=('h-10',), cls_custom='button: uk-input-fake dropdown: w-full', id='', name='', placeholder='', searchable=False, insertable=False, select_kwargs=None, **kwargs)
[/code]
> Creates a select dropdown with uk styling and option for adding a search box
**Params**
* `option` Options for the select dropdown (can use `Options` helper function to create)
* `inp_cls` Additional classes for the select input
* `cls` Classes for the outer div (default h-10 for consistent height)
* `cls_custom` Classes for the Uk_Select web component
* `id` ID for the select input
* `name` Name attribute for the select input
* `placeholder` Placeholder text for the select input
* `searchable` Whether the select should be searchable
* `insertable` Whether to allow user-defined options to be added
* `select_kwargs` Additional Arguments passed to Select
* `kwargs`
See Source
See Output
Option 1Option 2Option 3
Select
Option 1Option 2Option 3
[code]
def ex_select():
return Div(
Select(map(Option, ["Option 1", "Option 2", "Option 3"])),
LabelSelect(map(Option, ["Option 1", "Option 2", "Option 3"]), label="Select", id='myid'))
[/code]
### Example: Insertable Select
In a production app, the user-inserted option would be saved server-side (db, session etc.)
See Source
See Output
AppleOrangeBananaMango
AppleBananaMangoOrange
[code]
def ex_insertable_select1():
fruit_opts = ['apple', 'orange', 'banana', 'mango']
return Grid(
Select(Option('Apple', value='apple'),
Option('Orange', value='orange'),
Option('Banana', value='banana'),
Option('Mango', value='mango'),
id="fruit", icon=True, insertable=True, placeholder="Choose a fruit..."),
Select(Optgroup(label="Fruit")(
*map(lambda l: Option(l.capitalize(), value=l), sorted(fruit_opts))),
id="fruit", icon=True, insertable=True, placeholder="Choose a fruit...",
cls_custom="button: uk-input-fake justify-between w-full; dropdown: w-full"))
[/code]
### Legend
Source
[code]
Legend(*c, cls=(), **kwargs) -> fastcore.xml.FT
[/code]
> A Legend with default styling
**Params**
* `c` contents of Legend tag (often other tags)
* `cls` Classes in addition to Legend styling
* `kwargs`
**Returns:** Legend(..., cls='uk-legend')
### Fieldset
Source
[code]
Fieldset(*c, cls='flex', **kwargs) -> fastcore.xml.FT
[/code]
> A Fieldset with default styling
**Params**
* `c` contents of Fieldset tag (often other tags)
* `cls` Classes in addition to Fieldset styling
* `kwargs`
**Returns:** Fieldset(..., cls='uk-fieldset')