From d87a92a095d18900408b5dbe4cfd45a3feacd1d4 Mon Sep 17 00:00:00 2001 From: Innei Date: Tue, 11 Feb 2025 23:09:35 +0800 Subject: [PATCH] feat: custom content font size and line height, resolves FOL-354 Signed-off-by: Innei --- apps/renderer/src/atoms/settings/ui.ts | 3 + .../entry-content/components/EntryTitle.tsx | 12 +- .../modules/entry-content/index.desktop.tsx | 27 +++-- .../modules/entry-content/index.mobile.tsx | 17 +++ .../src/modules/settings/sections/fonts.tsx | 2 +- .../src/modules/settings/tabs/apperance.tsx | 104 +++++++++++++++++- changelog/next.md | 3 + locales/common/en.json | 1 + locales/settings/en.json | 12 +- packages/shared/src/interface/settings.ts | 3 + 10 files changed, 168 insertions(+), 16 deletions(-) diff --git a/apps/renderer/src/atoms/settings/ui.ts b/apps/renderer/src/atoms/settings/ui.ts index 5133b35f1..9b858efd0 100644 --- a/apps/renderer/src/atoms/settings/ui.ts +++ b/apps/renderer/src/atoms/settings/ui.ts @@ -30,6 +30,9 @@ export const createDefaultSettings = (): UISettings => ({ // Font uiFontFamily: "SN Pro", readerFontFamily: "inherit", + contentFontSize: 16, + dateFormat: "default", + contentLineHeight: 1.75, // Content readerRenderInlineStyle: false, codeHighlightThemeLight: "github-light", diff --git a/apps/renderer/src/modules/entry-content/components/EntryTitle.tsx b/apps/renderer/src/modules/entry-content/components/EntryTitle.tsx index 976e3a7fd..8a5fc8b44 100644 --- a/apps/renderer/src/modules/entry-content/components/EntryTitle.tsx +++ b/apps/renderer/src/modules/entry-content/components/EntryTitle.tsx @@ -1,9 +1,11 @@ import type { SupportedLanguages } from "@follow/models/types" import { cn } from "@follow/utils/utils" +import dayjs from "dayjs" import { useMemo } from "react" import { useShowAITranslation } from "~/atoms/ai-translation" import { useGeneralSettingSelector } from "~/atoms/settings/general" +import { useUISettingKey } from "~/atoms/settings/ui" import { useWhoami } from "~/atoms/user" import { RelativeTime } from "~/components/ui/datetime" import { useAuthQuery } from "~/hooks/common" @@ -65,6 +67,14 @@ export const EntryTitle = ({ entryId, compact }: EntryLinkProps) => { }, ) + const dateFormat = useUISettingKey("dateFormat") + + const dateRender = useMemo(() => { + if (!entry?.entries.publishedAt) return null + if (dateFormat === "default") return new Date(entry.entries.publishedAt).toLocaleString() + return dayjs(entry.entries.publishedAt).format(dateFormat) + }, [dateFormat, entry?.entries.publishedAt]) + if (!entry) return null return compact ? ( @@ -104,7 +114,7 @@ export const EntryTitle = ({ entryId, compact }: EntryLinkProps) => { {getPreferredTitle(feed || inbox, entry.entries)}
- {entry.entries.publishedAt && new Date(entry.entries.publishedAt).toLocaleString()} + {dateRender}
diff --git a/apps/renderer/src/modules/entry-content/index.desktop.tsx b/apps/renderer/src/modules/entry-content/index.desktop.tsx index 45f14009a..8d8aacf0e 100644 --- a/apps/renderer/src/modules/entry-content/index.desktop.tsx +++ b/apps/renderer/src/modules/entry-content/index.desktop.tsx @@ -6,6 +6,7 @@ import { IN_ELECTRON } from "@follow/shared/constants" import { stopPropagation } from "@follow/utils/dom" import { cn } from "@follow/utils/utils" import { ErrorBoundary } from "@sentry/react" +import * as React from "react" import { useEffect, useMemo, useRef } from "react" import { useShowAITranslation } from "~/atoms/ai-translation" @@ -82,15 +83,23 @@ export const EntryContent: Component = ({ [entryId, isPeekModal], ) useFocusEntryContainerSubscriptions(scrollerRef) - const stableRenderStyle = useMemo( - () => - readerFontFamily - ? { - fontFamily: readerFontFamily, - } - : undefined, - [readerFontFamily], - ) + const contentLineHeight = useUISettingKey("contentLineHeight") + const contentFontSize = useUISettingKey("contentFontSize") + + const stableRenderStyle = useMemo(() => { + const css = {} as React.CSSProperties + if (readerFontFamily) { + css.fontFamily = readerFontFamily + } + if (contentLineHeight) { + css.lineHeight = contentLineHeight + } + if (contentFontSize) { + css.fontSize = contentFontSize + } + + return css + }, [readerFontFamily, contentLineHeight, contentFontSize]) const mediaInfo = useMemo( () => Object.fromEntries( diff --git a/apps/renderer/src/modules/entry-content/index.mobile.tsx b/apps/renderer/src/modules/entry-content/index.mobile.tsx index 47eb6c4bd..ed33f5ef4 100644 --- a/apps/renderer/src/modules/entry-content/index.mobile.tsx +++ b/apps/renderer/src/modules/entry-content/index.mobile.tsx @@ -108,6 +108,22 @@ export const EntryContent: Component<{ (s) => s.translationLanguage, ) as SupportedLanguages + const contentLineHeight = useUISettingKey("contentLineHeight") + const contentFontSize = useUISettingKey("contentFontSize") + + const stableRenderStyle = useMemo(() => { + const css = {} as React.CSSProperties + + if (contentLineHeight) { + css.lineHeight = contentLineHeight + } + if (contentFontSize) { + css.fontSize = contentFontSize + } + + return css + }, [contentLineHeight, contentFontSize]) + if (!entry) return null const content = entry?.entries.content ?? data?.entries.content @@ -207,6 +223,7 @@ export const EntryContent: Component<{ as="article" className="prose !max-w-full hyphens-auto dark:prose-invert prose-h1:text-[1.6em] prose-h1:font-bold" renderInlineStyle={readerRenderInlineStyle} + style={stableRenderStyle} > {content} diff --git a/apps/renderer/src/modules/settings/sections/fonts.tsx b/apps/renderer/src/modules/settings/sections/fonts.tsx index 2e058ddb3..3c0556375 100644 --- a/apps/renderer/src/modules/settings/sections/fonts.tsx +++ b/apps/renderer/src/modules/settings/sections/fonts.tsx @@ -70,7 +70,7 @@ export const ContentFontSelector = () => { ) return ( -
+
{t("appearance.content_font")} { ) } + +const ContentFontSize = () => { + const { t } = useTranslation("settings") + const contentFontSize = useUISettingKey("contentFontSize") + return ( +
+ {t("appearance.content_font_size")} + + { + setUISetting("contentFontSize", Number.parseInt(value)) + }} + triggerClassName="w-48" + size="sm" + /> +
+ ) +} + +const ContentLineHeight = () => { + const { t } = useTranslation("settings") + const contentLineHeight = useUISettingKey("contentLineHeight") + return ( +
+ + {t("appearance.content_line_height.label")} + + + { + setUISetting("contentLineHeight", Number.parseFloat(value)) + }} + triggerClassName="w-48" + size="sm" + /> +
+ ) +} + +const DateFormat = () => { + const { t } = useTranslation("settings") + const { t: commonT } = useTranslation("common") + const dateFormat = useUISettingKey("dateFormat") + const [date] = useState(() => new Date()) + + const generateItem = (format: string) => ({ + value: format, + label: dayjs(date).format(format), + }) + return ( +
+ {t("appearance.date_format")} + + { + setUISetting("dateFormat", value) + }} + triggerClassName="w-48" + size="sm" + /> +
+ ) +} diff --git a/changelog/next.md b/changelog/next.md index 17888d80b..07e94b5a0 100644 --- a/changelog/next.md +++ b/changelog/next.md @@ -2,6 +2,9 @@ ## New Features +- Support custom font and line height for content +- Support custom date format for entry title date + ## Improvements ## Bug Fixes diff --git a/locales/common/en.json b/locales/common/en.json index 74a1ff4d5..d7d53dfa5 100644 --- a/locales/common/en.json +++ b/locales/common/en.json @@ -18,6 +18,7 @@ "words.back": "Back", "words.copy": "Copy", "words.create": "Create", + "words.default": "Default", "words.delete": "Delete", "words.download": "Download", "words.edit": "Edit", diff --git a/locales/settings/en.json b/locales/settings/en.json index 1c3d65e55..654ddb24b 100644 --- a/locales/settings/en.json +++ b/locales/settings/en.json @@ -55,10 +55,18 @@ "appearance.code_highlight_theme": "Code highlight theme", "appearance.content": "Content", "appearance.content_font": "Content Font", + "appearance.content_font_size": "Content Font Size", + "appearance.content_line_height.label": "Content Line Height", + "appearance.content_line_height.loose": "Loose", + "appearance.content_line_height.normal": "Normal", + "appearance.content_line_height.relaxed": "Relaxed", + "appearance.content_line_height.snug": "Snug", + "appearance.content_line_height.tight": "Tight", "appearance.custom_css.button": "Edit", "appearance.custom_css.description": "Custom CSS style for content", "appearance.custom_css.label": "Custom CSS", "appearance.custom_font": "Custom Font", + "appearance.date_format": "Date format", "appearance.fonts": "Fonts", "appearance.general": "General", "appearance.guess_code_language.description": "Major programming languages that use models to infer unlabeled code blocks", @@ -80,7 +88,7 @@ "appearance.sidebar": "Sidebar", "appearance.sidebar_show_unread_count.label": "Show in sidebar", "appearance.sidebar_title": "Appearance", - "appearance.text_size": "Text size", + "appearance.text_size": "Global Text Size", "appearance.theme.dark": "Dark", "appearance.theme.label": "Theme", "appearance.theme.light": "Light", @@ -90,7 +98,7 @@ "appearance.thumbnail_ratio.square": "Square", "appearance.thumbnail_ratio.title": "Thumbnail ratio", "appearance.title": "Appearance", - "appearance.ui_font": "UI Font", + "appearance.ui_font": "Global Font", "appearance.unread_count": "Unread count", "appearance.use_pointer_cursor.description": "Change the cursor to a pointer when hovering over any interactive element.", "appearance.use_pointer_cursor.label": "Use pointer cursors", diff --git a/packages/shared/src/interface/settings.ts b/packages/shared/src/interface/settings.ts index d9375de77..7a4a39a20 100644 --- a/packages/shared/src/interface/settings.ts +++ b/packages/shared/src/interface/settings.ts @@ -52,6 +52,9 @@ export interface UISettings { pictureViewMasonry: boolean pictureViewFilterNoImage: boolean wideMode: boolean + contentFontSize: number + dateFormat: string + contentLineHeight: number // Action Order toolbarOrder: {