Skip to content
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
10 changes: 3 additions & 7 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ default_stages:

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
rev: v6.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
Expand All @@ -21,18 +21,14 @@ repos:
- id: detect-private-key

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.4.5
rev: v0.14.4
hooks:
- id: ruff-format

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.4.5
hooks:
- id: ruff
args: ["--fix", "--exit-non-zero-on-fix", "--config", "pyproject.toml"]

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.10.1
rev: v1.18.2
hooks:
- id: mypy
args: ["--ignore-missing-imports"]
Expand Down
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ dev = [
line-length = 88
target-version = "py312"

[tool.ruff.format]
quote-style = "double"

[tool.ruff.lint]
select = [
"E", # flake8 rules
Expand Down
16 changes: 8 additions & 8 deletions web/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,11 +260,11 @@ class Footer(Component[NoChildren, NoAttrs]):
@override
def render(self) -> Box:
return Box(
f"Made with {b(Link("Ludic", to=config.GITHUB_REPO_URL))} "
f"and {b(Link("HTMX", to="https://htmx.org"))} and 🐍 "
f"• {b(Link("Discord", to=config.DISCORD_INVITE_URL))} "
f"• {b(Link("GitHub", to=config.GITHUB_REPO_URL))} "
f"• Running on {b(Link("Leapcell", to="https://leapcell.io"))} "
f"Made with {b(Link('Ludic', to=config.GITHUB_REPO_URL))} "
f"and {b(Link('HTMX', to='https://htmx.org'))} and 🐍 "
f"• {b(Link('Discord', to=config.DISCORD_INVITE_URL))} "
f"• {b(Link('GitHub', to=config.GITHUB_REPO_URL))} "
f"• Running on {b(Link('Leapcell', to='https://leapcell.io'))} "
)


Expand Down Expand Up @@ -365,9 +365,9 @@ class EditOnGithub(Component[AnyChildren, EditOnGithubAttrs]):
@override
def render(self) -> div:
file_path = (
f"{self.attrs["base_url"].replace("-", "_")}index.py"
f"{self.attrs['base_url'].replace('-', '_')}index.py"
if self.attrs["base_url"].endswith("/")
else f"{self.attrs["base_url"].replace("-", "_")}.py"
else f"{self.attrs['base_url'].replace('-', '_')}.py"
)
url = f"{config.GITHUB_REPO_WEB_URL}/blob/main/web/endpoints{file_path}"
return div(
Expand Down Expand Up @@ -407,6 +407,6 @@ def render(self) -> blockquote:
return blockquote(
div(
p(i('"', *self.children, '"')),
p(b(f"– {self.attrs["source"]}")),
p(b(f"– {self.attrs['source']}")),
),
)
10 changes: 5 additions & 5 deletions web/endpoints/catalog/buttons.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def buttons(request: Request) -> Page:
return Page(
H1("Buttons"),
Paragraph(
f"The module {Code("ludic.catalog.buttons")} contains the following "
f"The module {Code('ludic.catalog.buttons')} contains the following "
"buttons:"
),
Box(
Expand Down Expand Up @@ -61,8 +61,8 @@ def buttons(request: Request) -> Page:
language="python",
),
Paragraph(
f"The {Code("ButtonLink")} component can be styled like any other "
f"button using the {Code("classes")} attribute:"
f"The {Code('ButtonLink')} component can be styled like any other "
f"button using the {Code('classes')} attribute:"
),
CodeBlock(
"""
Expand All @@ -72,7 +72,7 @@ def buttons(request: Request) -> Page:
""",
language="python",
),
Paragraph(f"You can disable a button using the {Code("disabled")} attribute:"),
Paragraph(f"You can disable a button using the {Code('disabled')} attribute:"),
Box(
Cluster(
Button("Button", disabled=True),
Expand All @@ -96,7 +96,7 @@ def buttons(request: Request) -> Page:
H2("Button Sizes"),
Paragraph(
"You can also change the size of the button appending the "
f"{Code("small")} or {Code("large")} class:"
f"{Code('small')} or {Code('large')} class:"
),
Box(
Cluster(
Expand Down
48 changes: 26 additions & 22 deletions web/endpoints/catalog/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ def forms(request: Request) -> Page:
return Page(
H1("Forms"),
Paragraph(
f"These components located in {Code("ludic.catalog.forms")} are in an "
f"These components located in {Code('ludic.catalog.forms')} are in an "
"experimental mode. There is the possibility to automatically create form "
f"{Link("fields from annotations", to="#generating-form-fields")}, but it "
f"{Link('fields from annotations', to='#generating-form-fields')}, but it "
"is far from production-ready."
),
H2("Input Field"),
Paragraph(
f"The {Code("InputField")} component is the most basic form field. It "
f"is a wrapper around the {Code("input")} HTML element which also "
f"The {Code('InputField')} component is the most basic form field. It "
f"is a wrapper around the {Code('input')} HTML element which also "
"generates a label if not disabled. Here is what it looks like:"
),
InputField(
Expand All @@ -59,7 +59,7 @@ def forms(request: Request) -> Page:
),
Paragraph(
"You can also create the input field without the label by not passing "
f"the {Code("label")} attribute:"
f"the {Code('label')} attribute:"
),
InputField(name="sample-input-field"),
CodeBlock(
Expand All @@ -74,8 +74,8 @@ def forms(request: Request) -> Page:
),
H2("Select Field"),
Paragraph(
f"The {Code("SelectField")} component is a wrapper around the "
f"{Code("select")} HTML element. It also generates a label if not "
f"The {Code('SelectField')} component is a wrapper around the "
f"{Code('select')} HTML element. It also generates a label if not "
"disabled. Here is what it looks like:"
),
SelectField(
Expand All @@ -101,8 +101,8 @@ def forms(request: Request) -> Page:
),
H2("Text Area"),
Paragraph(
f"The {Code("TextAreaField")} component is a wrapper around the "
f"{Code("textarea")} HTML element. It also generates a label if not "
f"The {Code('TextAreaField')} component is a wrapper around the "
f"{Code('textarea')} HTML element. It also generates a label if not "
"disabled. Here is what it looks like:"
),
TextAreaField(
Expand All @@ -126,7 +126,7 @@ def forms(request: Request) -> Page:
),
H2("Choices"),
Paragraph(
f"The {Code("ChoiceField")} component is a wrapper around the "
f"The {Code('ChoiceField')} component is a wrapper around the "
f"{Code("<input type='radio'>")} HTML element. It also generates a label "
"if not disabled. Here is what it looks like:"
),
Expand All @@ -151,7 +151,7 @@ def forms(request: Request) -> Page:
),
H2("Form"),
Paragraph(
f"The {Code("Form")} component is a wrapper around the {Code("form")} "
f"The {Code('Form')} component is a wrapper around the {Code('form')} "
"HTML element. Here is a sample form:"
),
Form(
Expand Down Expand Up @@ -188,9 +188,10 @@ def forms(request: Request) -> Page:
language="python",
),
Paragraph(
f"We use the {Code("Cluster")} component to create a form with multiple "
f"input fields and buttons. this component is described in the {Link(
"Layouts section", to=request.url_for("catalog:layouts").path)}. "
f"We use the {Code('Cluster')} component to create a form with multiple "
f"input fields and buttons. this component is described in the {
Link('Layouts section', to=request.url_for('catalog:layouts').path)
}. "
"You can also have the input field and the button aligned horizontally "
"using this layout component:"
),
Expand Down Expand Up @@ -229,7 +230,7 @@ def forms(request: Request) -> Page:
Paragraph(
"In some cases, the attributes of a component or class-based endpoint "
"can be used to create form fields automatically using the "
f"{Code("create_fields")} function. Here is an example:"
f"{Code('create_fields')} function. Here is an example:"
),
Form(
*create_fields(
Expand All @@ -253,9 +254,9 @@ class PersonAttrs(Attrs):
language="python",
),
Paragraph(
f"The {Code("create_fields")} function generates form fields from "
f"The {Code('create_fields')} function generates form fields from "
"annotations. It generates only fields that are annotated with the "
f"{Code("FieldMeta")} dataclass, which looks like this:"
f"{Code('FieldMeta')} dataclass, which looks like this:"
),
CodeBlock(
"""
Expand All @@ -270,7 +271,7 @@ class FieldMeta:
language="python",
),
Paragraph(
f"The {Code("parser")} attribute validates and parses the field. Here is "
f"The {Code('parser')} attribute validates and parses the field. Here is "
"how you would use it:"
),
CodeBlock(
Expand All @@ -296,10 +297,13 @@ class CustomerAttrs(Attrs):
language="python",
),
Paragraph(
f"Fields created with the {Code("create_fields")} function can be than "
f"extracted from submitted form data using the {Link(
"Parser class",
to=f"{request.url_for("docs:web_framework").path}#parsers")}."
f"Fields created with the {Code('create_fields')} function can be than "
f"extracted from submitted form data using the {
Link(
'Parser class',
to=f'{request.url_for("docs:web_framework").path}#parsers',
)
}."
),
request=request,
active_item="forms",
Expand Down
44 changes: 22 additions & 22 deletions web/endpoints/catalog/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,22 @@ def index(request: Request) -> Page:
return Page(
H1("Catalog"),
Paragraph(
f"The {Code("ludic.catalog")} module is a collection of components "
f"The {Code('ludic.catalog')} module is a collection of components "
"designed to help build applications using the Ludic framework. It "
"serves as both a resource for building new web applications and also "
"as a showcase of ways to implement components."
),
Paragraph(
"Each item in the catalog is a reusable component that generates HTML "
"code and registers its own CSS styles.. The registered CSS are loaded "
f"using the {Code("style.load()")} method, as detailed in the "
f"{Link("Styles and Themes", to=request.url_path_for("docs:styles"))} "
f"using the {Code('style.load()')} method, as detailed in the "
f"{Link('Styles and Themes', to=request.url_path_for('docs:styles'))} "
"section of the documentation."
),
Paragraph(
f"The catalog components are like {b("Lego pieces")} you can assemble "
f"together to build interactive and beautiful {b("HTML documents")} "
f"with {b("minimalistic")} approach:"
f"The catalog components are like {b('Lego pieces')} you can assemble "
f"together to build interactive and beautiful {b('HTML documents')} "
f"with {b('minimalistic')} approach:"
),
List(
Item(
Expand All @@ -41,13 +41,13 @@ def index(request: Request) -> Page:
"The generated CSS is simple, extensible, and easy to understand. "
"The layouts you can use for building your pages are responsive, "
"reusable, and robust. They are based on the amazing "
f"{Link("Every Layout Book", to="https://every-layout.dev/")}."
f"{Link('Every Layout Book', to='https://every-layout.dev/')}."
),
),
H2("How Do You Use The Catalog?"),
Paragraph(
f"In order for everything to work correctly, the first thing you usually "
f"need to do is to create a {Code("Page")} component. This component is "
f"need to do is to create a {Code('Page')} component. This component is "
"important for two reasons:"
),
List(
Expand All @@ -62,37 +62,37 @@ def index(request: Request) -> Page:
Message(
Title("How does CSS loading work?"),
f"The CSS styles for components are loaded when the component is imported "
f"anywhere in your application. The {Code("style.load()")} method iterates "
f"anywhere in your application. The {Code('style.load()')} method iterates "
"over all imported components and checks if the components have any styles "
"defined.",
),
Paragraph(
"All rendered HTML documents will have this component as a base similar to "
f"how all HTML pages in template engines like Jinja2 use the {i("base")} "
f"how all HTML pages in template engines like Jinja2 use the {i('base')} "
"template."
),
Message(
Title(
f"How does a {Code("Page")} component differ from a regular component?"
f"How does a {Code('Page')} component differ from a regular component?"
),
"The only difference is that it renders as a valid HTML5 document starting "
f"with the {Code("<!doctype html>")} declaration. You usually need only "
f"one {Code("Page")} component in the whole application.",
f"with the {Code('<!doctype html>')} declaration. You usually need only "
f"one {Code('Page')} component in the whole application.",
),
Paragraph(
f"After you are done with setting up your {Code("Page")} component, you "
f"After you are done with setting up your {Code('Page')} component, you "
"can use it along with all the other components in the catalog."
),
H3("HtmlPage Component"),
Paragraph(
"This component has already been mentioned throughout the documentation "
f"and can be used to create your {Code("Page")} component. The "
f"{Code("HtmlPage")} component is just for convenience so that you can "
f"and can be used to create your {Code('Page')} component. The "
f"{Code('HtmlPage')} component is just for convenience so that you can "
"quickly start and not worry about how to load e.g. CSS styles or HTMX. "
),
Paragraph(
f"Here is how you would use the {Code("HtmlPage")} component to "
f"create your own {Code("Page")} component:"
f"Here is how you would use the {Code('HtmlPage')} component to "
f"create your own {Code('Page')} component:"
),
CodeBlock(
"""
Expand Down Expand Up @@ -143,7 +143,7 @@ def render(self) -> HtmlPage:
Item(Code('htmx_version="latest"')),
),
Paragraph(
f"Now that you prepared your {Code("Page")} component, you can use it in "
f"Now that you prepared your {Code('Page')} component, you can use it in "
"your code like here:"
),
CodeBlock(
Expand Down Expand Up @@ -171,9 +171,9 @@ def clicked(request: Request) -> Paragraph:
language="python",
),
Paragraph(
f"The {Code("HtmlPage")} component comes also with default "
f"{Code("styles")}. In fact, the following list of styles are "
f"auto-loaded whenever you import anything from the {Code("ludic.catalog")}"
f"The {Code('HtmlPage')} component comes also with default "
f"{Code('styles')}. In fact, the following list of styles are "
f"auto-loaded whenever you import anything from the {Code('ludic.catalog')}"
" module:"
),
List(
Expand Down
8 changes: 4 additions & 4 deletions web/endpoints/catalog/layouts.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def layouts(request: Request) -> Page:
H1("Layouts"),
Paragraph(
"Layouts create a flexible structure for your user interface. "
f"The layouts in this module are based on the {b("Every Layout Book")}. "
f"The layouts in this module are based on the {b('Every Layout Book')}. "
"If you haven't read the book, go read it now: "
),
List(Item(Link("Every Layout Book", to="https://every-layout.dev/"))),
Expand All @@ -37,7 +37,7 @@ def layouts(request: Request) -> Page:
"The layouts can be combined together."
),
Paragraph(
f"All layouts are located in the {Code("ludic.catalog.layouts")} module."
f"All layouts are located in the {Code('ludic.catalog.layouts')} module."
),
Message(
Title("Viewing this page on mobile devices"),
Expand All @@ -51,15 +51,15 @@ def layouts(request: Request) -> Page:
"you can easily combine to create responsive, readable, and maintainable "
"user interfaces. Instead of starting from scratch with basic HTML "
"elements and manually writing CSS, you use these layouts as your "
f"{b("foundational building blocks")}. This approach allows you to compose "
f"{b('foundational building blocks')}. This approach allows you to compose "
"and arrange them in various ways to design your desired user interface, "
"making your code more organized and easier to manage."
),
b("A New Way of Thinking About Design"),
Paragraph(
"When writing CSS, you might be tempted to apply e.g. specific spacing, "
"colors, or font styles to an HTML element like a button. The idea of "
f"using the layout classes here is to define {b("context")} which "
f"using the layout classes here is to define {b('context')} which "
"determines how an HTML element should be displayed. So for example, we "
"might want to have a couple of buttons on one line, so we wrap them in "
"a Cluster class which inserts a margin between all its children and puts "
Expand Down
Loading