diff --git a/src/app/(page-detail)/[slug]/pageExtra.tsx b/src/app/(page-detail)/[slug]/pageExtra.tsx index 2d85a5fee7..3e185258c4 100644 --- a/src/app/(page-detail)/[slug]/pageExtra.tsx +++ b/src/app/(page-detail)/[slug]/pageExtra.tsx @@ -7,7 +7,7 @@ import type { Image } from '@mx-space/api-client' import type { PropsWithChildren } from 'react' import { useSetHeaderMetaInfo } from '~/components/layout/header/hooks' -import { Markdown } from '~/components/ui/markdown' +import { MainMarkdown } from '~/components/ui/markdown' import { GoToAdminEditingButton } from '~/components/widgets/shared/GoToAdminEditingButton' import { noopArr } from '~/lib/noop' import { MarkdownImageRecordProvider } from '~/providers/article/MarkdownImageRecordProvider' @@ -31,10 +31,9 @@ export const PageMarkdown = () => { if (!text) return null return ( - ) diff --git a/src/app/notes/[id]/layout.tsx b/src/app/notes/[id]/layout.tsx index 58ee24f71a..cb67bdca45 100644 --- a/src/app/notes/[id]/layout.tsx +++ b/src/app/notes/[id]/layout.tsx @@ -4,6 +4,7 @@ import type { Metadata } from 'next' import { BottomToUpSoftScaleTransitionView } from '~/components/ui/transition/BottomToUpSoftScaleTransitionView' import { OnlyMobile } from '~/components/ui/viewport/OnlyMobile' import { CommentAreaRootLazy } from '~/components/widgets/comment' +import { NoteFontSettingFab } from '~/components/widgets/note/NoteFontFab' import { NoteMainContainer } from '~/components/widgets/note/NoteMainContainer' import { TocFAB } from '~/components/widgets/toc/TocFAB' import { REQUEST_QUERY } from '~/constants/system' @@ -97,6 +98,8 @@ export default async ( + + diff --git a/src/app/notes/[id]/pageExtra.tsx b/src/app/notes/[id]/pageExtra.tsx index 5bbfc1ade6..414382b1d4 100644 --- a/src/app/notes/[id]/pageExtra.tsx +++ b/src/app/notes/[id]/pageExtra.tsx @@ -12,7 +12,7 @@ import type { PropsWithChildren } from 'react' import { MdiClockOutline } from '~/components/icons/clock' import { useSetHeaderMetaInfo } from '~/components/layout/header/hooks' import { FloatPopover } from '~/components/ui/float-popover' -import { Markdown } from '~/components/ui/markdown' +import { MainMarkdown } from '~/components/ui/markdown' import { GoToAdminEditingButton } from '~/components/widgets/shared/GoToAdminEditingButton' import { WithArticleSelectionAction } from '~/components/widgets/shared/WithArticleSelectionAction' import { parseDate } from '~/lib/datetime' @@ -89,12 +89,7 @@ export const NoteMarkdown = () => { const text = useCurrentNoteDataSelector((data) => data?.data.text)! return ( - + ) } export const NoteMarkdownImageRecordProvider = (props: PropsWithChildren) => { diff --git a/src/app/posts/(post-detail)/[category]/[slug]/pageExtra.tsx b/src/app/posts/(post-detail)/[category]/[slug]/pageExtra.tsx index 62254d3b01..723abeffad 100644 --- a/src/app/posts/(post-detail)/[category]/[slug]/pageExtra.tsx +++ b/src/app/posts/(post-detail)/[category]/[slug]/pageExtra.tsx @@ -6,7 +6,7 @@ import type { Image } from '@mx-space/api-client' import type { PropsWithChildren } from 'react' import { useSetHeaderMetaInfo } from '~/components/layout/header/hooks' -import { Markdown } from '~/components/ui/markdown' +import { MainMarkdown } from '~/components/ui/markdown' import { PostMetaBar } from '~/components/widgets/post/PostMetaBar' import { WithArticleSelectionAction } from '~/components/widgets/shared/WithArticleSelectionAction' import { noopArr } from '~/lib/noop' @@ -36,10 +36,9 @@ export const PostMarkdown = () => { if (!text) return null return ( - ) diff --git a/src/components/ui/markdown/Markdown.tsx b/src/components/ui/markdown/Markdown.tsx index caf6c1b58f..fb4b5aa677 100644 --- a/src/components/ui/markdown/Markdown.tsx +++ b/src/components/ui/markdown/Markdown.tsx @@ -11,6 +11,7 @@ import type { FC, PropsWithChildren } from 'react' import { MAIN_MARKDOWN_ID } from '~/constants/dom-id' import { isDev } from '~/lib/env' +import { noopObj } from '~/lib/noop' import { springScrollToElement } from '~/lib/scroller' import { Gallery } from '../gallery' @@ -254,7 +255,6 @@ export const Markdown: FC = return ( = ) }) Markdown.displayName = 'Markdown' + +export const MainMarkdown: FC< + MdProps & MarkdownToJSX.Options & PropsWithChildren +> = (props) => { + const { wrapperProps = noopObj } = props + return ( + ({ + ...wrapperProps, + id: MAIN_MARKDOWN_ID, + }), + [wrapperProps], + )} + /> + ) +} diff --git a/src/components/widgets/note/NoteFontFab.tsx b/src/components/widgets/note/NoteFontFab.tsx new file mode 100644 index 0000000000..ea40e5eed5 --- /dev/null +++ b/src/components/widgets/note/NoteFontFab.tsx @@ -0,0 +1,184 @@ +'use client' + +import { useEffect, useMemo } from 'react' +import { useAtomValue } from 'jotai' +import { atomWithStorage, selectAtom } from 'jotai/utils' + +import { MotionButtonBase } from '~/components/ui/button' +import { FABPortable } from '~/components/ui/fab' +import { FloatPanel } from '~/components/ui/float-panel' +import { MAIN_MARKDOWN_ID } from '~/constants/dom-id' +import { clsxm } from '~/lib/helper' +import { loadStyleSheet } from '~/lib/load-script' +import { Noop } from '~/lib/noop' +import { jotaiStore } from '~/lib/store' + +type Font = 'serif' | 'sans' | 'youzai' | 'lxgw' +const fontAtom = atomWithStorage('note-font', 'serif') + +export const NoteFontSettingFab = () => { + return ( + <> + + + + } + > +
+
字形选择
+
+ + + + + + + + + + + + + + + +
+
+
+ + + ) +} + +const FONT_CONFIG = { + youzai: { + stylesheetUrl: + 'https://fastly.jsdelivr.net/gh/Innei/static@master/fonts/yozai/stylesheet.css', + fontFamily: `'Yozai', 'LXGW WenKai Screen R', var(--font-sans), var(--font-serif), system-ui`, + }, + sans: { + fontFamily: `var(--font-sans), system-ui`, + }, + lxgw: { + stylesheetUrl: + 'https://cdnjs.cloudflare.com/ajax/libs/lxgw-wenkai-screen-webfont/1.7.0/lxgwwenkaiscreenr.css', + fontFamily: `'LXGW WenKai Screen R', Yozai, var(--font-sans), var(--font-serif), system-ui`, + }, +} + +function loadAndApplyFont( + config: (typeof FONT_CONFIG)[keyof typeof FONT_CONFIG], +) { + if ('stylesheetUrl' in config && config.stylesheetUrl) { + loadStyleSheet(config.stylesheetUrl) + } + + const $style = document.createElement('style') + $style.innerHTML = `#${MAIN_MARKDOWN_ID} { font-family: ${config.fontFamily};` + document.head.appendChild($style) + + return () => { + document.head.removeChild($style) + } +} + +const FontAdjust = () => { + const currentFont = useAtomValue(fontAtom) + + useEffect(() => { + const config = (FONT_CONFIG as any)[currentFont] + if (config) { + return loadAndApplyFont(config) + } + }, [currentFont]) + return null +} + +const FontItem: Component<{ + type: Font +}> = ({ children, type }) => { + const isSelected = useAtomValue( + useMemo( + () => + selectAtom(fontAtom, (value) => { + return value === type + }), + [type], + ), + ) + return ( + { + jotaiStore.set(fontAtom, type) + }} + > + {children} + + ) +} + +export const SansFont = () => { + return +} + +export const YouZaiFontSvg = () => { + return ( + + + + ) +} +export const LXGWFontSvg = () => { + return ( + + + + ) +} + +export const SerifFontSvg = () => { + return ( + + + + + + ) +}