From 556c518ea77aadbbfb5cb999668c0a6c6a41433b Mon Sep 17 00:00:00 2001 From: "tangly1024.com" Date: Wed, 8 Mar 2023 20:10:23 +0800 Subject: [PATCH 01/20] theme-simple & menun --- blog.config.js | 4 + lib/notion/getNotionData.js | 36 ++++++-- lib/notion/getPageProperties.js | 10 ++- public/css/theme-simple.css | 8 ++ styles/globals.css | 18 +++- styles/notion.css | 5 +- themes/example/LayoutBase.js | 2 +- themes/example/components/Header.js | 2 +- themes/example/components/Nav.js | 10 +-- .../{config_empty.js => config_example.js} | 4 +- themes/example/index.js | 4 +- themes/fukasawa/LayoutBase.js | 4 +- themes/hexo/LayoutBase.js | 2 +- themes/index.js | 23 ++++- themes/matery/LayoutBase.js | 2 +- themes/medium/LayoutBase.js | 2 +- themes/medium/components/GroupMenu.js | 6 +- themes/medium/components/TopNavBar.js | 4 +- themes/next/LayoutBase.js | 4 +- themes/nobelium/LayoutBase.js | 2 +- themes/simple/Layout404.js | 7 ++ themes/simple/LayoutArchive.js | 45 ++++++++++ themes/simple/LayoutBase.js | 60 +++++++++++++ themes/simple/LayoutCategory.js | 10 +++ themes/simple/LayoutCategoryIndex.js | 26 ++++++ themes/simple/LayoutIndex.js | 13 +++ themes/simple/LayoutPage.js | 10 +++ themes/simple/LayoutSearch.js | 54 ++++++++++++ themes/simple/LayoutSlug.js | 30 +++++++ themes/simple/LayoutTag.js | 10 +++ themes/simple/LayoutTagIndex.js | 29 +++++++ themes/simple/components/About.js | 21 +++++ themes/simple/components/Announcement.js | 13 +++ themes/simple/components/ArticleInfo.js | 52 +++++++++++ themes/simple/components/ArticleLock.js | 38 ++++++++ themes/simple/components/BlogListPage.js | 69 +++++++++++++++ themes/simple/components/BlogListScroll.js | 82 +++++++++++++++++ themes/simple/components/DropMenu.js | 30 +++++++ .../components/ExampleRecentComments.js | 35 ++++++++ themes/simple/components/Footer.js | 30 +++++++ themes/simple/components/Header.js | 22 +++++ themes/simple/components/JumpToTopButton.js | 19 ++++ themes/simple/components/Nav.js | 51 +++++++++++ themes/simple/components/SearchInput.js | 87 +++++++++++++++++++ themes/simple/components/SideBar.js | 24 +++++ themes/simple/components/SocialButton.js | 36 ++++++++ themes/simple/components/Title.js | 19 ++++ themes/simple/components/TopBar.js | 13 +++ themes/simple/config_simple.js | 13 +++ themes/simple/index.js | 25 ++++++ 50 files changed, 1088 insertions(+), 37 deletions(-) create mode 100644 public/css/theme-simple.css rename themes/example/{config_empty.js => config_example.js} (75%) create mode 100644 themes/simple/Layout404.js create mode 100644 themes/simple/LayoutArchive.js create mode 100644 themes/simple/LayoutBase.js create mode 100644 themes/simple/LayoutCategory.js create mode 100644 themes/simple/LayoutCategoryIndex.js create mode 100644 themes/simple/LayoutIndex.js create mode 100644 themes/simple/LayoutPage.js create mode 100644 themes/simple/LayoutSearch.js create mode 100644 themes/simple/LayoutSlug.js create mode 100644 themes/simple/LayoutTag.js create mode 100644 themes/simple/LayoutTagIndex.js create mode 100644 themes/simple/components/About.js create mode 100644 themes/simple/components/Announcement.js create mode 100644 themes/simple/components/ArticleInfo.js create mode 100644 themes/simple/components/ArticleLock.js create mode 100644 themes/simple/components/BlogListPage.js create mode 100644 themes/simple/components/BlogListScroll.js create mode 100644 themes/simple/components/DropMenu.js create mode 100644 themes/simple/components/ExampleRecentComments.js create mode 100644 themes/simple/components/Footer.js create mode 100644 themes/simple/components/Header.js create mode 100644 themes/simple/components/JumpToTopButton.js create mode 100644 themes/simple/components/Nav.js create mode 100644 themes/simple/components/SearchInput.js create mode 100644 themes/simple/components/SideBar.js create mode 100644 themes/simple/components/SocialButton.js create mode 100644 themes/simple/components/Title.js create mode 100644 themes/simple/components/TopBar.js create mode 100644 themes/simple/config_simple.js create mode 100644 themes/simple/index.js diff --git a/blog.config.js b/blog.config.js index 98baf066..fd3274ba 100644 --- a/blog.config.js +++ b/blog.config.js @@ -10,6 +10,8 @@ const BLOG = { SINCE: 2021, // e.g if leave this empty, current year will be used. APPEARANCE: process.env.NEXT_PUBLIC_APPEARANCE || 'light', // ['light', 'dark', 'auto'], // light 日间模式 , dark夜间模式, auto根据时间和主题自动夜间模式 + CUSTOM_MENU: process.env.NEXT_PUBLIC_CUSTOM_MENU || false, // 支持Menu 类型,从3.12.0版本起,各主题将逐步支持灵活的二级菜单配置,替代了原来的Page类型,此配置是试验功能、默认关闭。 + AUTHOR: process.env.NEXT_PUBLIC_AUTHOR || 'NotionNext', // 您的昵称 例如 tangly1024 BIO: process.env.NEXT_PUBLIC_BIO || '一个普通的干饭人🍚', // 作者简介 LINK: process.env.NEXT_PUBLIC_LINK || 'https://tangly1024.com', // 网站地址 @@ -198,6 +200,8 @@ const BLOG = { type_post: process.env.NEXT_PUBLIC_NOTION_PROPERTY_TYPE_POST || 'Post', // 当type文章类型与此值相同时,为博文。 type_page: process.env.NEXT_PUBLIC_NOTION_PROPERTY_TYPE_PAGE || 'Page', // 当type文章类型与此值相同时,为单页。 type_notice: process.env.NEXT_PUBLIC_NOTION_PROPERTY_TYPE_NOTICE || 'Notice', // 当type文章类型与此值相同时,为公告。 + type_menu: process.env.NEXT_PUBLIC_NOTION_PROPERTY_TYPE_MENU || 'Menu', // 当type文章类型与此值相同时,为菜单。 + type_sub_menu: process.env.NEXT_PUBLIC_NOTION_PROPERTY_TYPE_SUB_MENU || 'SubMenu', // 当type文章类型与此值相同时,为子菜单。 title: process.env.NEXT_PUBLIC_NOTION_PROPERTY_TITLE || 'title', // 文章标题 status: process.env.NEXT_PUBLIC_NOTION_PROPERTY_STATUS || 'status', status_publish: process.env.NEXT_PUBLIC_NOTION_PROPERTY_STATUS_PUBLISH || 'Published', // 当status状态值与此相同时为发布,可以为中文 diff --git a/lib/notion/getNotionData.js b/lib/notion/getNotionData.js index 93a22d29..7f4db333 100644 --- a/lib/notion/getNotionData.js +++ b/lib/notion/getNotionData.js @@ -85,18 +85,39 @@ function getCustomNav({ allPages }) { const customNav = [] if (allPages && allPages.length > 0) { allPages.forEach(p => { - if (p?.status === 'Published' && p?.type === 'Page') { - if (p?.slug?.indexOf('http') === 0) { - customNav.push({ icon: p.icon || null, name: p.title, to: p.slug, show: true }) - } else { - customNav.push({ icon: p.icon || null, name: p.title, to: '/' + p.slug, show: true }) - } + if (p?.slug?.indexOf('http') === 0) { + customNav.push({ icon: p.icon || null, name: p.title, to: p.slug, show: true }) + } else { + customNav.push({ icon: p.icon || null, name: p.title, to: '/' + p.slug, show: true }) } }) } return customNav } +function getCustomMenu({ collectionData }) { + const menuPages = collectionData.filter(post => (post.type === BLOG.NOTION_PROPERTY_NAME.type_menu || post.type === BLOG.NOTION_PROPERTY_NAME.type_sub_menu) && post.status === 'Published') + const menus = [] + if (menuPages && menuPages.length > 0) { + menuPages.forEach(e => { + e.show = true + if (e.type === BLOG.NOTION_PROPERTY_NAME.type_menu) { + menus.push(e) + } else if (e.type === BLOG.NOTION_PROPERTY_NAME.type_sub_menu) { + const parentMenu = menus[menus.length - 1] + if (parentMenu) { + if (parentMenu.subMenus) { + parentMenu.subMenus.push(e) + } else { + parentMenu.subMenus = [e] + } + } + } + }) + } + return menus +} + /** * 获取标签选项 * @param schema @@ -219,6 +240,8 @@ async function getPageRecordMapByNotionAPI({ pageId, from }) { const tagOptions = getAllTags({ allPages, tagOptions: getTagOptions(schema) }) const siteInfo = getBlogInfo({ collection, block }) const customNav = getCustomNav({ allPages: collectionData.filter(post => post.type === 'Page' && post.status === 'Published') }) + // 新的菜单 + const customMenu = getCustomMenu({ collectionData }) const latestPosts = getLatestPosts({ allPages, from, latestPostCount: 5 }) return { @@ -236,6 +259,7 @@ async function getPageRecordMapByNotionAPI({ pageId, from }) { categoryOptions, rawMetadata, customNav, + customMenu, postCount, pageIds, latestPosts diff --git a/lib/notion/getPageProperties.js b/lib/notion/getPageProperties.js index eb3428d0..53b1bee7 100644 --- a/lib/notion/getPageProperties.js +++ b/lib/notion/getPageProperties.js @@ -76,10 +76,14 @@ export default async function getPageProperties(id, block, schema, authToken, ta // 映射值:用户个性化type和status字段的下拉框选项,在此映射回代码的英文标识 mapProperties(properties) - if (properties.type === 'Post') { + if (properties.type === BLOG.NOTION_PROPERTY_NAME.type_post) { properties.slug = BLOG.POST_URL_PREFIX ? (BLOG.POST_URL_PREFIX + '/' + (properties.slug ?? properties.id)) : (properties.slug ?? properties.id) - } else { - properties.slug = (properties.slug ?? properties.id) + } else if (properties.type === BLOG.NOTION_PROPERTY_NAME.type_page) { + properties.slug = properties.slug ?? properties.id + } else if (properties.type === BLOG.NOTION_PROPERTY_NAME.type_menu || properties.type === BLOG.NOTION_PROPERTY_NAME.type_sub_menu) { + // 菜单路径为空、作为可展开菜单使用 + properties.to = properties.slug ?? '#' + properties.name = properties.title ?? '' } // 开启伪静态路径 diff --git a/public/css/theme-simple.css b/public/css/theme-simple.css new file mode 100644 index 00000000..f09aebd2 --- /dev/null +++ b/public/css/theme-simple.css @@ -0,0 +1,8 @@ +#theme-simple #announcement-content { + background-color: #f6f6f6; +} + +.notion { + margin-top: 0 !important; + margin-bottom: 0 !important; +} diff --git a/styles/globals.css b/styles/globals.css index 69097839..07163cf9 100644 --- a/styles/globals.css +++ b/styles/globals.css @@ -215,4 +215,20 @@ nav { /* twikoo 评论区超链接样式 */ .tk-main a { @apply text-blue-700 -} \ No newline at end of file +} + + +/* 菜单下划线动画 */ +.menu-link { + text-decoration: none; + background-image: linear-gradient(#dd3333, #dd3333); + background-repeat: no-repeat; + background-position: bottom center; + background-size: 0 2px; + transition: background-size 100ms ease-in-out; +} + +.menu-link:hover { + background-size: 100% 2px; + color: #dd3333; +} diff --git a/styles/notion.css b/styles/notion.css index 2476a6ac..e966fe8e 100644 --- a/styles/notion.css +++ b/styles/notion.css @@ -1118,10 +1118,11 @@ code[class*='language-'] { .notion-table-of-contents { width: 100%; margin: 4px 0; + @apply bg-gray-50 dark:bg-black p-2 } .notion-table-of-contents-item { - color: inherit; + /* color: inherit; */ text-decoration: none; user-select: none; transition: background 20ms ease-in 0s; @@ -1137,6 +1138,8 @@ code[class*='language-'] { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + + @apply text-blue-600 dark:text-blue-200 } .notion-table-of-contents-item:hover { diff --git a/themes/example/LayoutBase.js b/themes/example/LayoutBase.js index 83193866..90ec3ff9 100644 --- a/themes/example/LayoutBase.js +++ b/themes/example/LayoutBase.js @@ -16,7 +16,7 @@ import BLOG from '@/blog.config' const LayoutBase = props => { const { children, meta } = props return ( -
+
{/* 顶栏LOGO */}
diff --git a/themes/example/components/Header.js b/themes/example/components/Header.js index 7651018b..0cd85268 100644 --- a/themes/example/components/Header.js +++ b/themes/example/components/Header.js @@ -21,5 +21,5 @@ export const Header = (props) => {
- ); + ) } diff --git a/themes/example/components/Nav.js b/themes/example/components/Nav.js index 701e902c..9e05646b 100644 --- a/themes/example/components/Nav.js +++ b/themes/example/components/Nav.js @@ -1,6 +1,6 @@ import { useGlobal } from '@/lib/global' import Link from 'next/link' -import CONFIG_EMPTY from '../config_empty' +import CONFIG_EXAMPLE from '../config_example' /** * 菜单导航 @@ -11,10 +11,10 @@ export const Nav = (props) => { const { customNav } = props const { locale } = useGlobal() let links = [ - { icon: 'fas fa-search', name: locale.NAV.SEARCH, to: '/search', show: CONFIG_EMPTY.MENU_SEARCH }, - { icon: 'fas fa-archive', name: locale.NAV.ARCHIVE, to: '/archive', show: CONFIG_EMPTY.MENU_ARCHIVE }, - { icon: 'fas fa-folder', name: locale.COMMON.CATEGORY, to: '/category', show: CONFIG_EMPTY.MENU_CATEGORY }, - { icon: 'fas fa-tag', name: locale.COMMON.TAGS, to: '/tag', show: CONFIG_EMPTY.MENU_TAG } + { icon: 'fas fa-search', name: locale.NAV.SEARCH, to: '/search', show: CONFIG_EXAMPLE.MENU_SEARCH }, + { icon: 'fas fa-archive', name: locale.NAV.ARCHIVE, to: '/archive', show: CONFIG_EXAMPLE.MENU_ARCHIVE }, + { icon: 'fas fa-folder', name: locale.COMMON.CATEGORY, to: '/category', show: CONFIG_EXAMPLE.MENU_CATEGORY }, + { icon: 'fas fa-tag', name: locale.COMMON.TAGS, to: '/tag', show: CONFIG_EXAMPLE.MENU_TAG } ] if (customNav) { diff --git a/themes/example/config_empty.js b/themes/example/config_example.js similarity index 75% rename from themes/example/config_empty.js rename to themes/example/config_example.js index 1c349a89..c77b1d2d 100644 --- a/themes/example/config_empty.js +++ b/themes/example/config_example.js @@ -1,8 +1,8 @@ -const CONFIG_EMPTY = { +const CONFIG_EXAMPLE = { // 菜单配置 MENU_CATEGORY: true, // 显示分类 MENU_TAG: true, // 显示标签 MENU_ARCHIVE: true, // 显示归档 MENU_SEARCH: true // 显示搜索 } -export default CONFIG_EMPTY +export default CONFIG_EXAMPLE diff --git a/themes/example/index.js b/themes/example/index.js index 95b0a6b2..dd762bd4 100644 --- a/themes/example/index.js +++ b/themes/example/index.js @@ -1,4 +1,4 @@ -import CONFIG_EMPTY from './config_empty' +import CONFIG_EXAMPLE from './config_example' import { LayoutIndex } from './LayoutIndex' import { LayoutSearch } from './LayoutSearch' import { LayoutArchive } from './LayoutArchive' @@ -11,7 +11,7 @@ import { LayoutTag } from './LayoutTag' import { LayoutTagIndex } from './LayoutTagIndex' export { - CONFIG_EMPTY as THEME_CONFIG, + CONFIG_EXAMPLE as THEME_CONFIG, LayoutIndex, LayoutSearch, LayoutArchive, diff --git a/themes/fukasawa/LayoutBase.js b/themes/fukasawa/LayoutBase.js index d06e92d1..b54fcae6 100644 --- a/themes/fukasawa/LayoutBase.js +++ b/themes/fukasawa/LayoutBase.js @@ -25,7 +25,7 @@ const LayoutBase = (props) => { meta } = props const leftAreaSlot = - return (<> + return (
@@ -38,7 +38,7 @@ const LayoutBase = (props) => {
- ) +
) } export default LayoutBase diff --git a/themes/hexo/LayoutBase.js b/themes/hexo/LayoutBase.js index 43086104..0d74522d 100644 --- a/themes/hexo/LayoutBase.js +++ b/themes/hexo/LayoutBase.js @@ -59,7 +59,7 @@ const LayoutBase = props => { }, [show]) return ( -
+
diff --git a/themes/index.js b/themes/index.js index 386a45dc..7f87efb1 100644 --- a/themes/index.js +++ b/themes/index.js @@ -8,6 +8,25 @@ import * as medium from './medium' import * as nobelium from './nobelium' import * as matery from './matery' import * as example from './example' +import * as simple from './simple' -export const ALL_THEME = ['hexo', 'matery', 'next', 'medium', 'fukasawa', 'nobelium', 'example'] -export { hexo, next, medium, fukasawa, nobelium, matery, example } +export const ALL_THEME = [ + 'hexo', + 'matery', + 'next', + 'medium', + 'fukasawa', + 'nobelium', + 'example', + 'simple' +] +export { + hexo, + next, + medium, + fukasawa, + nobelium, + matery, + example, + simple +} diff --git a/themes/matery/LayoutBase.js b/themes/matery/LayoutBase.js index c529c788..949c02aa 100644 --- a/themes/matery/LayoutBase.js +++ b/themes/matery/LayoutBase.js @@ -43,7 +43,7 @@ const LayoutBase = props => { }, [show]) return ( -
+
diff --git a/themes/medium/LayoutBase.js b/themes/medium/LayoutBase.js index 83ee9807..3cdddd5a 100644 --- a/themes/medium/LayoutBase.js +++ b/themes/medium/LayoutBase.js @@ -28,7 +28,7 @@ const LayoutBase = props => { return ( -
+
diff --git a/themes/medium/components/GroupMenu.js b/themes/medium/components/GroupMenu.js index ee1ddb43..a64cf4e7 100644 --- a/themes/medium/components/GroupMenu.js +++ b/themes/medium/components/GroupMenu.js @@ -4,7 +4,7 @@ import { useRouter } from 'next/router' import { useGlobal } from '@/lib/global' import CONFIG_MEDIUM from '../config_medium' -function GroupMenu ({ customNav }) { +function GroupMenu ({ customMenu, customNav }) { const { locale } = useGlobal() const router = useRouter() @@ -39,13 +39,13 @@ function GroupMenu ({ customNav }) { {link.slot} - ); + ) } else { return null } })} - ); + ) } export default GroupMenu diff --git a/themes/medium/components/TopNavBar.js b/themes/medium/components/TopNavBar.js index 50017781..592e2a2f 100644 --- a/themes/medium/components/TopNavBar.js +++ b/themes/medium/components/TopNavBar.js @@ -74,7 +74,7 @@ export default function TopNavBar(props) { {link.slot} - ); + ) } else { return null } @@ -82,5 +82,5 @@ export default function TopNavBar(props) {
- ); + ) } diff --git a/themes/next/LayoutBase.js b/themes/next/LayoutBase.js index 647dbcc8..b96144b3 100644 --- a/themes/next/LayoutBase.js +++ b/themes/next/LayoutBase.js @@ -59,7 +59,7 @@ const LayoutBase = (props) => { return () => document.removeEventListener('scroll', scrollListener) }, [show]) - return (<> + return (
@@ -90,7 +90,7 @@ const LayoutBase = (props) => {
- +
) } diff --git a/themes/nobelium/LayoutBase.js b/themes/nobelium/LayoutBase.js index 598a9b9b..8a84843b 100644 --- a/themes/nobelium/LayoutBase.js +++ b/themes/nobelium/LayoutBase.js @@ -16,7 +16,7 @@ const LayoutBase = props => { const fullWidth = post?.fullWidth ?? false return ( -
+
{/* 顶部导航栏 */} diff --git a/themes/simple/Layout404.js b/themes/simple/Layout404.js new file mode 100644 index 00000000..5f92f0cc --- /dev/null +++ b/themes/simple/Layout404.js @@ -0,0 +1,7 @@ +import LayoutBase from './LayoutBase' + +export const Layout404 = (props) => { + return + 404 Not found. + +} diff --git a/themes/simple/LayoutArchive.js b/themes/simple/LayoutArchive.js new file mode 100644 index 00000000..4ba92d8a --- /dev/null +++ b/themes/simple/LayoutArchive.js @@ -0,0 +1,45 @@ +import BLOG from '@/blog.config' +import Link from 'next/link' +import LayoutBase from './LayoutBase' + +export const LayoutArchive = props => { + const { archivePosts } = props + + return ( + +
+ {Object.keys(archivePosts).map(archiveTitle => ( +
+
+ {archiveTitle} +
+ +
    + {archivePosts[archiveTitle].map(post => ( +
  • +
    + + {post.date?.start_date} + {' '} +   + + + {post.title} + + +
    +
  • + ))} +
+
+ ))} +
+
+ ) +} diff --git a/themes/simple/LayoutBase.js b/themes/simple/LayoutBase.js new file mode 100644 index 00000000..714733ae --- /dev/null +++ b/themes/simple/LayoutBase.js @@ -0,0 +1,60 @@ +import CommonHead from '@/components/CommonHead' +import React from 'react' +import { Header } from './components/Header' +import { Nav } from './components/Nav' +import { Footer } from './components/Footer' +// import { Title } from './components/Title' +import { SideBar } from './components/SideBar' +import JumpToTopButton from './components/JumpToTopButton' +import BLOG from '@/blog.config' +import { TopBar } from './components/TopBar' +import CONFIG_SIMPLE from './config_simple' +import { isBrowser, loadExternalResource } from '@/lib/utils' +/** + * 基础布局 采用左右两侧布局,移动端使用顶部导航栏 + + * @returns {JSX.Element} + * @constructor + */ +const LayoutBase = props => { + const { children, meta } = props + if (isBrowser()) { + loadExternalResource('/css/theme-simple.css', 'css') + } + return ( +
+ + + {CONFIG_SIMPLE.TOP_BAR && } + + {/* 顶部LOGO */} +
+ + {/* 菜单 */} +