mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-05-14 07:26:52 +00:00
登录结合OpenWrite
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import { isBrowser, loadExternalResource } from '@/lib/utils'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect } from 'react'
|
||||
@@ -24,14 +25,10 @@ const OpenWrite = () => {
|
||||
// 白名单
|
||||
const whiteList = siteConfig('OPEN_WRITE_WHITE_LIST', '')
|
||||
|
||||
// 登录信息
|
||||
const { isLoaded, isSignedIn } = useGlobal()
|
||||
|
||||
const loadOpenWrite = async () => {
|
||||
const existWhite = existedWhiteList(router.asPath, whiteList)
|
||||
|
||||
// 如果当前页面在白名单中,则屏蔽加锁
|
||||
if (existWhite) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await loadExternalResource(
|
||||
'https://readmore.openwrite.cn/js/readmore-2.0.js',
|
||||
@@ -74,11 +71,24 @@ const OpenWrite = () => {
|
||||
}
|
||||
}
|
||||
useEffect(() => {
|
||||
const existWhite = existedWhiteList(router.asPath, whiteList)
|
||||
// 白名单中,免检
|
||||
if (existWhite) {
|
||||
return
|
||||
}
|
||||
if (isSignedIn) {
|
||||
// 用户已登录免检
|
||||
console.log('用户已登录')
|
||||
return
|
||||
}
|
||||
|
||||
// 开发环境免检
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.log('开发环境:屏蔽OpenWrite')
|
||||
return
|
||||
}
|
||||
if (isBrowser && blogId) {
|
||||
|
||||
if (isBrowser && blogId && !isSignedIn) {
|
||||
toggleTocItems(true) // 禁止目录项的点击
|
||||
|
||||
// Check if the element with id 'read-more-wrap' already exists
|
||||
@@ -89,7 +99,7 @@ const OpenWrite = () => {
|
||||
loadOpenWrite()
|
||||
}
|
||||
}
|
||||
})
|
||||
}, [isLoaded, router])
|
||||
|
||||
// 启动一个监听器,当页面上存在#read-more-wrap对象时,所有的 a .notion-table-of-contents-item 对象都禁止点击
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
initDarkMode,
|
||||
saveDarkModeToLocalStorage
|
||||
} from '@/themes/theme'
|
||||
import { useUser } from '@clerk/nextjs'
|
||||
import { useRouter } from 'next/router'
|
||||
import { createContext, useContext, useEffect, useState } from 'react'
|
||||
import {
|
||||
@@ -13,6 +14,10 @@ import {
|
||||
redirectUserLang,
|
||||
saveLangToLocalStorage
|
||||
} from './lang'
|
||||
|
||||
/**
|
||||
* 全局上下文
|
||||
*/
|
||||
const GlobalContext = createContext()
|
||||
|
||||
export function GlobalContextProvider(props) {
|
||||
@@ -37,6 +42,12 @@ export function GlobalContextProvider(props) {
|
||||
const [onLoading, setOnLoading] = useState(true) // 抓取文章数据
|
||||
const router = useRouter()
|
||||
|
||||
// 登录验证相关
|
||||
const enableClerk = process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
|
||||
const { isLoaded, isSignedIn, user } = enableClerk
|
||||
? useUser()
|
||||
: { isLoaded: true, isSignedIn: false, user: false }
|
||||
|
||||
// 是否全屏
|
||||
const fullWidth = post?.fullWidth ?? false
|
||||
|
||||
@@ -119,6 +130,9 @@ export function GlobalContextProvider(props) {
|
||||
return (
|
||||
<GlobalContext.Provider
|
||||
value={{
|
||||
isLoaded,
|
||||
isSignedIn,
|
||||
user,
|
||||
fullWidth,
|
||||
NOTION_CONFIG,
|
||||
THEME_CONFIG,
|
||||
|
||||
@@ -21,6 +21,8 @@ export default {
|
||||
},
|
||||
COMMON: {
|
||||
THEME: 'Theme',
|
||||
SIGN_IN: 'Sign In',
|
||||
SIGN_OUT: 'Sign Out',
|
||||
ARTICLE_LIST: 'Article List',
|
||||
RECOMMEND_POSTS: 'Recommend Posts',
|
||||
MORE: 'More',
|
||||
|
||||
@@ -21,6 +21,8 @@ export default {
|
||||
},
|
||||
COMMON: {
|
||||
THEME: 'Theme',
|
||||
SIGN_IN: '登录',
|
||||
SIGN_OUT: '登出',
|
||||
ARTICLE_LIST: '文章列表',
|
||||
RECOMMEND_POSTS: '推荐文章',
|
||||
MORE: '更多',
|
||||
|
||||
@@ -194,6 +194,8 @@ const nextConfig = {
|
||||
},
|
||||
webpack: (config, { dev, isServer }) => {
|
||||
// 动态主题:添加 resolve.alias 配置,将动态路径映射到实际路径
|
||||
config.resolve.alias['@'] = path.resolve(__dirname)
|
||||
|
||||
if (!isServer) {
|
||||
console.log('[默认主题]', path.resolve(__dirname, 'themes', THEME))
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
"build-all-in-dev": "cross-env VERCEL_ENV=production next build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@clerk/localizations": "^3.0.4",
|
||||
"@clerk/nextjs": "^5.1.5",
|
||||
"@headlessui/react": "^1.7.15",
|
||||
"@next/bundle-analyzer": "^12.1.1",
|
||||
|
||||
@@ -17,8 +17,8 @@ import { getQueryParam } from '../lib/utils'
|
||||
import BLOG from '@/blog.config'
|
||||
import ExternalPlugins from '@/components/ExternalPlugins'
|
||||
import GlobalHead from '@/components/GlobalHead'
|
||||
import { zhCN } from '@clerk/localizations'
|
||||
import { ClerkProvider } from '@clerk/nextjs'
|
||||
|
||||
/**
|
||||
* App挂载DOM 入口文件
|
||||
* @param {*} param0
|
||||
@@ -57,7 +57,15 @@ const MyApp = ({ Component, pageProps }) => {
|
||||
<ExternalPlugins {...pageProps} />
|
||||
</GlobalContextProvider>
|
||||
)
|
||||
return <>{enableClerk ? <ClerkProvider>{content}</ClerkProvider> : content}</>
|
||||
return (
|
||||
<>
|
||||
{enableClerk ? (
|
||||
<ClerkProvider localization={zhCN}>{content}</ClerkProvider>
|
||||
) : (
|
||||
content
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default MyApp
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// import BLOG from '@/blog.config'
|
||||
import BLOG from '@/blog.config'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { getGlobalData } from '@/lib/db/getSiteData'
|
||||
|
||||
@@ -10,7 +10,8 @@ export default function ArticleInfo({ post }) {
|
||||
return (
|
||||
<div className='pt-10 pb-6 text-gray-400 text-sm'>
|
||||
<i className='fa-regular fa-clock mr-1' />
|
||||
Last update: {post.date?.start_date}
|
||||
Last update:{' '}
|
||||
{post.date?.start_date || post?.publishDay || post?.lastEditedDay}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import Collapse from '@/components/Collapse'
|
||||
import DarkModeButton from '@/components/DarkModeButton'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import { SignInButton, SignedOut, UserButton } from '@clerk/nextjs'
|
||||
import { useRef, useState } from 'react'
|
||||
import CONFIG from '../config'
|
||||
import LogoBar from './LogoBar'
|
||||
@@ -59,6 +60,8 @@ export default function Header(props) {
|
||||
links = customMenu
|
||||
}
|
||||
|
||||
const enableClerk = process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
|
||||
|
||||
return (
|
||||
<div id='top-nav' className={'fixed top-0 w-full z-20 ' + className}>
|
||||
{/* PC端菜单 */}
|
||||
@@ -79,6 +82,19 @@ export default function Header(props) {
|
||||
|
||||
{/* 右侧 */}
|
||||
<div className='flex items-center gap-4'>
|
||||
{/* 登录相关 */}
|
||||
{enableClerk && (
|
||||
<>
|
||||
<SignedOut>
|
||||
<SignInButton mode='modal'>
|
||||
<button className='bg-green-500 hover:bg-green-600 text-white rounded-lg px-3 py-2'>
|
||||
{locale.COMMON.SIGN_IN}
|
||||
</button>
|
||||
</SignInButton>
|
||||
</SignedOut>
|
||||
<UserButton />
|
||||
</>
|
||||
)}
|
||||
<DarkModeButton className='text-sm items-center h-full hidden md:flex' />
|
||||
<SearchInput className='hidden md:flex md:w-52 lg:w-72' />
|
||||
{/* 折叠按钮、仅移动端显示 */}
|
||||
|
||||
@@ -11,6 +11,7 @@ import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import { isBrowser } from '@/lib/utils'
|
||||
import { getShortId } from '@/lib/utils/pageId'
|
||||
import { SignIn, SignUp } from '@clerk/nextjs'
|
||||
import dynamic from 'next/dynamic'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
@@ -164,7 +165,7 @@ const LayoutBase = props => {
|
||||
{/* 中间内容区域 */}
|
||||
<div
|
||||
id='center-wrapper'
|
||||
className='dark:bg-hexo-black-gray flex flex-col justify-between w-full relative z-10 pt-14 min-h-screen'>
|
||||
className='flex flex-col justify-between w-full relative z-10 pt-14 min-h-screen'>
|
||||
<div
|
||||
id='container-inner'
|
||||
className={`w-full ${fullWidth ? 'px-5' : 'max-w-3xl px-3 lg:px-0'} justify-center mx-auto`}>
|
||||
@@ -473,6 +474,58 @@ const LayoutTagIndex = props => {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录页面
|
||||
* @param {*} props
|
||||
* @returns
|
||||
*/
|
||||
const LayoutSignIn = props => {
|
||||
const { post } = props
|
||||
const enableClerk = process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='grow mt-20'>
|
||||
{/* clerk预置表单 */}
|
||||
{enableClerk && (
|
||||
<div className='flex justify-center py-6'>
|
||||
<SignIn />
|
||||
</div>
|
||||
)}
|
||||
<div id='article-wrapper'>
|
||||
<NotionPage post={post} />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册页面
|
||||
* @param {*} props
|
||||
* @returns
|
||||
*/
|
||||
const LayoutSignUp = props => {
|
||||
const { post } = props
|
||||
const enableClerk = process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='grow mt-20'>
|
||||
{/* clerk预置表单 */}
|
||||
{enableClerk && (
|
||||
<div className='flex justify-center py-6'>
|
||||
<SignUp />
|
||||
</div>
|
||||
)}
|
||||
<div id='article-wrapper'>
|
||||
<NotionPage post={post} />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export {
|
||||
Layout404,
|
||||
LayoutArchive,
|
||||
@@ -481,6 +534,8 @@ export {
|
||||
LayoutIndex,
|
||||
LayoutPostList,
|
||||
LayoutSearch,
|
||||
LayoutSignIn,
|
||||
LayoutSignUp,
|
||||
LayoutSlug,
|
||||
LayoutTagIndex,
|
||||
CONFIG as THEME_CONFIG
|
||||
|
||||
@@ -23,9 +23,6 @@ const Catalog = ({ post, toc, className }) => {
|
||||
actionSectionScrollSpy()
|
||||
window.addEventListener('scroll', actionSectionScrollSpy)
|
||||
}
|
||||
setTimeout(() => {
|
||||
console.log('目录', post, toc)
|
||||
}, 1000)
|
||||
return () => {
|
||||
window.removeEventListener('scroll', actionSectionScrollSpy)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import Collapse from '@/components/Collapse'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import { SignInButton, SignedOut, UserButton } from '@clerk/nextjs'
|
||||
import throttle from 'lodash.throttle'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
@@ -112,6 +113,8 @@ export default function Header(props) {
|
||||
return null
|
||||
}
|
||||
|
||||
const enableClerk = process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
|
||||
|
||||
return (
|
||||
<div
|
||||
id='top-navbar-wrapper'
|
||||
@@ -154,7 +157,7 @@ export default function Header(props) {
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* 右侧移动端折叠按钮 */}
|
||||
{/* 右侧按钮 */}
|
||||
<div className='flex items-center gap-x-2 pr-2'>
|
||||
{/* 搜索按钮 */}
|
||||
<div
|
||||
@@ -167,6 +170,8 @@ export default function Header(props) {
|
||||
: 'fa-solid fa-magnifying-glass' + ' align-middle'
|
||||
}></i>
|
||||
</div>
|
||||
|
||||
{/* 移动端显示开关 */}
|
||||
<div className='mr-1 flex md:hidden justify-end items-center text-lg space-x-4 font-serif dark:text-gray-200'>
|
||||
<div onClick={toggleMenuOpen} className='cursor-pointer p-2'>
|
||||
{isOpen ? (
|
||||
@@ -176,6 +181,20 @@ export default function Header(props) {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 登录相关 */}
|
||||
{enableClerk && (
|
||||
<>
|
||||
<SignedOut>
|
||||
<SignInButton mode='modal'>
|
||||
<button className='bg-gray-800 hover:bg-gray-900 text-white rounded-lg px-3 py-2'>
|
||||
{locale.COMMON.SIGN_IN}
|
||||
</button>
|
||||
</SignInButton>
|
||||
</SignedOut>
|
||||
<UserButton />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import WWAds from '@/components/WWAds'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import { isBrowser } from '@/lib/utils'
|
||||
import { SignIn, SignUp } from '@clerk/nextjs'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import { createContext, useContext, useEffect, useRef, useState } from 'react'
|
||||
@@ -440,6 +441,58 @@ const LayoutTagIndex = props => {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录页面
|
||||
* @param {*} props
|
||||
* @returns
|
||||
*/
|
||||
const LayoutSignIn = props => {
|
||||
const { post } = props
|
||||
const enableClerk = process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='grow mt-20'>
|
||||
{/* clerk预置表单 */}
|
||||
{enableClerk && (
|
||||
<div className='flex justify-center py-6'>
|
||||
<SignIn />
|
||||
</div>
|
||||
)}
|
||||
<div id='article-wrapper'>
|
||||
<NotionPage post={post} />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册页面
|
||||
* @param {*} props
|
||||
* @returns
|
||||
*/
|
||||
const LayoutSignUp = props => {
|
||||
const { post } = props
|
||||
const enableClerk = process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='grow mt-20'>
|
||||
{/* clerk预置表单 */}
|
||||
{enableClerk && (
|
||||
<div className='flex justify-center py-6'>
|
||||
<SignUp />
|
||||
</div>
|
||||
)}
|
||||
<div id='article-wrapper'>
|
||||
<NotionPage post={post} />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export {
|
||||
Layout404,
|
||||
LayoutArchive,
|
||||
@@ -448,6 +501,8 @@ export {
|
||||
LayoutIndex,
|
||||
LayoutPostList,
|
||||
LayoutSearch,
|
||||
LayoutSignIn,
|
||||
LayoutSignUp,
|
||||
LayoutSlug,
|
||||
LayoutTagIndex,
|
||||
CONFIG as THEME_CONFIG
|
||||
|
||||
@@ -68,7 +68,28 @@ export const Header = props => {
|
||||
{/* 深色模式切换 */}
|
||||
<DarkModeButton />
|
||||
{/* 注册登录功能 */}
|
||||
<SignedOut>
|
||||
{enableClerk && (
|
||||
<>
|
||||
<SignedOut>
|
||||
<div className='hidden sm:flex gap-4'>
|
||||
<a
|
||||
href={siteConfig('STARTER_NAV_BUTTON_1_URL')}
|
||||
className={`loginBtn ${buttonTextColor} p-2 text-base font-medium hover:opacity-70`}>
|
||||
{siteConfig('STARTER_NAV_BUTTON_1_TEXT')}
|
||||
</a>
|
||||
<a
|
||||
href={siteConfig('STARTER_NAV_BUTTON_2_URL')}
|
||||
className={`signUpBtn ${buttonTextColor} p-2 rounded-md bg-white bg-opacity-20 py-2 text-base font-medium duration-300 ease-in-out hover:bg-opacity-100 hover:text-dark`}>
|
||||
{siteConfig('STARTER_NAV_BUTTON_2_TEXT')}
|
||||
</a>
|
||||
</div>
|
||||
</SignedOut>
|
||||
<SignedIn>
|
||||
<UserButton />
|
||||
</SignedIn>
|
||||
</>
|
||||
)}
|
||||
{!enableClerk && (
|
||||
<div className='hidden sm:flex gap-4'>
|
||||
<a
|
||||
href={siteConfig('STARTER_NAV_BUTTON_1_URL')}
|
||||
@@ -81,10 +102,7 @@ export const Header = props => {
|
||||
{siteConfig('STARTER_NAV_BUTTON_2_TEXT')}
|
||||
</a>
|
||||
</div>
|
||||
</SignedOut>
|
||||
<SignedIn>
|
||||
<UserButton />
|
||||
</SignedIn>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -99,7 +99,11 @@ const checkThemeDOM = () => {
|
||||
elements[elements.length - 1].scrollIntoView()
|
||||
// 删除前面的元素,只保留最后一个元素
|
||||
for (let i = 0; i < elements.length - 1; i++) {
|
||||
if (elements[i] && elements[i].parentNode && elements[i].parentNode.contains(elements[i])) {
|
||||
if (
|
||||
elements[i] &&
|
||||
elements[i].parentNode &&
|
||||
elements[i].parentNode.contains(elements[i])
|
||||
) {
|
||||
elements[i].parentNode.removeChild(elements[i])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/blog.config": ["./blog.config"],
|
||||
"@/components/*": ["components/*"],
|
||||
"@/hooks/*": ["hooks/*"],
|
||||
"@/themes/*": ["themes/*"],
|
||||
"@/pages/*": ["pages/*"],
|
||||
"@/data/*": ["data/*"],
|
||||
"@/lib/*": ["lib/*"],
|
||||
"@/styles/*": ["styles/*"]
|
||||
|
||||
14
yarn.lock
14
yarn.lock
@@ -143,6 +143,13 @@
|
||||
"@clerk/types" "4.6.0"
|
||||
tslib "2.4.1"
|
||||
|
||||
"@clerk/localizations@^3.0.4":
|
||||
version "3.0.4"
|
||||
resolved "https://registry.npmjs.org/@clerk/localizations/-/localizations-3.0.4.tgz#6f9e807f31c675b197179582fca711521b83ba22"
|
||||
integrity sha512-cOvkGXpWbVXU5F0CRedGKVIAaEUQSikBtD+HpsfSxFW9HshTA4DQdkhiQUlpJAyf8WYDJE11V9Dw5cS6ZPlhBg==
|
||||
dependencies:
|
||||
"@clerk/types" "4.21.0"
|
||||
|
||||
"@clerk/nextjs@^5.1.5":
|
||||
version "5.1.5"
|
||||
resolved "https://r.cnpmjs.org/@clerk/nextjs/-/nextjs-5.1.5.tgz#559473a0e61af61d43e4e4a3242794db65b0ebfc"
|
||||
@@ -167,6 +174,13 @@
|
||||
std-env "^3.7.0"
|
||||
swr "^2.2.0"
|
||||
|
||||
"@clerk/types@4.21.0":
|
||||
version "4.21.0"
|
||||
resolved "https://registry.npmjs.org/@clerk/types/-/types-4.21.0.tgz#0ef79321d72983ef6e8c4a945617fe1f7d657c92"
|
||||
integrity sha512-yyPNF4agzub9zXOht9Bk8HG+OkHfLKIpsQuTCiZJszehcKNUqKvJZRxUwdRREBYnBdMl632PKCwbckZsChVxVQ==
|
||||
dependencies:
|
||||
csstype "3.1.1"
|
||||
|
||||
"@clerk/types@4.6.0":
|
||||
version "4.6.0"
|
||||
resolved "https://r.cnpmjs.org/@clerk/types/-/types-4.6.0.tgz#2dd88a3ee603f4577606ad8ad1a46ae8c70401ec"
|
||||
|
||||
Reference in New Issue
Block a user