Community影像github.com

RevanthThota55/FreeFrame-Studio

Sonner React 吐司函式庫完全指南 — 安裝與設定 Toaster、選擇正確的 toast() 呼叫、Promise 與載入中吐司、更新、關閉與持久化吐司、樣式、主題與圖示、定位與多個 Toaster。適用於使用 Sonner 或疑難排解時 — 吐司不出現、出現兩次、遺失樣式、忽略 Tailwind 類別、藏在 Modal 後面或不跟隨深色模式。

FreeFrame-Studio 是什麼?

此技能是一份專注於 Sonner (由 Emil Kowalski 開發的 React 吐司函式庫) 的完整指南。它提供結構化的逐步指引,從基本的安裝與設定 (掛載一次 `<Toaster />` 並在客戶端使用 `toast()`) 開始,到進階的使用模式如 Promise 吐司、更新、關閉、持久化以及連結元件。技能的核心價值在於其「問題排除分級」概念,這是一種逐步升級的樣式調整方法:從預設值、行內樣式、帶有 `!important` 的類別,到最終的無頭 (`toast.custom()`) 自訂,以在不犧牲 Sonner 定位與滑動功能的同時,達成完全的控制。技能最後提供了一份詳盡的疑難排解表格,涵蓋了如吐司不顯示、顯示兩次、Tailwind 類別無效、在 Astro 或 Shadow DOM 中樣式遺失、被 Modal 遮擋、深色模式問題以及 Promise 卡住等常見問題。此技能適用於 Claude Code、Cusror 或 Codex 等 AI 代理工具,協助開發者有效設定、樣式化及除錯 Sonner。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/RevanthThota55/FreeFrame-Studio/tree/HEAD/.claude/skills/ask-sonner

Installed? Explore more 影像 skills: steipete/songsee, affaan-m/frontend-design, mattpocock/improve-codebase-architecture · View all 6 →

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

使用 Sonner 工作

初始回應

當此技能首次被呼叫且沒有特定問題時,僅回覆:

我已準備好協助您設定、樣式化及疑難排解 Sonner,我的知識來自其作者 Emil Kowalski。

在用戶提出問題之前,請勿提供任何其他資訊。

這是一份關於 Sonner (吐司函式庫) 的指南技能。當任務涉及 Sonner — 連接它、渲染吐司、設定樣式或修復問題時,請優先從此檔案回答。完整的 <Toaster /> 和 toast() 屬性表格位於 API.md 中;當您需要確切的屬性名稱、型別或預設值時,請閱讀該檔案。

設定

只有兩個部分:

  1. 一個 <Toaster />,只掛載一次,並盡可能靠近根節點 (在 Next.js 中:layout.tsx — 它在伺服器元件內也可運作)。切勿按頁面或有條件地渲染它;第二個掛載的 Toaster 會複製每個吐司。
  2. 從客戶端程式碼呼叫 toast() — 事件處理器、副作用、回呼。它是一個純函數,不需要 Hook 或 Provider,但在伺服器上無作用:在伺服器動作中,請回傳結果並在接收該結果的客戶端程式碼中呼叫 toast()。
import { Toaster } from 'sonner'; // 一次,在 layout 中
import { toast } from 'sonner';   // 任何客戶端位置

選擇正確的呼叫

您想要呼叫方式
純文字訊息toast('Title') — 加入 { description } 以顯示第二行
成功 / 錯誤 / 資訊 / 警告圖示toast.success('…'), toast.error('…') 等
在自己管理狀態時顯示載入中旋轉圖示toast.loading('…'),然後依 ID 更新
載入中 → 與 Promise 綁定的成功/錯誤toast.promise(promise, { loading, success, error }) — success/error 可接收帶有解析值/錯誤的函數
可執行某動作的按鈕{ action: { label, onClick } } — 除非 onClick 呼叫 event.preventDefault(),否則會關閉吐司;cancel 是次要變體
自訂 JSX,使用預設吐司外殼toast(<jsx />)
自訂 JSX,無任何樣式toast.custom((t) => <jsx />) — 無頭模式,t 提供用於關閉的 id

使用技巧

更新吐司 — 使用相同的 id 再次呼叫 toast();只有您傳遞的屬性會變更。切換到 toast.success(…, { id }) 會變更類型。這就是無需 toast.promise 實現載入中 → 成功流程的方法:

const id = toast.loading('上傳中…');
toast.success('已上傳', { id });

持久化 — { duration: Infinity }。關閉 — toast.dismiss(id),或使用 toast.dismiss() 關閉全部。讀取作用中的吐司 — 在 React 中使用 useSonner(),在 React 外部使用 toast.getActiveToasts()。

文字中的連結或元件 — 為標題或描述傳遞一個函數:toast(() => <a href="…">檢視</a>)。

多個 Toaster — 為每個 Toaster 指定一個 id,並使用 toast('…', { toasterId: 'canvas' }) 定位目標。如果沒有 toasterId,每個 Toaster 都會渲染該吐司。

關閉回呼 — onDismiss 在點擊關閉按鈕或滑動時觸發;onAutoClose 在超時時觸發。它們是分開的;沒有單一的「已關閉」回呼。

樣式調整 — 問題排除分級

