Skip to content
fandhe-frontendcore v0.4.3
GitHub

contact-info-columns

fandhe-frontend-pre-styled-ui の heading / text / icon / link の 4 部品のみを合成した、連絡先カラム一覧(お問い合わせ窓口・拠点一覧)の合成例です。Blocks セクションは新規部品を追加するものではなく、既存の Themes/Primitives 部品を組み合わせた実例集であることに注意してください(主参照は対応表 ID R0857、集約元は対応表 ID R0856 の 2 件です。出典の固有名・ファイル名は記載しません)。

上部に見出しと説明文を置き、その下へ「お問い合わせ窓口」(角丸アイコンタイル + 見出し + 説明 + 矢印付きリンクの 3 列)と「拠点一覧」(左罫線 + 拠点名 + 住所 2 行 + 矢印付きリンクの 4 列)の 2 段を並べています。狭い画面幅では 1 列、sm(640px)以上で 2 列、lg(1024px)以上で全列表示(窓口は 3 列・拠点は 4 列)に切り替わります。

文言・窓口名・拠点住所はすべて独自に書いた架空のものです。リンク先は本リポジトリの固定 URL とし、同じ可視テキストが複数並ぶため aria-label に「(可視テキスト)(窓口名/拠点名)」の形式を付けて区別しています。<form> 要素は出力せず、送信処理・入力値検証は一切持ちません(docs/policy/intentional-non-adoption.md §3.25 の責務境界: UI コンポーネント層はアプリケーションロジックを内包しません)。連絡先情報は mailto:/tel: によるリンク化を行わず、プレーンテキストで表示するに留めています。

Demo

お問い合わせ

用件に合わせた窓口をお選びください

各種お問い合わせは以下の窓口から、拠点へのご訪問は下記の一覧からご確認ください。

お問い合わせ窓口

導入のご相談

導入検討中のお客様からのご相談を承ります。

お問い合わせはこちら

技術サポート

導入後の技術的なお問い合わせに対応します。

サポート窓口へ

取材・提携のご相談

取材・協業に関するご相談を受け付けています。

お問い合わせはこちら

拠点一覧

東京オフィス

〒000-0001 東京都千代田区架空 1-2-3

本社機能・営業窓口

地図を見る

大阪オフィス

〒000-0002 大阪府大阪市架空 4-5-6

西日本エリア担当

地図を見る

福岡オフィス

〒000-0003 福岡県福岡市架空 7-8-9

九州エリア担当

地図を見る

札幌オフィス

〒000-0004 北海道札幌市架空 10-11

北日本エリア担当

地図を見る

使用部品

Rust コード

Rust
const REPO: &str = "https://github.com/Fandhe-AI/fandhe-frontend";

use fandhe_frontend_core::{div, el, text, Node};
use fandhe_frontend_pre_styled_ui::heading::{
    heading, HeadingLevel, HeadingProps, HeadingSize, HeadingWeight,
};
use fandhe_frontend_pre_styled_ui::icon::{icon, IconProps};
use fandhe_frontend_pre_styled_ui::link::{self, LinkProps, LinkVariant};
use fandhe_frontend_pre_styled_ui::recipe::ColorPalette;
use fandhe_frontend_pre_styled_ui::text::{
    self as styled_text, TextProps, TextSize, TextVariant, TextWeight,
};
use fandhe_frontend_pre_styled_ui::Size;

/// 装飾用の自作幾何アイコン(lucide 等の既存アイコンセットの path を
/// 複製しないための単純図形、`careers_card_grid::geo_icon` と同型)。
fn geo_icon(path_d: &'static str) -> Node {
    icon(
        &IconProps {
            size: Size::Sm,
            ..IconProps::default()
        },
        vec![],
        vec![el(
            "path",
            vec![
                ("d", path_d),
                ("fill", "none"),
                ("stroke", "currentColor"),
                ("stroke-width", "2"),
                ("stroke-linecap", "round"),
                ("stroke-linejoin", "round"),
            ],
            vec![],
        )],
    )
}

/// 吹き出しの幾何アイコン(相談窓口)。
fn bubble_icon() -> Node {
    geo_icon("M4 5h16v9H10l-4 4v-4H4V5z")
}

/// 円 + 疑問符の幾何アイコン(サポート窓口)。
fn support_icon() -> Node {
    geo_icon(
        "M12 3a9 9 0 100 18 9 9 0 000-18z M9.5 9a2.5 2.5 0 015 0c0 1.5-1.5 2-2.5 3 M12 16.5v.01",
    )
}

/// 封筒の幾何アイコン(取材・提携窓口)。
fn envelope_icon() -> Node {
    geo_icon("M4 6h16v12H4V6z M4 7l8 6 8-6")
}

