Salad UIを使ってイケてるデザインを行いたい

こんにちは、rickyです。
今回はつい先日こちらの勉強会で学んだSaladUIについて書いていきます。

https://fukuokaex.connpass.com/event/324359/

## はじめに
そもそもSalad UIとは？
以下それぞれドキュメントから引用しました。

> This library is my attemp to port shadcn ui to Phoenix Liveview Component.

shadcnというものをPhoenixで使えるようにしたコンポーネントのことです。

ではshadcnとは？

> Beautifully designed components that you can copy and paste into your apps.

公式ドキュメントを見るからにデザインのコンポーネントのことです。

使いこなすとボタンのデザインを良くしたりリストを見やすく作り出すことができます。

## 実践
実際の動かすにあたって以下の記事を参考にさせていただきました。

https://qiita.com/RyoWakabayashi/items/c3dc2ec8bb67adb6dc3e

完全な動作の後追いとなる内容になります。
私の解説にわかりにくさを感じられた場合は上記の記事をチェックしてください。

今回はデフォルトのトップページにボタンとリストを表示させます。

手順１
プロジェクトの作成とプロジェクトの起動まで

バージョンを最新化し、プロジェクトを作成します。
今回データベースは不要のためオプションに--no-ectoを追加します。

```sh
mix archive.install hex phx_new
mix phx.new salad_test --no-ecto
```
プロジェクトの作成に対してYで許可します。

続いて作成したプロジェクトが問題なく機能してるのかを確認します。
```sh
cd salad_test
mix phx.server
```

サーバーを起動したのでlocalhost4000にてデフォルトページが表示できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330568/b190486b-b9d8-435d-304d-2bc2a1d149b7.png)



手順２
SaladUIの設定
SaladUIのドキュメントに従って設定の編集と必要なファイルをコピーして書き込みを行います。

https://github.com/bluzky/salad_ui

mix.exsを編集しモジュールの追加を行います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330568/c854944f-fec1-2986-8490-2332da3405b8.png)

```elixir
{:salad_ui, "~> 0.5"}
```

コマンドから
```sh
mix deps.get
```
でモジュールの反映をさせます。


assets/css/app.cssにui.shadcnからcopy codeで取得できる以下のコードを追記します。

https://ui.shadcn.com/themes

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330568/3640a7d2-8166-6518-e7ad-e06643be4d37.png)

```css
@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 222.2 84% 4.9%;
    --card: 0 0% 100%;
    --card-foreground: 222.2 84% 4.9%;
    --popover: 0 0% 100%;
    --popover-foreground: 222.2 84% 4.9%;
    --primary: 221.2 83.2% 53.3%;
    --primary-foreground: 210 40% 98%;
    --secondary: 210 40% 96.1%;
    --secondary-foreground: 222.2 47.4% 11.2%;
    --muted: 210 40% 96.1%;
    --muted-foreground: 215.4 16.3% 46.9%;
    --accent: 210 40% 96.1%;
    --accent-foreground: 222.2 47.4% 11.2%;
    --destructive: 0 84.2% 60.2%;
    --destructive-foreground: 210 40% 98%;
    --border: 214.3 31.8% 91.4%;
    --input: 214.3 31.8% 91.4%;
    --ring: 221.2 83.2% 53.3%;
    --radius: 0.5rem;
    --chart-1: 12 76% 61%;
    --chart-2: 173 58% 39%;
    --chart-3: 197 37% 24%;
    --chart-4: 43 74% 66%;
    --chart-5: 27 87% 67%;
  }

  .dark {
    --background: 222.2 84% 4.9%;
    --foreground: 210 40% 98%;
    --card: 222.2 84% 4.9%;
    --card-foreground: 210 40% 98%;
    --popover: 222.2 84% 4.9%;
    --popover-foreground: 210 40% 98%;
    --primary: 217.2 91.2% 59.8%;
    --primary-foreground: 222.2 47.4% 11.2%;
    --secondary: 217.2 32.6% 17.5%;
    --secondary-foreground: 210 40% 98%;
    --muted: 217.2 32.6% 17.5%;
    --muted-foreground: 215 20.2% 65.1%;
    --accent: 217.2 32.6% 17.5%;
    --accent-foreground: 210 40% 98%;
    --destructive: 0 62.8% 30.6%;
    --destructive-foreground: 210 40% 98%;
    --border: 217.2 32.6% 17.5%;
    --input: 217.2 32.6% 17.5%;
    --ring: 224.3 76.3% 48%;
    --chart-1: 220 70% 50%;
    --chart-2: 160 60% 45%;
    --chart-3: 30 80% 55%;
    --chart-4: 280 65% 60%;
    --chart-5: 340 75% 55%;
  }
}
```

