This commit is contained in:
sunzhongyi
2026-05-19 21:09:56 +08:00
commit f3e6b95be9
78 changed files with 10099 additions and 0 deletions
+43
View File
@@ -0,0 +1,43 @@
'use client';
import { useState } from 'react';
interface CodeBlockProps {
code: string;
language?: string;
title?: string;
}
export function CodeBlock({ code, language = 'tsx', title }: CodeBlockProps) {
const [copied, setCopied] = useState(false);
const handleCopy = async () => {
await navigator.clipboard.writeText(code);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
return (
<div className="my-4 rounded-lg overflow-hidden border border-gray-200">
{title && (
<div className="bg-gray-50 px-4 py-2 border-b border-gray-200 flex justify-between items-center">
<span className="text-sm font-medium text-gray-700">{title}</span>
<span className="text-xs text-gray-500">{language}</span>
</div>
)}
<div className="relative">
<button
onClick={handleCopy}
className="absolute top-2 right-2 px-3 py-1 text-xs bg-gray-700 hover:bg-gray-600 text-white rounded"
>
{copied ? '已复制' : '复制'}
</button>
<pre className="p-4 bg-gray-900 text-gray-100 overflow-x-auto">
<code>{code}</code>
</pre>
</div>
</div>
);
}
+50
View File
@@ -0,0 +1,50 @@
'use client';
import { useState } from 'react';
interface DemoProps {
title: string;
description?: string;
code?: string;
children: React.ReactNode;
}
export function Demo({ title, description, code, children }: DemoProps) {
const [showCode, setShowCode] = useState(false);
return (
<div className="my-8 border border-gray-200 rounded-lg overflow-hidden">
<div className="bg-gray-50 px-4 py-3 border-b border-gray-200">
<h3 className="text-lg font-semibold text-gray-900">{title}</h3>
{description && (
<p className="mt-1 text-sm text-gray-600">{description}</p>
)}
</div>
<div className="p-6 bg-white">
{children}
</div>
{code && (
<>
<div className="border-t border-gray-200 px-4 py-2 bg-gray-50">
<button
onClick={() => setShowCode(!showCode)}
className="text-sm font-medium text-gray-700 hover:text-gray-900"
>
{showCode ? '隐藏代码' : '查看代码'}
</button>
</div>
{showCode && (
<div className="border-t border-gray-200">
<pre className="p-4 bg-gray-900 text-gray-100 overflow-x-auto text-sm">
<code>{code}</code>
</pre>
</div>
)}
</>
)}
</div>
);
}
+51
View File
@@ -0,0 +1,51 @@
interface PropDefinition {
name: string;
type: string;
default?: string;
description: string;
required?: boolean;
}
interface PropsTableProps {
data: PropDefinition[];
}
export function PropsTable({ data }: PropsTableProps) {
return (
<div className="my-6 overflow-x-auto">
<table className="w-full border-collapse">
<thead>
<tr className="border-b-2 border-gray-300">
<th className="text-left py-3 px-4 font-semibold text-gray-900"></th>
<th className="text-left py-3 px-4 font-semibold text-gray-900"></th>
<th className="text-left py-3 px-4 font-semibold text-gray-900"></th>
<th className="text-left py-3 px-4 font-semibold text-gray-900"></th>
</tr>
</thead>
<tbody>
{data.map((prop) => (
<tr key={prop.name} className="border-b border-gray-200">
<td className="py-3 px-4">
<code className="text-sm bg-gray-100 px-2 py-1 rounded">
{prop.name}
{prop.required && <span className="text-red-500 ml-1">*</span>}
</code>
</td>
<td className="py-3 px-4">
<code className="text-sm text-blue-600">{prop.type}</code>
</td>
<td className="py-3 px-4">
{prop.default ? (
<code className="text-sm bg-gray-100 px-2 py-1 rounded">{prop.default}</code>
) : (
<span className="text-gray-400">-</span>
)}
</td>
<td className="py-3 px-4 text-sm text-gray-700">{prop.description}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
+96
View File
@@ -0,0 +1,96 @@
'use client';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
interface NavItem {
title: string;
href: string;
items?: NavItem[];
}
const navigation: NavItem[] = [
{
title: '概览',
href: '/',
},
{
title: '栅格系统',
href: '/grid-system',
},
{
title: '核心组件',
href: '/components',
items: [
{ title: 'Article', href: '/components/article' },
{ title: 'Layer', href: '/components/layer' },
{ title: '媒体组件', href: '/components/media' },
],
},
{
title: '文本组件',
href: '/text',
},
{
title: '主题系统',
href: '/theme',
},
{
title: '示例',
href: '/examples',
items: [
{ title: '跨栏布局', href: '/examples/spanning' },
{ title: '响应式布局', href: '/examples/responsive' },
],
},
];
export function Sidebar() {
const pathname = usePathname();
return (
<nav className="w-64 border-r border-gray-200 bg-white h-screen sticky top-0 overflow-y-auto">
<div className="p-6">
<Link href="/" className="text-xl font-bold text-gray-900">
NewspaperUI
</Link>
<p className="mt-1 text-sm text-gray-600"></p>
</div>
<div className="px-4 pb-6">
{navigation.map((item) => (
<div key={item.href} className="mb-4">
<Link
href={item.href}
className={`block px-3 py-2 rounded-md text-sm font-medium ${
pathname === item.href
? 'bg-gray-100 text-gray-900'
: 'text-gray-700 hover:bg-gray-50'
}`}
>
{item.title}
</Link>
{item.items && (
<div className="ml-4 mt-2 space-y-1">
{item.items.map((subItem) => (
<Link
key={subItem.href}
href={subItem.href}
className={`block px-3 py-2 rounded-md text-sm ${
pathname === subItem.href
? 'bg-gray-100 text-gray-900'
: 'text-gray-600 hover:bg-gray-50'
}`}
>
{subItem.title}
</Link>
))}
</div>
)}
</div>
))}
</div>
</nav>
);
}