Skip to content
fandhe-frontendcore v0.4.3
GitHub

footer-sticky-reveal

card / heading / link / nav_list を合成した、Motion+ sections/footers の sticky reveal 相当の合成例です。

Demo 枠を固定高スクロールコンテナにし、position: sticky のみで footer が本文の下から現れます(JS 不使用)。prefers-reduced-motion: reduce ではフェードイン強調を無効化します。リンク先は GitHub への外部 URL です。<form> は使用しません。

Demo

使用部品

Rust コード

Rust
use fandhe_frontend_core::{div, footer, p, text, Node};
use fandhe_frontend_pre_styled_ui::card::{self, CardProps};
use fandhe_frontend_pre_styled_ui::heading::{
    heading, HeadingLevel, HeadingProps, HeadingSize, HeadingWeight,
};
use fandhe_frontend_pre_styled_ui::link::{self, LinkProps};
use fandhe_frontend_pre_styled_ui::nav_list;

/// ダミー段落(架空)。
const PARAGRAPHS: &[&str] = &["スクロールすると footer が下から現れます。"];

/// ダミーカードの (見出し, 説明) 一覧(架空、sticky reveal を見せる高さ用)。
const CARDS: &[(&str, &str)] = &[
    ("Realtime Sync", "同期します。"),
    ("Access Control", "保護します。"),
    ("Usage Insights", "可視化します。"),
];

/// ダミーカード 1 件(架空)。
fn content_card(title: &str, description: &str) -> Node {
    card::root(
        CardProps::default(),
        vec![],
        vec![
            card::header(vec![], vec![card::title(vec![], vec![text(title)])]),
            card::body(
                vec![],
                vec![card::description(vec![], vec![text(description)])],
            ),
        ],
    )
}

/// 本文ダミー(段落 + カード群)。
fn dummy_content() -> Node {
    let mut children: Vec<Node> = PARAGRAPHS
        .iter()
        .map(|t| p(vec![], vec![text(*t)]))
        .collect();
    children.extend(CARDS.iter().map(|(t, d)| content_card(t, d)));

    div(
        vec![("data-blocks-footer-sticky-reveal-content", "")],
        children,
    )
}

/// footer リンク列(見出し + リンク群)。`heading_text` は `nav_list::heading`
/// (固定 `h2`)ではなく `p` で表現する(モジュール doc「`nav_list::heading`
/// を使わない理由」節参照)。
fn footer_nav_group(heading_text: &str, links: &[(&str, &str)]) -> Node {
    let items: Vec<Node> = links
        .iter()
        .map(|(href, label)| {
            nav_list::item(
                vec![],
                vec![nav_list::link(href, false, vec![], vec![text(*label)])],
            )
        })
        .collect();
    div(
        vec![("class", "blocks-footer-sticky-reveal-group")],
        vec![
            p(
                vec![("class", "blocks-footer-sticky-reveal-group-title")],
                vec![text(heading_text)],
            ),
            nav_list::list(vec![], items),
        ],
    )
}

/// footer 本体(ブランド見出し + リンク群 2 種)。
fn footer_element() -> Node {
    let brand = heading(
        HeadingLevel::H3,
        &HeadingProps {
            size: HeadingSize::Lg,
            weight: HeadingWeight::Bold,
        },
        vec![("data-blocks-footer-sticky-reveal-brand", "")],
        vec![text("Fandhe Frontend")],
    );

    const REPO: &str = "https://github.com/Fandhe-AI/fandhe-frontend";
    let nav = nav_list::root(
        "Footer",
        vec![("data-blocks-footer-sticky-reveal-nav", "")],
        vec![
            footer_nav_group("Product", &[(REPO, "Guide"), (REPO, "API Reference")]),
            footer_nav_group("Community", &[(REPO, "Spec"), (REPO, "GitHub")]),
        ],
    );

    let bottom_link = link::root(
        REPO,
        &LinkProps::default(),
        vec![],
        vec![text("© Fandhe Frontend")],
    );

    footer(
        vec![("data-blocks-footer-sticky-reveal-footer", "")],
        vec![div(
            vec![("data-blocks-footer-sticky-reveal-footer-inner", "")],
            vec![brand, nav, bottom_link],
        )],
    )
}

/// `footer-sticky-reveal` の Demo 本体(モジュール doc「sticky reveal の
/// 実体」節参照)。
pub fn demo() -> Node {
    div(vec![], vec![dummy_content(), footer_element()])
}