mirror of
https://github.com/fankes/komari-theme-purcarte.git
synced 2025-10-19 20:09:24 +08:00
feat: 初步适配主题颜色效果
This commit is contained in:
@@ -2,8 +2,8 @@ import React from "react";
|
||||
|
||||
const Footer: React.FC = () => {
|
||||
return (
|
||||
<footer className="fixed inset-shadow-sm bottom-0 left-0 right-0 p-2 text-center purcarte-blur z-50">
|
||||
<p className="flex justify-center text-sm text-second-foreground text-shadow-lg whitespace-pre">
|
||||
<footer className="fixed inset-shadow-sm inset-shadow-(color:--accent-a4) bottom-0 left-0 right-0 p-2 text-center purcarte-blur z-50">
|
||||
<p className="flex justify-center text-sm text-second-foreground text-shadow-lg text-shadow-(color:--accent-a4) whitespace-pre">
|
||||
Powered by{" "}
|
||||
<a
|
||||
href="https://github.com/komari-monitor/komari"
|
||||
|
@@ -13,6 +13,7 @@ import { useEffect, useState } from "react";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { useIsMobile } from "@/hooks/useMobile";
|
||||
import { useConfigItem } from "@/config";
|
||||
import type { Appearance } from "@/hooks/useTheme";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
@@ -23,8 +24,8 @@ import {
|
||||
interface HeaderProps {
|
||||
viewMode: "grid" | "table";
|
||||
setViewMode: (mode: "grid" | "table") => void;
|
||||
theme: string;
|
||||
toggleTheme: () => void;
|
||||
appearance: Appearance;
|
||||
setAppearance: (appearance: Appearance) => void;
|
||||
searchTerm: string;
|
||||
setSearchTerm: (term: string) => void;
|
||||
}
|
||||
@@ -32,8 +33,8 @@ interface HeaderProps {
|
||||
export const Header = ({
|
||||
viewMode,
|
||||
setViewMode,
|
||||
theme,
|
||||
toggleTheme,
|
||||
appearance,
|
||||
setAppearance,
|
||||
searchTerm,
|
||||
setSearchTerm,
|
||||
}: HeaderProps) => {
|
||||
@@ -54,10 +55,15 @@ export const Header = ({
|
||||
}
|
||||
}, [sitename]);
|
||||
|
||||
const toggleAppearance = () => {
|
||||
const newAppearance = appearance === "light" ? "dark" : "light";
|
||||
setAppearance(newAppearance);
|
||||
};
|
||||
|
||||
return (
|
||||
<header className="purcarte-blur border-b border-border sticky top-0 flex items-center justify-center shadow-sm z-10">
|
||||
<header className="purcarte-blur border-b border-(--accent-a4) sticky top-0 flex items-center justify-center shadow-sm shadow-(color:--accent-a4) z-10">
|
||||
<div className="w-[90%] max-w-screen-2xl px-4 py-2 flex items-center justify-between">
|
||||
<div className="flex items-center text-shadow-lg text-accent-foreground">
|
||||
<div className="flex items-center text-shadow-lg text-shadow-(color:--accent-a4) text-accent-foreground">
|
||||
<a href="/" className="flex items-center gap-2 text-2xl font-bold">
|
||||
{enableLogo && logoUrl && (
|
||||
<img src={logoUrl} alt="logo" className="h-8" />
|
||||
@@ -79,13 +85,13 @@ export const Header = ({
|
||||
className="relative group">
|
||||
<Search className="size-5 text-primary" />
|
||||
{searchTerm && (
|
||||
<span className="absolute top-0 right-0 w-1.5 h-1.5 rounded-full bg-primary transform -translate-x-1/2"></span>
|
||||
<span className="absolute top-0 right-0 w-1.5 h-1.5 rounded-full bg-(--accent-indicator) transform -translate-x-1/2"></span>
|
||||
)}
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
align="end"
|
||||
className="purcarte-blur border-border rounded-xl w-48">
|
||||
className="purcarte-blur border-(--accent-a4) rounded-xl w-48">
|
||||
<div className="p-2">
|
||||
<Input
|
||||
type="search"
|
||||
@@ -107,12 +113,12 @@ export const Header = ({
|
||||
size="icon"
|
||||
className="relative group">
|
||||
<Menu className="size-5 text-primary transition-transform duration-300 group-data-[state=open]:rotate-180" />
|
||||
<span className="absolute top-0 right-0 w-1.5 h-1.5 rounded-full bg-primary transform -translate-x-1/2 scale-0 transition-transform duration-300 group-data-[state=open]:scale-100"></span>
|
||||
<span className="absolute top-0 right-0 w-1.5 h-1.5 rounded-full bg-(--accent-indicator) transform -translate-x-1/2 scale-0 transition-transform duration-300 group-data-[state=open]:scale-100"></span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
align="end"
|
||||
className="purcarte-blur border-border rounded-xl">
|
||||
className="purcarte-blur border-(--accent-a4) rounded-xl">
|
||||
<DropdownMenuItem
|
||||
onClick={() =>
|
||||
setViewMode(viewMode === "grid" ? "table" : "grid")
|
||||
@@ -126,14 +132,14 @@ export const Header = ({
|
||||
{viewMode === "grid" ? "表格视图" : "网格视图"}
|
||||
</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={toggleTheme}>
|
||||
{theme === "dark" ? (
|
||||
<DropdownMenuItem onClick={toggleAppearance}>
|
||||
{appearance === "dark" ? (
|
||||
<Sun className="size-4 mr-2 text-primary" />
|
||||
) : (
|
||||
<Moon className="size-4 mr-2 text-primary" />
|
||||
)}
|
||||
<span>
|
||||
{theme === "dark" ? "浅色模式" : "深色模式"}
|
||||
{appearance === "dark" ? "浅色模式" : "深色模式"}
|
||||
</span>
|
||||
</DropdownMenuItem>
|
||||
{enableAdminButton && (
|
||||
@@ -177,7 +183,7 @@ export const Header = ({
|
||||
onClick={() => setIsSearchOpen(!isSearchOpen)}>
|
||||
<Search className="size-5 text-primary" />
|
||||
{searchTerm && (
|
||||
<span className="absolute top-0 right-0 w-1.5 h-1.5 rounded-full bg-primary transform -translate-x-1/2"></span>
|
||||
<span className="absolute top-0 right-0 w-1.5 h-1.5 rounded-full bg-(--accent-indicator) transform -translate-x-1/2"></span>
|
||||
)}
|
||||
</Button>
|
||||
)}
|
||||
@@ -193,8 +199,11 @@ export const Header = ({
|
||||
<Grid3X3 className="size-5 text-primary" />
|
||||
)}
|
||||
</Button>
|
||||
<Button variant="ghost" size="icon" onClick={toggleTheme}>
|
||||
{theme === "dark" ? (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={toggleAppearance}>
|
||||
{appearance === "dark" ? (
|
||||
<Sun className="size-5 text-primary" />
|
||||
) : (
|
||||
<Moon className="size-5 text-primary" />
|
||||
@@ -226,14 +235,16 @@ export const Header = ({
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
align="end"
|
||||
className="animate-in slide-in-from-top-5 duration-300 purcarte-blur border-border rounded-xl">
|
||||
<DropdownMenuItem onClick={toggleTheme}>
|
||||
{theme === "dark" ? (
|
||||
className="animate-in slide-in-from-top-5 duration-300 purcarte-blur border-(--accent-a4) rounded-xl">
|
||||
<DropdownMenuItem onClick={toggleAppearance}>
|
||||
{appearance === "dark" ? (
|
||||
<Sun className="size-4 mr-2 text-primary" />
|
||||
) : (
|
||||
<Moon className="size-4 mr-2 text-primary" />
|
||||
)}
|
||||
<span>{theme === "dark" ? "浅色模式" : "深色模式"}</span>
|
||||
<span>
|
||||
{appearance === "dark" ? "浅色模式" : "深色模式"}
|
||||
</span>
|
||||
</DropdownMenuItem>
|
||||
{enableAdminButton && (
|
||||
<DropdownMenuItem asChild>
|
||||
@@ -251,8 +262,11 @@ export const Header = ({
|
||||
</DropdownMenu>
|
||||
) : (
|
||||
<>
|
||||
<Button variant="ghost" size="icon" onClick={toggleTheme}>
|
||||
{theme === "dark" ? (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={toggleAppearance}>
|
||||
{appearance === "dark" ? (
|
||||
<Sun className="size-5 text-primary" />
|
||||
) : (
|
||||
<Moon className="size-5 text-primary" />
|
||||
|
@@ -58,7 +58,7 @@ export const NodeCard = ({ node, enableSwap }: NodeCardProps) => {
|
||||
<div className="flex flex-wrap gap-1">
|
||||
<Tag tags={tagList} />
|
||||
</div>
|
||||
<div className="border-t border-border/60 my-2"></div>
|
||||
<div className="border-t border-(--accent-a4) my-2"></div>
|
||||
<div className="flex items-center justify-around whitespace-nowrap">
|
||||
<div className="flex items-center gap-1">
|
||||
<CpuIcon className="size-4 text-blue-600 flex-shrink-0" />
|
||||
@@ -113,7 +113,7 @@ export const NodeCard = ({ node, enableSwap }: NodeCardProps) => {
|
||||
<span className="w-12 text-right">{diskUsage.toFixed(0)}%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="border-t border-border/60 my-2"></div>
|
||||
<div className="border-t border-(--accent-a4) my-2"></div>
|
||||
<div className="flex justify-between text-xs">
|
||||
<span className="text-secondary-foreground">网络:</span>
|
||||
<div>
|
||||
@@ -167,7 +167,7 @@ export const NodeCard = ({ node, enableSwap }: NodeCardProps) => {
|
||||
到期:{expired_at}
|
||||
</span>
|
||||
</div>
|
||||
<div className="border-l border-border/60 mx-2"></div>
|
||||
<div className="border-l border-(--accent-a4) mx-2"></div>
|
||||
<div className="flex justify-end w-full">
|
||||
<span className="text-secondary-foreground">
|
||||
{isOnline && stats
|
||||
|
@@ -6,7 +6,7 @@ export const NodeListHeader = ({ enableSwap }: NodeListHeaderProps) => {
|
||||
const gridCols = enableSwap ? "grid-cols-10" : "grid-cols-9";
|
||||
return (
|
||||
<div
|
||||
className={`text-primary font-bold grid ${gridCols} text-center shadow-md gap-4 p-2 items-center rounded-lg bg-card transition-colors duration-200`}>
|
||||
className={`text-primary font-bold grid ${gridCols} text-center shadow-sm shadow-(color:--accent-a4) gap-4 p-2 items-center rounded-lg bg-card transition-colors duration-200`}>
|
||||
<div className="col-span-2">节点名称</div>
|
||||
<div className="col-span-1">CPU</div>
|
||||
<div className="col-span-1">内存</div>
|
||||
|
@@ -36,7 +36,7 @@ export const NodeListItem = ({
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`grid ${gridCols} text-center shadow-md gap-4 p-2 text-nowrap items-center rounded-lg ${
|
||||
className={`grid ${gridCols} text-center shadow-sm shadow-(color:--accent-a4) gap-4 p-2 text-nowrap items-center rounded-lg ${
|
||||
isOnline
|
||||
? ""
|
||||
: "striped-bg-red-translucent-diagonal ring-2 ring-red-500/50"
|
||||
|
@@ -156,7 +156,7 @@ export const StatsBar = ({
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className="purcarte-blur min-w-[300px] rounded-lg text-secondary-foreground my-6 mx-4 px-4 box-border border border-border text-sm relative flex items-center min-h-[5rem]">
|
||||
<div className="purcarte-blur min-w-[300px] rounded-lg text-secondary-foreground my-6 mx-4 px-4 box-border border border-(--accent-a4) text-sm relative flex items-center min-h-[5rem]">
|
||||
<div className="absolute top-2 right-2">
|
||||
<DropdownMenu modal={false}>
|
||||
<DropdownMenuTrigger asChild>
|
||||
|
Reference in New Issue
Block a user