WebberUI

Balance Scale Compare

天平比較版面:把功能籌碼勾進左右任一側,兩欄依累計權重物理下沉與翹起,支點槓桿同步傾斜並停在反映實際差距的角度。

載入預覽⋯

Playground

即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。

14
<BalanceScaleCompare />

安裝

npx shadcn@latest add https://webberui.com/r/balance-scale-compare.json

或在 components.json 設定 registries 後,改用 @webberui/balance-scale-compare 安裝。

安裝依賴後,從 registry JSON(/r/balance-scale-compare.jsonfiles[0].content)複製 balance-scale-compare.tsx 原始碼到你的 components/ui/ 目錄:

npm install motion clsx tailwind-merge lucide-react

調校點可選用 --wb-duration-fast--wb-ease-out CSS 變數;未定義時會退回內建預設值。

使用

import {
  BalanceScaleCompare,
  type ScaleFeature,
} from "@/components/ui/balance-scale-compare";

const features: ScaleFeature[] = [
  { id: "price", label: "價格", weight: 3, icon: "💰" },
  { id: "speed", label: "效能", weight: 2, icon: "⚡" },
  { id: "support", label: "客服", weight: 2, icon: "🎧" },
];

<BalanceScaleCompare
  features={features}
  leftLabel="自建方案"
  rightLabel="WebberUI"
  defaultAssignments={{ price: "left", speed: "right" }}
/>;

受控模式下傳入 assignments 並以 onAssignmentsChange 同步狀態:

const [assignments, setAssignments] = React.useState<
  Record<string, "left" | "right">
>({});

<BalanceScaleCompare
  features={features}
  assignments={assignments}
  onAssignmentsChange={setAssignments}
/>;

Props

Prop型別預設值說明
featuresScaleFeature[]—(必填)可指派到任一側的功能籌碼清單
leftLabelstring"方案 A"左側欄位標題
rightLabelstring"方案 B"右側欄位標題
assignmentsRecord<string, "left" | "right">受控指派表;未在表內的籌碼=尚未指派
defaultAssignmentsRecord<string, "left" | "right">{}非受控初始指派表
onAssignmentsChange(next: Record<string, "left" | "right">) => void指派變更時觸發,帶入完整新指派表
maxTiltnumber14最大傾斜角度(度),全部權重壓在一側時的極限
unitstring"分"權重單位標籤
classNamestring附加到最外層容器的 class

ScaleFeature

欄位型別預設值說明
idstring—(必填)唯一識別 key
labelstring—(必填)顯示名稱
weightnumber1權重(正數),加總後決定天平傾斜
iconReact.ReactNode可選圖示(emoji 或節點),顯示在籌碼前

細節

  • 物理傾斜:以兩側權重差 ÷ 總權重正規化到 -1..1,再乘上 maxTilt 得出角度,因此天平會停在反映實際差距的角度;全部壓在一側時到達極限,兩側相等時回正
  • 托盤沉降:橫桿旋轉 θ 度時,端點的垂直位移=sin(θ) × 半桿長,兩側托盤各自跟著端點沉降或翹起,較重一側下沉、較輕一側抬起
  • 圖層分離:橫桿與支點指針同屬一個旋轉組繞支點旋轉;托盤的水平定位由外層負責、垂直沉降交給內層 motion,兩者的 transform 互不干擾
  • 擺盪落位:橫桿與托盤共用帶輕微過衝的 spring,指派變更後會像真實天平一樣晃幾下才停穩
  • 籌碼進出:籌碼勾進某側時以 spring 彈入該側托盤、AnimatePresence 讓移出的籌碼縮小淡出,其餘籌碼以 layout 動畫補位

可及性

  • 每個側別鈕是原生 button,帶 aria-label(含籌碼名稱與目標側標題)與 aria-pressed 標示目前選取狀態,可用鍵盤操作
  • 天平圖形以 aria-hidden 對輔助科技隱藏,另以 role="status" + aria-live="polite" 的文字區朗讀目前哪一側較重與差距
  • 使用者系統開啟「減少動態效果」時,橫桿與托盤改為瞬間切換、籌碼進出不縮放,功能完全不受影響

On this page