assets/tailwind.colors.jsonを作成し
以下のコードをペーストします。
```json
{
  "accent": {
    "DEFAULT": "hsl(var(--accent))",
    "foreground": "hsl(var(--accent-foreground))"
  },
  "background": "hsl(var(--background))",
  "border": "hsl(var(--border))",
  "card": {
    "DEFAULT": "hsl(var(--card))",
    "foreground": "hsl(var(--card-foreground))"
  },
  "destructive": {
    "DEFAULT": "hsl(var(--destructive))",
    "foreground": "hsl(var(--destructive-foreground))"
  },
  "foreground": "hsl(var(--foreground))",
  "input": "hsl(var(--input))",
  "muted": {
    "DEFAULT": "hsl(var(--muted))",
    "foreground": "hsl(var(--muted-foreground))"
  },
  "popover": {
    "DEFAULT": "hsl(var(--popover))",
    "foreground": "hsl(var(--popover-foreground))"
  },
  "primary": {
    "DEFAULT": "hsl(var(--primary))",
    "foreground": "hsl(var(--primary-foreground))"
  },
  "ring": "hsl(var(--ring))",
  "secondary": {
    "DEFAULT": "hsl(var(--secondary))",
    "foreground": "hsl(var(--secondary-foreground))"
  }
}
```

tailwindの設定とインストールを行います。
asstes/tailwind.config.jsのcontentとextend、そしてpluginsを修正します。

```js
module.exports = {
  content: [
    "../deps/salad_ui/lib/**/*.ex",
    ],
  theme: {
    extend: {
      colors: require("./tailwind.colors.json"),
    },
  },
  plugins: [
    require("@tailwindcss/forms"),
    require("@tailwindcss/typography"),
    require("tailwindcss-animate"),
    ...
  ]
}
```


```sh
cd assets
npm i -D tailwindcss-animate
```

cd assetsでプロジェクト直下に戻り、config/config.exsに以下のコードを追記します。
```exs
config :tails, colors_file: Path.join(File.cwd!(), "assets/tailwind.colors.json")
```

手順３
デフォルトのトップページの編集
まずはインポート文の追記を行います。
importの書き方は公式ドキュメントを参考に書いていきます。
なおこの際にCoreComponentsと共存させるために、lib/salad_test_web.exにaliasで別名を付けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330568/90ec57e1-36be-6102-c2b7-4f3da2024d4c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330568/7fd97059-878a-f0e2-0c87-f77570f79d32.png)


```exs
  defp html_helpers do
    quote do
      # HTML escaping functionality
      import Phoenix.HTML
      # Core UI components and translation
      import SaladTestWeb.CoreComponents
      import SaladTestWeb.Gettext

      # Shortcut for generating JS commands
      alias Phoenix.LiveView.JS

      alias SaladUI.Button, as: SaladButton
      alias SaladUI.Slider, as: SaladSlider

      # Routes generation with the ~p sigil
      unquote(verified_routes())
    end
  end
```

lib/salad_test_web/controllers/page_html.exのSaladTestWeb.PageHTMLモジュールに以下のインポート文を付け加えます。
```exs
  import SaladUI.Button
  import SaladUI.Slider
```

以下のコードをlib/salad_test_web/controllers/page_html/home.html.heexの
```heex
<div class="px-4 py-10 sm:px-6 sm:py-28 lg:px-8 xl:px-28 xl:py-32">
  <div class="mx-auto max-w-xl lg:mx-0">
```
の下に書きます

```heex
    <SaladButton.button>
      これはボタン
    </SaladButton.button>

    <.form class="w-full mb-2" phx-change="validate">
      <SaladSlider.slider id="slider-single-step-slider" max={50} name="amount" value={20} class="w-[60%]" step={5}/>
    </.form>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330568/02b26bfe-583e-ae40-19aa-0e06b1b79a9c.png)


## 後書き
今回学んだことはサクサク手が動いてかつ目指す目的のデザインを行うことができたので非常に満足感が高かったです。
理解が複雑化したり動作原理がつかめないと混乱してしまうのですが、今回の作業量だとしっかり意図を理解しながら作りこむことができたので楽しかったです。
まぁサクサクと言いつつサイトのカラー情報の取得方法とバージョンの問題でコケてしまったのですが。
動作原理も良いですが、やはり見えやすい、わかりやすい部分が変化すると面白いものです。

## 補足
SaladUIの利点や具体的な利用シーンについては以下の動画が参考になります。
10分程度の動画のため見ておいて損はないです。

https://www.youtube.com/watch?v=OqGYnsdVOZc&t=8s

## 引用

https://hexdocs.pm/salad_ui/readme.html

https://ui.shadcn.com/