テーマ
コンポーネントは色と角の丸みをデザイントークンから読みます。トークンの値は、ページ全体にはテーマが、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 の普通の値です。トークンをページに書き出す方法は、トークンとテーマ で説明しています。