visionA 雲端版前端 — 沿用 local-tool 既有 UI(原則 4:先抄 local-tool)+
新增雲端特有的登入 / 配對 / 設定流程,含以下整合階段:
- Phase 0:13 頁 + 30+ 元件 + 雛形 banner
- dashboard / devices / models / workspace / clusters / settings 等頁
- AppShell + Sidebar + Header + tokens + i18n(中英雙語 96 keys)
- API client + 5 stores + 3 hooks
- Phase 0.6:OIDC redirect 改造
- login 頁改為 OIDC redirect(`window.location.href = /api/auth/login`)
- register 改說明頁、account 改唯讀(user 資料來源是 MC)
- api client 改 cookie session(credentials: include)+ 完全清掉 localStorage
- Phase 0.7:stage 部署 + nil guard
- getApiBaseUrl() 修:browser 環境視為 same-origin(與 login 頁一致)
- login 頁加「已登入 → router.replace('/')」effect
- User type email/name 改 optional(MC id_token 不一定回 email/name claim)
- header.tsx UserMenu displayName 4 層 fallback:name → email → id → i18n
- 雛形 banner 文案更新(已接 Innovedus 帳號中心)+ 版號 Phase 0.7
驗證:pnpm lint / test (125/125) / build 全綠
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
77 lines
2.5 KiB
TypeScript
77 lines
2.5 KiB
TypeScript
"use client";
|
||
|
||
import * as React from "react";
|
||
import { Tooltip as TooltipPrimitive } from "radix-ui";
|
||
|
||
import { cn } from "@/lib/utils";
|
||
|
||
/**
|
||
* Tooltip — Shadcn 風提示泡泡(Radix Tooltip 封裝)
|
||
*
|
||
* 來源:Shadcn UI 官方樣板(New York style),local-tool 未提供此元件,F4 任務新增。
|
||
*
|
||
* 使用方式:
|
||
* <TooltipProvider>(通常放在 root layout,App 層級包一次即可)
|
||
* <Tooltip>
|
||
* <TooltipTrigger>...</TooltipTrigger>
|
||
* <TooltipContent>提示文字</TooltipContent>
|
||
* </Tooltip>
|
||
*
|
||
* 雲端版主要使用情境:
|
||
* - Header Tunnel 狀態燈(懸停顯示 RTT)
|
||
* - 離線裝置「為什麼不能操作」的說明
|
||
* - Sidebar 摺疊時的 icon 提示(若未來實作摺疊)
|
||
*
|
||
* 動畫依賴 tw-animate-css。
|
||
*/
|
||
function TooltipProvider({
|
||
delayDuration = 0,
|
||
...props
|
||
}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
|
||
return (
|
||
<TooltipPrimitive.Provider
|
||
data-slot="tooltip-provider"
|
||
delayDuration={delayDuration}
|
||
{...props}
|
||
/>
|
||
);
|
||
}
|
||
|
||
function Tooltip({
|
||
...props
|
||
}: React.ComponentProps<typeof TooltipPrimitive.Root>) {
|
||
return <TooltipPrimitive.Root data-slot="tooltip" {...props} />;
|
||
}
|
||
|
||
function TooltipTrigger({
|
||
...props
|
||
}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
|
||
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
|
||
}
|
||
|
||
function TooltipContent({
|
||
className,
|
||
sideOffset = 0,
|
||
children,
|
||
...props
|
||
}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
|
||
return (
|
||
<TooltipPrimitive.Portal>
|
||
<TooltipPrimitive.Content
|
||
data-slot="tooltip-content"
|
||
sideOffset={sideOffset}
|
||
className={cn(
|
||
"bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
|
||
className,
|
||
)}
|
||
{...props}
|
||
>
|
||
{children}
|
||
<TooltipPrimitive.Arrow className="bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" />
|
||
</TooltipPrimitive.Content>
|
||
</TooltipPrimitive.Portal>
|
||
);
|
||
}
|
||
|
||
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };
|