Source code for duck.html.components.duck

"""
Module containing Duck specific components.
"""
from duck.shortcuts import static

from duck.html.components import to_component
from duck.html.components.theme import Theme
from duck.html.components.container import FlexContainer
from duck.html.components.image import Image
from duck.html.components.label import Label
from duck.html.components.link import Link
from duck.html.components.style import Style


# Default badge content, overridable via kwargs
DEFAULT_URL = "https://duckframework.com"
DEFAULT_TEXT = "Made with Duck"
DEFAULT_LOGO_SRC = "images/duck-logo.png"


[docs] class MadeWithDuck(Link, FlexContainer): """ A small clickable badge reading "Made with Duck". Renders as a pill-shaped chip with the Duck logo, label text, and a trailing arrow. On hover the badge lifts, its border picks up an accent color, the logo gives a small wiggle, and the arrow slides — inviting a click rather than sitting there as a static credit line. Args: url (str, optional): Link target. Defaults to duckframework.com. text (str, optional): Label text. Defaults to "Made with Duck". logo_src (str, optional): Static path to the logo image. accent_color (str, optional): Hover border/glow color. Defaults to `Theme.current.accent_color`. id (str, optional): Element id, used to scope the hover styling. """
[docs] def on_create(self) -> None: # Resolve link target and text color before Link builds itself self.url = self.kwargs.get("url", DEFAULT_URL) self.color = self.kwargs.get("color", Theme.current.muted_text_color) # Super create super().on_create() # Base pill badge layout self.id = self.kwargs.get("id", "made-with-duck") self.klass = "made-with-duck" # Update style self.style.update({ "display": "inline-flex", "gap": "8px", "align-items": "center", "justify-content": "center", "padding": "6px 14px 6px 8px", "border-radius": "999px", "background": Theme.current.surface_elevated_color, "border": f"1px solid {Theme.current.border_color}", "font-size": "0.8rem", "font-weight": "500", "text-decoration": "none", "transition": ( "transform 0.25s ease, border-color 0.25s ease, " "background 0.25s ease, box-shadow 0.25s ease" ), }) # Badge content and scoped hover behaviour self.add_children(self.build_children()) self.add_child(self.build_style())
[docs] def build_children(self) -> list: """ Builds the badge's logo, label, and trailing arrow. Returns: List of components making up the badge content. """ return [ self.build_logo(), self.build_label(), self.build_arrow(), ]
[docs] def build_label(self) -> Label: """ Builds the badge's label text. Returns: A configured Label component. """ return Label( text=self.kwargs.get("text") or DEFAULT_TEXT, style={"margin": "0px", "white-space": "nowrap"}, )
[docs] def build_arrow(self): """ Builds the trailing arrow that slides on hover. Returns: A Component rendering the arrow glyph. """ return to_component( "↗", tag="span", klass="made-with-duck-arrow", style={ "display": "inline-block", "transition": "transform 0.25s ease", }, )
[docs] def build_style(self) -> Style: """ Builds the badge's hover styling, scoped to this instance's id. Returns: A Style component containing the badge's css rules. """ # Explicit kwarg wins, otherwise fall back to the active theme's accent accent = self.kwargs.get("accent_color", Theme.current.accent_color) return Style( inner_html=f""" #{self.id} {{ box-shadow: 0 0 0 rgba(0, 0, 0, 0); }} #{self.id}:hover {{ background: {Theme.current.surface_elevated_color}; border-color: {accent}; transform: translateY(-2px); box-shadow: 0 6px 18px color-mix(in srgb, {accent} 35%, transparent); }} #{self.id}:hover .made-with-duck-logo {{ transform: rotate(-10deg) scale(1.12); }} #{self.id}:hover .made-with-duck-arrow {{ transform: translateX(4px); }} """ )