Novi UI

テーマの調整

変える手段は3つあります。上から順に試してください。下にいくほど強く、壊れやすくなります。

1. CSS 変数を上書きする

ブランド色を変えるならこれだけで済みます。 --novi-color-primary を使う全コンポーネントに一度に効きます。

/* app/globals.css */
@import '@novi-ui/core/base.css';
@import '@novi-ui/raster/raster.css';

:root {
  --novi-color-primary: oklch(58% 0.18 265);
  --novi-color-primary-fg: oklch(99% 0 0);
}

[data-novi-scheme='dark'] {
  --novi-color-primary: oklch(72% 0.15 265);
}

色は oklch() で書いてください。明度を数値で扱えるため、 ライトとダークで同じコントラスト比を保ったまま色相だけ差し替えられます。

2. slot にクラスを足す

1箇所だけ形を変えたいときは classNames を使います。 variant が付けたクラスを打ち消したいときも、拡張ではなくこちらが正解です。

import { Button, Card, CardBody, CardHeader } from '@novi-ui/raster'

// slot ごとにクラスを足す。variant のクラスを上書きしたいときもこれを使う。
export function WideSaveButton() {
  return (
    <Button
      color="primary"
      classNames={{
        root: 'w-full justify-between',
        label: 'tracking-wide',
      }}
    >
      保存
    </Button>
  )
}

// どの slot があるかは各コンポーネントのページの slot 表にある。
export function TightCard() {
  return (
    <Card classNames={{ header: 'pb-1', body: 'pt-1' }}>
      <CardHeader>売上</CardHeader>
      <CardBody>¥1,240,000</CardBody>
    </Card>
  )
}

3. styles を拡張する

同じ見た目を何度も使うなら、派生した styles を1つ作ります。tailwind-variants が必要です。

pnpm add tailwind-variants
import { Button, buttonStyles } from '@novi-ui/raster'
import { tv } from 'tailwind-variants'

// slot ベースの定義では `base` は効かない。**必ず `slots` を使う。**
export const wideButtonStyles = tv({
  extend: buttonStyles,
  slots: {
    root: 'w-full justify-between',
  },
})

// 拡張した styles は自分で呼び、結果を classNames に渡す。
export function WideButton() {
  const s = wideButtonStyles({ size: 'lg' })

  return (
    <Button size="lg" classNames={{ root: s.root() }}>
      続ける
    </Button>
  )
}

slot ベースの定義では base が効きません。 tv({ extend, base }) と書いても無視されるため、slots を使ってください。 また extend で足したクラスは base に加算されるだけなので、 variant のクラスには勝てません。勝たせたいときは 2 の classNames を使います。

上書きできる変数

Raster@novi-ui/raster)が定義する値です。 この表は CSS を出力しているのと同じ定義から作られているため、実装とズレません。

角丸

Raster では full 以外すべて 2px 以下。角を立てるのが思想(ADR-R1)

Raster角丸トークン
CSS 変数
--novi-radius-none0px
--novi-radius-sm2px
--novi-radius-md2px
--novi-radius-lg2px
--novi-radius-full9999px

Raster ではすべて none。階層は境界線と背景色の差で表す

Rasterトークン
CSS 変数
--novi-shadow-nonenone
--novi-shadow-smnone
--novi-shadow-mdnone
--novi-shadow-lgnone

文字サイズ

比率 1.2(minor third)。単一比率で階層を作る

Raster文字サイズトークン
CSS 変数
--novi-text-xs12px
--novi-text-sm14px
--novi-text-base16px
--novi-text-lg20px
--novi-text-xl24px
--novi-text-2xl30px
--novi-text-3xl36px

モーション

Raster では速度を1つに固定している。動きで飾らない

Rasterモーショントークン
CSS 変数
--novi-duration-fast120ms
--novi-duration-base120ms
--novi-duration-slow120ms
--novi-ease-standardcubic-bezier(0.2, 0, 0, 1)
--novi-ease-emphasizedcubic-bezier(0.2, 0, 0, 1)

ブランド色を変えるならここ。中立色の chroma は 0 に固定している

  • bg
  • subtle
  • fg
  • muted
  • border
  • border-strong
  • overlay
  • default
  • default-fg
  • primary
  • primary-fg
  • secondary
  • secondary-fg
  • success
  • success-fg
  • warning
  • warning-fg
  • danger
  • danger-fg
Rasterトークン
CSS 変数ライトダーク
--novi-color-bgoklch(99% 0 0)oklch(16% 0 0)
--novi-color-subtleoklch(96% 0 0)oklch(21% 0 0)
--novi-color-fgoklch(20% 0 0)oklch(95% 0 0)
--novi-color-mutedoklch(48% 0 0)oklch(72% 0 0)
--novi-color-borderoklch(88% 0 0)oklch(28% 0 0)
--novi-color-border-strongoklch(58% 0 0)oklch(55% 0 0)
--novi-color-overlayoklch(20% 0 0 / 0.45)oklch(10% 0 0 / 0.6)
--novi-color-defaultoklch(96% 0 0)oklch(25% 0 0)
--novi-color-default-fgoklch(20% 0 0)oklch(95% 0 0)
--novi-color-primaryoklch(48% 0.18 250)oklch(74% 0.14 250)
--novi-color-primary-fgoklch(99% 0 0)oklch(16% 0 0)
--novi-color-secondaryoklch(46% 0.16 300)oklch(74% 0.13 300)
--novi-color-secondary-fgoklch(99% 0 0)oklch(16% 0 0)
--novi-color-successoklch(45% 0.13 150)oklch(76% 0.13 150)
--novi-color-success-fgoklch(99% 0 0)oklch(16% 0 0)
--novi-color-warningoklch(45% 0.12 70)oklch(82% 0.12 70)
--novi-color-warning-fgoklch(99% 0 0)oklch(16% 0 0)
--novi-color-dangeroklch(48% 0.19 25)oklch(72% 0.16 25)
--novi-color-danger-fgoklch(99% 0 0)oklch(16% 0 0)

変えても効かないもの

テーマは語彙を解釈する自由を持っています。Raster は角を立てる思想のため、radius="lg" を渡しても見た目が変わりません。 これは仕様であって不具合ではありません。詳しくは Raster のデザイン言語を読んでください。