) : (incidents?.length ?? 0) === 0 ? (
diff --git a/apps/web/src/components/layout/page-tabs.tsx b/apps/web/src/components/layout/page-tabs.tsx
index 43b6bb4ce..acfdcb6b5 100644
--- a/apps/web/src/components/layout/page-tabs.tsx
+++ b/apps/web/src/components/layout/page-tabs.tsx
@@ -56,10 +56,29 @@ export interface PageTabsProps {
function TabSkeleton() {
return (
-
-
-
-
+
+
+
+
+
+
+ 載入中...
+
)
}
diff --git a/apps/web/src/components/shared/lobster-loading.tsx b/apps/web/src/components/shared/lobster-loading.tsx
new file mode 100644
index 000000000..2b2daa4d9
--- /dev/null
+++ b/apps/web/src/components/shared/lobster-loading.tsx
@@ -0,0 +1,79 @@
+'use client'
+
+/**
+ * LobsterLoading — 小龍蝦載入動畫
+ * =================================
+ * Sprint 5: 所有「載入中」用小龍蝦動畫取代純文字
+ * 設計: Q版龍蝦上下浮動 + 文字提示
+ *
+ * 建立時間: 2026-04-08 (台北時區)
+ */
+
+import { useTranslations } from 'next-intl'
+
+interface LobsterLoadingProps {
+ /** 自訂提示文字 (預設 '載入中...') */
+ text?: string
+ /** 大小: 'sm' (24px) | 'md' (36px) | 'lg' (48px) */
+ size?: 'sm' | 'md' | 'lg'
+}
+
+const SIZES = {
+ sm: { svg: 24, bob: 2, fontSize: 11 },
+ md: { svg: 36, bob: 3, fontSize: 12 },
+ lg: { svg: 48, bob: 4, fontSize: 13 },
+}
+
+export function LobsterLoading({ text, size = 'md' }: LobsterLoadingProps) {
+ const tc = useTranslations('common')
+ const s = SIZES[size]
+ const displayText = text ?? tc('loading')
+
+ return (
+
+
+
+
+
+
+ {displayText}
+
+
+ )
+}
+
+export default LobsterLoading