diff --git a/src/pages/Jwt/JwtSection.tsx b/src/pages/Jwt/JwtSection.tsx
deleted file mode 100644
index 8d78ecd..0000000
--- a/src/pages/Jwt/JwtSection.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import { CopyButton } from '@/components/CopyButton';
-import { stringifyJson } from '@/utils/jwt';
-import { cn } from '@/lib/utils';
-
-interface JwtSectionProps {
- title: string;
- content: unknown;
- colorClass: string;
- bgClass: string;
- borderClass: string;
-}
-
-export default function JwtSection({
- title,
- content,
- colorClass,
- bgClass,
- borderClass,
-}: JwtSectionProps) {
- return (
-
-
-
- {title}
-
-
-
-
- {content ? stringifyJson(content) : '无法解析'}
-
-
- );
-}
diff --git a/src/pages/Jwt/components/JwtCopyBlock.tsx b/src/pages/Jwt/components/JwtCopyBlock.tsx
new file mode 100644
index 0000000..4f865e8
--- /dev/null
+++ b/src/pages/Jwt/components/JwtCopyBlock.tsx
@@ -0,0 +1,30 @@
+import { CopyButton } from '@/components/CopyButton';
+import { cn } from '@/lib/utils';
+
+interface JwtCopyBlockProps {
+ title: string;
+ copyText: string;
+ titleClassName?: string;
+ containerClassName?: string;
+ children: React.ReactNode;
+}
+
+export default function JwtCopyBlock({
+ title,
+ copyText,
+ titleClassName,
+ containerClassName,
+ children,
+}: JwtCopyBlockProps) {
+ return (
+
+
+
+ {title}
+
+
+
+ {children}
+
+ );
+}
diff --git a/src/pages/Jwt/components/JwtResultView.tsx b/src/pages/Jwt/components/JwtResultView.tsx
new file mode 100644
index 0000000..b3464bf
--- /dev/null
+++ b/src/pages/Jwt/components/JwtResultView.tsx
@@ -0,0 +1,49 @@
+import { stringifyJson } from '@/utils/jwt';
+import type { JwtResult } from '@/utils/jwt';
+import { cn } from '@/lib/utils';
+import {
+ JWT_JSON_CONTENT_CLASS,
+ JWT_SECTION_CONFIG,
+ JWT_SIGNATURE_SECTION,
+ JWT_TEXT_CONTENT_CLASS,
+} from '../constants';
+import JwtCopyBlock from './JwtCopyBlock';
+
+interface JwtResultViewProps {
+ result: JwtResult;
+}
+
+export default function JwtResultView({ result }: JwtResultViewProps) {
+ return (
+
+ {JWT_SECTION_CONFIG.map(({ contentKey, title, colorClass, bgClass, borderClass }) => {
+ const content = result[contentKey];
+
+ return (
+
+
+ {content ? stringifyJson(content) : '无法解析'}
+
+
+ );
+ })}
+
+
+
+ {result.signature || JWT_SIGNATURE_SECTION.emptyLabel}
+
+
+
+ );
+}
diff --git a/src/pages/Jwt/constants.ts b/src/pages/Jwt/constants.ts
new file mode 100644
index 0000000..64aacc8
--- /dev/null
+++ b/src/pages/Jwt/constants.ts
@@ -0,0 +1,41 @@
+export const JWT_INPUT_PLACEHOLDER = '在此粘贴 JWT 令牌 (Encoded JWT)...';
+
+export type JwtSectionContentKey = 'header' | 'payload';
+
+export interface JwtSectionConfig {
+ contentKey: JwtSectionContentKey;
+ title: string;
+ colorClass: string;
+ borderClass: string;
+ bgClass: string;
+}
+
+export const JWT_SECTION_CONFIG: JwtSectionConfig[] = [
+ {
+ contentKey: 'header',
+ title: 'HEADER: 算法 & 令牌类型',
+ colorClass: 'text-[#fb015b] dark:text-rose-400',
+ borderClass: 'border-[#fb015b]/20 dark:border-rose-500/20',
+ bgClass: 'bg-[#fb015b]/5 dark:bg-rose-500/5',
+ },
+ {
+ contentKey: 'payload',
+ title: 'PAYLOAD: 数据',
+ colorClass: 'text-[#a03aff] dark:text-purple-400',
+ borderClass: 'border-[#a03aff]/20 dark:border-purple-500/20',
+ bgClass: 'bg-[#a03aff]/5 dark:bg-purple-500/5',
+ },
+];
+
+export const JWT_SIGNATURE_SECTION = {
+ title: '签名',
+ titleClassName: 'text-muted-foreground/90',
+ containerClassName: 'border border-border bg-secondary/40',
+ emptyLabel: '无签名',
+} as const;
+
+export const JWT_JSON_CONTENT_CLASS =
+ 'm-0 p-3 bg-muted/30 dark:bg-muted/10 rounded-lg text-xs font-mono overflow-x-auto whitespace-pre-wrap break-all border border-border/50 text-foreground/90 leading-relaxed select-text';
+
+export const JWT_TEXT_CONTENT_CLASS =
+ 'block text-xs font-mono break-all text-foreground/80 bg-muted/30 dark:bg-muted/10 p-3 rounded-lg border border-border/50 leading-relaxed select-text';
diff --git a/src/pages/Jwt/index.tsx b/src/pages/Jwt/index.tsx
index ee75e12..3754441 100644
--- a/src/pages/Jwt/index.tsx
+++ b/src/pages/Jwt/index.tsx
@@ -1,66 +1,26 @@
import TextInputArea from '@/components/TextInputArea';
-import { CopyButton } from '@/components/CopyButton';
-import EmptyPlaceholder from '@/components/EmptyPlaceholder';
-import JwtSection from './JwtSection';
+import JwtResultView from './components/JwtResultView';
+import { JWT_INPUT_PLACEHOLDER } from './constants';
import { useJwt } from './useJwt';
export default function Index() {
const { jwtInput, result, handleChange, handleClear } = useJwt();
return (
-
-
-
+
+
- {result && !result.error && (
-
-
-
-
-
-
-
-
- {'签名'}
-
-
-
-
- {result.signature || '无签名'}
-
-
-
- )}
-
- {result?.error && (
-
{'无效的 JSON 格式'}
- )}
-
+ {result && !result.error &&
}
);
}