Exported source
footer = SingleValueFactory("footer", "Base footer component") # Base footer component
footer_title = SingleValueFactory("footer-title", "Title of a footer column") # footer title partFooterPlacement (value, names=None, module=None, qualname=None, type=None, start=1, boundary=None)
*str(object=’’) -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to ‘strict’.*
FooterDirection (value, names=None, module=None, qualname=None, type=None, start=1, boundary=None)
*str(object=’’) -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to ‘strict’.*
test_footer_basic_examples ()
Test basic footer utilities.
def test_footer_basic_examples():
"""Test basic footer utilities."""
# Basic footer
assert str(footer) == "footer"
assert str(footer_title) == "footer-title"
# Test with modifiers
assert str(footer.hover) == "hover:footer"
assert str(footer.md) == "md:footer"
assert str(footer.dark) == "dark:footer"
# Run the tests
test_footer_basic_examples()test_footer_placement_examples ()
Test footer placement variants.
test_footer_directions_examples ()
Test footer directions variants.
test_footer_basic_fasthtml_examples ()
Test basic footer with navigation sections from daisyUI v5 documentation.
def test_footer_basic_fasthtml_examples():
"""Test basic footer with navigation sections from daisyUI v5 documentation."""
from fasthtml.common import Footer, Nav, H6, A
from cjm_fasthtml_tailwind.utilities.spacing import p
from cjm_fasthtml_daisyui.utilities.semantic_colors import bg_dui, text_dui
from cjm_fasthtml_daisyui.components.navigation.link import link, link_styles
# Footer (vertical by default, horizontal for sm and up)
basic_footer = Footer(
Nav(
H6("Services", cls=str(footer_title)),
A("Branding", href="#", cls=combine_classes(link, link_styles.hover)),
A("Design", href="#", cls=combine_classes(link, link_styles.hover)),
A("Marketing", href="#", cls=combine_classes(link, link_styles.hover)),
A("Advertisement", href="#", cls=combine_classes(link, link_styles.hover))
),
Nav(
H6("Company", cls=str(footer_title)),
A("About us", href="#", cls=combine_classes(link, link_styles.hover)),
A("Contact", href="#", cls=combine_classes(link, link_styles.hover)),
A("Jobs", href="#", cls=combine_classes(link, link_styles.hover)),
A("Press kit", href="#", cls=combine_classes(link, link_styles.hover))
),
Nav(
H6("Legal", cls=str(footer_title)),
A("Terms of use", href="#", cls=combine_classes(link, link_styles.hover)),
A("Privacy policy", href="#", cls=combine_classes(link, link_styles.hover)),
A("Cookie policy", href="#", cls=combine_classes(link, link_styles.hover))
),
cls=combine_classes(footer, footer_directions.horizontal.sm, bg_dui.neutral, text_dui.neutral_content, p._10)
)
# Verify structure
assert basic_footer.tag == "footer"
assert "footer" in basic_footer.attrs['class']
assert "sm:footer-horizontal" in basic_footer.attrs['class']
assert "bg-neutral" in basic_footer.attrs['class']
assert "text-neutral-content" in basic_footer.attrs['class']
assert "p-10" in basic_footer.attrs['class']
# Verify nav sections
assert len(basic_footer.children) == 3
for nav in basic_footer.children:
assert nav.tag == "nav"
assert nav.children[0].tag == "h6"
assert "footer-title" in nav.children[0].attrs['class']
# Check links
for i in range(1, len(nav.children)):
assert nav.children[i].tag == "a"
assert "link" in nav.children[i].attrs['class']
assert "link-hover" in nav.children[i].attrs['class']
return basic_footer
# Run the tests
test_footer_basic_fasthtml_examples()<footer class="footer sm:footer-horizontal bg-neutral text-neutral-content p-10">
<nav>
<h6 class="footer-title">Services</h6>
<a href="#" class="link link-hover">Branding</a><a href="#" class="link link-hover">Design</a><a href="#" class="link link-hover">Marketing</a><a href="#" class="link link-hover">Advertisement</a> </nav>
<nav>
<h6 class="footer-title">Company</h6>
<a href="#" class="link link-hover">About us</a><a href="#" class="link link-hover">Contact</a><a href="#" class="link link-hover">Jobs</a><a href="#" class="link link-hover">Press kit</a> </nav>
<nav>
<h6 class="footer-title">Legal</h6>
<a href="#" class="link link-hover">Terms of use</a><a href="#" class="link link-hover">Privacy policy</a><a href="#" class="link link-hover">Cookie policy</a> </nav>
</footer>test_footer_with_logo_fasthtml_examples ()
Test footer with logo section from daisyUI v5 documentation.
def test_footer_with_logo_fasthtml_examples():
"""Test footer with logo section from daisyUI v5 documentation."""
from fasthtml.common import Footer, Nav, Aside, H6, A, P, Br
from fasthtml.svg import Svg, Path
from cjm_fasthtml_tailwind.utilities.spacing import p
from cjm_fasthtml_tailwind.utilities.svg import fill
from cjm_fasthtml_daisyui.utilities.semantic_colors import bg_dui, text_dui
from cjm_fasthtml_daisyui.components.navigation.link import link, link_styles
# Create reusable logo SVG
logo_svg = Svg(
Path(
d="M22.672 15.226l-2.432.811.841 2.515c.33 1.019-.209 2.127-1.23 2.456-1.15.325-2.148-.321-2.463-1.226l-.84-2.518-5.013 1.677.84 2.517c.391 1.203-.434 2.542-1.831 2.542-.88 0-1.601-.564-1.86-1.314l-.842-2.516-2.431.809c-1.135.328-2.145-.317-2.463-1.229-.329-1.018.211-2.127 1.231-2.456l2.432-.809-1.621-4.823-2.432.808c-1.355.384-2.558-.59-2.558-1.839 0-.817.509-1.582 1.327-1.846l2.433-.809-.842-2.515c-.33-1.02.211-2.129 1.232-2.458 1.02-.329 2.13.209 2.461 1.229l.842 2.515 5.011-1.677-.839-2.517c-.403-1.238.484-2.553 1.843-2.553.819 0 1.585.509 1.85 1.326l.841 2.517 2.431-.81c1.02-.33 2.131.211 2.461 1.229.332 1.018-.21 2.126-1.23 2.456l-2.433.809 1.622 4.823 2.433-.809c1.242-.401 2.557.484 2.557 1.838 0 .819-.51 1.583-1.328 1.847m-8.992-6.428l-5.01 1.675 1.619 4.828 5.011-1.674-1.62-4.829z"
),
width="50",
height="50",
viewBox="0 0 24 24",
xmlns="http://www.w3.org/2000/svg",
fill_rule="evenodd",
clip_rule="evenodd",
cls=str(fill.current)
)
# Footer with a logo section
footer_with_logo = Footer(
Aside(
logo_svg,
P(
"ACME Industries Ltd.",
Br(),
"Providing reliable tech since 1992"
)
),
Nav(
H6("Services", cls=str(footer_title)),
A("Branding", href="#", cls=combine_classes(link, link_styles.hover)),
A("Design", href="#", cls=combine_classes(link, link_styles.hover)),
A("Marketing", href="#", cls=combine_classes(link, link_styles.hover)),
A("Advertisement", href="#", cls=combine_classes(link, link_styles.hover))
),
Nav(
H6("Company", cls=str(footer_title)),
A("About us", href="#", cls=combine_classes(link, link_styles.hover)),
A("Contact", href="#", cls=combine_classes(link, link_styles.hover)),
A("Jobs", href="#", cls=combine_classes(link, link_styles.hover)),
A("Press kit", href="#", cls=combine_classes(link, link_styles.hover))
),
Nav(
H6("Legal", cls=str(footer_title)),
A("Terms of use", href="#", cls=combine_classes(link, link_styles.hover)),
A("Privacy policy", href="#", cls=combine_classes(link, link_styles.hover)),
A("Cookie policy", href="#", cls=combine_classes(link, link_styles.hover))
),
cls=combine_classes(footer, footer_directions.horizontal.sm, bg_dui.base_200, text_dui.base_content, p._10)
)
# Verify structure
assert footer_with_logo.tag == "footer"
assert "footer" in footer_with_logo.attrs['class']
assert "sm:footer-horizontal" in footer_with_logo.attrs['class']
assert "bg-base-200" in footer_with_logo.attrs['class']
assert "text-base-content" in footer_with_logo.attrs['class']
# Verify aside section
aside = footer_with_logo.children[0]
assert aside.tag == "aside"
assert aside.children[0].tag == "svg"
assert aside.children[0].attrs['width'] == "50"
assert aside.children[0].attrs['height'] == "50"
assert aside.children[1].tag == "p"
assert aside.children[1].children[0] == "ACME Industries Ltd."
assert aside.children[1].children[1].tag == "br"
assert aside.children[1].children[2] == "Providing reliable tech since 1992"
# Verify nav sections
for i in range(1, 4):
nav = footer_with_logo.children[i]
assert nav.tag == "nav"
assert nav.children[0].tag == "h6"
assert "footer-title" in nav.children[0].attrs['class']
return footer_with_logo
# Run the tests
test_footer_with_logo_fasthtml_examples()<footer class="footer sm:footer-horizontal bg-base-200 text-base-content p-10">
<aside>
<svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" height="50" width="50" fill-rule="evenodd" clip-rule="evenodd" class="fill-current"><path d="M22.672 15.226l-2.432.811.841 2.515c.33 1.019-.209 2.127-1.23 2.456-1.15.325-2.148-.321-2.463-1.226l-.84-2.518-5.013 1.677.84 2.517c.391 1.203-.434 2.542-1.831 2.542-.88 0-1.601-.564-1.86-1.314l-.842-2.516-2.431.809c-1.135.328-2.145-.317-2.463-1.229-.329-1.018.211-2.127 1.231-2.456l2.432-.809-1.621-4.823-2.432.808c-1.355.384-2.558-.59-2.558-1.839 0-.817.509-1.582 1.327-1.846l2.433-.809-.842-2.515c-.33-1.02.211-2.129 1.232-2.458 1.02-.329 2.13.209 2.461 1.229l.842 2.515 5.011-1.677-.839-2.517c-.403-1.238.484-2.553 1.843-2.553.819 0 1.585.509 1.85 1.326l.841 2.517 2.431-.81c1.02-.33 2.131.211 2.461 1.229.332 1.018-.21 2.126-1.23 2.456l-2.433.809 1.622 4.823 2.433-.809c1.242-.401 2.557.484 2.557 1.838 0 .819-.51 1.583-1.328 1.847m-8.992-6.428l-5.01 1.675 1.619 4.828 5.011-1.674-1.62-4.829z"></path></svg> <p>
ACME Industries Ltd.<br>Providing reliable tech since 1992 </p>
</aside>
<nav>
<h6 class="footer-title">Services</h6>
<a href="#" class="link link-hover">Branding</a><a href="#" class="link link-hover">Design</a><a href="#" class="link link-hover">Marketing</a><a href="#" class="link link-hover">Advertisement</a> </nav>
<nav>
<h6 class="footer-title">Company</h6>
<a href="#" class="link link-hover">About us</a><a href="#" class="link link-hover">Contact</a><a href="#" class="link link-hover">Jobs</a><a href="#" class="link link-hover">Press kit</a> </nav>
<nav>
<h6 class="footer-title">Legal</h6>
<a href="#" class="link link-hover">Terms of use</a><a href="#" class="link link-hover">Privacy policy</a><a href="#" class="link link-hover">Cookie policy</a> </nav>
</footer>test_footer_with_form_fasthtml_examples ()
Test footer with newsletter form from daisyUI v5 documentation.
def test_footer_with_form_fasthtml_examples():
"""Test footer with newsletter form from daisyUI v5 documentation."""
from fasthtml.common import Footer, Nav, Form, Fieldset, Label, H6, A, Input, Button, Div
from cjm_fasthtml_tailwind.utilities.spacing import p
from cjm_fasthtml_tailwind.utilities.sizing import w
from cjm_fasthtml_daisyui.utilities.semantic_colors import bg_dui, text_dui
from cjm_fasthtml_daisyui.components.navigation.link import link, link_styles
from cjm_fasthtml_daisyui.components.data_input.text_input import text_input, text_input_styles
from cjm_fasthtml_daisyui.components.layout.join import join, join_item
from cjm_fasthtml_daisyui.components.actions.button import btn, btn_colors
# Footer with a form
footer_with_form = Footer(
Nav(
H6("Services", cls=str(footer_title)),
A("Branding", href="#", cls=combine_classes(link, link_styles.hover)),
A("Design", href="#", cls=combine_classes(link, link_styles.hover)),
A("Marketing", href="#", cls=combine_classes(link, link_styles.hover)),
A("Advertisement", href="#", cls=combine_classes(link, link_styles.hover))
),
Nav(
H6("Company", cls=str(footer_title)),
A("About us", href="#", cls=combine_classes(link, link_styles.hover)),
A("Contact", href="#", cls=combine_classes(link, link_styles.hover)),
A("Jobs", href="#", cls=combine_classes(link, link_styles.hover)),
A("Press kit", href="#", cls=combine_classes(link, link_styles.hover))
),
Nav(
H6("Legal", cls=str(footer_title)),
A("Terms of use", href="#", cls=combine_classes(link, link_styles.hover)),
A("Privacy policy", href="#", cls=combine_classes(link, link_styles.hover)),
A("Cookie policy", href="#", cls=combine_classes(link, link_styles.hover))
),
Form(
H6("Newsletter", cls=str(footer_title)),
Fieldset(
Label("Enter your email address"),
Div(
Input(
type="text",
placeholder="[email protected]",
cls=combine_classes(text_input, join_item)
),
Button("Subscribe", cls=combine_classes(btn, btn_colors.primary, join_item)),
cls=str(join)
),
cls=str(w._80)
)
),
cls=combine_classes(footer, footer_directions.horizontal.sm, bg_dui.base_200, text_dui.base_content, p._10)
)
# Verify structure
assert footer_with_form.tag == "footer"
assert "footer" in footer_with_form.attrs['class']
assert "sm:footer-horizontal" in footer_with_form.attrs['class']
assert "bg-base-200" in footer_with_form.attrs['class']
assert "text-base-content" in footer_with_form.attrs['class']
# Verify nav sections
for i in range(3):
nav = footer_with_form.children[i]
assert nav.tag == "nav"
assert nav.children[0].tag == "h6"
assert "footer-title" in nav.children[0].attrs['class']
# Verify form section
form = footer_with_form.children[3]
assert form.tag == "form"
assert form.children[0].tag == "h6"
assert "footer-title" in form.children[0].attrs['class']
assert form.children[0].children[0] == "Newsletter"
# Verify fieldset
fieldset = form.children[1]
assert fieldset.tag == "fieldset"
assert "w-80" in fieldset.attrs['class']
assert fieldset.children[0].tag == "label"
assert fieldset.children[0].children[0] == "Enter your email address"
# Verify join div
join_div = fieldset.children[1]
assert join_div.tag == "div"
assert "join" in join_div.attrs['class']
assert join_div.children[0].tag == "input"
assert "input" in join_div.children[0].attrs['class']
assert "join-item" in join_div.children[0].attrs['class']
assert join_div.children[1].tag == "button"
assert "btn" in join_div.children[1].attrs['class']
assert "btn-primary" in join_div.children[1].attrs['class']
assert "join-item" in join_div.children[1].attrs['class']
return footer_with_form
# Run the tests
test_footer_with_form_fasthtml_examples()<footer class="footer sm:footer-horizontal bg-base-200 text-base-content p-10">
<nav>
<h6 class="footer-title">Services</h6>
<a href="#" class="link link-hover">Branding</a><a href="#" class="link link-hover">Design</a><a href="#" class="link link-hover">Marketing</a><a href="#" class="link link-hover">Advertisement</a> </nav>
<nav>
<h6 class="footer-title">Company</h6>
<a href="#" class="link link-hover">About us</a><a href="#" class="link link-hover">Contact</a><a href="#" class="link link-hover">Jobs</a><a href="#" class="link link-hover">Press kit</a> </nav>
<nav>
<h6 class="footer-title">Legal</h6>
<a href="#" class="link link-hover">Terms of use</a><a href="#" class="link link-hover">Privacy policy</a><a href="#" class="link link-hover">Cookie policy</a> </nav>
<form enctype="multipart/form-data"> <h6 class="footer-title">Newsletter</h6>
<fieldset class="w-80"><label>Enter your email address</label> <div class="join">
<input type="text" placeholder="[email protected]" class="input join-item">
<button class="btn btn-primary join-item">Subscribe</button> </div>
</fieldset></form></footer>test_footer_with_social_icons_fasthtml_examples ()
Test footer with social icons from daisyUI v5 documentation.
def test_footer_with_social_icons_fasthtml_examples():
"""Test footer with social icons from daisyUI v5 documentation."""
from fasthtml.common import Footer, Nav, Aside, H6, A, P, Br, Div
from fasthtml.svg import Svg, Path
from cjm_fasthtml_tailwind.utilities.spacing import p
from cjm_fasthtml_tailwind.utilities.svg import fill
from cjm_fasthtml_tailwind.utilities.layout import display_tw
from cjm_fasthtml_tailwind.utilities.flexbox_and_grid import grid_flow, gap, grid_display
from cjm_fasthtml_daisyui.utilities.semantic_colors import bg_dui, text_dui
from cjm_fasthtml_daisyui.components.navigation.link import link, link_styles
# Create reusable logo SVG
logo_svg = Svg(
Path(
d="M22.672 15.226l-2.432.811.841 2.515c.33 1.019-.209 2.127-1.23 2.456-1.15.325-2.148-.321-2.463-1.226l-.84-2.518-5.013 1.677.84 2.517c.391 1.203-.434 2.542-1.831 2.542-.88 0-1.601-.564-1.86-1.314l-.842-2.516-2.431.809c-1.135.328-2.145-.317-2.463-1.229-.329-1.018.211-2.127 1.231-2.456l2.432-.809-1.621-4.823-2.432.808c-1.355.384-2.558-.59-2.558-1.839 0-.817.509-1.582 1.327-1.846l2.433-.809-.842-2.515c-.33-1.02.211-2.129 1.232-2.458 1.02-.329 2.13.209 2.461 1.229l.842 2.515 5.011-1.677-.839-2.517c-.403-1.238.484-2.553 1.843-2.553.819 0 1.585.509 1.85 1.326l.841 2.517 2.431-.81c1.02-.33 2.131.211 2.461 1.229.332 1.018-.21 2.126-1.23 2.456l-2.433.809 1.622 4.823 2.433-.809c1.242-.401 2.557.484 2.557 1.838 0 .819-.51 1.583-1.328 1.847m-8.992-6.428l-5.01 1.675 1.619 4.828 5.011-1.674-1.62-4.829z"
),
width="50",
height="50",
viewBox="0 0 24 24",
xmlns="http://www.w3.org/2000/svg",
fill_rule="evenodd",
clip_rule="evenodd",
cls=str(fill.current)
)
# Create social media icons
twitter_icon = Svg(
Path(
d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"
),
xmlns="http://www.w3.org/2000/svg",
width="24",
height="24",
viewBox="0 0 24 24",
cls=str(fill.current)
)
youtube_icon = Svg(
Path(
d="M19.615 3.184c-3.604-.246-11.631-.245-15.23 0-3.897.266-4.356 2.62-4.385 8.816.029 6.185.484 8.549 4.385 8.816 3.6.245 11.626.246 15.23 0 3.897-.266 4.356-2.62 4.385-8.816-.029-6.185-.484-8.549-4.385-8.816zm-10.615 12.816v-8l8 3.993-8 4.007z"
),
xmlns="http://www.w3.org/2000/svg",
width="24",
height="24",
viewBox="0 0 24 24",
cls=str(fill.current)
)
facebook_icon = Svg(
Path(
d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z"
),
xmlns="http://www.w3.org/2000/svg",
width="24",
height="24",
viewBox="0 0 24 24",
cls=str(fill.current)
)
# Footer with logo and social icons
footer_with_social = Footer(
Aside(
logo_svg,
P(
"ACME Industries Ltd.",
Br(),
"Providing reliable tech since 1992"
)
),
Nav(
H6("Social", cls=str(footer_title)),
Div(
A(twitter_icon, href="#"),
A(youtube_icon, href="#"),
A(facebook_icon, href="#"),
cls=combine_classes(grid_display, grid_flow.col, gap._4)
)
),
cls=combine_classes(footer, footer_directions.horizontal.sm, bg_dui.neutral, text_dui.neutral_content, p._10)
)
# Verify structure
assert footer_with_social.tag == "footer"
assert "footer" in footer_with_social.attrs['class']
assert "sm:footer-horizontal" in footer_with_social.attrs['class']
assert "bg-neutral" in footer_with_social.attrs['class']
assert "text-neutral-content" in footer_with_social.attrs['class']
# Verify aside section
aside = footer_with_social.children[0]
assert aside.tag == "aside"
assert aside.children[0].tag == "svg"
assert aside.children[1].tag == "p"
# Verify social nav section
social_nav = footer_with_social.children[1]
assert social_nav.tag == "nav"
assert social_nav.children[0].tag == "h6"
assert "footer-title" in social_nav.children[0].attrs['class']
assert social_nav.children[0].children[0] == "Social"
# Verify social icons grid
social_grid = social_nav.children[1]
assert social_grid.tag == "div"
assert "grid" in social_grid.attrs['class']
assert "grid-flow-col" in social_grid.attrs['class']
assert "gap-4" in social_grid.attrs['class']
assert len(social_grid.children) == 3
for child in social_grid.children:
assert child.tag == "a"
assert child.children[0].tag == "svg"
return footer_with_social
# Run the tests
test_footer_with_social_icons_fasthtml_examples()<footer class="footer sm:footer-horizontal bg-neutral text-neutral-content p-10">
<aside>
<svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" height="50" width="50" fill-rule="evenodd" clip-rule="evenodd" class="fill-current"><path d="M22.672 15.226l-2.432.811.841 2.515c.33 1.019-.209 2.127-1.23 2.456-1.15.325-2.148-.321-2.463-1.226l-.84-2.518-5.013 1.677.84 2.517c.391 1.203-.434 2.542-1.831 2.542-.88 0-1.601-.564-1.86-1.314l-.842-2.516-2.431.809c-1.135.328-2.145-.317-2.463-1.229-.329-1.018.211-2.127 1.231-2.456l2.432-.809-1.621-4.823-2.432.808c-1.355.384-2.558-.59-2.558-1.839 0-.817.509-1.582 1.327-1.846l2.433-.809-.842-2.515c-.33-1.02.211-2.129 1.232-2.458 1.02-.329 2.13.209 2.461 1.229l.842 2.515 5.011-1.677-.839-2.517c-.403-1.238.484-2.553 1.843-2.553.819 0 1.585.509 1.85 1.326l.841 2.517 2.431-.81c1.02-.33 2.131.211 2.461 1.229.332 1.018-.21 2.126-1.23 2.456l-2.433.809 1.622 4.823 2.433-.809c1.242-.401 2.557.484 2.557 1.838 0 .819-.51 1.583-1.328 1.847m-8.992-6.428l-5.01 1.675 1.619 4.828 5.011-1.674-1.62-4.829z"></path></svg> <p>
ACME Industries Ltd.<br>Providing reliable tech since 1992 </p>
</aside>
<nav>
<h6 class="footer-title">Social</h6>
<div class="grid grid-flow-col gap-4">
<a href="#"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" height="24" width="24" class="fill-current"><path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"></path></svg></a><a href="#"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" height="24" width="24" class="fill-current"><path d="M19.615 3.184c-3.604-.246-11.631-.245-15.23 0-3.897.266-4.356 2.62-4.385 8.816.029 6.185.484 8.549 4.385 8.816 3.6.245 11.626.246 15.23 0 3.897-.266 4.356-2.62 4.385-8.816-.029-6.185-.484-8.549-4.385-8.816zm-10.615 12.816v-8l8 3.993-8 4.007z"></path></svg></a><a href="#"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" height="24" width="24" class="fill-current"><path d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z"></path></svg></a> </div>
</nav>
</footer>test_footer_copyright_fasthtml_examples ()
Test footer with copyright text from daisyUI v5 documentation.
def test_footer_copyright_fasthtml_examples():
"""Test footer with copyright text from daisyUI v5 documentation."""
from fasthtml.common import Footer, Aside, P
from datetime import datetime
from cjm_fasthtml_tailwind.utilities.spacing import p
from cjm_fasthtml_daisyui.utilities.semantic_colors import bg_dui, text_dui
# Footer with copyright text
copyright_footer = Footer(
Aside(
P(f"Copyright © {datetime.now().year} - All right reserved by ACME Industries Ltd")
),
cls=combine_classes(footer, footer_directions.horizontal.sm, footer_placement.center, bg_dui.base_300, text_dui.base_content, p._4)
)
# Verify structure
assert copyright_footer.tag == "footer"
assert "footer" in copyright_footer.attrs['class']
assert "sm:footer-horizontal" in copyright_footer.attrs['class']
assert "footer-center" in copyright_footer.attrs['class']
assert "bg-base-300" in copyright_footer.attrs['class']
assert "text-base-content" in copyright_footer.attrs['class']
assert "p-4" in copyright_footer.attrs['class']
# Verify aside section
aside = copyright_footer.children[0]
assert aside.tag == "aside"
assert aside.children[0].tag == "p"
assert f"Copyright © {datetime.now().year} - All right reserved by ACME Industries Ltd" in aside.children[0].children[0]
return copyright_footer
# Run the tests
test_footer_copyright_fasthtml_examples()test_footer_copyright_with_icons_fasthtml_examples ()
Test footer with copyright text and social icons from daisyUI v5 documentation.
def test_footer_copyright_with_icons_fasthtml_examples():
"""Test footer with copyright text and social icons from daisyUI v5 documentation."""
from fasthtml.common import Footer, Aside, Nav, P, A, Div
from fasthtml.svg import Svg, Path
from datetime import datetime
from cjm_fasthtml_tailwind.utilities.spacing import p
from cjm_fasthtml_tailwind.utilities.svg import fill
from cjm_fasthtml_tailwind.utilities.layout import display_tw
from cjm_fasthtml_tailwind.utilities.flexbox_and_grid import grid_flow, gap, items, place_self, justify_self
from cjm_fasthtml_daisyui.utilities.semantic_colors import bg_dui, text_dui
# Create reusable logo SVG
logo_svg = Svg(
Path(
d="M22.672 15.226l-2.432.811.841 2.515c.33 1.019-.209 2.127-1.23 2.456-1.15.325-2.148-.321-2.463-1.226l-.84-2.518-5.013 1.677.84 2.517c.391 1.203-.434 2.542-1.831 2.542-.88 0-1.601-.564-1.86-1.314l-.842-2.516-2.431.809c-1.135.328-2.145-.317-2.463-1.229-.329-1.018.211-2.127 1.231-2.456l2.432-.809-1.621-4.823-2.432.808c-1.355.384-2.558-.59-2.558-1.839 0-.817.509-1.582 1.327-1.846l2.433-.809-.842-2.515c-.33-1.02.211-2.129 1.232-2.458 1.02-.329 2.13.209 2.461 1.229l.842 2.515 5.011-1.677-.839-2.517c-.403-1.238.484-2.553 1.843-2.553.819 0 1.585.509 1.85 1.326l.841 2.517 2.431-.81c1.02-.33 2.131.211 2.461 1.229.332 1.018-.21 2.126-1.23 2.456l-2.433.809 1.622 4.823 2.433-.809c1.242-.401 2.557.484 2.557 1.838 0 .819-.51 1.583-1.328 1.847m-8.992-6.428l-5.01 1.675 1.619 4.828 5.011-1.674-1.62-4.829z"
),
width="36",
height="36",
viewBox="0 0 24 24",
xmlns="http://www.w3.org/2000/svg",
fill_rule="evenodd",
clip_rule="evenodd",
cls=str(fill.current)
)
# Create social media icons
twitter_icon = Svg(
Path(
d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"
),
xmlns="http://www.w3.org/2000/svg",
width="24",
height="24",
viewBox="0 0 24 24",
cls=str(fill.current)
)
youtube_icon = Svg(
Path(
d="M19.615 3.184c-3.604-.246-11.631-.245-15.23 0-3.897.266-4.356 2.62-4.385 8.816.029 6.185.484 8.549 4.385 8.816 3.6.245 11.626.246 15.23 0 3.897-.266 4.356-2.62 4.385-8.816-.029-6.185-.484-8.549-4.385-8.816zm-10.615 12.816v-8l8 3.993-8 4.007z"
),
xmlns="http://www.w3.org/2000/svg",
width="24",
height="24",
viewBox="0 0 24 24",
cls=str(fill.current)
)
facebook_icon = Svg(
Path(
d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z"
),
xmlns="http://www.w3.org/2000/svg",
width="24",
height="24",
viewBox="0 0 24 24",
cls=str(fill.current)
)
# Footer with copyright text and social icons
copyright_social_footer = Footer(
Aside(
logo_svg,
P(f"Copyright © {datetime.now().year} - All right reserved"),
cls=combine_classes(grid_flow.col, items.center)
),
Nav(
A(twitter_icon, href="#"),
A(youtube_icon, href="#"),
A(facebook_icon, href="#"),
cls=combine_classes(grid_flow.col, gap._4, place_self.center.md, justify_self.end.md)
),
cls=combine_classes(footer, footer_directions.horizontal.sm, bg_dui.neutral, text_dui.neutral_content, items.center, p._4)
)
# Verify structure
assert copyright_social_footer.tag == "footer"
assert "footer" in copyright_social_footer.attrs['class']
assert "sm:footer-horizontal" in copyright_social_footer.attrs['class']
assert "bg-neutral" in copyright_social_footer.attrs['class']
assert "text-neutral-content" in copyright_social_footer.attrs['class']
assert "items-center" in copyright_social_footer.attrs['class']
assert "p-4" in copyright_social_footer.attrs['class']
# Verify aside section
aside = copyright_social_footer.children[0]
assert aside.tag == "aside"
assert "grid-flow-col" in aside.attrs['class']
assert "items-center" in aside.attrs['class']
assert aside.children[0].tag == "svg"
assert aside.children[0].attrs['width'] == "36"
assert aside.children[1].tag == "p"
# Verify nav section with social icons
nav = copyright_social_footer.children[1]
assert nav.tag == "nav"
assert "grid-flow-col" in nav.attrs['class']
assert "gap-4" in nav.attrs['class']
assert "md:place-self-center" in nav.attrs['class']
assert "md:justify-self-end" in nav.attrs['class']
assert len(nav.children) == 3
return copyright_social_footer
# Run the tests
test_footer_copyright_with_icons_fasthtml_examples()<footer class="footer sm:footer-horizontal bg-neutral text-neutral-content items-center p-4">
<aside class="grid-flow-col items-center">
<svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" height="36" width="36" fill-rule="evenodd" clip-rule="evenodd" class="fill-current"><path d="M22.672 15.226l-2.432.811.841 2.515c.33 1.019-.209 2.127-1.23 2.456-1.15.325-2.148-.321-2.463-1.226l-.84-2.518-5.013 1.677.84 2.517c.391 1.203-.434 2.542-1.831 2.542-.88 0-1.601-.564-1.86-1.314l-.842-2.516-2.431.809c-1.135.328-2.145-.317-2.463-1.229-.329-1.018.211-2.127 1.231-2.456l2.432-.809-1.621-4.823-2.432.808c-1.355.384-2.558-.59-2.558-1.839 0-.817.509-1.582 1.327-1.846l2.433-.809-.842-2.515c-.33-1.02.211-2.129 1.232-2.458 1.02-.329 2.13.209 2.461 1.229l.842 2.515 5.011-1.677-.839-2.517c-.403-1.238.484-2.553 1.843-2.553.819 0 1.585.509 1.85 1.326l.841 2.517 2.431-.81c1.02-.33 2.131.211 2.461 1.229.332 1.018-.21 2.126-1.23 2.456l-2.433.809 1.622 4.823 2.433-.809c1.242-.401 2.557.484 2.557 1.838 0 .819-.51 1.583-1.328 1.847m-8.992-6.428l-5.01 1.675 1.619 4.828 5.011-1.674-1.62-4.829z"></path></svg> <p>Copyright © 2025 - All right reserved</p>
</aside>
<nav class="grid-flow-col gap-4 md:place-self-center md:justify-self-end">
<a href="#"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" height="24" width="24" class="fill-current"><path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"></path></svg></a><a href="#"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" height="24" width="24" class="fill-current"><path d="M19.615 3.184c-3.604-.246-11.631-.245-15.23 0-3.897.266-4.356 2.62-4.385 8.816.029 6.185.484 8.549 4.385 8.816 3.6.245 11.626.246 15.23 0 3.897-.266 4.356-2.62 4.385-8.816-.029-6.185-.484-8.549-4.385-8.816zm-10.615 12.816v-8l8 3.993-8 4.007z"></path></svg></a><a href="#"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" height="24" width="24" class="fill-current"><path d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z"></path></svg></a> </nav>
</footer>test_footer_with_links_and_social_fasthtml_examples ()
Test footer with links and social icons from daisyUI v5 documentation.
def test_footer_with_links_and_social_fasthtml_examples():
"""Test footer with links and social icons from daisyUI v5 documentation."""
from fasthtml.common import Footer, Nav, H6, A, Div
from fasthtml.svg import Svg, Path
from cjm_fasthtml_tailwind.utilities.spacing import p
from cjm_fasthtml_tailwind.utilities.svg import fill
from cjm_fasthtml_tailwind.utilities.layout import display_tw
from cjm_fasthtml_tailwind.utilities.flexbox_and_grid import grid_flow, gap, grid_display
from cjm_fasthtml_daisyui.utilities.semantic_colors import bg_dui, text_dui
from cjm_fasthtml_daisyui.components.navigation.link import link, link_styles
# Create social media icons
twitter_icon = Svg(
Path(
d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"
),
xmlns="http://www.w3.org/2000/svg",
width="24",
height="24",
viewBox="0 0 24 24",
cls=str(fill.current)
)
youtube_icon = Svg(
Path(
d="M19.615 3.184c-3.604-.246-11.631-.245-15.23 0-3.897.266-4.356 2.62-4.385 8.816.029 6.185.484 8.549 4.385 8.816 3.6.245 11.626.246 15.23 0 3.897-.266 4.356-2.62 4.385-8.816-.029-6.185-.484-8.549-4.385-8.816zm-10.615 12.816v-8l8 3.993-8 4.007z"
),
xmlns="http://www.w3.org/2000/svg",
width="24",
height="24",
viewBox="0 0 24 24",
cls=str(fill.current)
)
facebook_icon = Svg(
Path(
d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z"
),
xmlns="http://www.w3.org/2000/svg",
width="24",
height="24",
viewBox="0 0 24 24",
cls=str(fill.current)
)
# Footer with links and social icons
footer_links_social = Footer(
Nav(
H6("Services", cls=str(footer_title)),
A("Branding", href="#", cls=combine_classes(link, link_styles.hover)),
A("Design", href="#", cls=combine_classes(link, link_styles.hover)),
A("Marketing", href="#", cls=combine_classes(link, link_styles.hover)),
A("Advertisement", href="#", cls=combine_classes(link, link_styles.hover))
),
Nav(
H6("Company", cls=str(footer_title)),
A("About us", href="#", cls=combine_classes(link, link_styles.hover)),
A("Contact", href="#", cls=combine_classes(link, link_styles.hover)),
A("Jobs", href="#", cls=combine_classes(link, link_styles.hover)),
A("Press kit", href="#", cls=combine_classes(link, link_styles.hover))
),
Nav(
H6("Social", cls=str(footer_title)),
Div(
A(twitter_icon, href="#"),
A(youtube_icon, href="#"),
A(facebook_icon, href="#"),
cls=combine_classes(grid_display, grid_flow.col, gap._4)
)
),
cls=combine_classes(footer, footer_directions.horizontal.sm, bg_dui.base_300, text_dui.base_content, p._10)
)
# Verify structure
assert footer_links_social.tag == "footer"
assert "footer" in footer_links_social.attrs['class']
assert "sm:footer-horizontal" in footer_links_social.attrs['class']
assert "bg-base-300" in footer_links_social.attrs['class']
assert "text-base-content" in footer_links_social.attrs['class']
assert "p-10" in footer_links_social.attrs['class']
# Verify service and company nav sections
for i in range(2):
nav = footer_links_social.children[i]
assert nav.tag == "nav"
assert nav.children[0].tag == "h6"
assert "footer-title" in nav.children[0].attrs['class']
for j in range(1, 5):
assert nav.children[j].tag == "a"
assert "link" in nav.children[j].attrs['class']
assert "link-hover" in nav.children[j].attrs['class']
# Verify social nav section
social_nav = footer_links_social.children[2]
assert social_nav.tag == "nav"
assert social_nav.children[0].tag == "h6"
assert social_nav.children[0].children[0] == "Social"
social_grid = social_nav.children[1]
assert social_grid.tag == "div"
assert "grid" in social_grid.attrs['class']
assert "grid-flow-col" in social_grid.attrs['class']
assert "gap-4" in social_grid.attrs['class']
assert len(social_grid.children) == 3
return footer_links_social
# Run the tests
test_footer_with_links_and_social_fasthtml_examples()<footer class="footer sm:footer-horizontal bg-base-300 text-base-content p-10">
<nav>
<h6 class="footer-title">Services</h6>
<a href="#" class="link link-hover">Branding</a><a href="#" class="link link-hover">Design</a><a href="#" class="link link-hover">Marketing</a><a href="#" class="link link-hover">Advertisement</a> </nav>
<nav>
<h6 class="footer-title">Company</h6>
<a href="#" class="link link-hover">About us</a><a href="#" class="link link-hover">Contact</a><a href="#" class="link link-hover">Jobs</a><a href="#" class="link link-hover">Press kit</a> </nav>
<nav>
<h6 class="footer-title">Social</h6>
<div class="grid grid-flow-col gap-4">
<a href="#"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" height="24" width="24" class="fill-current"><path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"></path></svg></a><a href="#"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" height="24" width="24" class="fill-current"><path d="M19.615 3.184c-3.604-.246-11.631-.245-15.23 0-3.897.266-4.356 2.62-4.385 8.816.029 6.185.484 8.549 4.385 8.816 3.6.245 11.626.246 15.23 0 3.897-.266 4.356-2.62 4.385-8.816-.029-6.185-.484-8.549-4.385-8.816zm-10.615 12.816v-8l8 3.993-8 4.007z"></path></svg></a><a href="#"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" height="24" width="24" class="fill-current"><path d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z"></path></svg></a> </div>
</nav>
</footer>test_footer_centered_with_logo_fasthtml_examples ()
Test centered footer with logo and social icons from daisyUI v5 documentation.
def test_footer_centered_with_logo_fasthtml_examples():
"""Test centered footer with logo and social icons from daisyUI v5 documentation."""
from fasthtml.common import Footer, Aside, Nav, P, A, Div, Br
from fasthtml.svg import Svg, Path
from datetime import datetime
from cjm_fasthtml_tailwind.utilities.spacing import p
from cjm_fasthtml_tailwind.utilities.svg import fill
from cjm_fasthtml_tailwind.utilities.typography import font_size, font_weight, font_family, text_color
from cjm_fasthtml_tailwind.utilities.layout import display_tw
from cjm_fasthtml_tailwind.utilities.flexbox_and_grid import grid_flow, gap, grid_display
from cjm_fasthtml_daisyui.utilities.semantic_colors import bg_dui, text_dui
# Create reusable logo SVG
logo_svg = Svg(
Path(
d="M22.672 15.226l-2.432.811.841 2.515c.33 1.019-.209 2.127-1.23 2.456-1.15.325-2.148-.321-2.463-1.226l-.84-2.518-5.013 1.677.84 2.517c.391 1.203-.434 2.542-1.831 2.542-.88 0-1.601-.564-1.86-1.314l-.842-2.516-2.431.809c-1.135.328-2.145-.317-2.463-1.229-.329-1.018.211-2.127 1.231-2.456l2.432-.809-1.621-4.823-2.432.808c-1.355.384-2.558-.59-2.558-1.839 0-.817.509-1.582 1.327-1.846l2.433-.809-.842-2.515c-.33-1.02.211-2.129 1.232-2.458 1.02-.329 2.13.209 2.461 1.229l.842 2.515 5.011-1.677-.839-2.517c-.403-1.238.484-2.553 1.843-2.553.819 0 1.585.509 1.85 1.326l.841 2.517 2.431-.81c1.02-.33 2.131.211 2.461 1.229.332 1.018-.21 2.126-1.23 2.456l-2.433.809 1.622 4.823 2.433-.809c1.242-.401 2.557.484 2.557 1.838 0 .819-.51 1.583-1.328 1.847m-8.992-6.428l-5.01 1.675 1.619 4.828 5.011-1.674-1.62-4.829z"
),
width="50",
height="50",
viewBox="0 0 24 24",
xmlns="http://www.w3.org/2000/svg",
fill_rule="evenodd",
clip_rule="evenodd",
cls=combine_classes(display_tw.inline_block, fill.current)
)
# Create social media icons
twitter_icon = Svg(
Path(
d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"
),
xmlns="http://www.w3.org/2000/svg",
width="24",
height="24",
viewBox="0 0 24 24",
cls=str(fill.current)
)
youtube_icon = Svg(
Path(
d="M19.615 3.184c-3.604-.246-11.631-.245-15.23 0-3.897.266-4.356 2.62-4.385 8.816.029 6.185.484 8.549 4.385 8.816 3.6.245 11.626.246 15.23 0 3.897-.266 4.356-2.62 4.385-8.816-.029-6.185-.484-8.549-4.385-8.816zm-10.615 12.816v-8l8 3.993-8 4.007z"
),
xmlns="http://www.w3.org/2000/svg",
width="24",
height="24",
viewBox="0 0 24 24",
cls=str(fill.current)
)
facebook_icon = Svg(
Path(
d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z"
),
xmlns="http://www.w3.org/2000/svg",
width="24",
height="24",
viewBox="0 0 24 24",
cls=str(fill.current)
)
# Centered footer with logo and social icons
centered_logo_footer = Footer(
Aside(
logo_svg,
P(
"ACME Industries Ltd.",
Br(),
"Providing reliable tech since 1992",
cls=str(font_weight.bold)
),
P(f"Copyright © {datetime.now().year} - All right reserved")
),
Nav(
Div(
A(twitter_icon, href="#"),
A(youtube_icon, href="#"),
A(facebook_icon, href="#"),
cls=combine_classes(grid_display, grid_flow.col, gap._4)
)
),
cls=combine_classes(footer, footer_directions.horizontal, footer_placement.center, bg_dui.primary, text_dui.primary_content, p._10)
)
# Verify structure
assert centered_logo_footer.tag == "footer"
assert "footer" in centered_logo_footer.attrs['class']
assert "footer-horizontal" in centered_logo_footer.attrs['class']
assert "footer-center" in centered_logo_footer.attrs['class']
assert "bg-primary" in centered_logo_footer.attrs['class']
assert "text-primary-content" in centered_logo_footer.attrs['class']
assert "p-10" in centered_logo_footer.attrs['class']
# Verify aside section
aside = centered_logo_footer.children[0]
assert aside.tag == "aside"
assert aside.children[0].tag == "svg"
assert "inline-block" in aside.children[0].attrs['class']
assert aside.children[1].tag == "p"
assert "font-bold" in aside.children[1].attrs['class']
assert aside.children[2].tag == "p"
# Verify nav section with social icons
nav = centered_logo_footer.children[1]
assert nav.tag == "nav"
social_grid = nav.children[0]
assert social_grid.tag == "div"
assert "grid" in social_grid.attrs['class']
assert "grid-flow-col" in social_grid.attrs['class']
assert "gap-4" in social_grid.attrs['class']
assert len(social_grid.children) == 3
return centered_logo_footer
# Run the tests
test_footer_centered_with_logo_fasthtml_examples()<footer class="footer footer-horizontal footer-center bg-primary text-primary-content p-10">
<aside>
<svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" height="50" width="50" fill-rule="evenodd" clip-rule="evenodd" class="inline-block fill-current"><path d="M22.672 15.226l-2.432.811.841 2.515c.33 1.019-.209 2.127-1.23 2.456-1.15.325-2.148-.321-2.463-1.226l-.84-2.518-5.013 1.677.84 2.517c.391 1.203-.434 2.542-1.831 2.542-.88 0-1.601-.564-1.86-1.314l-.842-2.516-2.431.809c-1.135.328-2.145-.317-2.463-1.229-.329-1.018.211-2.127 1.231-2.456l2.432-.809-1.621-4.823-2.432.808c-1.355.384-2.558-.59-2.558-1.839 0-.817.509-1.582 1.327-1.846l2.433-.809-.842-2.515c-.33-1.02.211-2.129 1.232-2.458 1.02-.329 2.13.209 2.461 1.229l.842 2.515 5.011-1.677-.839-2.517c-.403-1.238.484-2.553 1.843-2.553.819 0 1.585.509 1.85 1.326l.841 2.517 2.431-.81c1.02-.33 2.131.211 2.461 1.229.332 1.018-.21 2.126-1.23 2.456l-2.433.809 1.622 4.823 2.433-.809c1.242-.401 2.557.484 2.557 1.838 0 .819-.51 1.583-1.328 1.847m-8.992-6.428l-5.01 1.675 1.619 4.828 5.011-1.674-1.62-4.829z"></path></svg> <p class="font-bold">
ACME Industries Ltd.<br>Providing reliable tech since 1992 </p>
<p>Copyright © 2025 - All right reserved</p>
</aside>
<nav>
<div class="grid grid-flow-col gap-4">
<a href="#"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" height="24" width="24" class="fill-current"><path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"></path></svg></a><a href="#"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" height="24" width="24" class="fill-current"><path d="M19.615 3.184c-3.604-.246-11.631-.245-15.23 0-3.897.266-4.356 2.62-4.385 8.816.029 6.185.484 8.549 4.385 8.816 3.6.245 11.626.246 15.23 0 3.897-.266 4.356-2.62 4.385-8.816-.029-6.185-.484-8.549-4.385-8.816zm-10.615 12.816v-8l8 3.993-8 4.007z"></path></svg></a><a href="#"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" height="24" width="24" class="fill-current"><path d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z"></path></svg></a> </div>
</nav>
</footer>test_footer_with_two_rows_fasthtml_examples ()
Test footer with 2 rows from daisyUI v5 documentation.
def test_footer_with_two_rows_fasthtml_examples():
"""Test footer with 2 rows from daisyUI v5 documentation."""
from fasthtml.common import Footer, Nav, H6, A
from cjm_fasthtml_tailwind.utilities.spacing import p
from cjm_fasthtml_tailwind.utilities.flexbox_and_grid import grid_rows
from cjm_fasthtml_daisyui.utilities.semantic_colors import bg_dui, text_dui
from cjm_fasthtml_daisyui.components.navigation.link import link, link_styles
# Footer with 2 rows
two_row_footer = Footer(
Nav(
H6("Services", cls=str(footer_title)),
A("Branding", href="#", cls=combine_classes(link, link_styles.hover)),
A("Design", href="#", cls=combine_classes(link, link_styles.hover)),
A("Marketing", href="#", cls=combine_classes(link, link_styles.hover)),
A("Advertisement", href="#", cls=combine_classes(link, link_styles.hover))
),
Nav(
H6("Company", cls=str(footer_title)),
A("About us", href="#", cls=combine_classes(link, link_styles.hover)),
A("Contact", href="#", cls=combine_classes(link, link_styles.hover)),
A("Jobs", href="#", cls=combine_classes(link, link_styles.hover)),
A("Press kit", href="#", cls=combine_classes(link, link_styles.hover))
),
Nav(
H6("Legal", cls=str(footer_title)),
A("Terms of use", href="#", cls=combine_classes(link, link_styles.hover)),
A("Privacy policy", href="#", cls=combine_classes(link, link_styles.hover)),
A("Cookie policy", href="#", cls=combine_classes(link, link_styles.hover))
),
Nav(
H6("Social", cls=str(footer_title)),
A("Twitter", href="#", cls=combine_classes(link, link_styles.hover)),
A("Instagram", href="#", cls=combine_classes(link, link_styles.hover)),
A("Facebook", href="#", cls=combine_classes(link, link_styles.hover)),
A("GitHub", href="#", cls=combine_classes(link, link_styles.hover))
),
Nav(
H6("Explore", cls=str(footer_title)),
A("Features", href="#", cls=combine_classes(link, link_styles.hover)),
A("Enterprise", href="#", cls=combine_classes(link, link_styles.hover)),
A("Security", href="#", cls=combine_classes(link, link_styles.hover)),
A("Pricing", href="#", cls=combine_classes(link, link_styles.hover))
),
Nav(
H6("Apps", cls=str(footer_title)),
A("Mac", href="#", cls=combine_classes(link, link_styles.hover)),
A("Windows", href="#", cls=combine_classes(link, link_styles.hover)),
A("iPhone", href="#", cls=combine_classes(link, link_styles.hover)),
A("Android", href="#", cls=combine_classes(link, link_styles.hover))
),
cls=combine_classes(footer, footer_directions.horizontal.sm, bg_dui.neutral, text_dui.neutral_content, grid_rows._2, p._10)
)
# Verify structure
assert two_row_footer.tag == "footer"
assert "footer" in two_row_footer.attrs['class']
assert "sm:footer-horizontal" in two_row_footer.attrs['class']
assert "bg-neutral" in two_row_footer.attrs['class']
assert "text-neutral-content" in two_row_footer.attrs['class']
assert "grid-rows-2" in two_row_footer.attrs['class']
assert "p-10" in two_row_footer.attrs['class']
# Verify 6 nav sections
assert len(two_row_footer.children) == 6
for nav in two_row_footer.children:
assert nav.tag == "nav"
assert nav.children[0].tag == "h6"
assert "footer-title" in nav.children[0].attrs['class']
# Check links
for i in range(1, len(nav.children)):
assert nav.children[i].tag == "a"
assert "link" in nav.children[i].attrs['class']
assert "link-hover" in nav.children[i].attrs['class']
return two_row_footer
# Run the tests
test_footer_with_two_rows_fasthtml_examples()<footer class="footer sm:footer-horizontal bg-neutral text-neutral-content grid-rows-2 p-10">
<nav>
<h6 class="footer-title">Services</h6>
<a href="#" class="link link-hover">Branding</a><a href="#" class="link link-hover">Design</a><a href="#" class="link link-hover">Marketing</a><a href="#" class="link link-hover">Advertisement</a> </nav>
<nav>
<h6 class="footer-title">Company</h6>
<a href="#" class="link link-hover">About us</a><a href="#" class="link link-hover">Contact</a><a href="#" class="link link-hover">Jobs</a><a href="#" class="link link-hover">Press kit</a> </nav>
<nav>
<h6 class="footer-title">Legal</h6>
<a href="#" class="link link-hover">Terms of use</a><a href="#" class="link link-hover">Privacy policy</a><a href="#" class="link link-hover">Cookie policy</a> </nav>
<nav>
<h6 class="footer-title">Social</h6>
<a href="#" class="link link-hover">Twitter</a><a href="#" class="link link-hover">Instagram</a><a href="#" class="link link-hover">Facebook</a><a href="#" class="link link-hover">GitHub</a> </nav>
<nav>
<h6 class="footer-title">Explore</h6>
<a href="#" class="link link-hover">Features</a><a href="#" class="link link-hover">Enterprise</a><a href="#" class="link link-hover">Security</a><a href="#" class="link link-hover">Pricing</a> </nav>
<nav>
<h6 class="footer-title">Apps</h6>
<a href="#" class="link link-hover">Mac</a><a href="#" class="link link-hover">Windows</a><a href="#" class="link link-hover">iPhone</a><a href="#" class="link link-hover">Android</a> </nav>
</footer>test_footer_centered_with_social_fasthtml_examples ()
Test centered footer with social icons from daisyUI v5 documentation.
def test_footer_centered_with_social_fasthtml_examples():
"""Test centered footer with social icons from daisyUI v5 documentation."""
from fasthtml.common import Footer, Nav, Aside, A, P, Div
from fasthtml.svg import Svg, Path
from datetime import datetime
from cjm_fasthtml_tailwind.utilities.spacing import p
from cjm_fasthtml_tailwind.utilities.svg import fill
from cjm_fasthtml_tailwind.utilities.layout import display_tw
from cjm_fasthtml_tailwind.utilities.flexbox_and_grid import grid_flow, gap, grid_display
from cjm_fasthtml_tailwind.utilities.borders import rounded
from cjm_fasthtml_daisyui.utilities.semantic_colors import bg_dui, text_dui
from cjm_fasthtml_daisyui.components.navigation.link import link, link_styles
# Create social media icons
twitter_icon = Svg(
Path(
d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"
),
xmlns="http://www.w3.org/2000/svg",
width="24",
height="24",
viewBox="0 0 24 24",
cls=str(fill.current)
)
youtube_icon = Svg(
Path(
d="M19.615 3.184c-3.604-.246-11.631-.245-15.23 0-3.897.266-4.356 2.62-4.385 8.816.029 6.185.484 8.549 4.385 8.816 3.6.245 11.626.246 15.23 0 3.897-.266 4.356-2.62 4.385-8.816-.029-6.185-.484-8.549-4.385-8.816zm-10.615 12.816v-8l8 3.993-8 4.007z"
),
xmlns="http://www.w3.org/2000/svg",
width="24",
height="24",
viewBox="0 0 24 24",
cls=str(fill.current)
)
facebook_icon = Svg(
Path(
d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z"
),
xmlns="http://www.w3.org/2000/svg",
width="24",
height="24",
viewBox="0 0 24 24",
cls=str(fill.current)
)
# Centered footer with social icons
centered_social_footer = Footer(
Nav(
A("About us", href="#", cls=combine_classes(link, link_styles.hover)),
A("Contact", href="#", cls=combine_classes(link, link_styles.hover)),
A("Jobs", href="#", cls=combine_classes(link, link_styles.hover)),
A("Press kit", href="#", cls=combine_classes(link, link_styles.hover)),
cls=combine_classes(grid_display, grid_flow.col, gap._4)
),
Nav(
Div(
A(twitter_icon, href="#"),
A(youtube_icon, href="#"),
A(facebook_icon, href="#"),
cls=combine_classes(grid_display, grid_flow.col, gap._4)
)
),
Aside(
P(f"Copyright © {datetime.now().year} - All right reserved by ACME Industries Ltd")
),
cls=combine_classes(footer, footer_directions.horizontal, footer_placement.center, bg_dui.base_200, text_dui.base_content, rounded(), p._10)
)
# Verify structure
assert centered_social_footer.tag == "footer"
assert "footer" in centered_social_footer.attrs['class']
assert "footer-horizontal" in centered_social_footer.attrs['class']
assert "footer-center" in centered_social_footer.attrs['class']
assert "bg-base-200" in centered_social_footer.attrs['class']
assert "text-base-content" in centered_social_footer.attrs['class']
assert "rounded" in centered_social_footer.attrs['class']
assert "p-10" in centered_social_footer.attrs['class']
# Verify first nav section with links
first_nav = centered_social_footer.children[0]
assert first_nav.tag == "nav"
assert "grid" in first_nav.attrs['class']
assert "grid-flow-col" in first_nav.attrs['class']
assert "gap-4" in first_nav.attrs['class']
assert len(first_nav.children) == 4
for child in first_nav.children:
assert child.tag == "a"
assert "link" in child.attrs['class']
assert "link-hover" in child.attrs['class']
# Verify second nav section with social icons
second_nav = centered_social_footer.children[1]
assert second_nav.tag == "nav"
social_grid = second_nav.children[0]
assert social_grid.tag == "div"
assert "grid" in social_grid.attrs['class']
assert "grid-flow-col" in social_grid.attrs['class']
assert "gap-4" in social_grid.attrs['class']
assert len(social_grid.children) == 3
for child in social_grid.children:
assert child.tag == "a"
assert child.children[0].tag == "svg"
# Verify aside with copyright
aside = centered_social_footer.children[2]
assert aside.tag == "aside"
assert aside.children[0].tag == "p"
assert f"Copyright © {datetime.now().year}" in aside.children[0].children[0]
return centered_social_footer
# Run the tests
test_footer_centered_with_social_fasthtml_examples()<footer class="footer footer-horizontal footer-center bg-base-200 text-base-content rounded p-10">
<nav class="grid grid-flow-col gap-4">
<a href="#" class="link link-hover">About us</a><a href="#" class="link link-hover">Contact</a><a href="#" class="link link-hover">Jobs</a><a href="#" class="link link-hover">Press kit</a> </nav>
<nav>
<div class="grid grid-flow-col gap-4">
<a href="#"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" height="24" width="24" class="fill-current"><path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"></path></svg></a><a href="#"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" height="24" width="24" class="fill-current"><path d="M19.615 3.184c-3.604-.246-11.631-.245-15.23 0-3.897.266-4.356 2.62-4.385 8.816.029 6.185.484 8.549 4.385 8.816 3.6.245 11.626.246 15.23 0 3.897-.266 4.356-2.62 4.385-8.816-.029-6.185-.484-8.549-4.385-8.816zm-10.615 12.816v-8l8 3.993-8 4.007z"></path></svg></a><a href="#"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" height="24" width="24" class="fill-current"><path d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z"></path></svg></a> </div>
</nav>
<aside>
<p>Copyright © 2025 - All right reserved by ACME Industries Ltd</p>
</aside>
</footer>test_footer_two_stacked_fasthtml_examples ()
Test two stacked footers from daisyUI v5 documentation.
def test_footer_two_stacked_fasthtml_examples():
"""Test two stacked footers from daisyUI v5 documentation."""
from fasthtml.common import Footer, Nav, Aside, H6, A, P, Br, Div
from fasthtml.svg import Svg, Path
from cjm_fasthtml_tailwind.utilities.spacing import p
from cjm_fasthtml_tailwind.utilities.svg import fill
from cjm_fasthtml_tailwind.utilities.layout import display_tw
from cjm_fasthtml_tailwind.utilities.flexbox_and_grid import grid_flow, gap, items, place_self, justify_self, grid_display
from cjm_fasthtml_tailwind.utilities.borders import border
from cjm_fasthtml_daisyui.utilities.semantic_colors import bg_dui, text_dui, border_dui
from cjm_fasthtml_daisyui.components.navigation.link import link, link_styles
# Create reusable logo SVG
logo_svg = Svg(
Path(
d="M22.672 15.226l-2.432.811.841 2.515c.33 1.019-.209 2.127-1.23 2.456-1.15.325-2.148-.321-2.463-1.226l-.84-2.518-5.013 1.677.84 2.517c.391 1.203-.434 2.542-1.831 2.542-.88 0-1.601-.564-1.86-1.314l-.842-2.516-2.431.809c-1.135.328-2.145-.317-2.463-1.229-.329-1.018.211-2.127 1.231-2.456l2.432-.809-1.621-4.823-2.432.808c-1.355.384-2.558-.59-2.558-1.839 0-.817.509-1.582 1.327-1.846l2.433-.809-.842-2.515c-.33-1.02.211-2.129 1.232-2.458 1.02-.329 2.13.209 2.461 1.229l.842 2.515 5.011-1.677-.839-2.517c-.403-1.238.484-2.553 1.843-2.553.819 0 1.585.509 1.85 1.326l.841 2.517 2.431-.81c1.02-.33 2.131.211 2.461 1.229.332 1.018-.21 2.126-1.23 2.456l-2.433.809 1.622 4.823 2.433-.809c1.242-.401 2.557.484 2.557 1.838 0 .819-.51 1.583-1.328 1.847m-8.992-6.428l-5.01 1.675 1.619 4.828 5.011-1.674-1.62-4.829z"
),
width="24",
height="24",
viewBox="0 0 24 24",
xmlns="http://www.w3.org/2000/svg",
fill_rule="evenodd",
clip_rule="evenodd",
cls=str(fill.current)
)
# Create social media icons
twitter_icon = Svg(
Path(
d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"
),
xmlns="http://www.w3.org/2000/svg",
width="24",
height="24",
viewBox="0 0 24 24",
cls=str(fill.current)
)
youtube_icon = Svg(
Path(
d="M19.615 3.184c-3.604-.246-11.631-.245-15.23 0-3.897.266-4.356 2.62-4.385 8.816.029 6.185.484 8.549 4.385 8.816 3.6.245 11.626.246 15.23 0 3.897-.266 4.356-2.62 4.385-8.816-.029-6.185-.484-8.549-4.385-8.816zm-10.615 12.816v-8l8 3.993-8 4.007z"
),
xmlns="http://www.w3.org/2000/svg",
width="24",
height="24",
viewBox="0 0 24 24",
cls=str(fill.current)
)
facebook_icon = Svg(
Path(
d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z"
),
xmlns="http://www.w3.org/2000/svg",
width="24",
height="24",
viewBox="0 0 24 24",
cls=str(fill.current)
)
# Two footer - create a container Div to hold both footers
two_footer_container = Div(
# First footer
Footer(
Nav(
H6("Services", cls=str(footer_title)),
A("Branding", href="#", cls=combine_classes(link, link_styles.hover)),
A("Design", href="#", cls=combine_classes(link, link_styles.hover)),
A("Marketing", href="#", cls=combine_classes(link, link_styles.hover)),
A("Advertisement", href="#", cls=combine_classes(link, link_styles.hover))
),
Nav(
H6("Company", cls=str(footer_title)),
A("About us", href="#", cls=combine_classes(link, link_styles.hover)),
A("Contact", href="#", cls=combine_classes(link, link_styles.hover)),
A("Jobs", href="#", cls=combine_classes(link, link_styles.hover)),
A("Press kit", href="#", cls=combine_classes(link, link_styles.hover))
),
Nav(
H6("Legal", cls=str(footer_title)),
A("Terms of use", href="#", cls=combine_classes(link, link_styles.hover)),
A("Privacy policy", href="#", cls=combine_classes(link, link_styles.hover)),
A("Cookie policy", href="#", cls=combine_classes(link, link_styles.hover))
),
cls=combine_classes(footer, footer_directions.horizontal.sm, bg_dui.base_200, text_dui.base_content, p._10)
),
# Second footer
Footer(
Aside(
logo_svg,
P(
"ACME Industries Ltd.",
Br(),
"Providing reliable tech since 1992"
),
cls=combine_classes(grid_flow.col, items.center)
),
Nav(
Div(
A(twitter_icon, href="#"),
A(youtube_icon, href="#"),
A(facebook_icon, href="#"),
cls=combine_classes(grid_display, grid_flow.col, gap._4)
),
cls=combine_classes(place_self.center.md, justify_self.end.md)
),
cls=combine_classes(footer, bg_dui.base_200, text_dui.base_content, border_dui.base_300, border.t(), p.x._10, p.y._4)
)
)
# Verify structure
assert two_footer_container.tag == "div"
assert len(two_footer_container.children) == 2
# Verify first footer
first_footer = two_footer_container.children[0]
assert first_footer.tag == "footer"
assert "footer" in first_footer.attrs['class']
assert "sm:footer-horizontal" in first_footer.attrs['class']
assert "bg-base-200" in first_footer.attrs['class']
assert "text-base-content" in first_footer.attrs['class']
assert "p-10" in first_footer.attrs['class']
assert len(first_footer.children) == 3 # 3 nav sections
# Verify second footer
second_footer = two_footer_container.children[1]
assert second_footer.tag == "footer"
assert "footer" in second_footer.attrs['class']
assert "bg-base-200" in second_footer.attrs['class']
assert "text-base-content" in second_footer.attrs['class']
assert "border-base-300" in second_footer.attrs['class']
assert "border-t" in second_footer.attrs['class']
assert "px-10" in second_footer.attrs['class']
assert "py-4" in second_footer.attrs['class']
# Verify aside in second footer
aside = second_footer.children[0]
assert aside.tag == "aside"
assert "grid-flow-col" in aside.attrs['class']
assert "items-center" in aside.attrs['class']
assert aside.children[0].tag == "svg"
assert aside.children[1].tag == "p"
# Verify nav in second footer
nav = second_footer.children[1]
assert nav.tag == "nav"
assert "md:place-self-center" in nav.attrs['class']
assert "md:justify-self-end" in nav.attrs['class']
social_grid = nav.children[0]
assert social_grid.tag == "div"
assert "grid" in social_grid.attrs['class']
assert "grid-flow-col" in social_grid.attrs['class']
assert "gap-4" in social_grid.attrs['class']
return two_footer_container
# Run the tests
test_footer_two_stacked_fasthtml_examples()<div>
<footer class="footer sm:footer-horizontal bg-base-200 text-base-content p-10">
<nav>
<h6 class="footer-title">Services</h6>
<a href="#" class="link link-hover">Branding</a><a href="#" class="link link-hover">Design</a><a href="#" class="link link-hover">Marketing</a><a href="#" class="link link-hover">Advertisement</a> </nav>
<nav>
<h6 class="footer-title">Company</h6>
<a href="#" class="link link-hover">About us</a><a href="#" class="link link-hover">Contact</a><a href="#" class="link link-hover">Jobs</a><a href="#" class="link link-hover">Press kit</a> </nav>
<nav>
<h6 class="footer-title">Legal</h6>
<a href="#" class="link link-hover">Terms of use</a><a href="#" class="link link-hover">Privacy policy</a><a href="#" class="link link-hover">Cookie policy</a> </nav>
</footer>
<footer class="footer bg-base-200 text-base-content border-base-300 border-t px-10 py-4">
<aside class="grid-flow-col items-center">
<svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" height="24" width="24" fill-rule="evenodd" clip-rule="evenodd" class="fill-current"><path d="M22.672 15.226l-2.432.811.841 2.515c.33 1.019-.209 2.127-1.23 2.456-1.15.325-2.148-.321-2.463-1.226l-.84-2.518-5.013 1.677.84 2.517c.391 1.203-.434 2.542-1.831 2.542-.88 0-1.601-.564-1.86-1.314l-.842-2.516-2.431.809c-1.135.328-2.145-.317-2.463-1.229-.329-1.018.211-2.127 1.231-2.456l2.432-.809-1.621-4.823-2.432.808c-1.355.384-2.558-.59-2.558-1.839 0-.817.509-1.582 1.327-1.846l2.433-.809-.842-2.515c-.33-1.02.211-2.129 1.232-2.458 1.02-.329 2.13.209 2.461 1.229l.842 2.515 5.011-1.677-.839-2.517c-.403-1.238.484-2.553 1.843-2.553.819 0 1.585.509 1.85 1.326l.841 2.517 2.431-.81c1.02-.33 2.131.211 2.461 1.229.332 1.018-.21 2.126-1.23 2.456l-2.433.809 1.622 4.823 2.433-.809c1.242-.401 2.557.484 2.557 1.838 0 .819-.51 1.583-1.328 1.847m-8.992-6.428l-5.01 1.675 1.619 4.828 5.011-1.674-1.62-4.829z"></path></svg> <p>
ACME Industries Ltd.<br>Providing reliable tech since 1992 </p>
</aside>
<nav class="md:place-self-center md:justify-self-end">
<div class="grid grid-flow-col gap-4">
<a href="#"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" height="24" width="24" class="fill-current"><path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"></path></svg></a><a href="#"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" height="24" width="24" class="fill-current"><path d="M19.615 3.184c-3.604-.246-11.631-.245-15.23 0-3.897.266-4.356 2.62-4.385 8.816.029 6.185.484 8.549 4.385 8.816 3.6.245 11.626.246 15.23 0 3.897-.266 4.356-2.62 4.385-8.816-.029-6.185-.484-8.549-4.385-8.816zm-10.615 12.816v-8l8 3.993-8 4.007z"></path></svg></a><a href="#"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" height="24" width="24" class="fill-current"><path d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z"></path></svg></a> </div>
</nav>
</footer>
</div>