diff --git a/.env b/.env new file mode 100644 index 00000000..7d01d486 --- /dev/null +++ b/.env @@ -0,0 +1,3 @@ +NOTION_PAGE_ID=9fd80f60b1d54dcfa893db9da14b1a6f +NOTION_SPACES_ID=fff2d8331ef0811dbf54000c3df82816 +TELEGRAM_TOKEN= diff --git a/.env.example b/.env.example deleted file mode 100644 index 0a4a8201..00000000 --- a/.env.example +++ /dev/null @@ -1,3 +0,0 @@ -NOTION_PAGE_ID= -NOTION_SPACES_ID= -TELEGRAM_TOKEN= \ No newline at end of file diff --git a/blog.config.js b/blog.config.js index 318780df..2cc2abc9 100644 --- a/blog.config.js +++ b/blog.config.js @@ -1,82 +1,79 @@ const BLOG = { - title: 'Notionic', - author: '左蓝', - email: 'i@zuolan.me', - link: 'https://zuolan.me', - newsletter: 'Notionic Weekly', - description: 'A static blog build on top of Notion and Next.js', - lang: 'en-US', // ['en-US', 'zh-CN', 'zh-HK', 'zh-TW', 'ja-JP', 'es-ES'] - timezone: 'Asia/Shanghai', // See https://en.wikipedia.org/wiki/List_of_tz_database_time_zones for all options. - appearance: 'auto', // ['light', 'dark', 'auto'], - font: 'sans-serif', // ['sans-serif', 'serif'] - lightBackground: '#F6F8FA', // use hex value, don't forget '#' e.g #fffefc - darkBackground: '#212936', // use hex value, don't forget '#' - path: '', // leave this empty unless you want to deploy Notionic in a folder - since: 2022, // If leave this empty, current year will be used. - postsPerPage: 10, - sortByDate: true, - pagesShow: { + title: '810C', // 博客的标题 + author: 'FuHeng', // 博主的名字 + email: '2827162018@qq.com', // 博主的电子邮件 + link: 'https://810C.cn', // 博客链接 + newsletter: 'Notionic Weekly', // 新闻订阅的名称 + description: 'FuHeng的个人博客', // 博客的描述 + lang: 'zh-CN', // 博客语言,支持多种语言 + timezone: 'Asia/Shanghai', // 时区设置 + appearance: 'auto', // 外观模式,支持亮色、暗色和自动模式 + font: 'sans-serif', // 字体类型,可选择无衬线或有衬线字体 + lightBackground: '#F6F8FA', // 亮色背景的十六进制颜色值 + darkBackground: '#212936', // 暗色背景的十六进制颜色值 + path: '', // 部署时的路径,默认为空即根路径 + since: 2022, // 博客开始年份,如果留空则使用当前年份 + postsPerPage: 10, // 每页显示的文章数量 + sortByDate: true, // 是否按日期排序 + pagesShow: { // 控制哪些页面显示 newsletter: true, - notes: true, + notes: false, projects: true, contact: true, books: true, friends: true }, - showWeChatPay: true, - previewImagesEnabled: true, - autoCollapsedNavBar: false, // The automatically collapsed navigation bar - ogImageGenerateHost: 'og-zl.vercel.app', // The link to generate OG image, don't end with a slash - defaultCover: '/cover.jpg', - socialLink: { - twitter: 'https://twitter.com/izuolan', - github: 'https://github.com/izuolan', - telegram: 'https://t.me/zuolan' + showWeChatPay: true, // 是否显示微信支付选项 + previewImagesEnabled: true, // 是否启用预览图像 + autoCollapsedNavBar: false, // 导航栏是否自动折叠 + ogImageGenerateHost: 'og-zl.vercel.app', // 生成OG图像的链接 + defaultCover: '/cover.jpg', // 默认封面图片路径 + socialLink: { // 社交媒体链接 + twitter: '', // Twitter链接 + github: '', // GitHub链接 + telegram: '' // Telegram链接 }, - seo: { - keywords: ['Notionic', 'Zuolan', 'Blog'], - googleSiteVerification: '' // Remove the value or replace it with your own google site verification code + seo: { // SEO设置 + keywords: ['Notionic', 'Zuolan', 'Blog'], // 关键词 + googleSiteVerification: '' // Google站点验证代码 }, - notionPageId: process.env.NOTION_PAGE_ID, // DO NOT CHANGE THIS! Edit .env file! - notionSpacesId: process.env.NOTION_SPACES_ID, // DO NOT CHANGE THIS! Edit .env file! - notionAccessToken: process.env.NOTION_ACCESS_TOKEN, // Useful if you prefer not to make your database public - notionDomain: 'izuolan.notion.site', - telegramToken: process.env.TELEGRAM_TOKEN, // The token of your Telegram bot - telegramChatId: '263895784', // The chat id of your Telegram bot - telegramChannelUrl: 'https://channel.zuolan.me/', // The link of your Telegram channel - telegramChannelName: 'zuolan_me', // The name of your Telegram channel - craftConfigShareUrl: 'https://www.craft.do/s/kQtcWqkv98cHhB', // The link to share your craft config - analytics: { - provider: '', // Currently we support Google Analytics, Ackee, Umami and Cloudflare Insights, please fill with 'ga' or 'ackee' or 'umami' or 'cf', leave it empty to disable it. - ackeeConfig: { - tracker: '', // e.g 'https://ackee.example.com/tracker.js' - dataAckeeServer: '', // e.g https://ackee.example.com , don't end with a slash - domainId: '' // e.g '0e2257a8-54d4-4847-91a1-0311ea48cc7b' + notionPageId: process.env.NOTION_PAGE_ID, // Notion页面ID,需在.env文件中设置 + notionSpacesId: process.env.NOTION_SPACES_ID, // Notion空间ID,需在.env文件中设置 + notionAccessToken: process.env.NOTION_ACCESS_TOKEN, // Notion访问令牌,用于私有数据库 + notionDomain: 'fuheng-blog.notion.site', // Notion域名 + telegramChannelUrl: 'https://channel.zuolan.me/', // Telegram频道链接 + telegramChannelName: 'zuolan_me', // Telegram频道名称 + craftConfigShareUrl: 'https://www.craft.do/s/kQtcWqkv98cHhB', // Craft配置分享链接 + analytics: { // 分析设置 + provider: '', // 可选分析提供者: Google Analytics, Ackee, Umami, Cloudflare Insights + ackeeConfig: { // Ackee配置 + tracker: '', // Ackee跟踪器URL + dataAckeeServer: '', // Ackee数据服务器URL + domainId: '' // Ackee域ID }, - cfConfig: { - scriptUrl: 'https://static.cloudflareinsights.com/beacon.min.js', // Default - token: '' // Like '{"token": "xxxxxxxxxxxxxxxxxx"}' + cfConfig: { // Cloudflare配置 + scriptUrl: 'https://static.cloudflareinsights.com/beacon.min.js', // Cloudflare默认跟踪脚本 + token: '' // Cloudflare令牌 }, - gaConfig: { - measurementId: '' // e.g: G-XXXXXXXXXX + gaConfig: { // Google Analytics配置 + measurementId: '' // Google测量ID }, - umamiConfig: { - scriptUrl: '', // The url of your Umami script - websiteId: '' // The website id of your Umami instance + umamiConfig: { // Umami配置 + scriptUrl: '', // Umami脚本URL + websiteId: '' // Umami网站ID } }, - comment: { - // support provider: utterances, supacomments - provider: '', // leave it empty if you don't need any comment plugin - supaCommentsConfig: { - supabaseUrl: '', // The url of your Supabase instance - supabaseAnonKey: '' // The anonymous key of your Supabase instance + comment: { // 评论设置 + provider: '', // 支持的评论提供者,可以为空 + supaCommentsConfig: { // SupaComments配置 + supabaseUrl: '', // Supabase实例URL + supabaseAnonKey: '' // Supabase匿名密钥 }, - utterancesConfig: { - repo: '' + utterancesConfig: { // Utterances配置 + repo: '' // GitHub仓库 } }, - isProd: process.env.VERCEL_ENV === 'production' // distinguish between development and production environment (ref: https://vercel.com/docs/environment-variables#system-environment-variables) + isProd: process.env.VERCEL_ENV === 'production' // 判断是否为生产环境 } // export default BLOG -module.exports = BLOG +module.exports = BLOG // 导出博客配置 diff --git a/components/Common/Logo.js b/components/Common/Logo.js index a400bd52..7db45f5b 100644 --- a/components/Common/Logo.js +++ b/components/Common/Logo.js @@ -2,21 +2,22 @@ import * as React from 'react' const Logo = (props) => ( - - - - - - + + + + + + + + + ) export default Logo diff --git a/components/ContactForm.js b/components/ContactForm.js deleted file mode 100644 index 1568249d..00000000 --- a/components/ContactForm.js +++ /dev/null @@ -1,132 +0,0 @@ -import { useState } from 'react' -import { lang } from '@/lib/lang' -import { useRouter } from 'next/router' - -function Contact() { - const [showResult, setShowResult] = useState(false) - const [submitting, setSubmitting] = useState(false) - const { locale } = useRouter() - const t = lang[locale] - - const sentMessage = async (event) => { - event.preventDefault() - setSubmitting(true) - // setTimeout(() => { - // setSubmitting(false) - // setShowResult(true) - // }, 3000) - - const tgUrl = '/api/sendtotg' - const res = await fetch(tgUrl, { - body: JSON.stringify({ - name: event.target.name.value, - mail: event.target.mail.value, - message: event.target.message.value - }), - headers: { - 'Content-Type': 'application/json' - }, - method: 'POST' - }) - // await res.json() - const result = await res.json() - const status = result.status - console.log('status:', status) - if (status === 'Success') { - setSubmitting(false) - setShowResult(true) - } else { - alert(t.CONTACT.FAILED_MESSAGE) - } - } - return ( - <> - {showResult ? ( -
-

- {t.CONTACT.SUCCESS_MESSAGE} -

-
- ) : ( -
-
- -
-
- -
- -
- -
- -
- {submitting ? ( - - ) : ( - - )} -

- {t.CONTACT.FORM_EMAIL_REQUIRED} -

-
-
- )} - - ) -} - -export default Contact diff --git a/lib/lang.js b/lib/lang.js index 129c195d..0e0882c1 100644 --- a/lib/lang.js +++ b/lib/lang.js @@ -9,7 +9,7 @@ export const lang = { NOTES: '笔记', NEWSLETTER: '周刊', BOOKS: '书架', - CONTACT: '私信' + CONTACT: '联系' }, PAGINATION: { PREV: '上一页', @@ -18,7 +18,7 @@ export const lang = { LAYOUT: { NOTICE_TEXT: '对于本文内容有任何疑问, 可与我联系.', PAY_BUTTON: '微信赞赏', - NOTICE_BUTTON: '一键私信', + NOTICE_BUTTON: '联系我', COMMENT_TITLE: '评论区' }, SEARCH: { @@ -28,7 +28,7 @@ export const lang = { }, HERO: { HOME: { - CONTACT_BUTTON: '一键私信', + CONTACT_BUTTON: '联系我', CONTACT_BUTTON_DES: '快速与我联系', RSS_BUTTON: '订阅博客' }, @@ -44,18 +44,7 @@ export const lang = { RSS_BUTTON_COPIED: '已复制', RSS_BUTTON_DES_COPIED: '已复制 RSS 链接' }, - CONTACT: { - TITLE: '一键私信', - DESCRIPTION: '如有疑问或建议需与我联系, 请填写下面表单.', - TG_DESCRIPTION: '也可直接联系 Telegram: ', - SUCCESS_MESSAGE: '消息已发送, 我会尽快回复到你的邮箱.', - FORM_USERNAME: '你的昵称', - FORM_EMAIL: '你的邮箱*', - FORM_CONTENT: '消息内容', - SEND_BUTTON: '发送', - FORM_EMAIL_REQUIRED: '*可以填写其他有效联系方式', - FAILED_MESSAGE: '抱歉, 发送失败, 请直接联系我的 Telegram 吧.' - }, + FOOTER: { COPYRIGHT_START: '本站原创内容基于 ', COPYRIGHT_NAME: 'CC BY-SA 4.0', diff --git a/pages/api/sendtotg.js b/pages/api/sendtotg.js index 779ed1a4..475f2485 100644 --- a/pages/api/sendtotg.js +++ b/pages/api/sendtotg.js @@ -1,24 +1,2 @@ import BLOG from '@/blog.config' -export default async function sendtotg(req, res) { - const TG_TOKEN = BLOG.telegramToken - const TG_CHAT_ID = BLOG.telegramChatId - const tgUrl = 'https://api.telegram.org/bot' + TG_TOKEN + '/sendMessage' - const init = { - method: 'POST', - headers: { - 'content-type': 'application/json;charset=UTF-8' - }, - body: JSON.stringify({ - chat_id: TG_CHAT_ID, - text: req.body - }) - } - const response = await fetch(tgUrl, init) - if (response.status === 200) { - // const respText = await response.text() - res.send({ status: 'Success' }) - } else { - res.send({ status: 'Fail to send message to Telegram' }) - } -} diff --git a/pages/contact.js b/pages/contact.js deleted file mode 100644 index ee0574fe..00000000 --- a/pages/contact.js +++ /dev/null @@ -1,34 +0,0 @@ -import Container from '@/components/Container' -import ContactForm from '@/components/ContactForm' -import BLOG from '@/blog.config' -import { lang } from '@/lib/lang' -import { useRouter } from 'next/router' - -export const Contact = () => { - const { locale } = useRouter() - const t = lang[locale] - return ( - -
-

- {t.CONTACT.TITLE} -

-

- {t.CONTACT.DESCRIPTION} -

-

- {t.CONTACT.TG_DESCRIPTION} - - @{BLOG.socialLink.telegram.slice(13)} - -

-
- -
- ) -} - -export default Contact diff --git a/pages/notes.js b/pages/notes.js index eca395ef..eccca07b 100644 --- a/pages/notes.js +++ b/pages/notes.js @@ -1,25 +1,21 @@ -import Container from '@/components/Container' -import NotePost from '@/components/NotePost' -import NotesHero from '@/components/Hero/Notes' -import { getBlocksMaps } from '@/lib/getBlocksMaps' -import { getPostBlocks, getAllPosts } from '@/lib/notion' +import Container from '@/components/Container' // 导入Container组件 +import BlogPost from '@/components/BlogPost' // 导入BlogPost组件 +import NewsletterHero from '@/components/Hero/Newsletter' // 导入NewsletterHero组件 +import { getAllPosts, getPostBlocks } from '@/lib/notion' // 导入getAllPosts和getPostBlocks函数 +import BLOG from '@/blog.config' // 导入BLOG配置 export async function getStaticProps() { - const { pagesJson, siteConfigObj } = await getBlocksMaps() - - const blocksJson = pagesJson - // Hide table header and home page on Archive page. - for (let i = 0; i < blocksJson.length; i++) { - const deleteTitleBlock = blocksJson[i].title === 'Title' ? blocksJson.splice(i, i + 1) : blocksJson - const deleteIndexBlock = blocksJson[i].slug === 'index' ? blocksJson.splice(i, i + 1) : blocksJson - console.log('[INFO] Hide Craft Table Header: ', deleteTitleBlock.length, deleteIndexBlock.length) - } + // 获取所有只包含Newsletter的帖子 + const posts = await getAllPosts({ onlyNewsletter: true }) + // 获取所有隐藏的帖子 const heros = await getAllPosts({ onlyHidden: true }) - const hero = heros.find((t) => t.slug === 'notes') + // 找到slug为'newsletter'的帖子 + const hero = heros.find((t) => t.slug === 'newsletter') let blockMap try { + // 获取hero的blockMap blockMap = await getPostBlocks(hero.id) } catch (err) { console.error(err) @@ -28,27 +24,23 @@ export async function getStaticProps() { return { props: { - blocksJson, - siteConfigObj, + posts, blockMap }, revalidate: 1 } } -const Notes = ({ blocksJson, siteConfigObj, blockMap }) => { +// 定义newsletter函数 +const newsletter = ({ posts, blockMap }) => { return ( - - - {blocksJson.map((block) => ( - + + + {posts.map((post) => ( + ))} ) } -export default Notes +export default newsletter // 导出newsletter函数 \ No newline at end of file diff --git a/public/favicon.ico b/public/favicon.ico index a68da060..d0f52945 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/favicon.png b/public/favicon.png index d5efc4dd..73bad400 100644 Binary files a/public/favicon.png and b/public/favicon.png differ diff --git a/public/favicon.svg b/public/favicon.svg index 856b0181..f183c24a 100644 --- a/public/favicon.svg +++ b/public/favicon.svg @@ -1 +1,456 @@ - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file