/// 右矢印の幾何アイコン(各リンク末尾)。
fn arrow_icon() -> Node {
    geo_icon("M4 12h16 M13 5l7 7-7 7")
}

/// 窓口 1 件分のダミーデータ(架空、実在の企業・人物とは無関係)。
struct Channel {
    title: &'static str,
    description: &'static str,
    link_label: &'static str,
    icon_fn: fn() -> Node,
}

/// 窓口一覧(架空、3 件。主参照 R0857 の角丸アイコンタイル 3 列に対応)。
const CHANNELS: [Channel; 3] = [
    Channel {
        title: "導入のご相談",
        description: "導入検討中のお客様からのご相談を承ります。",
        link_label: "お問い合わせはこちら",
        icon_fn: bubble_icon,
    },
    Channel {
        title: "技術サポート",
        description: "導入後の技術的なお問い合わせに対応します。",
        link_label: "サポート窓口へ",
        icon_fn: support_icon,
    },
    Channel {
        title: "取材・提携のご相談",
        description: "取材・協業に関するご相談を受け付けています。",
        link_label: "お問い合わせはこちら",
        icon_fn: envelope_icon,
    },
];

/// 拠点 1 件分のダミーデータ(架空、実在の企業・住所とは無関係。
/// 郵便番号はすべて `000-000X` の架空値)。
struct Office {
    name: &'static str,
    line1: &'static str,
    line2: &'static str,
}

/// 拠点一覧(架空、4 件。集約元 R0856 の左罫線付き拠点住所 4 列に対応)。
const OFFICES: [Office; 4] = [
    Office {
        name: "東京オフィス",
        line1: "〒000-0001 東京都千代田区架空 1-2-3",
        line2: "本社機能・営業窓口",
    },
    Office {
        name: "大阪オフィス",
        line1: "〒000-0002 大阪府大阪市架空 4-5-6",
        line2: "西日本エリア担当",
    },
    Office {
        name: "福岡オフィス",
        line1: "〒000-0003 福岡県福岡市架空 7-8-9",
        line2: "九州エリア担当",
    },
    Office {
        name: "札幌オフィス",
        line1: "〒000-0004 北海道札幌市架空 10-11",
        line2: "北日本エリア担当",
    },
];

/// 窓口カラム 1 件(角丸アイコンタイル + 窓口名 + 説明 + 矢印付きリンク)。
fn channel_column(channel: &Channel) -> Node {
    let aria_label = format!("{}({})", channel.link_label, channel.title);
    div(
        vec![
            ("data-blocks-contact-info-columns-column", ""),
            ("data-blocks-contact-info-columns-variant", "tile"),
        ],
        vec![
            div(
                vec![("data-blocks-contact-info-columns-tile", "")],
                vec![(channel.icon_fn)()],
            ),
            heading(
                HeadingLevel::H4,
                &HeadingProps {
                    size: HeadingSize::Md,
                    weight: HeadingWeight::Semibold,
                },
                vec![],
                vec![text(channel.title)],
            ),
            styled_text::text(
                &TextProps {
                    variant: TextVariant::Muted,
                    ..TextProps::default()
                },
                vec![],
                vec![text(channel.description)],
            ),
            link::root(
                REPO,
                &LinkProps {
                    variant: LinkVariant::Underline,
                    palette: ColorPalette::Neutral,
                    ..LinkProps::default()
                },
                vec![
                    ("aria-label", aria_label.as_str()),
                    ("data-blocks-contact-info-columns-link", ""),
                ],
                vec![text(channel.link_label), arrow_icon()],
            ),
        ],
    )
}

/// 拠点カラム 1 件(左罫線 + 拠点名 + 住所 2 行 + 矢印付きリンク)。
fn office_column(office: &Office) -> Node {
    let aria_label = format!("地図を見る({})", office.name);
    div(
        vec![
            ("data-blocks-contact-info-columns-column", ""),
            ("data-blocks-contact-info-columns-variant", "border"),
        ],
        vec![
            heading(
                HeadingLevel::H4,
                &HeadingProps {
                    size: HeadingSize::Md,
                    weight: HeadingWeight::Semibold,
                },
                vec![],
                vec![text(office.name)],
            ),
            div(
                vec![("class", "blocks-contact-info-columns-address")],
                vec![
                    styled_text::text(
                        &TextProps {
                            size: TextSize::Sm,
                            variant: TextVariant::Muted,
                            ..TextProps::default()
                        },
                        vec![],
                        vec![text(office.line1)],
                    ),
                    styled_text::text(
                        &TextProps {
                            size: TextSize::Sm,
                            variant: TextVariant::Muted,
                            ..TextProps::default()
                        },
                        vec![],
                        vec![text(office.line2)],
                    ),
                ],
            ),
            link::root(
                REPO,
                &LinkProps {
                    variant: LinkVariant::Underline,
                    palette: ColorPalette::Neutral,
                    ..LinkProps::default()
                },
                vec![
                    ("aria-label", aria_label.as_str()),
                    ("data-blocks-contact-info-columns-link", ""),
                ],
                vec![text("地図を見る"), arrow_icon()],
            ),
        ],
    )
}

