diff --git a/components/Footer.tsx b/components/Footer.tsx index 542fca8..f85f15b 100644 --- a/components/Footer.tsx +++ b/components/Footer.tsx @@ -3,6 +3,7 @@ import { FaTwitter } from '@react-icons/all-files/fa/FaTwitter' import { FaZhihu } from '@react-icons/all-files/fa/FaZhihu' import { FaGithub } from '@react-icons/all-files/fa/FaGithub' import { FaLinkedin } from '@react-icons/all-files/fa/FaLinkedin' +import { FaYoutube } from '@react-icons/all-files/fa/FaYoutube' import { IoSunnyOutline } from '@react-icons/all-files/io5/IoSunnyOutline' import { IoMoonSharp } from '@react-icons/all-files/io5/IoMoonSharp' @@ -95,6 +96,18 @@ export const FooterImpl: React.FC = () => { )} + + {config.youtube && ( + + + + )} ) diff --git a/components/PageSocial.module.css b/components/PageSocial.module.css index bb16f8d..bb29c7d 100644 --- a/components/PageSocial.module.css +++ b/components/PageSocial.module.css @@ -100,6 +100,13 @@ border-color: #c9510c; } +.youtube .actionBgPane { + background: #FF0000; +} +.youtube:hover { + border-color: #FF0000; +} + .medium .actionBgPane { background: #00ab6c; } diff --git a/components/PageSocial.tsx b/components/PageSocial.tsx index 246f946..18fba13 100644 --- a/components/PageSocial.tsx +++ b/components/PageSocial.tsx @@ -44,6 +44,17 @@ const socialLinks: SocialLink[] = [ ) + }, + + config.youtube && { + name: 'youtube', + href: `https://www.youtube.com/${config.youtube}`, + title: `YouTube ${config.youtube}`, + icon: ( + + + + ) } ].filter(Boolean) diff --git a/components/styles.module.css b/components/styles.module.css index 0824880..ab9d464 100644 --- a/components/styles.module.css +++ b/components/styles.module.css @@ -101,6 +101,10 @@ color: #c9510c; } +.youtube:hover { + color: #ff0000; +} + .linkedin:hover { color: #0077b5; } diff --git a/lib/config.ts b/lib/config.ts index 3d17ae5..6461b75 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -5,199 +5,201 @@ * for optional depenencies. */ -import { parsePageId } from 'notion-utils' -import posthog from 'posthog-js' -import { getEnv, getSiteConfig } from './get-config-value' -import { NavigationLink } from './site-config' -import { - PageUrlOverridesInverseMap, - PageUrlOverridesMap, - NavigationStyle, - Site -} from './types' - -export const rootNotionPageId: string = parsePageId( - getSiteConfig('rootNotionPageId'), - { uuid: false } -) - -if (!rootNotionPageId) { - throw new Error('Config error invalid "rootNotionPageId"') -} - -// if you want to restrict pages to a single notion workspace (optional) -export const rootNotionSpaceId: string | null = parsePageId( - getSiteConfig('rootNotionSpaceId', null), - { uuid: true } -) - -export const pageUrlOverrides = cleanPageUrlMap( - getSiteConfig('pageUrlOverrides', {}) || {}, - { label: 'pageUrlOverrides' } -) - -export const pageUrlAdditions = cleanPageUrlMap( - getSiteConfig('pageUrlAdditions', {}) || {}, - { label: 'pageUrlAdditions' } -) - -export const inversePageUrlOverrides = invertPageUrlOverrides(pageUrlOverrides) - -export const environment = process.env.NODE_ENV || 'development' -export const isDev = environment === 'development' - -// general site config -export const name: string = getSiteConfig('name') -export const author: string = getSiteConfig('author') -export const domain: string = getSiteConfig('domain') -export const description: string = getSiteConfig('description', 'Notion Blog') -export const language: string = getSiteConfig('language', 'en') - -// social accounts -export const twitter: string | null = getSiteConfig('twitter', null) -export const github: string | null = getSiteConfig('github', null) -export const linkedin: string | null = getSiteConfig('linkedin', null) -export const zhihu: string | null = getSiteConfig('zhihu', null) - -// default notion values for site-wide consistency (optional; may be overridden on a per-page basis) -export const defaultPageIcon: string | null = getSiteConfig( - 'defaultPageIcon', - null -) -export const defaultPageCover: string | null = getSiteConfig( - 'defaultPageCover', - null -) -export const defaultPageCoverPosition: number = getSiteConfig( - 'defaultPageCoverPosition', - 0.5 -) - -// Optional whether or not to enable support for LQIP preview images -export const isPreviewImageSupportEnabled: boolean = getSiteConfig( - 'isPreviewImageSupportEnabled', - false -) - -// Optional whether or not to include the Notion ID in page URLs or just use slugs -export const includeNotionIdInUrls: boolean = getSiteConfig( - 'includeNotionIdInUrls', - !!isDev -) - -export const navigationStyle: NavigationStyle = getSiteConfig( - 'navigationStyle', - 'default' -) - -export const navigationLinks: Array = getSiteConfig( - 'navigationLinks', - null -) - -// Optional site search -export const isSearchEnabled: boolean = getSiteConfig('isSearchEnabled', true) - -// ---------------------------------------------------------------------------- - -// Optional redis instance for persisting preview images -export const isRedisEnabled: boolean = - getSiteConfig('isRedisEnabled', false) || !!getEnv('REDIS_ENABLED', null) - -// (if you want to enable redis, only REDIS_HOST and REDIS_PASSWORD are required) -// we recommend that you store these in a local `.env` file -export const redisHost: string | null = getEnv('REDIS_HOST', null) -export const redisPassword: string | null = getEnv('REDIS_PASSWORD', null) -export const redisUser: string = getEnv('REDIS_USER', 'default') -export const redisUrl = getEnv( - 'REDIS_URL', - `redis://${redisUser}:${redisPassword}@${redisHost}` -) -export const redisNamespace: string | null = getEnv( - 'REDIS_NAMESPACE', - 'preview-images' -) - -// ---------------------------------------------------------------------------- - -export const isServer = typeof window === 'undefined' - -export const port = getEnv('PORT', '3000') -export const host = isDev ? `http://localhost:${port}` : `https://${domain}` - -export const apiBaseUrl = `/api` - -export const api = { - searchNotion: `${apiBaseUrl}/search-notion`, - getSocialImage: `${apiBaseUrl}/social-image` -} - -// ---------------------------------------------------------------------------- - -export const site: Site = { - domain, - name, - rootNotionPageId, - rootNotionSpaceId, - description -} - -export const fathomId = isDev ? null : process.env.NEXT_PUBLIC_FATHOM_ID -export const fathomConfig = fathomId - ? { - excludedDomains: ['localhost', 'localhost:3000'] - } - : undefined - -export const posthogId = process.env.NEXT_PUBLIC_POSTHOG_ID -export const posthogConfig: posthog.Config = { - api_host: 'https://app.posthog.com' -} - -function cleanPageUrlMap( - pageUrlMap: PageUrlOverridesMap, - { - label - }: { - label: string - } -): PageUrlOverridesMap { - return Object.keys(pageUrlMap).reduce((acc, uri) => { - const pageId = pageUrlMap[uri] - const uuid = parsePageId(pageId, { uuid: false }) - - if (!uuid) { - throw new Error(`Invalid ${label} page id "${pageId}"`) - } - - if (!uri) { - throw new Error(`Missing ${label} value for page "${pageId}"`) - } - - if (!uri.startsWith('/')) { - throw new Error( - `Invalid ${label} value for page "${pageId}": value "${uri}" should be a relative URI that starts with "/"` - ) - } - - const path = uri.slice(1) - - return { - ...acc, - [path]: uuid - } - }, {}) -} - -function invertPageUrlOverrides( - pageUrlOverrides: PageUrlOverridesMap -): PageUrlOverridesInverseMap { - return Object.keys(pageUrlOverrides).reduce((acc, uri) => { - const pageId = pageUrlOverrides[uri] - - return { - ...acc, - [pageId]: uri - } - }, {}) -} + import { parsePageId } from 'notion-utils' + import posthog from 'posthog-js' + import { getEnv, getSiteConfig } from './get-config-value' + import { NavigationLink } from './site-config' + import { + PageUrlOverridesInverseMap, + PageUrlOverridesMap, + NavigationStyle, + Site + } from './types' + + export const rootNotionPageId: string = parsePageId( + getSiteConfig('rootNotionPageId'), + { uuid: false } + ) + + if (!rootNotionPageId) { + throw new Error('Config error invalid "rootNotionPageId"') + } + + // if you want to restrict pages to a single notion workspace (optional) + export const rootNotionSpaceId: string | null = parsePageId( + getSiteConfig('rootNotionSpaceId', null), + { uuid: true } + ) + + export const pageUrlOverrides = cleanPageUrlMap( + getSiteConfig('pageUrlOverrides', {}) || {}, + { label: 'pageUrlOverrides' } + ) + + export const pageUrlAdditions = cleanPageUrlMap( + getSiteConfig('pageUrlAdditions', {}) || {}, + { label: 'pageUrlAdditions' } + ) + + export const inversePageUrlOverrides = invertPageUrlOverrides(pageUrlOverrides) + + export const environment = process.env.NODE_ENV || 'development' + export const isDev = environment === 'development' + + // general site config + export const name: string = getSiteConfig('name') + export const author: string = getSiteConfig('author') + export const domain: string = getSiteConfig('domain') + export const description: string = getSiteConfig('description', 'Notion Blog') + export const language: string = getSiteConfig('language', 'en') + + // social accounts + export const twitter: string | null = getSiteConfig('twitter', null) + export const github: string | null = getSiteConfig('github', null) + export const youtube: string | null = getSiteConfig('youtube', null) + export const linkedin: string | null = getSiteConfig('linkedin', null) + export const zhihu: string | null = getSiteConfig('zhihu', null) + + // default notion values for site-wide consistency (optional; may be overridden on a per-page basis) + export const defaultPageIcon: string | null = getSiteConfig( + 'defaultPageIcon', + null + ) + export const defaultPageCover: string | null = getSiteConfig( + 'defaultPageCover', + null + ) + export const defaultPageCoverPosition: number = getSiteConfig( + 'defaultPageCoverPosition', + 0.5 + ) + + // Optional whether or not to enable support for LQIP preview images + export const isPreviewImageSupportEnabled: boolean = getSiteConfig( + 'isPreviewImageSupportEnabled', + false + ) + + // Optional whether or not to include the Notion ID in page URLs or just use slugs + export const includeNotionIdInUrls: boolean = getSiteConfig( + 'includeNotionIdInUrls', + !!isDev + ) + + export const navigationStyle: NavigationStyle = getSiteConfig( + 'navigationStyle', + 'default' + ) + + export const navigationLinks: Array = getSiteConfig( + 'navigationLinks', + null + ) + + // Optional site search + export const isSearchEnabled: boolean = getSiteConfig('isSearchEnabled', true) + + // ---------------------------------------------------------------------------- + + // Optional redis instance for persisting preview images + export const isRedisEnabled: boolean = + getSiteConfig('isRedisEnabled', false) || !!getEnv('REDIS_ENABLED', null) + + // (if you want to enable redis, only REDIS_HOST and REDIS_PASSWORD are required) + // we recommend that you store these in a local `.env` file + export const redisHost: string | null = getEnv('REDIS_HOST', null) + export const redisPassword: string | null = getEnv('REDIS_PASSWORD', null) + export const redisUser: string = getEnv('REDIS_USER', 'default') + export const redisUrl = getEnv( + 'REDIS_URL', + `redis://${redisUser}:${redisPassword}@${redisHost}` + ) + export const redisNamespace: string | null = getEnv( + 'REDIS_NAMESPACE', + 'preview-images' + ) + + // ---------------------------------------------------------------------------- + + export const isServer = typeof window === 'undefined' + + export const port = getEnv('PORT', '3000') + export const host = isDev ? `http://localhost:${port}` : `https://${domain}` + + export const apiBaseUrl = `/api` + + export const api = { + searchNotion: `${apiBaseUrl}/search-notion`, + getSocialImage: `${apiBaseUrl}/social-image` + } + + // ---------------------------------------------------------------------------- + + export const site: Site = { + domain, + name, + rootNotionPageId, + rootNotionSpaceId, + description + } + + export const fathomId = isDev ? null : process.env.NEXT_PUBLIC_FATHOM_ID + export const fathomConfig = fathomId + ? { + excludedDomains: ['localhost', 'localhost:3000'] + } + : undefined + + export const posthogId = process.env.NEXT_PUBLIC_POSTHOG_ID + export const posthogConfig: posthog.Config = { + api_host: 'https://app.posthog.com' + } + + function cleanPageUrlMap( + pageUrlMap: PageUrlOverridesMap, + { + label + }: { + label: string + } + ): PageUrlOverridesMap { + return Object.keys(pageUrlMap).reduce((acc, uri) => { + const pageId = pageUrlMap[uri] + const uuid = parsePageId(pageId, { uuid: false }) + + if (!uuid) { + throw new Error(`Invalid ${label} page id "${pageId}"`) + } + + if (!uri) { + throw new Error(`Missing ${label} value for page "${pageId}"`) + } + + if (!uri.startsWith('/')) { + throw new Error( + `Invalid ${label} value for page "${pageId}": value "${uri}" should be a relative URI that starts with "/"` + ) + } + + const path = uri.slice(1) + + return { + ...acc, + [path]: uuid + } + }, {}) + } + + function invertPageUrlOverrides( + pageUrlOverrides: PageUrlOverridesMap + ): PageUrlOverridesInverseMap { + return Object.keys(pageUrlOverrides).reduce((acc, uri) => { + const pageId = pageUrlOverrides[uri] + + return { + ...acc, + [pageId]: uri + } + }, {}) + } + \ No newline at end of file diff --git a/lib/site-config.ts b/lib/site-config.ts index 4521c86..f97845e 100644 --- a/lib/site-config.ts +++ b/lib/site-config.ts @@ -13,6 +13,7 @@ export interface SiteConfig { twitter?: string github?: string linkedin?: string + youtube?: string zhihu?: string defaultPageIcon?: string | null diff --git a/site.config.ts b/site.config.ts index b58e7fe..9c3e754 100644 --- a/site.config.ts +++ b/site.config.ts @@ -20,6 +20,7 @@ export default siteConfig({ twitter: 'transitive_bs', github: 'transitive-bullshit', linkedin: 'fisch2', + youtube: '#', //use custom channel name or `channel/UCGbXXXXXXXXXXXXXXXXXXXXXX` // default notion icon and cover images for site-wide consistency (optional) // page-specific values will override these site-wide defaults