diff --git a/blog.config.js b/blog.config.js
index ed0721cc..3b827a95 100644
--- a/blog.config.js
+++ b/blog.config.js
@@ -127,7 +127,8 @@ const BLOG = {
'/[prefix]/[slug]/[...suffix]': 'LayoutSlug',
'/auth/result': 'LayoutAuth',
'/sign-in/[[...index]]': 'LayoutSignIn',
- '/sign-up/[[...index]]': 'LayoutSignUp'
+ '/sign-up/[[...index]]': 'LayoutSignUp',
+ '/dashboard/[[...index]]': 'LayoutDashboard'
},
CAN_COPY: process.env.NEXT_PUBLIC_CAN_COPY || true, // 是否允许复制页面内容 默认允许,如果设置为false、则全栈禁止复制内容。
@@ -252,7 +253,7 @@ const BLOG = {
],
// 鼠标跟随特效
- MOUSE_FOLLOW: process.env.NEXT_PUBLIC_MOUSE_FOLLOW || true, // 开关
+ MOUSE_FOLLOW: process.env.NEXT_PUBLIC_MOUSE_FOLLOW || false, // 开关
// 这两个只有在鼠标跟随特效开启时才生效
// 鼠标类型 1:路劲散点 2:下降散点 3:上升散点 4:边缘向鼠标移动散点 5:跟踪转圈散点 6:路径线条 7:聚集散点 8:聚集网格 9:移动网格 10:上升粒子 11:转圈随机颜色粒子 12:圆锥放射跟随蓝色粒子
MOUSE_FOLLOW_EFFECT_TYPE: 11, // 1-12
@@ -551,7 +552,9 @@ const BLOG = {
VERSION: (() => {
try {
// 优先使用环境变量,否则从package.json中获取版本号
- return process.env.NEXT_PUBLIC_VERSION || require('./package.json').version
+ return (
+ process.env.NEXT_PUBLIC_VERSION || require('./package.json').version
+ )
} catch (error) {
console.warn('Failed to load package.json version:', error)
return '1.0.0' // 缺省版本号
diff --git a/components/ui/dashboard/DashboardBody.js b/components/ui/dashboard/DashboardBody.js
new file mode 100644
index 00000000..89b60329
--- /dev/null
+++ b/components/ui/dashboard/DashboardBody.js
@@ -0,0 +1,51 @@
+'use client'
+import { UserProfile } from '@clerk/nextjs'
+import dynamic from 'next/dynamic'
+import { useRouter } from 'next/router'
+
+const DashboardMenuList = dynamic(() => import('./DashboardMenuList'))
+const DashboardItemMembership = dynamic(
+ () => import('./DashboardItemMembership')
+)
+const DashboardItemBalance = dynamic(() => import('./DashboardItemBalance'))
+const DashboardItemHome = dynamic(() => import('./DashboardItemHome'))
+const DashboardItemOrder = dynamic(() => import('./DashboardItemOrder'))
+const DashboardItemAffliate = dynamic(() => import('./DashboardItemAffliate'))
+/**
+ * 仪表盘内容主体
+ * 组件懒加载
+ * @returns
+ */
+export default function DashboardBody() {
+ const { asPath } = useRouter()
+ // 提取不包含查询参数的路径部分
+ const basePath = asPath.split('?')[0]
+ return (
+
+
+
+
+
+ {basePath === '/dashboard' && }
+ {(basePath === '/dashboard/user-profile' ||
+ basePath === '/dashboard/user-profile/security') && (
+
+ )}
+ {basePath === '/dashboard/balance' && }
+ {basePath === '/dashboard/membership' && }
+ {basePath === '/dashboard/order' && }
+ {basePath === '/dashboard/affiliate' && }
+
+
+ )
+}
diff --git a/components/ui/dashboard/DashboardButton.js b/components/ui/dashboard/DashboardButton.js
new file mode 100644
index 00000000..5f382f1a
--- /dev/null
+++ b/components/ui/dashboard/DashboardButton.js
@@ -0,0 +1,27 @@
+import { siteConfig } from '@/lib/config'
+import Link from 'next/link'
+import { useRouter } from 'next/router'
+/**
+ * 跳转仪表盘的按钮
+ * @returns
+ */
+export default function DashboardButton() {
+ const { asPath } = useRouter()
+ const enableDashboardButton = siteConfig('ENABLE_DASHBOARD_BUTTON', false)
+
+ if (!enableDashboardButton) {
+ return null
+ }
+
+ if (asPath?.indexOf('/dashboard') === 0) {
+ return null
+ }
+
+ return (
+
+ )
+}
diff --git a/components/ui/dashboard/DashboardHeader.js b/components/ui/dashboard/DashboardHeader.js
new file mode 100644
index 00000000..7542eea1
--- /dev/null
+++ b/components/ui/dashboard/DashboardHeader.js
@@ -0,0 +1,53 @@
+import LazyImage from '@/components/LazyImage'
+import { useGlobal } from '@/lib/global'
+import formatDate from '@/lib/utils/formatDate'
+import { SignOutButton } from '@clerk/nextjs'
+import Link from 'next/link'
+/**
+ * 仪表盘页头
+ * @returns
+ */
+export default function DashboardHeader() {
+ const { user } = useGlobal()
+
+ return (
+ <>
+
+ {/* 头像昵称 */}
+
+
+
+
+
+ {user?.fullName}
+
+
+ 普通用户
+
+
+
+
+ {user?.username}
+ {formatDate(user?.createdAt)}
+
+
+
+
+ {/* 登出按钮 */}
+
+
+
+
+
+
+ >
+ )
+}
diff --git a/components/ui/dashboard/DashboardItemAffliate.js b/components/ui/dashboard/DashboardItemAffliate.js
new file mode 100644
index 00000000..443e0ac7
--- /dev/null
+++ b/components/ui/dashboard/DashboardItemAffliate.js
@@ -0,0 +1,187 @@
+import Link from 'next/link'
+
+/**
+ * 联盟行销
+ * @returns
+ */
+export default function DashboardItemAffliate() {
+ const cards = [
+ {
+ title: '¥0.00',
+ desc: '累计佣金',
+ className: 'bg-blue-600 hover:bg-blue-700 text-white'
+ },
+ {
+ title: '¥0.00',
+ desc: '已提现',
+ className: 'bg-cyan-600 hover:bg-cyan-700 text-white'
+ },
+ {
+ title: '¥0.00',
+ desc: '提现中',
+ className: 'bg-pink-600 hover:bg-pink-700 text-white'
+ },
+ {
+ title: '¥0.00',
+ desc: '可提现',
+ className: 'bg-emerald-600 hover:bg-emerald-700 text-white'
+ }
+ ]
+
+ return (
+
+
+ {cards?.map((card, index) => (
+
+
+ {card.title}
+
+
{card.desc}
+
+ ))}
+
+
+
+ )
+}
diff --git a/components/ui/dashboard/DashboardItemBalance.js b/components/ui/dashboard/DashboardItemBalance.js
new file mode 100644
index 00000000..4c623f6e
--- /dev/null
+++ b/components/ui/dashboard/DashboardItemBalance.js
@@ -0,0 +1,137 @@
+import { useEffect, useState } from 'react'
+
+/**
+ * 余额
+ * @returns
+ */
+export default function DashboardItemBalance() {
+ const [selectedCard, setSelectedCard] = useState(null)
+ const [amount, setAmount] = useState(0)
+
+ const cards = [
+ {
+ title: '0 积分',
+ desc: '当前余额',
+ className: 'bg-blue-600 hover:bg-blue-700 text-white'
+ },
+ {
+ title: '0 积分',
+ desc: '累计消费',
+ className: 'bg-cyan-600 hover:bg-cyan-700 text-white'
+ },
+ {
+ title: '0',
+ desc: '累计佣金',
+ className: 'bg-pink-600 hover:bg-pink-700 text-white'
+ }
+ ]
+
+ const cardData = [
+ { points: '1积分', price: '¥1' },
+ { points: '10积分', price: '¥10' },
+ { points: '50积分', price: '¥50' },
+ { points: '100积分', price: '¥100' },
+ { points: '300积分', price: '¥300' },
+ { points: '500积分', price: '¥500' }
+ ]
+
+ const handleCardSelect = index => {
+ setSelectedCard(index)
+ }
+
+ const handleAmountChange = e => {
+ const value = e.target.value
+ setAmount(value)
+ }
+
+ useEffect(() => {
+ if (selectedCard !== null) {
+ // 如果用户选中了充值卡片,则自动更新支付金额
+ const selectedPrice = cardData[selectedCard]?.price
+ if (selectedPrice) {
+ setAmount(selectedPrice.replace('¥', ''))
+ }
+ }
+ }, [selectedCard])
+
+ return (
+
+
+
余额充值中心
+
+
+
+ {/* 余额卡片 */}
+
+ {cards?.map((card, index) => (
+
handleCardSelect(index)}>
+
+ {card.title}
+
+
{card.desc}
+
+ ))}
+
+
+
+
+ )
+}
diff --git a/components/ui/dashboard/DashboardItemHome.js b/components/ui/dashboard/DashboardItemHome.js
new file mode 100644
index 00000000..2988aec3
--- /dev/null
+++ b/components/ui/dashboard/DashboardItemHome.js
@@ -0,0 +1,64 @@
+/**
+ * 首页组件
+ * @returns
+ */
+export default function DashboardItemHome() {
+ return (
+
+ {/* 提示消息 */}
+
+ 注意!{' '}
+ 整个后台都只是页面效果,仅供演示查看,没有对接实际功能。
+
+
+ {/* 页面说明 */}
+
+
+ 欢迎来到用户中心页面!在这里,您可以查看用户的账号信息与业务订单概况。
+
+
+
+ {/* 进度条 */}
+
+
当前任务进度
+
+
+ 任务进度:75%
+
+
+
+ {/* 背景动画块 */}
+
+
+
+
实时数据分析
+
监控您的系统数据,查看实时变化
+
+
+
+ {/* 数据卡片模块 */}
+
+
+ )
+}
diff --git a/components/ui/dashboard/DashboardItemMembership.js b/components/ui/dashboard/DashboardItemMembership.js
new file mode 100644
index 00000000..ab0b61b9
--- /dev/null
+++ b/components/ui/dashboard/DashboardItemMembership.js
@@ -0,0 +1,125 @@
+import { useEffect, useState } from 'react'
+
+/**
+ * 会员
+ * @returns
+ */
+export default function DashboardItemMembership() {
+ const [selectedMembership, setSelectedMembership] = useState(null)
+ const [amount, setAmount] = useState(0)
+
+ const memberships = [
+ {
+ title: '年度会员',
+ points: 98,
+ duration: '365天',
+ benefits: [
+ '日更5到20个热门项目',
+ '全站资源免费获取',
+ '内部会员专属交流群',
+ '可补差价升级',
+ '推广佣金高达40%'
+ ]
+ },
+ {
+ title: '永久会员',
+ points: 138,
+ duration: '永久',
+ benefits: [
+ '日更5到20个热门项目',
+ '全站资源免费获取',
+ '内部会员专属交流群',
+ '可补差价升级',
+ '推广佣金高达70%'
+ ]
+ },
+ {
+ title: '站长训练营',
+ points: 1998,
+ duration: '永久',
+ benefits: [
+ '站长学员请联系助理对接',
+ '一对一扶持搭建网站',
+ '提供独家引流技术照做就能成功',
+ '全站素材直接复刻到学员新站',
+ '软件一键同步更新',
+ '学员专属社群及交流群',
+ '设立高额福利的打卡机制(增强学员执行力)'
+ ]
+ }
+ ]
+
+ const handleMembershipSelect = index => {
+ setSelectedMembership(index)
+ setAmount(memberships[index].points)
+ }
+
+ const handleAmountChange = e => {
+ const value = e.target.value
+ setAmount(value)
+ }
+
+ useEffect(() => {
+ if (selectedMembership !== null) {
+ // 如果用户选中了会员,自动更新支付金额
+ const selectedPoints = memberships[selectedMembership]?.points
+ if (selectedPoints) {
+ setAmount(selectedPoints)
+ }
+ }
+ }, [selectedMembership])
+
+ return (
+
+
+
会员注册
+
+
+
+ {/* 会员卡片 */}
+
+ {memberships.map((membership, index) => (
+
handleMembershipSelect(index)}>
+
+ {membership.title}
+
+
所需积分:{membership.points} 积分
+
会员时长:{membership.duration}
+
+ {membership.benefits.map((benefit, i) => (
+ - {benefit}
+ ))}
+
+
+ ))}
+
+
+
+
+ )
+}
diff --git a/components/ui/dashboard/DashboardItemOrder.js b/components/ui/dashboard/DashboardItemOrder.js
new file mode 100644
index 00000000..37acc466
--- /dev/null
+++ b/components/ui/dashboard/DashboardItemOrder.js
@@ -0,0 +1,246 @@
+import { useState } from 'react'
+
+/**
+ * 订单列表
+ */
+export default function DashboardItemOrder() {
+ const [currentPage, setCurrentPage] = useState(1)
+
+ const totalPages = 5
+
+ const columns = [
+ { key: 'name', label: '商品名称' },
+ { key: 'color', label: '颜色' },
+ { key: 'category', label: '分类' },
+ {
+ key: 'accessories',
+ label: '配件',
+ render: value => (value ? '是' : '否')
+ },
+ { key: 'available', label: '库存', render: value => (value ? '有' : '无') },
+ { key: 'price', label: '价格', render: value => `¥${value}` },
+ { key: 'weight', label: '重量' },
+ {
+ key: 'action',
+ label: '操作',
+ render: () => (
+
+ )
+ }
+ ]
+
+ const data = [
+ {
+ name: '苹果 MacBook Pro 17"',
+ color: '银色',
+ category: '笔记本',
+ accessories: true,
+ available: true,
+ price: 2999,
+ weight: '3.0 公斤'
+ },
+ {
+ name: '微软 Surface Pro',
+ color: '白色',
+ category: '笔记本电脑',
+ accessories: false,
+ available: true,
+ price: 1999,
+ weight: '1.0 公斤'
+ },
+ {
+ name: 'Magic Mouse 2',
+ color: '黑色',
+ category: '配件',
+ accessories: true,
+ available: false,
+ price: 99,
+ weight: '0.2 公斤'
+ },
+ {
+ name: '苹果手表',
+ color: '黑色',
+ category: '手表',
+ accessories: true,
+ available: false,
+ price: 199,
+ weight: '0.12 公斤'
+ },
+ {
+ name: 'iPad Pro',
+ color: '金色',
+ category: '平板电脑',
+ accessories: false,
+ available: true,
+ price: 699,
+ weight: '1.3 公斤'
+ }
+ ]
+
+ const onPageChange = page => {
+ if (page >= 1 && page <= totalPages) {
+ setCurrentPage(page)
+ }
+ }
+
+ return (
+
+
+
+
+
+ - 订单说明:
+ - 这只是一个演示页面,不存在真实功能!
+
+
+
+ )
+}
+
+/**
+ * 分页组件
+ */
+const Pagination = ({ currentPage, totalPages, onPageChange }) => {
+ const pages = Array.from({ length: totalPages }, (_, i) => i + 1)
+
+ return (
+
+ )
+}
+
+/**
+ * 表格组件
+ */
+const Table = ({ columns, data }) => {
+ return (
+
+ )
+}
diff --git a/components/ui/dashboard/DashboardMenuList.js b/components/ui/dashboard/DashboardMenuList.js
new file mode 100644
index 00000000..b0ffed2a
--- /dev/null
+++ b/components/ui/dashboard/DashboardMenuList.js
@@ -0,0 +1,57 @@
+import Link from 'next/link'
+
+/**
+ * 仪表盘菜单
+ * @returns
+ */
+import { useRouter } from 'next/router'
+
+/**
+ * 仪表盘菜单
+ * @returns
+ */
+export default function DashboardMenuList() {
+ const { asPath } = useRouter() // 获取当前路径
+ const dashBoardMenus = [
+ { title: '仪表盘', icon: 'fas fa-gauge', href: '/dashboard' },
+ { title: '基础资料', icon: 'fas fa-user', href: '/dashboard/user-profile' },
+ { title: '我的余额', icon: 'fas fa-coins', href: '/dashboard/balance' },
+ { title: '我的会员', icon: 'fas fa-gem', href: '/dashboard/membership' },
+ {
+ title: '我的订单',
+ icon: 'fas fa-cart-shopping',
+ href: '/dashboard/order'
+ },
+ {
+ title: '推广中心',
+ icon: 'fas fa-hand-holding-usd',
+ href: '/dashboard/affiliate'
+ }
+ ]
+
+ return (
+
+ {dashBoardMenus.map((item, index) => {
+ // 判断当前菜单是否高亮
+ const isActive = asPath === item.href
+ return (
+ -
+
+
+ {item.title}
+
+
+ )
+ })}
+
+ )
+}
diff --git a/lib/config.js b/lib/config.js
index be7815b7..b690c1ae 100644
--- a/lib/config.js
+++ b/lib/config.js
@@ -36,6 +36,7 @@ export const siteConfig = (key, defaultVal = null, extendConfig = {}) => {
case 'POST_URL_PREFIX_MAPPING_CATEGORY':
case 'IS_TAG_COLOR_DISTINGUISHED':
case 'TAG_SORT_BY_COUNT':
+ case 'THEME':
case 'LINK':
return convertVal(
getValue(extendConfig[key], getValue(defaultVal, BLOG[key]))
diff --git a/lib/utils/formatDate.js b/lib/utils/formatDate.js
index 29190e3b..c40a5135 100644
--- a/lib/utils/formatDate.js
+++ b/lib/utils/formatDate.js
@@ -1,22 +1,31 @@
+import BLOG from '@/blog.config'
+
/**
* 格式化日期
* @param date
* @param local
* @returns {string}
*/
-export default function formatDate (date, local) {
+export default function formatDate(date, local = BLOG.LANG) {
if (!date || !local) return date || ''
const d = new Date(date)
const options = { year: 'numeric', month: 'short', day: 'numeric' }
const res = d.toLocaleDateString(local, options)
// 如果格式是中文日期,则转为横杆
- const format = local.slice(0, 2).toLowerCase() === 'zh'
- ? res.replace('年', '-').replace('月', '-').replace('日', '')
- : res
+ const format =
+ local.slice(0, 2).toLowerCase() === 'zh'
+ ? res.replace('年', '-').replace('月', '-').replace('日', '')
+ : res
return format
}
-export function formatDateFmt (timestamp, fmt) {
+/**
+ * 时间戳格式化
+ * @param {*} timestamp
+ * @param {*} fmt
+ * @returns
+ */
+export function formatDateFmt(timestamp, fmt) {
const date = new Date(timestamp)
const o = {
'M+': date.getMonth() + 1, // 月份
@@ -28,11 +37,17 @@ export function formatDateFmt (timestamp, fmt) {
S: date.getMilliseconds() // 毫秒
}
if (/(y+)/.test(fmt)) {
- fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))
+ fmt = fmt.replace(
+ RegExp.$1,
+ (date.getFullYear() + '').substr(4 - RegExp.$1.length)
+ )
}
for (const k in o) {
if (new RegExp('(' + k + ')').test(fmt)) {
- fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)))
+ fmt = fmt.replace(
+ RegExp.$1,
+ RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)
+ )
}
}
return fmt.trim()
diff --git a/middleware.ts b/middleware.ts
index 0ae00a72..dc623d08 100644
--- a/middleware.ts
+++ b/middleware.ts
@@ -12,7 +12,9 @@ export const config = {
// 限制登录访问的路由
const isTenantRoute = createRouteMatcher([
'/user/organization-selector(.*)',
- '/user/orgid/(.*)'
+ '/user/orgid/(.*)',
+ '/dashboard',
+ '/dashboard/(.*)'
])
// 限制权限访问的路由
@@ -32,27 +34,35 @@ const noAuthMiddleware = async (req: any, ev: any) => {
// 如果没有配置 Clerk 相关环境变量,返回一个默认响应或者继续处理请求
return NextResponse.next()
}
-
/**
* 鉴权中间件
*/
const authMiddleware = process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
- ? clerkMiddleware(
- (auth, req) => {
- // 限制管理员路由访问权限
- if (isTenantAdminRoute(req)) {
- auth().protect(has => {
- return (
- has({ permission: 'org:sys_memberships:manage' }) ||
- has({ permission: 'org:sys_domains_manage' })
- )
- })
+ ? clerkMiddleware(async (auth, req) => {
+ const { userId } = auth()
+ // 处理 /dashboard 路由的登录保护
+ if (isTenantRoute(req)) {
+ if (!userId) {
+ // 用户未登录,重定向到 /sign-in
+ const url = new URL('/sign-in', req.url)
+ url.searchParams.set('redirectTo', req.url) // 保存重定向目标
+ return NextResponse.redirect(url)
}
- // 限制组织路由访问权限
- if (isTenantRoute(req)) auth().protect()
}
- // { debug: process.env.npm_lifecycle_event === 'dev' } // 开发调试模式打印日志
- )
+
+ // 处理管理员相关权限保护
+ if (isTenantAdminRoute(req)) {
+ auth().protect(has => {
+ return (
+ has({ permission: 'org:sys_memberships:manage' }) ||
+ has({ permission: 'org:sys_domains_manage' })
+ )
+ })
+ }
+
+ // 默认继续处理请求
+ return NextResponse.next()
+ })
: noAuthMiddleware
export default authMiddleware
diff --git a/next.config.js b/next.config.js
index 00d08665..585c5435 100644
--- a/next.config.js
+++ b/next.config.js
@@ -220,6 +220,7 @@ const nextConfig = {
// export 静态导出时 忽略/pages/sitemap.xml.js , 否则和getServerSideProps这个动态文件冲突
const pages = { ...defaultPathMap }
delete pages['/sitemap.xml']
+ delete pages['/auth']
return pages
},
publicRuntimeConfig: {
diff --git a/package.json b/package.json
index b27d0d6e..c71a1fdf 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "notion-next",
- "version": "4.7.9",
+ "version": "4.7.10",
"homepage": "https://github.com/tangly1024/NotionNext.git",
"license": "MIT",
"repository": {
diff --git a/pages/404.js b/pages/404.js
index 78278918..4c58031e 100644
--- a/pages/404.js
+++ b/pages/404.js
@@ -1,6 +1,7 @@
+import BLOG from '@/blog.config'
import { siteConfig } from '@/lib/config'
import { getGlobalData } from '@/lib/db/getSiteData'
-import { getLayoutByTheme } from '@/themes/theme'
+import { DynamicLayout } from '@/themes/theme'
import { useRouter } from 'next/router'
/**
@@ -9,12 +10,9 @@ import { useRouter } from 'next/router'
* @returns
*/
const NoFound = props => {
- // 根据页面路径加载不同Layout文件
- const Layout = getLayoutByTheme({
- theme: siteConfig('THEME'),
- router: useRouter()
- })
- return
+ const router = useRouter()
+ const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
+ return
}
export async function getStaticProps(req) {
diff --git a/pages/[prefix]/index.js b/pages/[prefix]/index.js
index 6b05f7f1..a6d6e82f 100644
--- a/pages/[prefix]/index.js
+++ b/pages/[prefix]/index.js
@@ -8,7 +8,7 @@ import { getPageTableOfContents } from '@/lib/notion/getPageTableOfContents'
import { getPasswordQuery } from '@/lib/password'
import { uploadDataToAlgolia } from '@/lib/plugins/algolia'
import { checkSlugHasNoSlash, getRecommendPost } from '@/lib/utils/post'
-import { getLayoutByTheme } from '@/themes/theme'
+import { DynamicLayout } from '@/themes/theme'
import md5 from 'js-md5'
import { useRouter } from 'next/router'
import { idToUuid } from 'notion-utils'
@@ -83,15 +83,11 @@ const Slug = props => {
}, [router, lock])
props = { ...props, lock, validPassword }
- // 根据页面路径加载不同Layout文件
- const Layout = getLayoutByTheme({
- theme: siteConfig('THEME'),
- router: useRouter()
- })
+ const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
return (
<>
{/* 文章布局 */}
-
+
{/* 解锁密码提示框 */}
{post?.password && post?.password !== '' && !lock && }
{/* 导流工具 */}
diff --git a/pages/_app.js b/pages/_app.js
index e363b090..12002916 100644
--- a/pages/_app.js
+++ b/pages/_app.js
@@ -45,7 +45,6 @@ const MyApp = ({ Component, pageProps }) => {
// 整体布局
const GLayout = useCallback(
props => {
- // 根据页面路径加载不同Layout文件
const Layout = getGlobalLayoutByTheme(queryParam)
return
},
diff --git a/pages/archive/index.js b/pages/archive/index.js
index beecf79c..968803ee 100644
--- a/pages/archive/index.js
+++ b/pages/archive/index.js
@@ -3,17 +3,16 @@ import { siteConfig } from '@/lib/config'
import { getGlobalData } from '@/lib/db/getSiteData'
import { isBrowser } from '@/lib/utils'
import { formatDateFmt } from '@/lib/utils/formatDate'
-import { getLayoutByTheme } from '@/themes/theme'
+import { DynamicLayout } from '@/themes/theme'
import { useRouter } from 'next/router'
import { useEffect } from 'react'
+/**
+ * 归档首页
+ * @param {*} props
+ * @returns
+ */
const ArchiveIndex = props => {
- // 根据页面路径加载不同Layout文件
- const Layout = getLayoutByTheme({
- theme: siteConfig('THEME'),
- router: useRouter()
- })
-
useEffect(() => {
if (isBrowser) {
const anchor = window.location.hash
@@ -28,7 +27,9 @@ const ArchiveIndex = props => {
}
}, [])
- return
+ const router = useRouter()
+ const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
+ return
}
export async function getStaticProps({ locale }) {
diff --git a/pages/auth/index.js b/pages/auth/index.js
new file mode 100644
index 00000000..cce744d9
--- /dev/null
+++ b/pages/auth/index.js
@@ -0,0 +1,101 @@
+// pages/sitemap.xml.js
+import { getGlobalData } from '@/lib/db/getSiteData'
+import axios from 'axios'
+import { useRouter } from 'next/router'
+import { useEffect } from 'react'
+import Slug from '../[prefix]'
+
+/**
+ * 根据notion的slug访问页面
+ * 解析二级目录 /article/about
+ * @param {*} props
+ * @returns
+ */
+const UI = props => {
+ const { redirect_pathname, redirect_query } = props
+ const router = useRouter()
+ useEffect(() => {
+ router?.push({ pathname: redirect_pathname, query: redirect_query })
+ }, [])
+ return
+}
+
+/**
+ * 服务端接收参数处理
+ * @param {*} ctx
+ * @returns
+ */
+export const getServerSideProps = async ctx => {
+ const from = `auth`
+ const props = await getGlobalData({ from })
+ delete props.allPages
+ const code = ctx.query.code
+
+ let params = null
+ if (code) {
+ params = await fetchToken(code)
+ }
+
+ // 授权成功的划保存下用户的workspace信息
+ if (params?.status === 200) {
+ console.log('请求成功', params)
+ props.redirect_query = {
+ ...params.data,
+ msg: '成功了' + JSON.stringify(params.data)
+ }
+ console.log('用户信息', JSON.stringify(params.data))
+ } else if (!params) {
+ console.log('请求异常', params)
+ props.redirect_query = { msg: '无效请求' }
+ } else {
+ console.log('请求失败', params)
+ props.redirect_query = { msg: params.statusText }
+ }
+
+ props.redirect_pathname = '/auth/result'
+
+ return {
+ props
+ }
+}
+
+const fetchToken = async code => {
+ if (!code) {
+ return '无效请求'
+ }
+ console.log('Auth', code)
+ const clientId = process.env.OAUTH_CLIENT_ID
+ const clientSecret = process.env.OAUTH_CLIENT_SECRET
+ const redirectUri = process.env.OAUTH_REDIRECT_URI
+
+ // encode in base 64
+ const encoded = Buffer.from(`${clientId}:${clientSecret}`).toString('base64')
+
+ try {
+ console.log(
+ `请求Code换取Token ${clientId}:${clientSecret} -- ${redirectUri}`
+ )
+ const response = await axios.post(
+ 'https://api.notion.com/v1/oauth/token',
+ {
+ grant_type: 'authorization_code',
+ code: code,
+ redirect_uri: redirectUri
+ },
+ {
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ Authorization: `Basic ${encoded}`
+ }
+ }
+ )
+
+ console.log('Token response', response.data)
+ return response
+ } catch (error) {
+ console.error('Error fetching token', error)
+ }
+}
+
+export default UI
diff --git a/pages/category/[category]/index.js b/pages/category/[category]/index.js
index ea70b454..a3a531a1 100644
--- a/pages/category/[category]/index.js
+++ b/pages/category/[category]/index.js
@@ -1,7 +1,7 @@
import BLOG from '@/blog.config'
import { siteConfig } from '@/lib/config'
import { getGlobalData } from '@/lib/db/getSiteData'
-import { getLayoutByTheme } from '@/themes/theme'
+import { DynamicLayout } from '@/themes/theme'
import { useRouter } from 'next/router'
/**
@@ -10,13 +10,9 @@ import { useRouter } from 'next/router'
* @returns
*/
export default function Category(props) {
- // 根据页面路径加载不同Layout文件
- const Layout = getLayoutByTheme({
- theme: siteConfig('THEME'),
- router: useRouter()
- })
-
- return
+ const router = useRouter()
+ const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
+ return
}
export async function getStaticProps({ params: { category }, locale }) {
diff --git a/pages/category/[category]/page/[page].js b/pages/category/[category]/page/[page].js
index 120d762a..9668cdeb 100644
--- a/pages/category/[category]/page/[page].js
+++ b/pages/category/[category]/page/[page].js
@@ -1,7 +1,7 @@
import BLOG from '@/blog.config'
import { siteConfig } from '@/lib/config'
import { getGlobalData } from '@/lib/db/getSiteData'
-import { getLayoutByTheme } from '@/themes/theme'
+import { DynamicLayout } from '@/themes/theme'
import { useRouter } from 'next/router'
/**
@@ -11,13 +11,9 @@ import { useRouter } from 'next/router'
*/
export default function Category(props) {
- // 根据页面路径加载不同Layout文件
- const Layout = getLayoutByTheme({
- theme: siteConfig('THEME'),
- router: useRouter()
- })
-
- return
+ const router = useRouter()
+ const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
+ return
}
export async function getStaticProps({ params: { category, page } }) {
diff --git a/pages/category/index.js b/pages/category/index.js
index 62a3cc9f..4b2f3942 100644
--- a/pages/category/index.js
+++ b/pages/category/index.js
@@ -1,7 +1,7 @@
import BLOG from '@/blog.config'
import { siteConfig } from '@/lib/config'
import { getGlobalData } from '@/lib/db/getSiteData'
-import { getLayoutByTheme } from '@/themes/theme'
+import { DynamicLayout } from '@/themes/theme'
import { useRouter } from 'next/router'
/**
@@ -10,13 +10,9 @@ import { useRouter } from 'next/router'
* @returns
*/
export default function Category(props) {
- // 根据页面路径加载不同Layout文件
- const Layout = getLayoutByTheme({
- theme: siteConfig('THEME'),
- router: useRouter()
- })
-
- return
+ const router = useRouter()
+ const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
+ return
}
export async function getStaticProps({ locale }) {
diff --git a/pages/dashboard/[[...index]].js b/pages/dashboard/[[...index]].js
new file mode 100644
index 00000000..0a865d92
--- /dev/null
+++ b/pages/dashboard/[[...index]].js
@@ -0,0 +1,91 @@
+import BLOG from '@/blog.config'
+import { siteConfig } from '@/lib/config'
+import { getGlobalData, getPost, getPostBlocks } from '@/lib/db/getSiteData'
+import { DynamicLayout } from '@/themes/theme'
+import { useRouter } from 'next/router'
+
+/**
+ * 根据notion的slug访问页面
+ * 只解析一级目录例如 /about
+ * @param {*} props
+ * @returns
+ */
+const Dashboard = props => {
+ const router = useRouter()
+ const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
+ return
+}
+
+export async function getStaticProps({ locale }) {
+ const prefix = 'dashboard'
+ let fullSlug = 'dashboard'
+ const from = `slug-props-${fullSlug}`
+ const props = await getGlobalData({ from, locale })
+ if (siteConfig('PSEUDO_STATIC', false, props.NOTION_CONFIG)) {
+ if (!fullSlug.endsWith('.html')) {
+ fullSlug += '.html'
+ }
+ }
+
+ // 在列表内查找文章
+ props.post = props?.allPages?.find(p => {
+ return p.type.indexOf('Menu') < 0 && p.slug === fullSlug
+ })
+
+ // 处理非列表内文章的内信息
+ if (!props?.post) {
+ const pageId = prefix
+ if (pageId.length >= 32) {
+ const post = await getPost(pageId)
+ props.post = post
+ }
+ }
+ // 无法获取文章
+ if (!props?.post) {
+ props.post = null
+ return {
+ props,
+ revalidate: process.env.EXPORT
+ ? undefined
+ : siteConfig(
+ 'NEXT_REVALIDATE_SECOND',
+ BLOG.NEXT_REVALIDATE_SECOND,
+ props.NOTION_CONFIG
+ )
+ }
+ }
+
+ // 文章内容加载
+ if (!props?.post?.blockMap) {
+ props.post.blockMap = await getPostBlocks(props.post.id, from)
+ }
+
+ delete props.allPages
+ return {
+ props,
+ revalidate: process.env.EXPORT
+ ? undefined
+ : siteConfig(
+ 'NEXT_REVALIDATE_SECOND',
+ BLOG.NEXT_REVALIDATE_SECOND,
+ props.NOTION_CONFIG
+ )
+ }
+}
+
+export const getStaticPaths = async () => {
+ return {
+ paths: [
+ { params: { index: [] } }, // 对应首页路径
+ { params: { index: ['membership'] } },
+ { params: { index: ['balance'] } },
+ { params: { index: ['user-profile'] } },
+ { params: { index: ['user-profile', 'security'] } }, // 嵌套路由,按结构传递
+ { params: { index: ['order'] } },
+ { params: { index: ['affiliate'] } }
+ ],
+ fallback: 'blocking' // 或者 true,阻塞式渲染
+ }
+}
+
+export default Dashboard
diff --git a/pages/index.js b/pages/index.js
index a84c9b3b..eaa21167 100644
--- a/pages/index.js
+++ b/pages/index.js
@@ -4,7 +4,7 @@ import { getGlobalData, getPostBlocks } from '@/lib/db/getSiteData'
import { generateRobotsTxt } from '@/lib/robots.txt'
import { generateRss } from '@/lib/rss'
import { generateSitemapXml } from '@/lib/sitemap.xml'
-import { getLayoutByTheme } from '@/themes/theme'
+import { DynamicLayout } from '@/themes/theme'
import { useRouter } from 'next/router'
/**
@@ -13,12 +13,9 @@ import { useRouter } from 'next/router'
* @returns
*/
const Index = props => {
- // 根据页面路径加载不同Layout文件
- const Layout = getLayoutByTheme({
- theme: siteConfig('THEME'),
- router: useRouter()
- })
- return
+ const router = useRouter()
+ const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
+ return
}
/**
diff --git a/pages/page/[page].js b/pages/page/[page].js
index 9ccb3b81..0166aba2 100644
--- a/pages/page/[page].js
+++ b/pages/page/[page].js
@@ -1,7 +1,7 @@
import BLOG from '@/blog.config'
import { siteConfig } from '@/lib/config'
import { getGlobalData, getPostBlocks } from '@/lib/db/getSiteData'
-import { getLayoutByTheme } from '@/themes/theme'
+import { DynamicLayout } from '@/themes/theme'
import { useRouter } from 'next/router'
/**
@@ -10,13 +10,9 @@ import { useRouter } from 'next/router'
* @returns
*/
const Page = props => {
- // 根据页面路径加载不同Layout文件
- const Layout = getLayoutByTheme({
- theme: siteConfig('THEME'),
- router: useRouter()
- })
-
- return
+ const router = useRouter()
+ const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
+ return
}
export async function getStaticPaths({ locale }) {
diff --git a/pages/search/[keyword]/index.js b/pages/search/[keyword]/index.js
index 9b491b00..179583d8 100644
--- a/pages/search/[keyword]/index.js
+++ b/pages/search/[keyword]/index.js
@@ -2,17 +2,13 @@ import BLOG from '@/blog.config'
import { getDataFromCache } from '@/lib/cache/cache_manager'
import { siteConfig } from '@/lib/config'
import { getGlobalData } from '@/lib/db/getSiteData'
-import { getLayoutByTheme } from '@/themes/theme'
+import { DynamicLayout } from '@/themes/theme'
import { useRouter } from 'next/router'
const Index = props => {
- // 根据页面路径加载不同Layout文件
- const Layout = getLayoutByTheme({
- theme: siteConfig('THEME'),
- router: useRouter()
- })
-
- return
+ const router = useRouter()
+ const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
+ return
}
/**
diff --git a/pages/search/[keyword]/page/[page].js b/pages/search/[keyword]/page/[page].js
index bebaa9fc..4ced9f6c 100644
--- a/pages/search/[keyword]/page/[page].js
+++ b/pages/search/[keyword]/page/[page].js
@@ -2,19 +2,16 @@ import BLOG from '@/blog.config'
import { getDataFromCache } from '@/lib/cache/cache_manager'
import { siteConfig } from '@/lib/config'
import { getGlobalData } from '@/lib/db/getSiteData'
-import { getLayoutByTheme } from '@/themes/theme'
+import { DynamicLayout } from '@/themes/theme'
import { useRouter } from 'next/router'
const Index = props => {
const { keyword } = props
- // 根据页面路径加载不同Layout文件
- const Layout = getLayoutByTheme({
- theme: siteConfig('THEME'),
- router: useRouter()
- })
props = { ...props, currentSearch: keyword }
- return
+ const router = useRouter()
+ const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
+ return
}
/**
diff --git a/pages/search/index.js b/pages/search/index.js
index 6226a400..2000d72e 100644
--- a/pages/search/index.js
+++ b/pages/search/index.js
@@ -1,7 +1,7 @@
import BLOG from '@/blog.config'
import { siteConfig } from '@/lib/config'
import { getGlobalData } from '@/lib/db/getSiteData'
-import { getLayoutByTheme } from '@/themes/theme'
+import { DynamicLayout } from '@/themes/theme'
import { useRouter } from 'next/router'
/**
@@ -12,12 +12,6 @@ import { useRouter } from 'next/router'
const Search = props => {
const { posts } = props
- // 根据页面路径加载不同Layout文件
- const Layout = getLayoutByTheme({
- theme: siteConfig('THEME'),
- router: useRouter()
- })
-
const router = useRouter()
const keyword = router?.query?.s
@@ -37,7 +31,8 @@ const Search = props => {
props = { ...props, posts: filteredPosts }
- return
+ const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
+ return
}
/**
diff --git a/pages/sign-in/[[...index]].js b/pages/sign-in/[[...index]].js
index 2dca85ef..7ed893d5 100644
--- a/pages/sign-in/[[...index]].js
+++ b/pages/sign-in/[[...index]].js
@@ -2,7 +2,7 @@ import BLOG from '@/blog.config'
import { siteConfig } from '@/lib/config'
import { getGlobalData } from '@/lib/db/getSiteData'
// import { getGlobalData } from '@/lib/db/getSiteData'
-import { getLayoutByTheme } from '@/themes/theme'
+import { DynamicLayout } from '@/themes/theme'
import { useRouter } from 'next/router'
/**
@@ -11,12 +11,9 @@ import { useRouter } from 'next/router'
* @returns
*/
const SignIn = props => {
- // 根据页面路径加载不同Layout文件
- const Layout = getLayoutByTheme({
- theme: siteConfig('THEME'),
- router: useRouter()
- })
- return
+ const router = useRouter()
+ const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
+ return
}
export async function getStaticProps(req) {
diff --git a/pages/sign-up/[[...index]].js b/pages/sign-up/[[...index]].js
index 39fdbe4e..72ba97fc 100644
--- a/pages/sign-up/[[...index]].js
+++ b/pages/sign-up/[[...index]].js
@@ -1,7 +1,7 @@
import BLOG from '@/blog.config'
import { siteConfig } from '@/lib/config'
import { getGlobalData } from '@/lib/db/getSiteData'
-import { getLayoutByTheme } from '@/themes/theme'
+import { DynamicLayout } from '@/themes/theme'
import { useRouter } from 'next/router'
/**
@@ -10,12 +10,9 @@ import { useRouter } from 'next/router'
* @returns
*/
const SignUp = props => {
- // 根据页面路径加载不同Layout文件
- const Layout = getLayoutByTheme({
- theme: siteConfig('THEME'),
- router: useRouter()
- })
- return
+ const router = useRouter()
+ const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
+ return
}
export async function getStaticProps(req) {
diff --git a/pages/tag/[tag]/index.js b/pages/tag/[tag]/index.js
index 79458257..ff366c5f 100644
--- a/pages/tag/[tag]/index.js
+++ b/pages/tag/[tag]/index.js
@@ -1,7 +1,7 @@
import BLOG from '@/blog.config'
import { siteConfig } from '@/lib/config'
import { getGlobalData } from '@/lib/db/getSiteData'
-import { getLayoutByTheme } from '@/themes/theme'
+import { DynamicLayout } from '@/themes/theme'
import { useRouter } from 'next/router'
/**
@@ -10,13 +10,9 @@ import { useRouter } from 'next/router'
* @returns
*/
const Tag = props => {
- // 根据页面路径加载不同Layout文件
- const Layout = getLayoutByTheme({
- theme: siteConfig('THEME'),
- router: useRouter()
- })
-
- return
+ const router = useRouter()
+ const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
+ return
}
export async function getStaticProps({ params: { tag }, locale }) {
diff --git a/pages/tag/[tag]/page/[page].js b/pages/tag/[tag]/page/[page].js
index da93f16f..a13ebe04 100644
--- a/pages/tag/[tag]/page/[page].js
+++ b/pages/tag/[tag]/page/[page].js
@@ -1,16 +1,13 @@
import BLOG from '@/blog.config'
import { siteConfig } from '@/lib/config'
import { getGlobalData } from '@/lib/db/getSiteData'
-import { getLayoutByTheme } from '@/themes/theme'
+import { DynamicLayout } from '@/themes/theme'
import { useRouter } from 'next/router'
const Tag = props => {
- // 根据页面路径加载不同Layout文件
- const Layout = getLayoutByTheme({
- theme: siteConfig('THEME'),
- router: useRouter()
- })
- return
+ const router = useRouter()
+ const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
+ return
}
export async function getStaticProps({ params: { tag, page }, locale }) {
diff --git a/pages/tag/index.js b/pages/tag/index.js
index 5433a033..a04a5b88 100644
--- a/pages/tag/index.js
+++ b/pages/tag/index.js
@@ -1,7 +1,7 @@
import BLOG from '@/blog.config'
import { siteConfig } from '@/lib/config'
import { getGlobalData } from '@/lib/db/getSiteData'
-import { getLayoutByTheme } from '@/themes/theme'
+import { DynamicLayout } from '@/themes/theme'
import { useRouter } from 'next/router'
/**
@@ -10,12 +10,9 @@ import { useRouter } from 'next/router'
* @returns
*/
const TagIndex = props => {
- // 根据页面路径加载不同Layout文件
- const Layout = getLayoutByTheme({
- theme: siteConfig('THEME'),
- router: useRouter()
- })
- return
+ const router = useRouter()
+ const theme = siteConfig('THEME', BLOG.THEME, props.NOTION_CONFIG)
+ return
}
export async function getStaticProps(req) {
diff --git a/themes/gitbook/components/BottomMenuBar.js b/themes/gitbook/components/BottomMenuBar.js
index 478a52eb..c872941b 100644
--- a/themes/gitbook/components/BottomMenuBar.js
+++ b/themes/gitbook/components/BottomMenuBar.js
@@ -1,5 +1,5 @@
-import MobileButtonCatalog from './MobileButtonCatalog'
-import MobileButtonPageNav from './MobileButtonPageNav'
+import { useGlobal } from '@/lib/global'
+import { useGitBookGlobal } from '..'
/**
* 移动端底部导航
@@ -8,20 +8,43 @@ import MobileButtonPageNav from './MobileButtonPageNav'
*/
export default function BottomMenuBar({ post, className }) {
const showTocButton = post?.toc?.length > 1
+ const { locale } = useGlobal()
+ const { pageNavVisible, changePageNavVisible, tocVisible, changeTocVisible } =
+ useGitBookGlobal()
+ const togglePageNavVisible = () => {
+ changePageNavVisible(!pageNavVisible)
+ }
+
+ const toggleToc = () => {
+ changeTocVisible(!tocVisible)
+ }
return (
- <>
- {/* 移动端底部导航按钮 */}
-
-
-
-
+
+
+
+
{showTocButton && (
-
-
-
+
)}
- >
+
)
}
diff --git a/themes/gitbook/components/MobileButtonCatalog.js b/themes/gitbook/components/MobileButtonCatalog.js
deleted file mode 100644
index e9e8b4e0..00000000
--- a/themes/gitbook/components/MobileButtonCatalog.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import { useGlobal } from '@/lib/global'
-import { useGitBookGlobal } from '@/themes/gitbook'
-
-/**
- * 移动端目录按钮
- */
-export default function MobileButtonCatalog() {
- const { tocVisible, changeTocVisible } = useGitBookGlobal()
- const { locale } = useGlobal()
-
- const toggleToc = () => {
- changeTocVisible(!tocVisible)
- }
-
- return (
-
- )
-}
diff --git a/themes/gitbook/components/MobileButtonPageNav.js b/themes/gitbook/components/MobileButtonPageNav.js
deleted file mode 100644
index 78f038f1..00000000
--- a/themes/gitbook/components/MobileButtonPageNav.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import { useGlobal } from '@/lib/global'
-import { useGitBookGlobal } from '@/themes/gitbook'
-
-/**
- * 移动端文章导航按钮
- */
-export default function MobileButtonPageNav() {
- const { pageNavVisible, changePageNavVisible } = useGitBookGlobal()
- const { locale } = useGlobal()
- const togglePageNavVisible = () => {
- changePageNavVisible(!pageNavVisible)
- }
-
- return (
-
- )
-}
diff --git a/themes/gitbook/index.js b/themes/gitbook/index.js
index 0fac89b5..07197fdf 100644
--- a/themes/gitbook/index.js
+++ b/themes/gitbook/index.js
@@ -7,6 +7,8 @@ import LoadingCover from '@/components/LoadingCover'
import NotionIcon from '@/components/NotionIcon'
import NotionPage from '@/components/NotionPage'
import ShareBar from '@/components/ShareBar'
+import DashboardBody from '@/components/ui/dashboard/DashboardBody'
+import DashboardHeader from '@/components/ui/dashboard/DashboardHeader'
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import { isBrowser } from '@/lib/utils'
@@ -255,7 +257,9 @@ const LayoutIndex = props => {
// 重定向到指定文章
router.push(index).then(() => {
setTimeout(() => {
- const article = document.querySelector('#article-wrapper #notion-article')
+ const article = document.querySelector(
+ '#article-wrapper #notion-article'
+ )
if (!article) {
console.log(
'请检查您的Notion数据库中是否包含此slug页面: ',
@@ -309,7 +313,9 @@ const LayoutSlug = props => {
setTimeout(
() => {
if (isBrowser) {
- const article = document.querySelector('#article-wrapper #notion-article')
+ const article = document.querySelector(
+ '#article-wrapper #notion-article'
+ )
if (!article) {
router.push('/404').then(() => {
console.warn('找不到页面', router.asPath)
@@ -539,11 +545,40 @@ const LayoutSignUp = props => {
)
}
+/**
+ * 仪表盘
+ * @param {*} props
+ * @returns
+ */
+const LayoutDashboard = props => {
+ const { post } = props
+
+ return (
+ <>
+
+
+
+ {post && (
+
+
+
+ )}
+
+
+
+ {/* 仪表盘 */}
+
+
+ >
+ )
+}
+
export {
Layout404,
LayoutArchive,
LayoutBase,
LayoutCategoryIndex,
+ LayoutDashboard,
LayoutIndex,
LayoutPostList,
LayoutSearch,
diff --git a/themes/magzine/components/Header.js b/themes/magzine/components/Header.js
index 6464b712..3e4c3456 100644
--- a/themes/magzine/components/Header.js
+++ b/themes/magzine/components/Header.js
@@ -1,8 +1,9 @@
import Collapse from '@/components/Collapse'
import DarkModeButton from '@/components/DarkModeButton'
+import DashboardButton from '@/components/ui/dashboard/DashboardButton'
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
-import { SignInButton, SignedOut, UserButton } from '@clerk/nextjs'
+import { SignInButton, SignedIn, SignedOut, UserButton } from '@clerk/nextjs'
import throttle from 'lodash.throttle'
import { useRouter } from 'next/router'
import { useEffect, useRef, useState } from 'react'
@@ -200,7 +201,10 @@ export default function Header(props) {
-
+
+
+
+
>
)}
diff --git a/themes/magzine/index.js b/themes/magzine/index.js
index e5165bdd..bdfb2c72 100644
--- a/themes/magzine/index.js
+++ b/themes/magzine/index.js
@@ -6,6 +6,8 @@ import replaceSearchResult from '@/components/Mark'
import NotionPage from '@/components/NotionPage'
import ShareBar from '@/components/ShareBar'
import WWAds from '@/components/WWAds'
+import DashboardBody from '@/components/ui/dashboard/DashboardBody'
+import DashboardHeader from '@/components/ui/dashboard/DashboardHeader'
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import { isBrowser } from '@/lib/utils'
@@ -155,7 +157,9 @@ const LayoutSlug = props => {
setTimeout(
() => {
if (isBrowser) {
- const article = document.querySelector('#article-wrapper #notion-article')
+ const article = document.querySelector(
+ '#article-wrapper #notion-article'
+ )
if (!article) {
router.push('/404').then(() => {
console.warn('找不到页面', router.asPath)
@@ -495,11 +499,39 @@ const LayoutSignUp = props => {
)
}
+/**
+ * 仪表盘
+ * @param {*} props
+ * @returns
+ */
+const LayoutDashboard = props => {
+ const { post } = props
+
+ return (
+ <>
+
+
+
+ {post && (
+
+
+
+ )}
+
+
+
+ {/* 仪表盘 */}
+
+
+ >
+ )
+}
export {
Layout404,
LayoutArchive,
LayoutBase,
LayoutCategoryIndex,
+ LayoutDashboard,
LayoutIndex,
LayoutPostList,
LayoutSearch,
diff --git a/themes/starter/components/Header.js b/themes/starter/components/Header.js
index ef69c077..7a88df87 100644
--- a/themes/starter/components/Header.js
+++ b/themes/starter/components/Header.js
@@ -1,4 +1,5 @@
/* eslint-disable no-unreachable */
+import DashboardButton from '@/components/ui/dashboard/DashboardButton'
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import { SignedIn, SignedOut, UserButton } from '@clerk/nextjs'
@@ -87,6 +88,7 @@ export const Header = props => {
+
>
)}
diff --git a/themes/starter/components/MenuItem.js b/themes/starter/components/MenuItem.js
index ff184f36..3e32a08b 100644
--- a/themes/starter/components/MenuItem.js
+++ b/themes/starter/components/MenuItem.js
@@ -42,7 +42,7 @@ export const MenuItem = ({ link }) => {
-
+
{link.subMenus.map((sLink, index) => {
return (
{
target={link?.target}
className='block rounded px-4 py-[10px] text-sm text-body-color hover:text-primary dark:text-dark-6 dark:hover:text-primary'>
{/* 子菜单SubMenuItem */}
-
+
{link?.icon && (
)}{' '}
diff --git a/themes/starter/index.js b/themes/starter/index.js
index 3ae161f6..c0311b77 100644
--- a/themes/starter/index.js
+++ b/themes/starter/index.js
@@ -27,6 +27,8 @@ import { Style } from './style'
import Comment from '@/components/Comment'
import replaceSearchResult from '@/components/Mark'
import ShareBar from '@/components/ShareBar'
+import DashboardBody from '@/components/ui/dashboard/DashboardBody'
+import DashboardHeader from '@/components/ui/dashboard/DashboardHeader'
import { useGlobal } from '@/lib/global'
import { loadWowJS } from '@/lib/plugins/wow'
import { SignIn, SignUp } from '@clerk/nextjs'
@@ -177,6 +179,39 @@ const LayoutSlug = props => {
)
}
+/**
+ * 仪表盘
+ * @param {*} props
+ * @returns
+ */
+const LayoutDashboard = props => {
+ const { post } = props
+
+ return (
+ <>
+
+
+
+ {post && (
+
+
+
+ )}
+
+
+
+ {/* 仪表盘 */}
+
+
+ >
+ )
+}
+
+/**
+ * 搜索
+ * @param {*} props
+ * @returns
+ */
const LayoutSearch = props => {
const { keyword } = props
const router = useRouter()
@@ -491,6 +526,7 @@ export {
LayoutArchive,
LayoutBase,
LayoutCategoryIndex,
+ LayoutDashboard,
LayoutIndex,
LayoutPostList,
LayoutSearch,
diff --git a/themes/theme.js b/themes/theme.js
index aa5c07e5..c8760927 100644
--- a/themes/theme.js
+++ b/themes/theme.js
@@ -8,17 +8,50 @@ import { getQueryParam, getQueryVariable, isBrowser } from '../lib/utils'
export const { THEMES = [] } = getConfig().publicRuntimeConfig
/**
- * 获取主体配置
+ * 获取主题配置
+ * @param {string} themeQuery - 主题查询参数(支持多个主题用逗号分隔)
+ * @returns {Promise