/// `contact-info-columns` の Demo 本体(見出し + 窓口カラム 3 列 + 拠点
/// カラム 4 列)。呼び出しごとに同一の `Node` を返す純関数
/// (モジュール doc「2 段構成」節)。
pub fn demo() -> Node {
    let header = div(
        vec![("class", "blocks-contact-info-columns-header")],
        vec![
            styled_text::text(
                &TextProps {
                    size: TextSize::Sm,
                    weight: TextWeight::Medium,
                    ..TextProps::default()
                },
                vec![("data-blocks-contact-info-columns-tagline", "")],
                vec![text("お問い合わせ")],
            ),
            heading(
                HeadingLevel::H3,
                &HeadingProps {
                    size: HeadingSize::Xl2,
                    weight: HeadingWeight::Bold,
                },
                vec![],
                vec![text("用件に合わせた窓口をお選びください")],
            ),
            styled_text::text(
                &TextProps {
                    variant: TextVariant::Muted,
                    ..TextProps::default()
                },
                vec![],
                vec![text(
                    "各種お問い合わせは以下の窓口から、拠点へのご訪問は下記の一覧からご確認ください。",
                )],
            ),
        ],
    );

    let channels_label = styled_text::text(
        &TextProps {
            size: TextSize::Sm,
            weight: TextWeight::Medium,
            ..TextProps::default()
        },
        vec![("data-blocks-contact-info-columns-section-label", "")],
        vec![text("お問い合わせ窓口")],
    );
    let channels = div(
        vec![("class", "blocks-contact-info-columns-channels")],
        CHANNELS.iter().map(channel_column).collect(),
    );
    let channels_section = div(
        vec![("class", "blocks-contact-info-columns-section")],
        vec![channels_label, channels],
    );

    let offices_label = styled_text::text(
        &TextProps {
            size: TextSize::Sm,
            weight: TextWeight::Medium,
            ..TextProps::default()
        },
        vec![("data-blocks-contact-info-columns-section-label", "")],
        vec![text("拠点一覧")],
    );
    let offices = div(
        vec![("class", "blocks-contact-info-columns-offices")],
        OFFICES.iter().map(office_column).collect(),
    );
    let offices_section = div(
        vec![("class", "blocks-contact-info-columns-section")],
        vec![offices_label, offices],
    );

    div(
        vec![("class", "blocks-contact-info-columns-layout")],
        vec![header, channels_section, offices_section],
    )
}

原案差分メモ

参照(主参照は対応表 ID R0857、集約元は対応表 ID R0856。出典の固有名・ファイル名は記載しません)から取り込んだのは構造(領域の配置と部品構成)のみであり、次の点を独自に設計・変更しています。

  • 主参照(角丸アイコンタイル 3 列)と集約元(左罫線付き拠点住所 4 列)を 1 つの Demo の中に「お問い合わせ窓口」「拠点一覧」の 2 段として並べました(要件が「拠点や問い合わせ窓口を 3〜4 列のカラムで並べる」を 1 種類のレイアウトに限定していなかったため)。
  • セクション見出しを H3、各カラムの窓口名/拠点名を H4 にしました。各段の小見出し(「お問い合わせ窓口」「拠点一覧」)は見出しレベルの重複を避けるため heading ではなく text で表しています。
  • アイコンは既存アイコンセットの複製を避けるため、吹き出し・円 + 疑問符・封筒・右矢印の自作幾何図形にしました。
  • 文言・窓口名・拠点住所・郵便番号はすべて独自に書いた架空のものにしました(郵便番号は 000-000X の架空値、実在の企業・人物・PII は含みません)。
  • 配色は --fandhe-color-accent/--fandhe-color-bg-subtle/ --fandhe-color-border 等のトークンに従わせました。
  • リンクは本リポジトリの固定 URL にし、同じ可視テキストが複数並ぶため aria-label で区別しています。参照元にあった mailto:/tel: 相当の連絡先リンクは使わず、住所・窓口名はプレーンテキストで表示するに留めています。
  • 列の切り替えを「1 列 → sm(640px)以上で 2 列 → lg(1024px)以上で全列表示(窓口 3 列・拠点 4 列)」にしました。

関連情報: Heading / Text / Icon / Link