mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-02-24 04:00:59 +01:00
editor: encapsulate font family utility
This commit is contained in:
@@ -17,8 +17,8 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import "@tiptap/extension-text-style";
|
||||
import { getFontConfig } from "@notesnook/theme/dist/theme/font";
|
||||
import { Extension } from "@tiptap/core";
|
||||
import { getFontById } from "../../utils/font";
|
||||
|
||||
export type FontFamilyOptions = {
|
||||
types: string[];
|
||||
@@ -39,12 +39,6 @@ declare module "@tiptap/core" {
|
||||
}
|
||||
}
|
||||
|
||||
export const FONTS: Record<string, string> = {
|
||||
monospace: getFontConfig().fonts.monospace,
|
||||
"sans-serif": getFontConfig().fonts.body,
|
||||
serif: `Noto Serif, Times New Roman, serif`
|
||||
};
|
||||
|
||||
export const FontFamily = Extension.create<FontFamilyOptions>({
|
||||
name: "fontFamily",
|
||||
|
||||
@@ -70,7 +64,8 @@ export const FontFamily = Extension.create<FontFamilyOptions>({
|
||||
|
||||
const realFontFamily =
|
||||
attributes["data-font-family"] || attributes.fontFamily;
|
||||
const font = FONTS[realFontFamily] || attributes.fontFamily;
|
||||
const font =
|
||||
getFontById(realFontFamily)?.font || attributes.fontFamily;
|
||||
return {
|
||||
"data-font-family": realFontFamily,
|
||||
style: `font-family: ${font}`
|
||||
|
||||
@@ -22,7 +22,6 @@ import "@tiptap/extension-text-style";
|
||||
|
||||
type FontSizeOptions = {
|
||||
types: string[];
|
||||
defaultFontSize: number;
|
||||
};
|
||||
|
||||
declare module "@tiptap/core" {
|
||||
@@ -44,8 +43,7 @@ export const FontSize = Extension.create<FontSizeOptions>({
|
||||
name: "fontSize",
|
||||
|
||||
defaultOptions: {
|
||||
types: ["textStyle"],
|
||||
defaultFontSize: 16
|
||||
types: ["textStyle"]
|
||||
},
|
||||
|
||||
addGlobalAttributes() {
|
||||
@@ -54,7 +52,6 @@ export const FontSize = Extension.create<FontSizeOptions>({
|
||||
types: this.options.types,
|
||||
attributes: {
|
||||
fontSize: {
|
||||
default: `${this.options.defaultFontSize}px`,
|
||||
parseHTML: (element) => element.style.fontSize,
|
||||
renderHTML: (attributes) => {
|
||||
if (!attributes.fontSize) {
|
||||
|
||||
@@ -271,7 +271,7 @@ export * from "./extensions/react";
|
||||
export * from "./toolbar";
|
||||
export * from "./types";
|
||||
export * from "./utils/word-counter";
|
||||
export { FONTS } from "./extensions/font-family/font-family";
|
||||
export * from "./utils/font";
|
||||
export {
|
||||
useTiptap,
|
||||
Toolbar,
|
||||
|
||||
@@ -20,7 +20,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import { Theme } from "@notesnook/theme";
|
||||
import create from "zustand";
|
||||
import { DownloadOptions } from "../../utils/downloader";
|
||||
import { FontFamily } from "../tools/font";
|
||||
|
||||
export type ToolbarLocation = "top" | "bottom";
|
||||
|
||||
@@ -44,8 +43,8 @@ interface ToolbarState {
|
||||
closeAllPopups: () => void;
|
||||
fontFamily: string;
|
||||
setFontFamily: (fontFamily: string) => void;
|
||||
fontSize: string;
|
||||
setFontSize: (fontSize: string) => void;
|
||||
fontSize: number;
|
||||
setFontSize: (fontSize: number) => void;
|
||||
}
|
||||
|
||||
export const useToolbarStore = create<ToolbarState>((set, get) => ({
|
||||
@@ -105,12 +104,12 @@ export const useToolbarStore = create<ToolbarState>((set, get) => ({
|
||||
state.openedPopups[key] = undefined;
|
||||
}
|
||||
}),
|
||||
fontFamily: "",
|
||||
fontFamily: "sans-serif",
|
||||
setFontFamily: (fontFamily) =>
|
||||
set((state) => {
|
||||
state.fontFamily = fontFamily;
|
||||
}),
|
||||
fontSize: "",
|
||||
fontSize: 16,
|
||||
setFontSize: (fontSize) =>
|
||||
set((state) => {
|
||||
state.fontSize = fontSize;
|
||||
|
||||
@@ -42,7 +42,7 @@ type ToolbarProps = FlexProps & {
|
||||
location: ToolbarLocation;
|
||||
tools?: ToolbarDefinition;
|
||||
defaultFontFamily: string;
|
||||
defaultFontSize: string;
|
||||
defaultFontSize: number;
|
||||
};
|
||||
|
||||
export function Toolbar(props: ToolbarProps) {
|
||||
|
||||
@@ -21,17 +21,19 @@ import { ToolProps } from "../types";
|
||||
import { Editor } from "../../types";
|
||||
import { Dropdown } from "../components/dropdown";
|
||||
import { MenuItem } from "../../components/menu/types";
|
||||
import { useCallback, useEffect, useMemo } from "react";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import { Counter } from "../components/counter";
|
||||
import { useRefValue } from "../../hooks/use-ref-value";
|
||||
import { useToolbarStore } from "../stores/toolbar-store";
|
||||
import { getFontById, getFontIds, getFonts } from "../../utils/font";
|
||||
|
||||
export function FontSize(props: ToolProps) {
|
||||
const { editor } = props;
|
||||
const defaultFontSize = useToolbarStore((store) => store.fontSize);
|
||||
const { fontSize: _fontSize } = editor.getAttributes("textStyle");
|
||||
const fontSize = _fontSize || defaultFontSize;
|
||||
const fontSizeAsNumber = useRefValue(parseInt(fontSize.replace("px", "")));
|
||||
const { fontSize } = editor.getAttributes("textStyle");
|
||||
const fontSizeAsNumber = useRefValue(
|
||||
fontSize ? parseInt(fontSize.replace("px", "")) : defaultFontSize
|
||||
);
|
||||
|
||||
const decreaseFontSize = useCallback(() => {
|
||||
return Math.max(8, fontSizeAsNumber.current - 1);
|
||||
@@ -59,46 +61,27 @@ export function FontSize(props: ToolProps) {
|
||||
.run();
|
||||
}}
|
||||
onReset={() =>
|
||||
editor.current?.chain().focus().setFontSize(defaultFontSize).run()
|
||||
editor.current
|
||||
?.chain()
|
||||
.focus()
|
||||
.setFontSize(`${defaultFontSize}px`)
|
||||
.run()
|
||||
}
|
||||
value={fontSize}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
interface CustomFonts {
|
||||
[key: string]: string;
|
||||
}
|
||||
function fontFamilies(defaultFontFamily: string) {
|
||||
const fonts: { [key: string]: string } = {
|
||||
"Sans-serif": "Open Sans",
|
||||
Serif: "serif",
|
||||
Monospace: "monospace"
|
||||
};
|
||||
|
||||
const customFonts: CustomFonts = {};
|
||||
customFonts[defaultFontFamily] = fonts[defaultFontFamily];
|
||||
|
||||
Object.entries(fonts).map(([key, value]) => {
|
||||
if (key !== defaultFontFamily) customFonts[key] = value;
|
||||
});
|
||||
return customFonts;
|
||||
}
|
||||
|
||||
export function FontFamily(props: ToolProps) {
|
||||
const { editor } = props;
|
||||
const defaultFontFamily = useToolbarStore((store) => store.fontFamily);
|
||||
const customFonts = fontFamilies(defaultFontFamily);
|
||||
const currentFontFamily =
|
||||
Object.entries(customFonts)
|
||||
.find(([_key, value]) =>
|
||||
editor.isActive("textStyle", { fontFamily: value })
|
||||
)
|
||||
?.map((a) => a)
|
||||
?.at(0) || defaultFontFamily;
|
||||
getFontIds().find((id) =>
|
||||
editor.isActive("textStyle", { fontFamily: id })
|
||||
) || defaultFontFamily;
|
||||
|
||||
const items = useMemo(
|
||||
() => toMenuItems(editor, currentFontFamily, customFonts),
|
||||
() => toMenuItems(editor, currentFontFamily),
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[currentFontFamily]
|
||||
);
|
||||
@@ -107,29 +90,25 @@ export function FontFamily(props: ToolProps) {
|
||||
<Dropdown
|
||||
id="fontFamily"
|
||||
group="font"
|
||||
selectedItem={currentFontFamily}
|
||||
selectedItem={getFontById(currentFontFamily)?.title || defaultFontFamily}
|
||||
items={items}
|
||||
menuWidth={130}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function toMenuItems(
|
||||
editor: Editor,
|
||||
currentFontFamily: string,
|
||||
customFonts: CustomFonts
|
||||
): MenuItem[] {
|
||||
function toMenuItems(editor: Editor, currentFontFamily: string): MenuItem[] {
|
||||
const menuItems: MenuItem[] = [];
|
||||
for (const key in customFonts) {
|
||||
const value = customFonts[key as keyof typeof customFonts];
|
||||
for (const font of getFonts()) {
|
||||
menuItems.push({
|
||||
key,
|
||||
key: font.id,
|
||||
type: "button",
|
||||
title: key,
|
||||
isChecked: key === currentFontFamily,
|
||||
onClick: () => editor.current?.chain().focus().setFontFamily(value).run(),
|
||||
title: font.title,
|
||||
isChecked: font.id === currentFontFamily,
|
||||
onClick: () =>
|
||||
editor.current?.chain().focus().setFontFamily(font.id).run(),
|
||||
styles: {
|
||||
fontFamily: value
|
||||
fontFamily: font.font
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
50
packages/editor/src/utils/font.ts
Normal file
50
packages/editor/src/utils/font.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { getFontConfig } from "@notesnook/theme/dist/theme/font";
|
||||
|
||||
const FONTS = [
|
||||
{
|
||||
title: "Monospace",
|
||||
id: "monospace",
|
||||
font: getFontConfig().fonts.monospace
|
||||
},
|
||||
{
|
||||
title: "Sans-serif",
|
||||
id: "sans-serif",
|
||||
font: getFontConfig().fonts.body
|
||||
},
|
||||
{
|
||||
title: "Serif",
|
||||
id: "serif",
|
||||
font: `Noto Serif, Times New Roman, serif`
|
||||
}
|
||||
];
|
||||
|
||||
export function getFonts() {
|
||||
return FONTS;
|
||||
}
|
||||
|
||||
export function getFontById(id: string) {
|
||||
return FONTS.find((a) => a.id === id);
|
||||
}
|
||||
|
||||
export function getFontIds() {
|
||||
return FONTS.map((a) => a.id);
|
||||
}
|
||||
Reference in New Issue
Block a user