僅根據變更需求爬升到所需的層級;過早跳至頂層是可行的 (這是建議的最終狀態),但停留在中間層級則不建議。

  1. 預設值 — 加上 Toaster 上的 richColors 以獲得彩色的成功/錯誤,invert 以翻轉主題。
  2. 行內微調 — 在 Toaster 上使用 toastOptions={{ style: {…} }} 作用於所有吐司,或在每個 toast() 呼叫中使用 style。
  3. 部分類別 — toastOptions={{ classNames: { toast, title, description, actionButton, cancelButton, closeButton } }}。Sonner 注入的樣式會在級聯中獲勝,因此每個類別都需要 !important (Tailwind:!text-red-900)。如果您對多個東西標記了 important,請停止 — 改用無頭模式。
  4. 無頭模式 — 使用 toast.custom() 搭配您自己的 JSX,保留 Sonner 的定位、堆疊和滑動功能。這是設計系統吐司的推薦方法:將其包裝在您自己的 toast() 抽象層中。(unstyled: true 可作為過渡方案,但無頭模式在相同努力下提供了更多控制。)

圖示 — 使用 Toaster 的 icons 屬性按類型切換預設圖示,使用 icon 按吐司切換,使用 null 移除。

主題 — theme 預設為 'light',且不會追蹤作業系統。傳遞 theme="system",或連接您的主題 Provider:使用 next-themes 的 <Toaster theme={resolvedTheme} />。

疑難排解

症狀原因 → 修正
吐司從未出現未掛載 <Toaster />,或它被卸載了 (有條件渲染、按頁面放置)。在根節點掛載一個。如果是從伺服器動作呼叫:toast() 僅限客戶端 — 在客戶端使用動作的結果來呼叫它。
同一個吐司出現兩次掛載了兩個 Toaster (layout 和 page) — 只保留一個。或者 toast() 在 React StrictMode 的開發模式下於副作用中被雙重觸發 — 改為從事件處理器觸發,或傳遞一個穩定的 id,以便第二次呼叫更新而非複製。
Tailwind/CSS 類別無效預設樣式會覆蓋它們。將它們標記為 !important,或使用 unstyled / 無頭模式 (請參閱上述分級)。
吐司完全無樣式渲染 (常見於 Astro、視角轉場)Sonner 注入的樣式表遺失了 — 在 layout 中明確匯入它:import 'sonner/dist/styles.css'。
在 Shadow DOM 中無樣式樣式會進入 document.head,而非 shadow root。將文字包含 [data-sonner-toaster] 的樣式標籤複製到 shadow root 中。
吐司在 Modal/覆蓋層後面,或被裁剪祖先元素建立了堆疊上下文 (transform、filter、overflow),或覆蓋層的 z-index 高於 Toaster。將 <Toaster /> 移至文件根節點,位於任何對話框/Portal 容器之外。
深色模式被忽略theme 預設為 'light' — 設定 theme="system" 或傳遞已解析的主題 (請參閱上方的主題)。
成功/錯誤看起來是灰色,而非綠色/紅色這是預設值。為 Toaster 加入 richColors。
吐司從未關閉duration: Infinity、dismissible: false,或 toast.promise 的 Promise 從未解決 — 載入中的吐司會永遠等待。
toast.promise 卡在載入中它需要一個 Promise (或一個回傳 Promise 的函數) 作為第一個引數,且該 Promise 必須實際 resolve/reject。
滑動關閉的方向錯誤 / 無法運作方向取決於 position。使用 Toaster 上的 swipeDirections 覆蓋。
吐司出現在每個 Toaster 中多個 Toaster 需要定位目標:為每個 Toaster 指定一個 id,並在 toast() 呼叫中傳遞 toasterId。
在行動裝置上吐司太靠近螢幕邊緣offset (桌面,預設 32px) 和 mobileOffset (<600px,預設 16px) — 數值、CSS 字串或按邊界區分的物件。

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

RevanthThota55/FreeFrame-Studio

Build an animation from scratch, making the decisions in the order that determines whether it feels right — should it animate at all, what purpose, which tool, which properties, which curve and duration, how it interrupts, how it exits. Writes the implementation. Use when asked to animate something, add motion, make a component feel alive, or build a transition. For critiquing existing motion use review-animations; for auditing a whole codebase use improve-animations.

RevanthThota55/FreeFrame-Studio

Keep web animations inside the frame budget — animate composite-only properties, keep motion off the main thread when the page is busy, and find the cause when an animation drops frames. Covers the layout/paint/composite pipeline, cheaper property swaps, CSS vs WAAPI vs requestAnimationFrame, Framer Motion's hardware-accelerated path, React re-rendering per frame, inherited CSS variable recalculation, blur cost, and when `will-change` actually helps. Use when an animation is janky, choppy, stutters, or drops frames; when choosing which property to animate; when deciding between CSS and JS animation on performance grounds; or when reaching for `will-change` or GPU layers. For choosing easing, duration, or whether to animate at all use animate; for reviewing motion as a whole use review-animations.

RevanthThota55/FreeFrame-Studio

Reverse-lookup glossary that turns a vague description of a web animation or motion effect into its exact term ("the bouncy thing when a popover opens" → Pop in; "the iOS rubber-band scroll" → Rubber-banding). Use when the user asks "what's it called when…", or describes a motion effect without knowing its name and wants the right word to prompt an AI or designer with. For naming an effect, not designing or building one.

RevanthThota55/FreeFrame-Studio

Apple's approach to interface design and fluid, physical motion, translated for the web. Use when building or reviewing gesture-driven UI, spring animations, drag/swipe/sheet interactions, momentum and interruptible transitions, translucent materials and depth, typography (optical sizing, tracking, leading), reduced-motion, or the design foundations (feedback, spatial consistency, restraint) behind Apple-style interfaces.

相關技能