feat(Jwt): 重构 JWT 组件,新增常量和结果视图
- 新增 constants.ts 文件,定义 JWT 输入占位符和配置常量,提升代码可读性。 - 删除 JwtSection 组件,重构为 JwtResultView 组件,简化结果展示逻辑。 - 更新 index.tsx,使用 JwtResultView 组件替代原有的 JWT 结果展示方式,优化页面结构。
This commit is contained in:
@@ -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 (
|
||||
<div className={cn('p-4 rounded-xl border border-solid', bgClass, borderClass)}>
|
||||
<div className="flex justify-between items-center mb-2 select-none">
|
||||
<span className={cn('text-xs font-bold tracking-wider uppercase', colorClass)}>
|
||||
{title}
|
||||
</span>
|
||||
<CopyButton
|
||||
text={JSON.stringify(content)}
|
||||
className="h-6 w-6 rounded-md border text-muted-foreground"
|
||||
/>
|
||||
</div>
|
||||
<pre className="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">
|
||||
{content ? stringifyJson(content) : '无法解析'}
|
||||
</pre>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -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 (
|
||||
<div className={cn('p-4 rounded-xl border shadow-sm', containerClassName)}>
|
||||
<div className="flex justify-between items-center mb-2 select-none">
|
||||
<span className={cn('text-xs font-bold tracking-wider uppercase', titleClassName)}>
|
||||
{title}
|
||||
</span>
|
||||
<CopyButton text={copyText} className="h-6 w-6 rounded-md border text-muted-foreground" />
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -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 (
|
||||
<div className="flex flex-col gap-4">
|
||||
{JWT_SECTION_CONFIG.map(({ contentKey, title, colorClass, bgClass, borderClass }) => {
|
||||
const content = result[contentKey];
|
||||
|
||||
return (
|
||||
<JwtCopyBlock
|
||||
key={contentKey}
|
||||
title={title}
|
||||
copyText={JSON.stringify(content)}
|
||||
titleClassName={colorClass}
|
||||
containerClassName={cn('border-solid', bgClass, borderClass)}
|
||||
>
|
||||
<pre className={JWT_JSON_CONTENT_CLASS}>
|
||||
{content ? stringifyJson(content) : '无法解析'}
|
||||
</pre>
|
||||
</JwtCopyBlock>
|
||||
);
|
||||
})}
|
||||
|
||||
<JwtCopyBlock
|
||||
title={JWT_SIGNATURE_SECTION.title}
|
||||
copyText={result.signature || ''}
|
||||
titleClassName={JWT_SIGNATURE_SECTION.titleClassName}
|
||||
containerClassName={JWT_SIGNATURE_SECTION.containerClassName}
|
||||
>
|
||||
<span className={JWT_TEXT_CONTENT_CLASS}>
|
||||
{result.signature || JWT_SIGNATURE_SECTION.emptyLabel}
|
||||
</span>
|
||||
</JwtCopyBlock>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -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';
|
||||
+5
-45
@@ -1,19 +1,17 @@
|
||||
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 (
|
||||
<div className="p-4 w-full flex flex-col space-y-4 select-none">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="p-4 w-full flex flex-col gap-4 select-none">
|
||||
<TextInputArea
|
||||
minRows={5}
|
||||
maxRows={10}
|
||||
placeholder={'在此粘贴 JWT 令牌 (Encoded JWT)...'}
|
||||
placeholder={JWT_INPUT_PLACEHOLDER}
|
||||
value={jwtInput}
|
||||
onChange={handleChange}
|
||||
allowCopy={true}
|
||||
@@ -22,45 +20,7 @@ export default function Index() {
|
||||
onClear={handleClear}
|
||||
/>
|
||||
|
||||
{result && !result.error && (
|
||||
<div className="flex flex-col gap-4">
|
||||
<JwtSection
|
||||
title={'HEADER: 算法 & 令牌类型'}
|
||||
content={result.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"
|
||||
/>
|
||||
|
||||
<JwtSection
|
||||
title={'PAYLOAD: 数据'}
|
||||
content={result.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"
|
||||
/>
|
||||
|
||||
<div className="p-4 rounded-xl border border-border bg-secondary/40 shadow-sm">
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<span className="text-xs font-bold tracking-wider text-muted-foreground/90 uppercase">
|
||||
{'签名'}
|
||||
</span>
|
||||
<CopyButton
|
||||
text={result.signature || ''}
|
||||
className="h-6 w-6 rounded-md border text-muted-foreground"
|
||||
/>
|
||||
</div>
|
||||
<span className="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">
|
||||
{result.signature || '无签名'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{result?.error && (
|
||||
<EmptyPlaceholder className="p-6 min-h-0">{'无效的 JSON 格式'}</EmptyPlaceholder>
|
||||
)}
|
||||
</div>
|
||||
{result && !result.error && <JwtResultView result={result} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user