editor: encapsulate font family utility

This commit is contained in:
Abdullah Atta
2023-04-16 00:57:30 +05:00
parent 9744679550
commit ecd4a08b1c
7 changed files with 84 additions and 64 deletions

View File

@@ -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}`

View File

@@ -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) {

View File

@@ -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,

View File

@@ -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;

View File

@@ -42,7 +42,7 @@ type ToolbarProps = FlexProps & {
location: ToolbarLocation;
tools?: ToolbarDefinition;
defaultFontFamily: string;
defaultFontSize: string;
defaultFontSize: number;
};
export function Toolbar(props: ToolbarProps) {

View File

@@ -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
}
});
}

View 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);
}