创建项目
首先,确保您的系统已安装Node.js。然后使用npm全局安装pnpm和yggjs_react:
bash
npm install -g pnpm
npm install -g yggjs_react
创建项目:
bash
ggr create hello
启动服务:
bash
cd hello
pnpm install --registry=https://registry.npmmirror.com
pnpm dev
整合rlayout
安装依赖:
bash
pnpm add react-router-dom
pnpm add yggjs_rlayout
效果预览
首页

文档页面

关于页面

完整代码
package.json
json
{
"name": "hello",
"private": true,
"version": "0.0.0",
"type": "module",
"packageManager": "pnpm@8.15.0",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^6.30.1",
"yggjs_rlayout": "^0.1.1",
"zustand": "^5.0.1"
},
"devDependencies": {
"@types/react": "^18.3.23",
"@types/react-dom": "^18.3.7",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
"@vitejs/plugin-react": "^4.3.4",
"eslint": "^8.57.1",
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-react-refresh": "^0.4.14",
"typescript": "^5.9.2",
"vite": "^4.5.14"
},
"pnpm": {
"registry": "https://registry.npmmirror.com"
}
}
tsconfig.json
json
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": [
"ES2020",
"DOM",
"DOM.Iterable"
],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": [
"src"
],
"references": [
{
"path": "./tsconfig.node.json"
}
]
}
tsconfig.node.json
json
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": [
"vite.config.ts"
]
}
vite.config.ts
ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
})
index.html
html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
.npmrc
bash
# 使用国内镜像源加速包下载
registry=https://registry.npmmirror.com
# React 相关包的镜像源
@types:registry=https://registry.npmmirror.com
@typescript-eslint:registry=https://registry.npmmirror.com
@vitejs:registry=https://registry.npmmirror.com
# 禁用包锁定文件的自动更新
package-lock=false
# 设置缓存目录
cache-dir=.pnpm-cache
# 启用严格的 peer dependencies 检查
strict-peer-dependencies=false
# 设置网络超时时间
network-timeout=60000
# 启用进度条
progress=true
# 禁用工作区模式,强制在当前目录安装依赖
ignore-workspace=true
src/main.tsx
tsx
import React from "react";
import { createRoot } from "react-dom/client";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Layout from "./pages/Layout";
import Dashboard from "./pages/Dashboard";
import Docs from "./pages/Docs";
import About from "./pages/About";
import "./styles.css";
const root = createRoot(document.getElementById("root")!);
root.render(
<React.StrictMode>
<BrowserRouter
future={{ v7_startTransition: true, v7_relativeSplatPath: true }}
>
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Dashboard />} />
<Route path="docs" element={<Docs />} />
<Route path="docs/api" element={<Docs />} />
<Route path="about" element={<About />} />
</Route>
</Routes>
</BrowserRouter>
</React.StrictMode>
);
src/styles.css
css
:root {
--bg: #0b1020;
--panel: #121a36;
--card: #111a2a;
--text: #cfe4ff;
--muted: #7aa2ff;
--primary: #2fd7ff;
--accent: #7c4dff;
--grid: #0e1630;
--box: #1d284b;
}
* {
box-sizing: border-box;
}
html,
body,
#root {
height: 100%;
}
body {
margin: 0;
font-family: Inter, system-ui, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
background: radial-gradient(70% 70% at 50% 0%, #0e1938 0%, #070b1a 100%);
color: var(--text);
}
.app {
padding: 24px;
}
.hero {
padding: 32px;
border: 1px solid #223066;
background: linear-gradient(
135deg,
rgba(47, 215, 255, 0.06),
rgba(124, 77, 255, 0.06)
);
border-radius: 16px;
backdrop-filter: blur(6px);
}
.hero h1 {
margin: 0 0 8px;
color: var(--primary);
}
.hero p {
margin: 0;
color: var(--muted);
}
.nav-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 12px;
margin: 24px 0;
}
.card {
display: block;
padding: 14px 16px;
border-radius: 12px;
background: var(--card);
color: var(--text);
text-decoration: none;
border: 1px solid #1b2550;
transition: all 0.2s;
}
.card:hover {
transform: translateY(-2px);
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.25);
border-color: #2b3c7a;
}
.routes ul {
padding-left: 18px;
}
.routes a {
color: var(--primary);
}
.page {
padding: 24px;
}
.panel {
margin: 16px 0;
padding: 16px;
border-radius: 12px;
background: var(--panel);
border: 1px solid #1b2550;
}
.box {
padding: 12px 14px;
border-radius: 10px;
background: var(--box);
border: 1px solid #1b2550;
}
.chip {
padding: 6px 10px;
border-radius: 999px;
border: 1px solid #2a3a7a;
background: #0e1630;
color: var(--text);
cursor: pointer;
}
.chip.active {
background: linear-gradient(
135deg,
rgba(47, 215, 255, 0.18),
rgba(124, 77, 255, 0.18)
);
border-color: #3a54b6;
}
src/pages/Layout.tsx
tsx
import React from "react";
import { useLocation, Link, Outlet } from "react-router-dom";
import {
TechLayout,
TechButton,
TechUserCenter,
createBreadcrumb,
type TechMenuItem,
type TechUserCenterItem,
} from "yggjs_rlayout/tech";
// 创建 Link 适配器组件,匹配 LinkLikeComponent 接口
const LinkAdapter: React.FC<{
to: string;
className?: string;
children?: React.ReactNode;
}> = ({ to, className, children }) => {
return (
<Link to={to} className={className}>
{children}
</Link>
);
};
// 布局组件
export default function Layout() {
const location = useLocation();
// 头部菜单项 - 使用 to 属性进行 SPA 导航
const headerMenuItems: TechMenuItem[] = [
{ key: "dash", label: "面板", icon: "dashboard", to: "/" },
{ key: "docs", label: "文档", icon: "book", to: "/docs" },
{ key: "about", label: "关于", icon: "info", to: "/about" },
];
// 用户中心菜单项
const userCenterItems: TechUserCenterItem[] = [
{
key: "profile",
label: "个人资料",
icon: "profile",
onClick: () => alert("跳转到个人资料页面"),
},
{
key: "settings",
label: "账户设置",
icon: "settings",
onClick: () => alert("跳转到账户设置页面"),
},
{
key: "help",
label: "帮助中心",
icon: "help",
onClick: () => alert("跳转到帮助中心"),
},
{
key: "logout",
label: "退出登录",
icon: "logout",
danger: true,
onClick: () => {
if (confirm("确定要退出登录吗?")) {
alert("已退出登录");
}
},
},
];
// 侧边栏菜单项 - 使用 to 属性进行 SPA 导航
const sidebarItems: TechMenuItem[] = [
{ key: "home", label: "首页", icon: "home", to: "/" },
{ key: "guide", label: "概览", icon: "guide", to: "/docs" },
{ key: "api", label: "接口文档", icon: "api", to: "/docs/api" },
{ key: "about", label: "关于", icon: "info", to: "/about" },
];
// 根据当前路径确定选中的菜单项
const selectedHeaderKey = location.pathname.startsWith("/docs")
? "docs"
: location.pathname.startsWith("/about")
? "about"
: "dash";
const selectedSidebarKey = location.pathname.startsWith("/docs/api")
? "api"
: location.pathname.startsWith("/docs")
? "guide"
: location.pathname.startsWith("/about")
? "about"
: "home";
// 处理搜索
const handleSearch = (value: string) => {
console.log("Search:", value);
if (value.trim()) {
alert(`正在搜索: "${value}"`);
}
};
// 处理菜单选中事件
const handleMenuSelect = (key: string) => {
console.log("Header menu selected:", key);
};
// 处理侧边栏选中事件
const handleSidebarSelect = (key: string) => {
console.log("Sidebar menu selected:", key);
};
// Footer配置
const footerSections = [
{
title: "产品",
links: [
{ label: "功能", href: "#features" },
{ label: "价格", href: "#pricing" },
{ label: "使用教程", href: "#docs", icon: "book" as const },
{ label: "接口文档", href: "#api", icon: "api" as const },
],
},
{
title: "企业",
links: [
{ label: "关于我们", href: "#about" },
{ label: "联系我们", href: "#contact" },
{ label: "赞助", href: "#careers" },
{ label: "博客", href: "#blog" },
],
},
{
title: "支持",
links: [
{ label: "用户中心", href: "#help" },
{ label: "社区", href: "#community" },
{ label: "状态", href: "#status" },
{ label: "反馈", href: "#feedback" },
],
},
];
// 社交连接
const socialLinks = [
{ label: "GitHub", href: "#github", icon: "api" as const },
{ label: "Twitter", href: "#twitter", icon: "info" as const },
{ label: "Discord", href: "#discord", icon: "guide" as const },
];
// 创建面包屑导航(简约版不需要图标)
const breadcrumbItems = createBreadcrumb()
.add("Dashboard", "/")
.add("SPA 导航演示")
.build();
return (
<TechLayout
// Header配置
brand="YGG Admin"
headerMenuItems={headerMenuItems}
selectedHeaderKey={selectedHeaderKey}
onHeaderMenuSelect={handleMenuSelect}
onSearch={handleSearch}
headerExtra={
<TechUserCenter
username="张三"
userInfo="zhangsan@example.com"
items={userCenterItems}
showUsername={false}
onAvatarClick={() => console.log("Avatar clicked")}
/>
}
version="v0.1.0"
// Sidebar配置
sidebarItems={sidebarItems}
selectedSidebarKey={selectedSidebarKey}
onSidebarSelect={handleSidebarSelect}
// SPA 导航配置 - 关键配置
headerMenuLinkComponent={LinkAdapter}
sidebarLinkComponent={LinkAdapter}
// Footer配置
footerProps={{
description:
"YGG Admin 是一个现代化的科技风管理后台框架,提供完整的布局解决方案和组件库。",
sections: footerSections,
socialLinks: socialLinks,
copyright: "© 2024 YGG Admin. All rights reserved.",
}}
// 页面头部
breadcrumb={breadcrumbItems}
title="YGG RLayout - 快速构建科技风后台管理系统模板"
pageActions={
<>
<TechButton variant="secondary">新建</TechButton>
<TechButton variant="primary" icon="deploy">
部署
</TechButton>
</>
}
>
{/* 渲染子路由内容 */}
<Outlet />
</TechLayout>
);
}
src/pages/Dashboard.tsx
tsx
import { TechCard, TechButton } from "yggjs_rlayout/tech";
export default function Dashboard() {
return (
<div>
<h1 style={{ color: "var(--tech-text)", marginBottom: "24px" }}>
面板
</h1>
<div className="tech-cards">
<TechCard
title="系统概览"
subtitle="当前系统运行状态"
icon="dashboard"
variant="default"
hoverable
>
<div style={{ padding: "16px 0" }}>
<div
style={{
display: "grid",
gridTemplateColumns: "repeat(auto-fit, minmax(120px, 1fr))",
gap: "16px",
}}
>
<div style={{ textAlign: "center" }}>
<div
style={{
fontSize: "24px",
fontWeight: "bold",
color: "var(--tech-accent)",
}}
>
1,234
</div>
<div
style={{ fontSize: "12px", color: "var(--tech-text-muted)" }}
>
总用户数
</div>
</div>
<div style={{ textAlign: "center" }}>
<div
style={{
fontSize: "24px",
fontWeight: "bold",
color: "var(--tech-accent)",
}}
>
567
</div>
<div
style={{ fontSize: "12px", color: "var(--tech-text-muted)" }}
>
活跃用户
</div>
</div>
<div style={{ textAlign: "center" }}>
<div
style={{
fontSize: "24px",
fontWeight: "bold",
color: "var(--tech-accent)",
}}
>
89%
</div>
<div
style={{ fontSize: "12px", color: "var(--tech-text-muted)" }}
>
系统负载
</div>
</div>
</div>
</div>
</TechCard>
<TechCard
title="快速操作"
subtitle="常用功能快捷入口"
icon="deploy"
variant="glass"
hoverable
actions={
<>
<TechButton variant="ghost" size="small">
查看更多
</TechButton>
<TechButton variant="primary" size="small">
立即操作
</TechButton>
</>
}
>
<div
style={{
display: "flex",
gap: "12px",
flexWrap: "wrap",
padding: "16px 0",
}}
>
<TechButton variant="secondary" size="small" icon="user">
用户管理
</TechButton>
<TechButton variant="secondary" size="small" icon="settings">
系统设置
</TechButton>
<TechButton variant="secondary" size="small" icon="api">
API 配置
</TechButton>
</div>
</TechCard>
<TechCard
title="最近活动"
subtitle="系统最新动态"
icon="guide"
variant="outlined"
hoverable
>
<div style={{ padding: "16px 0" }}>
<div
style={{
fontSize: "14px",
color: "var(--tech-text-muted)",
lineHeight: 1.6,
}}
>
<div style={{ marginBottom: "8px" }}>
• 用户 张三 登录系统 (2分钟前)
</div>
<div style={{ marginBottom: "8px" }}>
• 系统配置已更新 (15分钟前)
</div>
<div style={{ marginBottom: "8px" }}>
• 新增 3 个用户 (1小时前)
</div>
<div>• 数据备份完成 (2小时前)</div>
</div>
</div>
</TechCard>
</div>
<div style={{ marginTop: "32px" }}>
<h2 style={{ color: "var(--tech-text)", marginBottom: "16px" }}>
SPA 导航演示说明
</h2>
<TechCard
title="Link/to 导航功能"
subtitle="基于 react-router-dom 的单页应用导航"
icon="guide"
variant="filled"
hoverable
>
<div style={{ padding: "16px 0" }}>
<p
style={{
color: "var(--tech-text-muted)",
margin: "0 0 16px 0",
fontSize: "14px",
lineHeight: 1.5,
}}
>
这个演示展示了如何在 YGG Admin 中使用 Link/to 进行 SPA 导航:
</p>
<ul
style={{
color: "var(--tech-text-muted)",
fontSize: "14px",
margin: 0,
paddingLeft: "20px",
lineHeight: 1.6,
}}
>
<li>
头部菜单和侧边栏菜单都使用 <code>to</code> 属性而不是{" "}
<code>href</code>
</li>
<li>
通过 <code>linkComponent</code> 属性传入 react-router-dom 的
Link 组件
</li>
<li>页面切换无需刷新,保持 SPA 体验</li>
<li>URL 会正确更新,支持浏览器前进后退</li>
<li>菜单项会根据当前路由自动高亮显示</li>
</ul>
</div>
</TechCard>
<br />
</div>
</div>
);
}
src/pages/About.tsx
tsx
import { TechCard, TechButton } from 'yggjs_rlayout/tech';
export default function About() {
return (
<div>
<h1 style={{ color: 'var(--tech-text)', marginBottom: '24px' }}>
关于 YGG Admin
</h1>
<div className="tech-cards">
<TechCard
title="项目介绍"
subtitle="现代化的科技风管理后台框架"
icon="info"
variant="default"
hoverable
>
<div style={{ padding: '16px 0' }}>
<p style={{ color: 'var(--tech-text-muted)', margin: '0 0 16px 0', fontSize: '14px', lineHeight: 1.5 }}>
YGG Admin 是一个基于 React 的现代化管理后台组件库,
专注于提供科技感十足的用户界面和完整的布局解决方案。
</p>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: '16px', marginTop: '20px' }}>
<div style={{ textAlign: 'center', padding: '16px', background: 'rgba(90, 162, 255, 0.05)', borderRadius: '8px' }}>
<div style={{ fontSize: '20px', fontWeight: 'bold', color: 'var(--tech-accent)', marginBottom: '8px' }}>🚀</div>
<div style={{ fontSize: '14px', color: 'var(--tech-text)' }}>现代化设计</div>
</div>
<div style={{ textAlign: 'center', padding: '16px', background: 'rgba(90, 162, 255, 0.05)', borderRadius: '8px' }}>
<div style={{ fontSize: '20px', fontWeight: 'bold', color: 'var(--tech-accent)', marginBottom: '8px' }}>⚡</div>
<div style={{ fontSize: '14px', color: 'var(--tech-text)' }}>高性能</div>
</div>
<div style={{ textAlign: 'center', padding: '16px', background: 'rgba(90, 162, 255, 0.05)', borderRadius: '8px' }}>
<div style={{ fontSize: '20px', fontWeight: 'bold', color: 'var(--tech-accent)', marginBottom: '8px' }}>🎨</div>
<div style={{ fontSize: '14px', color: 'var(--tech-text)' }}>科技风格</div>
</div>
</div>
</div>
</TechCard>
<TechCard
title="核心特性"
subtitle="为现代 Web 应用而生"
icon="deploy"
variant="glass"
hoverable
>
<div style={{ padding: '16px 0' }}>
<ul style={{ color: 'var(--tech-text-muted)', fontSize: '14px', margin: 0, paddingLeft: '20px', lineHeight: 1.8 }}>
<li><strong>完整布局方案</strong> - TechLayout 提供头部、侧边栏、面包屑等完整功能</li>
<li><strong>SPA 路由支持</strong> - 原生支持 react-router-dom 的 Link 组件</li>
<li><strong>科技风设计</strong> - 渐变背景、发光效果、毛玻璃质感</li>
<li><strong>响应式布局</strong> - 适配桌面端和移动端</li>
<li><strong>主题定制</strong> - 通过 CSS 变量轻松定制主题</li>
<li><strong>TypeScript</strong> - 完整的类型定义支持</li>
</ul>
</div>
</TechCard>
<TechCard
title="技术栈"
subtitle="基于现代前端技术构建"
icon="api"
variant="outlined"
hoverable
>
<div style={{ padding: '16px 0' }}>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(120px, 1fr))', gap: '12px' }}>
{[
{ name: 'React 18', color: '#61DAFB' },
{ name: 'TypeScript', color: '#3178C6' },
{ name: 'Vite', color: '#646CFF' },
{ name: 'CSS Variables', color: '#1572B6' },
{ name: 'React Router', color: '#CA4245' },
{ name: 'Vitest', color: '#6E9F18' }
].map(tech => (
<div key={tech.name} style={{
padding: '12px 8px',
background: `${tech.color}15`,
border: `1px solid ${tech.color}30`,
borderRadius: '6px',
textAlign: 'center'
}}>
<div style={{ fontSize: '12px', color: tech.color, fontWeight: 'bold' }}>
{tech.name}
</div>
</div>
))}
</div>
</div>
</TechCard>
</div>
<div style={{ marginTop: '32px' }}>
<h2 style={{ color: 'var(--tech-text)', marginBottom: '16px' }}>
开始使用
</h2>
<TechCard
title="安装和使用"
subtitle="快速集成到你的项目中"
icon="guide"
variant="filled"
hoverable
actions={
<>
<TechButton variant="ghost" size="small">查看文档</TechButton>
<TechButton variant="primary" size="small">立即开始</TechButton>
</>
}
>
<div style={{ padding: '16px 0' }}>
<pre style={{
background: 'rgba(0,0,0,0.3)',
padding: '16px',
borderRadius: '8px',
color: 'var(--tech-text)',
fontSize: '13px',
lineHeight: 1.5,
overflow: 'auto',
margin: '0 0 16px 0'
}}>
{`# 安装
npm install yggjs_rlayout
# 使用
import { TechLayout } from 'yggjs_rlayout/tech';
function App() {
return (
<TechLayout brand="Your App">
{/* 你的内容 */}
</TechLayout>
);
}`}
</pre>
<p style={{ color: 'var(--tech-text-muted)', margin: 0, fontSize: '14px', lineHeight: 1.5 }}>
这个演示页面展示了 SPA 导航的完整实现,
点击头部和侧边栏的菜单项体验无刷新页面切换。
</p>
</div>
</TechCard>
<br />
</div>
</div>
);
}