mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-10-09 03:06:37 +08:00
fix(frontend): extend h5 tabbar safe-area coverage (#197)
Ensure the PWA bottom tab bar and tab hit areas fully cover the safe-area inset while keeping related frontend formatting updates consistent.
This commit is contained in:
@@ -50,7 +50,9 @@ export default function AdminLayout({
|
|||||||
const { isOpen, onOpen, onOpenChange } = useDisclosure();
|
const { isOpen, onOpen, onOpenChange } = useDisclosure();
|
||||||
|
|
||||||
const [mobileMenuVisible, setMobileMenuVisible] = useState(false);
|
const [mobileMenuVisible, setMobileMenuVisible] = useState(false);
|
||||||
const [isCollapsed, setIsCollapsed] = useState(() => localStorage.getItem("sidebar_collapsed") === "true");
|
const [isCollapsed, setIsCollapsed] = useState(
|
||||||
|
() => localStorage.getItem("sidebar_collapsed") === "true",
|
||||||
|
);
|
||||||
const [username, setUsername] = useState("");
|
const [username, setUsername] = useState("");
|
||||||
const [isAdmin, setIsAdmin] = useState(false);
|
const [isAdmin, setIsAdmin] = useState(false);
|
||||||
const [passwordLoading, setPasswordLoading] = useState(false);
|
const [passwordLoading, setPasswordLoading] = useState(false);
|
||||||
@@ -208,6 +210,7 @@ export default function AdminLayout({
|
|||||||
// 切换折叠状态
|
// 切换折叠状态
|
||||||
const toggleCollapse = () => {
|
const toggleCollapse = () => {
|
||||||
const newCollapsed = !isCollapsed;
|
const newCollapsed = !isCollapsed;
|
||||||
|
|
||||||
setIsCollapsed(newCollapsed);
|
setIsCollapsed(newCollapsed);
|
||||||
localStorage.setItem("sidebar_collapsed", newCollapsed.toString());
|
localStorage.setItem("sidebar_collapsed", newCollapsed.toString());
|
||||||
};
|
};
|
||||||
@@ -328,11 +331,15 @@ export default function AdminLayout({
|
|||||||
<div className="flex-shrink-0 flex items-center justify-center w-10">
|
<div className="flex-shrink-0 flex items-center justify-center w-10">
|
||||||
<Logo size={28} />
|
<Logo size={28} />
|
||||||
</div>
|
</div>
|
||||||
<div className={`transition-all duration-300 overflow-hidden ${isCollapsed ? "max-w-0 opacity-0 ml-0" : "max-w-[180px] opacity-100 ml-2"}`}>
|
<div
|
||||||
|
className={`transition-all duration-300 overflow-hidden ${isCollapsed ? "max-w-0 opacity-0 ml-0" : "max-w-[180px] opacity-100 ml-2"}`}
|
||||||
|
>
|
||||||
<h1 className="text-sm font-bold text-foreground overflow-hidden whitespace-nowrap text-ellipsis">
|
<h1 className="text-sm font-bold text-foreground overflow-hidden whitespace-nowrap text-ellipsis">
|
||||||
{siteConfig.name}
|
{siteConfig.name}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-xs text-default-500 overflow-hidden whitespace-nowrap text-ellipsis">v{siteConfig.version}</p>
|
<p className="text-xs text-default-500 overflow-hidden whitespace-nowrap text-ellipsis">
|
||||||
|
v{siteConfig.version}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -345,15 +352,16 @@ export default function AdminLayout({
|
|||||||
return (
|
return (
|
||||||
<li key={item.path}>
|
<li key={item.path}>
|
||||||
<motion.button
|
<motion.button
|
||||||
title={isCollapsed ? item.label : undefined}
|
|
||||||
className={`
|
className={`
|
||||||
w-full flex items-center p-2 rounded-lg text-left
|
w-full flex items-center p-2 rounded-lg text-left
|
||||||
relative min-h-[44px] overflow-hidden transition-colors
|
relative min-h-[44px] overflow-hidden transition-colors
|
||||||
${isActive
|
${
|
||||||
? "text-primary-600 dark:text-primary-300"
|
isActive
|
||||||
: "text-gray-700 dark:text-gray-200"
|
? "text-primary-600 dark:text-primary-300"
|
||||||
}
|
: "text-gray-700 dark:text-gray-200"
|
||||||
|
}
|
||||||
`}
|
`}
|
||||||
|
title={isCollapsed ? item.label : undefined}
|
||||||
transition={{ duration: 0.15 }}
|
transition={{ duration: 0.15 }}
|
||||||
onClick={() => handleMenuClick(item.path)}
|
onClick={() => handleMenuClick(item.path)}
|
||||||
>
|
>
|
||||||
@@ -378,7 +386,9 @@ export default function AdminLayout({
|
|||||||
<div className="flex-shrink-0 w-10 h-10 flex items-center justify-center relative z-10">
|
<div className="flex-shrink-0 w-10 h-10 flex items-center justify-center relative z-10">
|
||||||
{item.icon}
|
{item.icon}
|
||||||
</div>
|
</div>
|
||||||
<div className={`transition-all duration-300 overflow-hidden flex items-center ${isCollapsed ? "max-w-0 opacity-0 ml-0" : "max-w-[200px] opacity-100 ml-2"}`}>
|
<div
|
||||||
|
className={`transition-all duration-300 overflow-hidden flex items-center ${isCollapsed ? "max-w-0 opacity-0 ml-0" : "max-w-[200px] opacity-100 ml-2"}`}
|
||||||
|
>
|
||||||
<span className="font-medium text-sm relative z-10 whitespace-nowrap">
|
<span className="font-medium text-sm relative z-10 whitespace-nowrap">
|
||||||
{item.label}
|
{item.label}
|
||||||
</span>
|
</span>
|
||||||
@@ -392,7 +402,9 @@ export default function AdminLayout({
|
|||||||
|
|
||||||
{/* 底部版权信息和折叠按钮 */}
|
{/* 底部版权信息和折叠按钮 */}
|
||||||
<div className="px-5 py-2 pb-4 mt-auto flex-shrink-0 flex items-center justify-between overflow-hidden whitespace-nowrap box-border">
|
<div className="px-5 py-2 pb-4 mt-auto flex-shrink-0 flex items-center justify-between overflow-hidden whitespace-nowrap box-border">
|
||||||
<div className={`transition-all duration-300 overflow-hidden flex items-center ${isCollapsed ? "max-w-0 opacity-0" : "max-w-[200px] opacity-100"}`}>
|
<div
|
||||||
|
className={`transition-all duration-300 overflow-hidden flex items-center ${isCollapsed ? "max-w-0 opacity-0" : "max-w-[200px] opacity-100"}`}
|
||||||
|
>
|
||||||
<p className="text-xs text-gray-400 dark:text-gray-500">
|
<p className="text-xs text-gray-400 dark:text-gray-500">
|
||||||
Powered by{" "}
|
Powered by{" "}
|
||||||
<a
|
<a
|
||||||
@@ -410,20 +422,40 @@ export default function AdminLayout({
|
|||||||
{!isMobile && (
|
{!isMobile && (
|
||||||
<Button
|
<Button
|
||||||
isIconOnly
|
isIconOnly
|
||||||
variant="light"
|
|
||||||
size="sm"
|
|
||||||
className="flex-shrink-0 text-gray-400 hover:text-gray-700 dark:text-gray-500 dark:hover:text-gray-300 min-w-0 w-10 h-10 rounded-full ml-auto"
|
className="flex-shrink-0 text-gray-400 hover:text-gray-700 dark:text-gray-500 dark:hover:text-gray-300 min-w-0 w-10 h-10 rounded-full ml-auto"
|
||||||
|
size="sm"
|
||||||
|
variant="light"
|
||||||
onPress={toggleCollapse}
|
onPress={toggleCollapse}
|
||||||
>
|
>
|
||||||
{isCollapsed ? (
|
{isCollapsed ? (
|
||||||
// 向右扩展的提示
|
// 向右扩展的提示
|
||||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 5l7 7-7 7M5 5l7 7-7 7" />
|
className="w-5 h-5"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M13 5l7 7-7 7M5 5l7 7-7 7"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={2}
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
) : (
|
) : (
|
||||||
// 向左收起的提示
|
// 向左收起的提示
|
||||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M11 19l-7-7 7-7m8 14l-7-7 7-7" />
|
className="w-5 h-5"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M11 19l-7-7 7-7m8 14l-7-7 7-7"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={2}
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -532,9 +564,7 @@ export default function AdminLayout({
|
|||||||
</header>
|
</header>
|
||||||
|
|
||||||
{/* 主内容 */}
|
{/* 主内容 */}
|
||||||
<main
|
<main className="flex-1 bg-gray-100 dark:bg-black overflow-y-auto">
|
||||||
className="flex-1 bg-gray-100 dark:bg-black overflow-y-auto"
|
|
||||||
>
|
|
||||||
<AnimatePresence mode="wait">
|
<AnimatePresence mode="wait">
|
||||||
<motion.div
|
<motion.div
|
||||||
key={location.pathname}
|
key={location.pathname}
|
||||||
|
|||||||
@@ -115,10 +115,10 @@ export default function H5Layout({ children }: { children: React.ReactNode }) {
|
|||||||
<main className="flex-1 bg-gray-100 dark:bg-black">{children}</main>
|
<main className="flex-1 bg-gray-100 dark:bg-black">{children}</main>
|
||||||
|
|
||||||
{/* 用于给固定 Tabbar 腾出空间的占位元素 */}
|
{/* 用于给固定 Tabbar 腾出空间的占位元素 */}
|
||||||
<div aria-hidden className="h-16 safe-bottom" />
|
<div aria-hidden className="h-[calc(4rem+var(--safe-area-bottom))]" />
|
||||||
|
|
||||||
{/* 底部Tabbar */}
|
{/* 底部Tabbar */}
|
||||||
<nav className="bg-white dark:bg-black border-t border-gray-200 dark:border-gray-600 h-16 safe-bottom flex-shrink-0 flex items-center justify-around px-2 fixed bottom-0 left-0 right-0 z-30">
|
<nav className="bg-white dark:bg-black border-t border-gray-200 dark:border-gray-600 h-[calc(4rem+var(--safe-area-bottom))] flex-shrink-0 flex items-center justify-around px-2 fixed bottom-0 left-0 right-0 z-30">
|
||||||
{filteredTabItems.map((item) => {
|
{filteredTabItems.map((item) => {
|
||||||
const isActive = location.pathname === item.path;
|
const isActive = location.pathname === item.path;
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@ export default function H5Layout({ children }: { children: React.ReactNode }) {
|
|||||||
<button
|
<button
|
||||||
key={item.path}
|
key={item.path}
|
||||||
className={`
|
className={`
|
||||||
flex flex-col items-center justify-center flex-1 h-full
|
flex flex-col items-center justify-center flex-1 h-full pb-[var(--safe-area-bottom)]
|
||||||
transition-colors duration-200 min-h-[44px]
|
transition-colors duration-200 min-h-[44px]
|
||||||
${
|
${
|
||||||
isActive
|
isActive
|
||||||
|
|||||||
@@ -230,7 +230,7 @@ export default function ForwardPage() {
|
|||||||
setViewMode(newMode);
|
setViewMode(newMode);
|
||||||
try {
|
try {
|
||||||
localStorage.setItem("forward-view-mode", newMode);
|
localStorage.setItem("forward-view-mode", newMode);
|
||||||
} catch { }
|
} catch {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 加载所有数据
|
// 加载所有数据
|
||||||
@@ -1196,10 +1196,10 @@ export default function ForwardPage() {
|
|||||||
const style: React.CSSProperties = {
|
const style: React.CSSProperties = {
|
||||||
transform: transform
|
transform: transform
|
||||||
? CSS.Transform.toString({
|
? CSS.Transform.toString({
|
||||||
...transform,
|
...transform,
|
||||||
x: Math.round(transform.x),
|
x: Math.round(transform.x),
|
||||||
y: Math.round(transform.y),
|
y: Math.round(transform.y),
|
||||||
})
|
})
|
||||||
: undefined,
|
: undefined,
|
||||||
transition: isDragging ? undefined : transition || undefined,
|
transition: isDragging ? undefined : transition || undefined,
|
||||||
opacity: isDragging ? 0.5 : 1,
|
opacity: isDragging ? 0.5 : 1,
|
||||||
@@ -1257,10 +1257,10 @@ export default function ForwardPage() {
|
|||||||
const style = {
|
const style = {
|
||||||
transform: transform
|
transform: transform
|
||||||
? CSS.Transform.toString({
|
? CSS.Transform.toString({
|
||||||
...transform,
|
...transform,
|
||||||
x: Math.round(transform.x),
|
x: Math.round(transform.x),
|
||||||
y: Math.round(transform.y),
|
y: Math.round(transform.y),
|
||||||
})
|
})
|
||||||
: undefined,
|
: undefined,
|
||||||
transition: isDragging ? undefined : transition || undefined,
|
transition: isDragging ? undefined : transition || undefined,
|
||||||
opacity: isDragging ? 0.5 : 1,
|
opacity: isDragging ? 0.5 : 1,
|
||||||
@@ -1317,10 +1317,11 @@ export default function ForwardPage() {
|
|||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="max-w-[220px]">
|
<TableCell className="max-w-[220px]">
|
||||||
<button
|
<button
|
||||||
className={`w-full truncate rounded-md bg-default-100/50 px-2.5 py-1.5 text-left font-mono text-xs font-medium text-default-700 transition-all ${hasMultipleAddresses(forward.inIp)
|
className={`w-full truncate rounded-md bg-default-100/50 px-2.5 py-1.5 text-left font-mono text-xs font-medium text-default-700 transition-all ${
|
||||||
? "hover:bg-default-200 hover:shadow-sm"
|
hasMultipleAddresses(forward.inIp)
|
||||||
: ""
|
? "hover:bg-default-200 hover:shadow-sm"
|
||||||
}`}
|
: ""
|
||||||
|
}`}
|
||||||
title={formatInAddress(forward.inIp, forward.inPort)}
|
title={formatInAddress(forward.inIp, forward.inPort)}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
@@ -1332,10 +1333,11 @@ export default function ForwardPage() {
|
|||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="max-w-[240px]">
|
<TableCell className="max-w-[240px]">
|
||||||
<button
|
<button
|
||||||
className={`w-full truncate rounded-md bg-default-100/50 px-2.5 py-1.5 text-left font-mono text-xs font-medium text-default-700 transition-all ${hasMultipleAddresses(forward.remoteAddr)
|
className={`w-full truncate rounded-md bg-default-100/50 px-2.5 py-1.5 text-left font-mono text-xs font-medium text-default-700 transition-all ${
|
||||||
? "hover:bg-default-200 hover:shadow-sm"
|
hasMultipleAddresses(forward.remoteAddr)
|
||||||
: ""
|
? "hover:bg-default-200 hover:shadow-sm"
|
||||||
}`}
|
: ""
|
||||||
|
}`}
|
||||||
title={formatRemoteAddress(forward.remoteAddr)}
|
title={formatRemoteAddress(forward.remoteAddr)}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
@@ -1472,10 +1474,11 @@ export default function ForwardPage() {
|
|||||||
<div className="flex items-center gap-1.5 ml-2">
|
<div className="flex items-center gap-1.5 ml-2">
|
||||||
{viewMode === "direct" && (
|
{viewMode === "direct" && (
|
||||||
<div
|
<div
|
||||||
className={`cursor-grab active:cursor-grabbing p-2 text-default-400 hover:text-default-600 transition-colors touch-manipulation ${isMobile
|
className={`cursor-grab active:cursor-grabbing p-2 text-default-400 hover:text-default-600 transition-colors touch-manipulation ${
|
||||||
? "opacity-100" // 移动端始终显示
|
isMobile
|
||||||
: "opacity-0 group-hover:opacity-100 sm:opacity-0 sm:group-hover:opacity-100"
|
? "opacity-100" // 移动端始终显示
|
||||||
}`}
|
: "opacity-0 group-hover:opacity-100 sm:opacity-0 sm:group-hover:opacity-100"
|
||||||
|
}`}
|
||||||
{...listeners}
|
{...listeners}
|
||||||
style={{ touchAction: "none" }}
|
style={{ touchAction: "none" }}
|
||||||
title={isMobile ? "长按拖拽排序" : "拖拽排序"}
|
title={isMobile ? "长按拖拽排序" : "拖拽排序"}
|
||||||
@@ -1513,10 +1516,11 @@ export default function ForwardPage() {
|
|||||||
{/* 地址信息 */}
|
{/* 地址信息 */}
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<button
|
<button
|
||||||
className={`cursor-pointer px-2 py-1 bg-default-50 dark:bg-default-100/50 rounded border border-default-200 dark:border-default-300 transition-colors duration-200 ${hasMultipleAddresses(forward.inIp)
|
className={`cursor-pointer px-2 py-1 bg-default-50 dark:bg-default-100/50 rounded border border-default-200 dark:border-default-300 transition-colors duration-200 ${
|
||||||
? "hover:bg-default-100 dark:hover:bg-default-200/50"
|
hasMultipleAddresses(forward.inIp)
|
||||||
: ""
|
? "hover:bg-default-100 dark:hover:bg-default-200/50"
|
||||||
}`}
|
: ""
|
||||||
|
}`}
|
||||||
title={formatInAddress(forward.inIp, forward.inPort)}
|
title={formatInAddress(forward.inIp, forward.inPort)}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
@@ -1552,10 +1556,11 @@ export default function ForwardPage() {
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
className={`cursor-pointer px-2 py-1 bg-default-50 dark:bg-default-100/50 rounded border border-default-200 dark:border-default-300 transition-colors duration-200 ${hasMultipleAddresses(forward.remoteAddr)
|
className={`cursor-pointer px-2 py-1 bg-default-50 dark:bg-default-100/50 rounded border border-default-200 dark:border-default-300 transition-colors duration-200 ${
|
||||||
? "hover:bg-default-100 dark:hover:bg-default-200/50"
|
hasMultipleAddresses(forward.remoteAddr)
|
||||||
: ""
|
? "hover:bg-default-100 dark:hover:bg-default-200/50"
|
||||||
}`}
|
: ""
|
||||||
|
}`}
|
||||||
title={formatRemoteAddress(forward.remoteAddr)}
|
title={formatRemoteAddress(forward.remoteAddr)}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
@@ -1973,39 +1978,39 @@ export default function ForwardPage() {
|
|||||||
</Card>
|
</Card>
|
||||||
)
|
)
|
||||||
) : /* 直接显示模式 */
|
) : /* 直接显示模式 */
|
||||||
forwards.length > 0 ? (
|
forwards.length > 0 ? (
|
||||||
<DndContext
|
<DndContext
|
||||||
collisionDetection={closestCenter}
|
collisionDetection={closestCenter}
|
||||||
sensors={sensors}
|
sensors={sensors}
|
||||||
onDragEnd={handleDragEnd}
|
onDragEnd={handleDragEnd}
|
||||||
onDragStart={() => { }} // 添加空的 onDragStart 处理器
|
onDragStart={() => {}} // 添加空的 onDragStart 处理器
|
||||||
|
>
|
||||||
|
<SortableContext
|
||||||
|
items={sortableForwardIds}
|
||||||
|
strategy={rectSortingStrategy}
|
||||||
>
|
>
|
||||||
<SortableContext
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 gap-4">
|
||||||
items={sortableForwardIds}
|
{sortedForwards.map((forward) =>
|
||||||
strategy={rectSortingStrategy}
|
forward && forward.id ? (
|
||||||
>
|
<SortableForwardCard key={forward.id} forward={forward} />
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 gap-4">
|
) : null,
|
||||||
{sortedForwards.map((forward) =>
|
)}
|
||||||
forward && forward.id ? (
|
</div>
|
||||||
<SortableForwardCard key={forward.id} forward={forward} />
|
</SortableContext>
|
||||||
) : null,
|
</DndContext>
|
||||||
)}
|
) : (
|
||||||
</div>
|
/* 空状态 */
|
||||||
</SortableContext>
|
<Card className="shadow-sm border border-gray-200 dark:border-gray-700 bg-default-50/50">
|
||||||
</DndContext>
|
<CardBody className="text-center py-20 flex flex-col items-center justify-center min-h-[240px]">
|
||||||
) : (
|
<h3 className="text-xl font-medium text-foreground tracking-tight mb-2">
|
||||||
/* 空状态 */
|
暂无转发配置
|
||||||
<Card className="shadow-sm border border-gray-200 dark:border-gray-700 bg-default-50/50">
|
</h3>
|
||||||
<CardBody className="text-center py-20 flex flex-col items-center justify-center min-h-[240px]">
|
<p className="text-default-500 text-sm max-w-xs mx-auto leading-relaxed">
|
||||||
<h3 className="text-xl font-medium text-foreground tracking-tight mb-2">
|
还没有创建任何转发配置,点击上方按钮开始创建
|
||||||
暂无转发配置
|
</p>
|
||||||
</h3>
|
</CardBody>
|
||||||
<p className="text-default-500 text-sm max-w-xs mx-auto leading-relaxed">
|
</Card>
|
||||||
还没有创建任何转发配置,点击上方按钮开始创建
|
)}
|
||||||
</p>
|
|
||||||
</CardBody>
|
|
||||||
</Card>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* 新增/编辑模态框 */}
|
{/* 新增/编辑模态框 */}
|
||||||
<Modal
|
<Modal
|
||||||
@@ -2474,10 +2479,11 @@ export default function ForwardPage() {
|
|||||||
{importResults.map((result, index) => (
|
{importResults.map((result, index) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className={`p-2 rounded border ${result.success
|
className={`p-2 rounded border ${
|
||||||
? "bg-success-50 dark:bg-success-100/10 border-success-200 dark:border-success-300/20"
|
result.success
|
||||||
: "bg-danger-50 dark:bg-danger-100/10 border-danger-200 dark:border-danger-300/20"
|
? "bg-success-50 dark:bg-success-100/10 border-success-200 dark:border-success-300/20"
|
||||||
}`}
|
: "bg-danger-50 dark:bg-danger-100/10 border-danger-200 dark:border-danger-300/20"
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{result.success ? (
|
{result.success ? (
|
||||||
@@ -2510,10 +2516,11 @@ export default function ForwardPage() {
|
|||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
<div className="flex items-center gap-2 mb-0.5">
|
<div className="flex items-center gap-2 mb-0.5">
|
||||||
<span
|
<span
|
||||||
className={`text-xs font-medium ${result.success
|
className={`text-xs font-medium ${
|
||||||
? "text-success-700 dark:text-success-300"
|
result.success
|
||||||
: "text-danger-700 dark:text-danger-300"
|
? "text-success-700 dark:text-success-300"
|
||||||
}`}
|
: "text-danger-700 dark:text-danger-300"
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
{result.success ? "成功" : "失败"}
|
{result.success ? "成功" : "失败"}
|
||||||
</span>
|
</span>
|
||||||
@@ -2525,10 +2532,11 @@ export default function ForwardPage() {
|
|||||||
</code>
|
</code>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`text-xs ${result.success
|
className={`text-xs ${
|
||||||
? "text-success-600 dark:text-success-400"
|
result.success
|
||||||
: "text-danger-600 dark:text-danger-400"
|
? "text-success-600 dark:text-success-400"
|
||||||
}`}
|
: "text-danger-600 dark:text-danger-400"
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
{result.message}
|
{result.message}
|
||||||
</div>
|
</div>
|
||||||
@@ -2711,18 +2719,20 @@ export default function ForwardPage() {
|
|||||||
return (
|
return (
|
||||||
<tr
|
<tr
|
||||||
key={index}
|
key={index}
|
||||||
className={`hover:bg-default-50 dark:hover:bg-gray-700/50 ${result.success
|
className={`hover:bg-default-50 dark:hover:bg-gray-700/50 ${
|
||||||
? "bg-white dark:bg-gray-800"
|
result.success
|
||||||
: "bg-danger-50 dark:bg-danger-900/30"
|
? "bg-white dark:bg-gray-800"
|
||||||
}`}
|
: "bg-danger-50 dark:bg-danger-900/30"
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
<td className="px-3 py-2">
|
<td className="px-3 py-2">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span
|
<span
|
||||||
className={`w-5 h-5 rounded-full flex items-center justify-center text-xs ${result.success
|
className={`w-5 h-5 rounded-full flex items-center justify-center text-xs ${
|
||||||
? "bg-success text-white"
|
result.success
|
||||||
: "bg-danger text-white"
|
? "bg-success text-white"
|
||||||
}`}
|
: "bg-danger text-white"
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
{result.success ? "✓" : "✗"}
|
{result.success ? "✓" : "✗"}
|
||||||
</span>
|
</span>
|
||||||
@@ -2764,10 +2774,11 @@ export default function ForwardPage() {
|
|||||||
<td className="px-3 py-2 text-center">
|
<td className="px-3 py-2 text-center">
|
||||||
{result.success ? (
|
{result.success ? (
|
||||||
<span
|
<span
|
||||||
className={`font-semibold ${(result.packetLoss || 0) > 0
|
className={`font-semibold ${
|
||||||
? "text-warning"
|
(result.packetLoss || 0) > 0
|
||||||
: "text-success"
|
? "text-warning"
|
||||||
}`}
|
: "text-success"
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
{result.packetLoss?.toFixed(1)}%
|
{result.packetLoss?.toFixed(1)}%
|
||||||
</span>
|
</span>
|
||||||
@@ -2881,17 +2892,19 @@ export default function ForwardPage() {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className={`border rounded-lg p-3 ${result.success
|
className={`border rounded-lg p-3 ${
|
||||||
? "border-divider bg-white dark:bg-gray-800"
|
result.success
|
||||||
: "border-danger-200 dark:border-danger-300/30 bg-danger-50 dark:bg-danger-900/30"
|
? "border-divider bg-white dark:bg-gray-800"
|
||||||
}`}
|
: "border-danger-200 dark:border-danger-300/30 bg-danger-50 dark:bg-danger-900/30"
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex items-start gap-2 mb-2">
|
<div className="flex items-start gap-2 mb-2">
|
||||||
<span
|
<span
|
||||||
className={`w-6 h-6 rounded-full flex items-center justify-center text-xs flex-shrink-0 ${result.success
|
className={`w-6 h-6 rounded-full flex items-center justify-center text-xs flex-shrink-0 ${
|
||||||
? "bg-success text-white"
|
result.success
|
||||||
: "bg-danger text-white"
|
? "bg-success text-white"
|
||||||
}`}
|
: "bg-danger text-white"
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
{result.success ? "✓" : "✗"}
|
{result.success ? "✓" : "✗"}
|
||||||
</span>
|
</span>
|
||||||
@@ -2927,10 +2940,11 @@ export default function ForwardPage() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<div
|
<div
|
||||||
className={`text-lg font-bold ${(result.packetLoss || 0) > 0
|
className={`text-lg font-bold ${
|
||||||
? "text-warning"
|
(result.packetLoss || 0) > 0
|
||||||
: "text-success"
|
? "text-warning"
|
||||||
}`}
|
: "text-success"
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
{result.packetLoss?.toFixed(1)}%
|
{result.packetLoss?.toFixed(1)}%
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -674,7 +674,11 @@ export default function PanelSharingPage() {
|
|||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
{/* Create Share Modal */}
|
{/* Create Share Modal */}
|
||||||
<Modal isOpen={createShareOpen} onClose={() => setCreateShareOpen(false)} scrollBehavior="inside">
|
<Modal
|
||||||
|
isOpen={createShareOpen}
|
||||||
|
scrollBehavior="inside"
|
||||||
|
onClose={() => setCreateShareOpen(false)}
|
||||||
|
>
|
||||||
<ModalContent>
|
<ModalContent>
|
||||||
<ModalHeader>创建分享</ModalHeader>
|
<ModalHeader>创建分享</ModalHeader>
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
@@ -777,7 +781,11 @@ export default function PanelSharingPage() {
|
|||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
{/* Edit Share Modal */}
|
{/* Edit Share Modal */}
|
||||||
<Modal isOpen={editShareOpen} onClose={() => setEditShareOpen(false)} scrollBehavior="inside">
|
<Modal
|
||||||
|
isOpen={editShareOpen}
|
||||||
|
scrollBehavior="inside"
|
||||||
|
onClose={() => setEditShareOpen(false)}
|
||||||
|
>
|
||||||
<ModalContent>
|
<ModalContent>
|
||||||
<ModalHeader>编辑分享</ModalHeader>
|
<ModalHeader>编辑分享</ModalHeader>
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
|
|||||||
Reference in New Issue
Block a user