English

テーマ

コンポーネントは色と角の丸みをデザイントークンから読みます。トークンの値は、ページ全体にはテーマが、1 つの要素にはスタイルが設定します。

トークン

token モジュールにはトークンごとに 1 つの関数があり、名前は shadcn/ui に合わせています。background、foreground、primary、muted、border、ring、radius などです。どの関数も Token を返します。Token は型の付いた既定値を持つ CSS のカスタムプロパティです。何も設定しないページには、ライトの値が入ります。

use hypersig::style::value::{Color, rem};
use hypersig::style::{Media, Style, Theme};
use hypersig::{Page, Signals};
use hypersig_ui::{ButtonSize, ButtonVariant, button, token};
use serde::{Deserialize, Serialize};

#[derive(Signals, Serialize, Deserialize)]
struct App {
    saved: bool,
}

// A blue primary color, lighter in the dark theme, and rounder corners.
let brand = Theme::new()
    .set(&token::primary(), Color::hex(0x0025_63eb))
    .set(&token::radius(), rem(1))
    .on(Media::Dark, Theme::new().set(&token::primary(), Color::hex(0x0060_a5fa)));

let html = Page::new("App", App { saved: false })
    .global(hypersig_ui::global())
    .theme(hypersig_ui::theme())
    .theme(brand)
    .child(
        button::<App>(ButtonVariant::Default, ButtonSize::Default)
            // One element can set a token for itself and what is inside it.
            .css(Style::new().token(&token::primary(), Color::hex(0x0016_a34a)))
            .text("Save"),
    )
    .render();
assert!(html.contains("--primary:#2563eb"));

ライトとダーク

hypersig_ui::theme() は prefers-color-scheme: dark のときにダークの値を設定します。代わりにシグナルで配色を選ぶには、hypersig_ui::dark() か hypersig_ui::light() を css_when や css_match で要素に付けます。どちらもその要素と内側の要素に色のトークンをすべて設定し、color-scheme も一緒に設定するので、スクロールバーのようなネイティブのコントロールも配色に従います。

実行結果

theme.rs
use hypersig::html::div;
use hypersig::style::Style;
use hypersig::style::pattern::stack;
use hypersig::style::value::rem;
use hypersig::{Page, Signals};
use hypersig_ui::{
    ButtonSize, ButtonVariant, Level, button, card, card_content, card_description, card_header,
    card_title, select_field, switch, token,
};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Clone, Copy, PartialEq)]
pub enum Scheme {
    System,
    Light,
    Dark,
}

#[derive(Signals, Serialize, Deserialize)]
pub struct Preview {
    scheme: Scheme,
    on: bool,
}

pub fn page() -> Page<Preview> {
    let initial = Preview {
        scheme: Scheme::System,
        on: true,
    };
    Page::new(
        "プレビュー",
        initial,
    )
    .child(
        div()
            .css(
                stack(rem(1))
                    .padding(rem(1))
                    .background_color(token::background().var())
                    .color(token::foreground().var()),
            )
            .css_match(
                Preview::scheme(),
                [
                    (Scheme::Light, hypersig_ui::light()),
                    (Scheme::Dark, hypersig_ui::dark()),
                ],
            )
            .child(
                div()
                    .css(Style::new().max_width(rem(12)))
                    .child(select_field(
                        "テーマ",
                        Preview::scheme(),
                        [
                            (
                                Scheme::System,
                                "システム",
                            ),
                            (
                                Scheme::Light,
                                "ライト",
                            ),
                            (
                                Scheme::Dark,
                                "ダーク",
                            ),
                        ],
                    )),
            )
            .child(
                card()
                    .child(
                        card_header()
                            .child(card_title(Level::H2).text("通知"))
                            .child(card_description().text("受信トレイに届ける内容を選んでください。")),
                    )
                    .child(
                        card_content()
                            .css(stack(rem(1)))
                            .child(switch(
                                "製品のお知らせ",
                                Preview::on(),
                            ))
                            .child(div().child(
                                button(ButtonVariant::Default, ButtonSize::Sm).text("保存"),
                            )),
                    ),
            ),
    )
}
トークンは hypersig::style の普通の値です。トークンをページに書き出す方法は、トークンとテーマ で説明しています。