{# macros/interactive.html - Interactive UI component macros for APEP. Import with: {% from "apep/macros/interactive.html" import btn, hero_btn, download_btn, theme_switch %} Macros: btn(label, variant, size, url, disabled) hero_btn(label, url, subtitle, variant) download_btn(label, file_path, variant) theme_switch(variant) Author: sora7672 #} {% from "apep/macros/helper.html" import alert %} {# Renders a button or, when url is provided and the button is not disabled, an anchor tag styled as a button. Disabled anchors always render as {% endif %} {% endif %} {% endmacro %} {# Renders a large call-to-action button with an optional subtitle line below it. Always renders as an anchor tag. Use the standard btn macro for non-hero actions. @param label {string} - main button text @param url {string} - link target, default "#" @param subtitle {string} - small muted text rendered below the button. Optional. @param variant {string} - "primary" | "secondary", default "primary" #} {% macro hero_btn(label, url="#", subtitle=None, variant="primary") %} {% if not label %} {{ alert("hero_btn: label is required", "Pass a non-empty string as the first argument.") }} {% elif variant not in ["primary", "secondary"] %} {{ alert("hero_btn: invalid variant \"" ~ variant ~ "\"", "Allowed values: \"primary\", \"secondary\".") }} {% else %}
{{ label }} {% if subtitle %} {{ subtitle }} {% endif %}
{% endif %} {% endmacro %} {# Renders a download button in one of three visual variants. The file_path is passed as a data attribute and handled by download-btn.js, which resolves the path under /downloads/ and triggers the browser download. External URLs in the "minimal" variant trigger a confirm dialog before download. @param label {string} - displayed button text @param file_path {string} - path to the file, resolved under /downloads/ by download-btn.js @param variant {string} - "default" | "icon" | "minimal", default "default" default - full button with filetype icon icon - compact icon + label, no wrapper minimal - compact button, download triggered entirely via JS #} {% macro download_btn(label, file_path, variant="default") %} {% if not label %} {{ alert("download_btn: label is required", "Pass a non-empty string as the first argument.") }} {% elif not file_path %} {{ alert("download_btn: file_path is required", "Pass a valid file path as the second argument.") }} {% elif variant not in ["default", "icon", "minimal"] %} {{ alert("download_btn: invalid variant \"" ~ variant ~ "\"", "Allowed values: \"default\", \"icon\", \"minimal\".") }} {% else %} {% if variant == "minimal" %} {% elif variant == "icon" %} {% else %}
{% endif %} {% endif %} {% endmacro %} {# Renders a light/dark theme toggle in one of three variants. The active theme is persisted and restored by theme-switch.js. theme-switch.js is loaded globally by the backend to prevent flash-of-wrong-theme on page load. All variants are detected via querySelectorAll("[data-theme-btn]") or "[data-theme-checkbox]" - placing multiple variants on one page is supported. @param variant {string} - "icon" | "slider" | "floating", default "icon" icon - plain button, place anywhere in layout slider - toggle slider with animated thumb floating - fixed-position button, bottom-right by default @param position {string} - only used for variant "floating" "top-left" | "top-right" | "bottom-left" | "bottom-right" default "bottom-right" #} {% macro theme_switch(variant="floating", position="top-right") %} {% if variant not in ["icon", "slider", "toggle", "floating"] %} {{ alert("theme_switch: invalid variant \"" ~ variant ~ "\"", "Allowed values: \"icon\", \"slider\", \"toggle\", \"floating\".") }} {% elif variant == "floating" and position not in ["top-left", "top-right", "bottom-left", "bottom-right"] %} {{ alert("theme_switch: invalid position \"" ~ position ~ "\"", "Allowed values: \"top-left\", \"top-right\", \"bottom-left\", \"bottom-right\".") }} {% else %} {% if variant == "floating" %}
{% elif variant == "slider" or variant == "toggle" %} {% else %} {% endif %} {% endif %} {% endmacro %}