mirror of
https://github.com/dream-num/univer.git
synced 2026-08-31 01:42:03 +08:00
feat(ui): add font management service & support appending custom font family (#6237)
This commit is contained in:
@@ -125,6 +125,10 @@ function createNewInstance() {
|
||||
[UniverUIPlugin, {
|
||||
container: 'app',
|
||||
// ribbonType: 'classic',
|
||||
customFontFamily: [
|
||||
{ value: 'PingFang SC', label: '苹方(简)', category: 'sans-serif' },
|
||||
{ value: 'Helvetica Neue', label: 'Helvetica Neue', category: 'sans-serif' },
|
||||
],
|
||||
}],
|
||||
[UniverWebComponentAdapterPlugin],
|
||||
[UniverVue3AdapterPlugin],
|
||||
@@ -192,6 +196,10 @@ function createNewInstance() {
|
||||
|
||||
window.univer = univer;
|
||||
window.univerAPI = FUniver.newAPI(univer);
|
||||
// window.univerAPI.addFonts([
|
||||
// { value: 'PingFang SC', label: '苹方(简)', category: 'sans-serif' },
|
||||
// { value: 'Helvetica Neue', label: 'Helvetica Neue', category: 'sans-serif' },
|
||||
// ]);
|
||||
|
||||
customRegisterEvent(univer, window.univerAPI!);
|
||||
customRangePopups(univer, window.univerAPI!);
|
||||
|
||||
@@ -46,7 +46,6 @@ import {
|
||||
COMMON_LABEL_COMPONENT,
|
||||
FONT_FAMILY_COMPONENT,
|
||||
FONT_FAMILY_ITEM_COMPONENT,
|
||||
FONT_FAMILY_LIST,
|
||||
FONT_SIZE_COMPONENT,
|
||||
FONT_SIZE_LIST,
|
||||
getMenuHiddenObservable,
|
||||
@@ -480,12 +479,16 @@ export function FontFamilySelectorMenuItemFactory(accessor: IAccessor): IMenuSel
|
||||
tooltip: 'toolbar.font',
|
||||
type: MenuItemType.SELECTOR,
|
||||
label: FONT_FAMILY_COMPONENT,
|
||||
selections: FONT_FAMILY_LIST.map((item) => ({
|
||||
selections: [{
|
||||
label: {
|
||||
name: FONT_FAMILY_ITEM_COMPONENT,
|
||||
hoverable: false,
|
||||
selectable: false,
|
||||
props: {
|
||||
id: SetInlineFormatFontFamilyCommand.id,
|
||||
},
|
||||
},
|
||||
value: item.value,
|
||||
})),
|
||||
}],
|
||||
// disabled$: getCurrentSheetDisabled$(accessor),
|
||||
value$: new Observable((subscriber) => {
|
||||
const defaultValue = DEFAULT_STYLES.ff;
|
||||
|
||||
@@ -210,15 +210,13 @@ export const FactoryOtherMenuItem = (accessor: IAccessor): IMenuSelectorItem =>
|
||||
tooltip: 'sheet.numfmt.title',
|
||||
type: MenuItemType.SELECTOR,
|
||||
slot: true,
|
||||
selections: [
|
||||
{
|
||||
label: {
|
||||
name: OPTIONS_KEY,
|
||||
hoverable: false,
|
||||
selectable: false,
|
||||
},
|
||||
selections: [{
|
||||
label: {
|
||||
name: OPTIONS_KEY,
|
||||
hoverable: false,
|
||||
selectable: false,
|
||||
},
|
||||
],
|
||||
}],
|
||||
value$,
|
||||
hidden$: getMenuHiddenObservable(accessor, UniverInstanceType.UNIVER_SHEET),
|
||||
disabled$: getCurrentRangeDisable$(accessor, { workbookTypes: [WorkbookEditablePermission], worksheetTypes: [WorksheetSetCellStylePermission, WorksheetEditPermission], rangeTypes: [RangeProtectionPermissionEditPoint] }),
|
||||
|
||||
@@ -27,7 +27,7 @@ import { MENU_OPTIONS } from '../../controllers/menu';
|
||||
export const MORE_NUMFMT_TYPE_KEY = 'sheet.numfmt.moreNumfmtType';
|
||||
export const OPTIONS_KEY = 'sheet.numfmt.moreNumfmtType.options';
|
||||
|
||||
export const MoreNumfmtType = (props: { value?: string }) => {
|
||||
export function MoreNumfmtType(props: { value?: string }) {
|
||||
const { value } = props;
|
||||
const localeService = useDependency(LocaleService);
|
||||
const text = value ?? localeService.t('sheet.numfmt.general');
|
||||
@@ -35,7 +35,7 @@ export const MoreNumfmtType = (props: { value?: string }) => {
|
||||
return <span className="univer-text-sm">{text}</span>;
|
||||
};
|
||||
|
||||
export const Options = () => {
|
||||
export function Options() {
|
||||
const commandService = useDependency(ICommandService);
|
||||
const localeService = useDependency(LocaleService);
|
||||
const layoutService = useDependency(ILayoutService);
|
||||
@@ -66,7 +66,8 @@ export const Options = () => {
|
||||
const currencySymbol = localeCurrencySymbolMap.get(localeService.getCurrentLocale()) as string;
|
||||
return MENU_OPTIONS(currencySymbol);
|
||||
}, [localeService]);
|
||||
const handleOnclick = (index: number) => {
|
||||
|
||||
const handleClick = (index: number) => {
|
||||
if (index === 0) {
|
||||
setNumfmt(null);
|
||||
} else if (index === menuOptions.length - 1) {
|
||||
@@ -87,6 +88,7 @@ export const Options = () => {
|
||||
if (item === '|') {
|
||||
return <Separator key={index} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
@@ -96,9 +98,7 @@ export const Options = () => {
|
||||
hover:univer-bg-gray-100
|
||||
dark:hover:!univer-bg-gray-700
|
||||
`}
|
||||
onClick={() => {
|
||||
handleOnclick(index);
|
||||
}}
|
||||
onClick={() => handleClick(index)}
|
||||
>
|
||||
<span>{localeService.t(item.label)}</span>
|
||||
|
||||
|
||||
@@ -75,7 +75,6 @@ import {
|
||||
CutCommand,
|
||||
FONT_FAMILY_COMPONENT,
|
||||
FONT_FAMILY_ITEM_COMPONENT,
|
||||
FONT_FAMILY_LIST,
|
||||
getMenuHiddenObservable,
|
||||
IClipboardInterfaceService,
|
||||
MenuItemType,
|
||||
@@ -400,13 +399,16 @@ export function FontFamilySelectorMenuItemFactory(accessor: IAccessor): IMenuSel
|
||||
tooltip: 'toolbar.font',
|
||||
type: MenuItemType.SELECTOR,
|
||||
label: FONT_FAMILY_COMPONENT,
|
||||
selections: FONT_FAMILY_LIST.map((item) => ({
|
||||
selections: [{
|
||||
label: {
|
||||
name: FONT_FAMILY_ITEM_COMPONENT,
|
||||
hoverable: false,
|
||||
selectable: false,
|
||||
props: {
|
||||
id: SetRangeFontFamilyCommand.id,
|
||||
},
|
||||
},
|
||||
value: item.value,
|
||||
})),
|
||||
|
||||
}],
|
||||
disabled$: getCurrentRangeDisable$(accessor, {
|
||||
workbookTypes: [WorkbookEditablePermission],
|
||||
worksheetTypes: [WorksheetEditPermission, WorksheetSetCellStylePermission],
|
||||
|
||||
@@ -14,18 +14,72 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { IFontFamilyItemProps } from './interface';
|
||||
import { LocaleService } from '@univerjs/core';
|
||||
import type { IFontConfig } from '../../services/font.service';
|
||||
import { ICommandService, LocaleService } from '@univerjs/core';
|
||||
import { Tooltip } from '@univerjs/design';
|
||||
import { InfoIcon } from '@univerjs/icons';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { IFontService } from '../../services/font.service';
|
||||
import { useDependency } from '../../utils/di';
|
||||
|
||||
export const FontFamilyItem = (props: IFontFamilyItemProps) => {
|
||||
const { value } = props;
|
||||
export const FontFamilyItem = ({ id, value }: { id: string; value: string }) => {
|
||||
const commandService = useDependency(ICommandService);
|
||||
const fontService = useDependency(IFontService);
|
||||
|
||||
const [fonts, setFonts] = useState<IFontConfig[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const subscription = fontService.fonts$.subscribe((fonts) => {
|
||||
setFonts(fonts);
|
||||
});
|
||||
|
||||
return () => {
|
||||
subscription.unsubscribe();
|
||||
};
|
||||
}, []);
|
||||
|
||||
const localeService = useDependency(LocaleService);
|
||||
|
||||
function handleSelectFont(value: string) {
|
||||
commandService.executeCommand(id, { value });
|
||||
}
|
||||
|
||||
return (
|
||||
<span className="univer-text-sm" style={{ fontFamily: value }}>
|
||||
{localeService.t(`fontFamily.${(`${value ?? ''}`).replace(/\s/g, '')}`)}
|
||||
</span>
|
||||
<ul
|
||||
className="univer-m-0 univer-list-none univer-p-0 univer-text-sm"
|
||||
style={{ fontFamily: value }}
|
||||
>
|
||||
{fonts.map((font) => (
|
||||
<li key={font.value}>
|
||||
<button
|
||||
className={`
|
||||
univer-flex univer-h-7 univer-w-full univer-appearance-none univer-items-center
|
||||
univer-justify-between univer-gap-6 univer-rounded univer-border-none univer-bg-transparent
|
||||
univer-px-2
|
||||
hover:univer-bg-gray-100
|
||||
dark:hover:!univer-bg-gray-700
|
||||
`}
|
||||
style={{
|
||||
fontFamily: font.value,
|
||||
}}
|
||||
type="button"
|
||||
onClick={() => handleSelectFont(font.value)}
|
||||
>
|
||||
{localeService.t(font.label)}
|
||||
|
||||
{!fontService.isFontSupported(font.value) && (
|
||||
<Tooltip title={localeService.t('fontFamily.not-supported')}>
|
||||
<InfoIcon
|
||||
className={`
|
||||
univer-text-gray-300
|
||||
dark:univer-text-gray-700
|
||||
`}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -16,4 +16,3 @@
|
||||
|
||||
export { FontFamily } from './FontFamily';
|
||||
export { FontFamilyItem } from './FontFamilyItem';
|
||||
export { FONT_FAMILY_LIST } from './interface';
|
||||
|
||||
@@ -22,66 +22,4 @@ export interface IFontFamilyProps extends ICustomComponentProps<string> {
|
||||
|
||||
export const FONT_FAMILY_COMPONENT = 'UI_FONT_FAMILY_COMPONENT';
|
||||
|
||||
export interface IFontFamilyItemProps extends ICustomComponentProps<string> {
|
||||
value: string;
|
||||
}
|
||||
|
||||
export const FONT_FAMILY_ITEM_COMPONENT = 'UI_FONT_FAMILY_ITEM_COMPONENT';
|
||||
|
||||
export const FONT_FAMILY_LIST = [
|
||||
{
|
||||
value: 'Arial',
|
||||
},
|
||||
{
|
||||
value: 'Times New Roman',
|
||||
},
|
||||
{
|
||||
value: 'Tahoma',
|
||||
},
|
||||
{
|
||||
value: 'Verdana',
|
||||
},
|
||||
{
|
||||
value: 'Microsoft YaHei',
|
||||
},
|
||||
{
|
||||
value: 'SimSun',
|
||||
},
|
||||
{
|
||||
value: 'SimHei',
|
||||
},
|
||||
{
|
||||
value: 'Kaiti',
|
||||
},
|
||||
{
|
||||
value: 'FangSong',
|
||||
},
|
||||
{
|
||||
value: 'NSimSun',
|
||||
},
|
||||
{
|
||||
value: 'STXinwei',
|
||||
},
|
||||
{
|
||||
value: 'STXingkai',
|
||||
},
|
||||
{
|
||||
value: 'STLiti',
|
||||
},
|
||||
// The following 3 fonts do not work, temporarily delete
|
||||
// {
|
||||
// label: 'fontFamily.HanaleiFill',
|
||||
// style: { 'font-family': 'HanaleiFill' },
|
||||
// value: 'HanaleiFill',
|
||||
// },
|
||||
// {
|
||||
// label: 'fontFamily.Anton',
|
||||
// style: { 'font-family': 'Anton' },
|
||||
// value: 'Anton',
|
||||
// },
|
||||
// {
|
||||
// label: 'fontFamily.Pacifico',
|
||||
// style: { 'font-family': 'Pacifico' },
|
||||
// value: 'Pacifico',
|
||||
// },
|
||||
];
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
import type { DependencyOverride } from '@univerjs/core';
|
||||
import type { IFontConfig } from '../services/font.service';
|
||||
import type { MenuConfig } from '../services/menu/menu';
|
||||
import type { IWorkbenchOptions } from './ui/ui.controller';
|
||||
|
||||
@@ -30,6 +31,11 @@ export interface IUniverUIConfig extends IWorkbenchOptions {
|
||||
|
||||
menu?: MenuConfig;
|
||||
|
||||
/**
|
||||
* Custom font family list to be added to the font service.
|
||||
*/
|
||||
customFontFamily?: IFontConfig[];
|
||||
|
||||
popupRootId?: string;
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { IFontConfig } from '../../services/font.service';
|
||||
import { createIdentifier } from '@univerjs/core';
|
||||
|
||||
export type RibbonType = 'default' | 'simple' | 'classic';
|
||||
@@ -31,8 +32,16 @@ export interface IWorkbenchOptions {
|
||||
*/
|
||||
toolbar?: boolean;
|
||||
|
||||
/**
|
||||
* The type of ribbon to be used in the UI.
|
||||
*/
|
||||
ribbonType?: RibbonType;
|
||||
|
||||
/**
|
||||
* Custom font family list to be added to the font service.
|
||||
*/
|
||||
customFontFamily?: IFontConfig[];
|
||||
|
||||
/**
|
||||
* If Univer should make the footer bar visible.
|
||||
*/
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
import type { IDisposable } from '@univerjs/core';
|
||||
import type { IMessageProps } from '@univerjs/design';
|
||||
import type { BuiltInUIPart, ComponentType, IComponentOptions, IDialogPartMethodOptions, ISidebarMethodOptions } from '@univerjs/ui';
|
||||
import type { BuiltInUIPart, ComponentType, IComponentOptions, IDialogPartMethodOptions, IFontConfig, ISidebarMethodOptions } from '@univerjs/ui';
|
||||
import type { IFacadeMenuItem, IFacadeSubmenuItem } from './f-menu-builder';
|
||||
import { FUniver } from '@univerjs/core/facade';
|
||||
import { IRenderManagerService } from '@univerjs/engine-render';
|
||||
import { ComponentManager, connectInjector, CopyCommand, IDialogService, IMessageService, ISidebarService, IUIPartsService, PasteCommand } from '@univerjs/ui';
|
||||
import { ComponentManager, connectInjector, CopyCommand, IDialogService, IFontService, IMessageService, ISidebarService, IUIPartsService, PasteCommand } from '@univerjs/ui';
|
||||
import { FMenu, FSubmenu } from './f-menu-builder';
|
||||
import { FShortcut } from './f-shortcut';
|
||||
|
||||
@@ -418,6 +418,27 @@ export interface IFUniverUIMixin {
|
||||
* This will render `unit2` in the workbench's main area.
|
||||
*/
|
||||
setCurrent(unitId: string): void;
|
||||
|
||||
/**
|
||||
* Append custom fonts to the font list.
|
||||
* @param fonts The array of font configurations to add.
|
||||
* @example
|
||||
* ```ts
|
||||
* univerAPI.addFonts([
|
||||
* {
|
||||
* value: 'CustomFont1',
|
||||
* label: 'Custom Font 1',
|
||||
* category: 'sans-serif',
|
||||
* },
|
||||
* {
|
||||
* value: 'CustomFont2',
|
||||
* label: 'Custom Font 2',
|
||||
* category: 'serif',
|
||||
* },
|
||||
* ]);
|
||||
* ```
|
||||
*/
|
||||
addFonts(fonts: IFontConfig[]): void;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -508,6 +529,16 @@ export class FUniverUIMixin extends FUniver implements IFUniverUIMixin {
|
||||
|
||||
this._univerInstanceService.setCurrentUnitForType(unitId);
|
||||
}
|
||||
|
||||
override addFonts(fonts: IFontConfig[]): void {
|
||||
const fontService = this._injector.get(IFontService);
|
||||
fonts.forEach((font) => {
|
||||
fontService.addFont({
|
||||
...font,
|
||||
isCustom: true,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
FUniver.extend(FUniverUIMixin);
|
||||
|
||||
@@ -24,7 +24,7 @@ export * from './components';
|
||||
export { COLOR_PICKER_COMPONENT } from './components/color-picker/interface';
|
||||
export { FontFamily } from './components/font-family/FontFamily';
|
||||
export { FontFamilyItem } from './components/font-family/FontFamilyItem';
|
||||
export { FONT_FAMILY_COMPONENT, FONT_FAMILY_ITEM_COMPONENT, FONT_FAMILY_LIST, type IFontFamilyItemProps, type IFontFamilyProps } from './components/font-family/interface';
|
||||
export { FONT_FAMILY_COMPONENT, FONT_FAMILY_ITEM_COMPONENT, type IFontFamilyProps } from './components/font-family/interface';
|
||||
export { FontSize } from './components/font-size/FontSize';
|
||||
export { FONT_SIZE_COMPONENT, FONT_SIZE_LIST, HEADING_LIST } from './components/font-size/interface';
|
||||
export * from './components/hooks';
|
||||
@@ -71,6 +71,7 @@ export { ContextMenuService, type IContextMenuHandler, IContextMenuService } fro
|
||||
export { DesktopDialogService } from './services/dialog/desktop-dialog.service';
|
||||
export { IDialogService } from './services/dialog/dialog.service';
|
||||
export { CanvasFloatDomService, type IFloatDom, type IFloatDomLayout } from './services/dom/canvas-dom-layer.service';
|
||||
export { type IFontConfig, IFontService } from './services/font.service';
|
||||
export { DesktopGalleryService } from './services/gallery/desktop-gallery.service';
|
||||
export { IGalleryService } from './services/gallery/gallery.service';
|
||||
export { DesktopGlobalZoneService } from './services/global-zone/desktop-global-zone.service';
|
||||
|
||||
@@ -47,22 +47,20 @@ const locale: typeof enUS = {
|
||||
more: 'Més',
|
||||
},
|
||||
fontFamily: {
|
||||
TimesNewRoman: 'Times New Roman',
|
||||
Arial: 'Arial',
|
||||
Tahoma: 'Tahoma',
|
||||
Verdana: 'Verdana',
|
||||
MicrosoftYaHei: 'Microsoft YaHei',
|
||||
SimSun: 'SimSun',
|
||||
SimHei: 'SimHei',
|
||||
Kaiti: 'Kaiti',
|
||||
FangSong: 'FangSong',
|
||||
NSimSun: 'NSimSun',
|
||||
STXinwei: 'STXinwei',
|
||||
STXingkai: 'STXingkai',
|
||||
STLiti: 'STLiti',
|
||||
HanaleiFill: 'HanaleiFill',
|
||||
Anton: 'Anton',
|
||||
Pacifico: 'Pacifico',
|
||||
'not-supported': 'No s\'ha trobat aquesta font al sistema, s\'utilitza la font per defecte.',
|
||||
arial: 'Arial',
|
||||
'times-new-roman': 'Times New Roman',
|
||||
tahoma: 'Tahoma',
|
||||
verdana: 'Verdana',
|
||||
'microsoft-yahei': 'Microsoft YaHei',
|
||||
simsun: 'SimSun',
|
||||
simhei: 'SimHei',
|
||||
kaiti: 'Kaiti',
|
||||
fangsong: 'FangSong',
|
||||
nsimsun: 'NSimSun',
|
||||
stxinwei: 'STXinwei',
|
||||
stxingkai: 'STXingkai',
|
||||
stliti: 'STLiti',
|
||||
},
|
||||
'shortcut-panel': {
|
||||
title: 'Dreceres',
|
||||
|
||||
@@ -45,22 +45,20 @@ const locale = {
|
||||
more: 'More',
|
||||
},
|
||||
fontFamily: {
|
||||
TimesNewRoman: 'Times New Roman',
|
||||
Arial: 'Arial',
|
||||
Tahoma: 'Tahoma',
|
||||
Verdana: 'Verdana',
|
||||
MicrosoftYaHei: 'Microsoft YaHei',
|
||||
SimSun: 'SimSun',
|
||||
SimHei: 'SimHei',
|
||||
Kaiti: 'Kaiti',
|
||||
FangSong: 'FangSong',
|
||||
NSimSun: 'NSimSun',
|
||||
STXinwei: 'STXinwei',
|
||||
STXingkai: 'STXingkai',
|
||||
STLiti: 'STLiti',
|
||||
HanaleiFill: 'HanaleiFill',
|
||||
Anton: 'Anton',
|
||||
Pacifico: 'Pacifico',
|
||||
'not-supported': 'No such font found in the system, using default font.',
|
||||
arial: 'Arial',
|
||||
'times-new-roman': 'Times New Roman',
|
||||
tahoma: 'Tahoma',
|
||||
verdana: 'Verdana',
|
||||
'microsoft-yahei': 'Microsoft YaHei',
|
||||
simsun: 'SimSun',
|
||||
simhei: 'SimHei',
|
||||
kaiti: 'Kaiti',
|
||||
fangsong: 'FangSong',
|
||||
nsimsun: 'NSimSun',
|
||||
stxinwei: 'STXinwei',
|
||||
stxingkai: 'STXingkai',
|
||||
stliti: 'STLiti',
|
||||
},
|
||||
'shortcut-panel': {
|
||||
title: 'Shortcuts',
|
||||
|
||||
@@ -47,22 +47,20 @@ const locale: typeof enUS = {
|
||||
more: 'Más',
|
||||
},
|
||||
fontFamily: {
|
||||
TimesNewRoman: 'Times New Roman',
|
||||
Arial: 'Arial',
|
||||
Tahoma: 'Tahoma',
|
||||
Verdana: 'Verdana',
|
||||
MicrosoftYaHei: 'Microsoft YaHei',
|
||||
SimSun: 'SimSun',
|
||||
SimHei: 'SimHei',
|
||||
Kaiti: 'Kaiti',
|
||||
FangSong: 'FangSong',
|
||||
NSimSun: 'NSimSun',
|
||||
STXinwei: 'STXinwei',
|
||||
STXingkai: 'STXingkai',
|
||||
STLiti: 'STLiti',
|
||||
HanaleiFill: 'HanaleiFill',
|
||||
Anton: 'Anton',
|
||||
Pacifico: 'Pacifico',
|
||||
'not-supported': 'No se encontró esta fuente en el sistema, se utiliza la fuente predeterminada.',
|
||||
arial: 'Arial',
|
||||
'times-new-roman': 'Times New Roman',
|
||||
tahoma: 'Tahoma',
|
||||
verdana: 'Verdana',
|
||||
'microsoft-yahei': 'Microsoft YaHei',
|
||||
simsun: 'SimSun',
|
||||
simhei: 'SimHei',
|
||||
kaiti: 'Kaiti',
|
||||
fangsong: 'FangSong',
|
||||
nsimsun: 'NSimSun',
|
||||
stxinwei: 'STXinwei',
|
||||
stxingkai: 'STXingkai',
|
||||
stliti: 'STLiti',
|
||||
},
|
||||
'shortcut-panel': {
|
||||
title: 'Atajos',
|
||||
|
||||
@@ -47,22 +47,20 @@ const locale: typeof enUS = {
|
||||
more: 'بیشتر',
|
||||
},
|
||||
fontFamily: {
|
||||
TimesNewRoman: 'Times New Roman',
|
||||
Arial: 'Arial',
|
||||
Tahoma: 'Tahoma',
|
||||
Verdana: 'Verdana',
|
||||
MicrosoftYaHei: 'Microsoft YaHei',
|
||||
SimSun: 'SimSun',
|
||||
SimHei: 'SimHei',
|
||||
Kaiti: 'Kaiti',
|
||||
FangSong: 'FangSong',
|
||||
NSimSun: 'NSimSun',
|
||||
STXinwei: 'STXinwei',
|
||||
STXingkai: 'STXingkai',
|
||||
STLiti: 'STLiti',
|
||||
HanaleiFill: 'HanaleiFill',
|
||||
Anton: 'Anton',
|
||||
Pacifico: 'Pacifico',
|
||||
'not-supported': 'هیچ فونتی با این نام در سیستم یافت نشد، از فونت پیشفرض استفاده میشود.',
|
||||
arial: 'Arial',
|
||||
'times-new-roman': 'Times New Roman',
|
||||
tahoma: 'Tahoma',
|
||||
verdana: 'Verdana',
|
||||
'microsoft-yahei': 'Microsoft YaHei',
|
||||
simsun: 'SimSun',
|
||||
simhei: 'SimHei',
|
||||
kaiti: 'Kaiti',
|
||||
fangsong: 'FangSong',
|
||||
nsimsun: 'NSimSun',
|
||||
stxinwei: 'STXinwei',
|
||||
stxingkai: 'STXingkai',
|
||||
stliti: 'STLiti',
|
||||
},
|
||||
'shortcut-panel': {
|
||||
title: 'کلیدهای میانبر',
|
||||
|
||||
@@ -47,22 +47,20 @@ const locale: typeof enUS = {
|
||||
more: 'Plus',
|
||||
},
|
||||
fontFamily: {
|
||||
TimesNewRoman: 'Times New Roman',
|
||||
Arial: 'Arial',
|
||||
Tahoma: 'Tahoma',
|
||||
Verdana: 'Verdana',
|
||||
MicrosoftYaHei: 'Microsoft YaHei',
|
||||
SimSun: 'SimSun',
|
||||
SimHei: 'SimHei',
|
||||
Kaiti: 'Kaiti',
|
||||
FangSong: 'FangSong',
|
||||
NSimSun: 'NSimSun',
|
||||
STXinwei: 'STXinwei',
|
||||
STXingkai: 'STXingkai',
|
||||
STLiti: 'STLiti',
|
||||
HanaleiFill: 'HanaleiFill',
|
||||
Anton: 'Anton',
|
||||
Pacifico: 'Pacifico',
|
||||
'not-supported': 'Aucune police de ce type trouvée dans le système, utilisation de la police par défaut.',
|
||||
arial: 'Arial',
|
||||
'times-new-roman': 'Times New Roman',
|
||||
tahoma: 'Tahoma',
|
||||
verdana: 'Verdana',
|
||||
'microsoft-yahei': 'Microsoft YaHei',
|
||||
simsun: 'SimSun',
|
||||
simhei: 'SimHei',
|
||||
kaiti: 'Kaiti',
|
||||
fangsong: 'FangSong',
|
||||
nsimsun: 'NSimSun',
|
||||
stxinwei: 'STXinwei',
|
||||
stxingkai: 'STXingkai',
|
||||
stliti: 'STLiti',
|
||||
},
|
||||
'shortcut-panel': {
|
||||
title: 'Raccourcis',
|
||||
|
||||
@@ -47,22 +47,20 @@ const locale: typeof enUS = {
|
||||
more: 'もっと見る',
|
||||
},
|
||||
fontFamily: {
|
||||
TimesNewRoman: 'Times New Roman',
|
||||
Arial: 'Arial',
|
||||
Tahoma: 'Tahoma',
|
||||
Verdana: 'Verdana',
|
||||
MicrosoftYaHei: 'Microsoft YaHei',
|
||||
SimSun: 'SimSun',
|
||||
SimHei: 'SimHei',
|
||||
Kaiti: 'Kaiti',
|
||||
FangSong: 'FangSong',
|
||||
NSimSun: 'NSimSun',
|
||||
STXinwei: 'STXinwei',
|
||||
STXingkai: 'STXingkai',
|
||||
STLiti: 'STLiti',
|
||||
HanaleiFill: 'HanaleiFill',
|
||||
Anton: 'Anton',
|
||||
Pacifico: 'Pacifico',
|
||||
'not-supported': 'システムにそのようなフォントが見つからないため、デフォルトのフォントを使用しています。',
|
||||
arial: 'Arial',
|
||||
'times-new-roman': 'Times New Roman',
|
||||
tahoma: 'Tahoma',
|
||||
verdana: 'Verdana',
|
||||
'microsoft-yahei': '微軟雅黒',
|
||||
simsun: 'SimSun',
|
||||
simhei: 'SimHei',
|
||||
kaiti: 'Kaiti',
|
||||
fangsong: 'FangSong',
|
||||
nsimsun: 'NSimSun',
|
||||
stxinwei: 'STXinwei',
|
||||
stxingkai: 'STXingkai',
|
||||
stliti: 'STLiti',
|
||||
},
|
||||
'shortcut-panel': {
|
||||
title: 'ショートカット',
|
||||
|
||||
@@ -47,22 +47,20 @@ const locale: typeof enUS = {
|
||||
more: '더 보기',
|
||||
},
|
||||
fontFamily: {
|
||||
TimesNewRoman: 'Times New Roman',
|
||||
Arial: 'Arial',
|
||||
Tahoma: 'Tahoma',
|
||||
Verdana: 'Verdana',
|
||||
MicrosoftYaHei: 'Microsoft YaHei',
|
||||
SimSun: 'SimSun',
|
||||
SimHei: 'SimHei',
|
||||
Kaiti: 'Kaiti',
|
||||
FangSong: 'FangSong',
|
||||
NSimSun: 'NSimSun',
|
||||
STXinwei: 'STXinwei',
|
||||
STXingkai: 'STXingkai',
|
||||
STLiti: 'STLiti',
|
||||
HanaleiFill: 'HanaleiFill',
|
||||
Anton: 'Anton',
|
||||
Pacifico: 'Pacifico',
|
||||
'not-supported': '시스템에 해당 폰트가 없어 기본 폰트를 사용합니다.',
|
||||
arial: 'Arial',
|
||||
'times-new-roman': 'Times New Roman',
|
||||
tahoma: 'Tahoma',
|
||||
verdana: 'Verdana',
|
||||
'microsoft-yahei': 'Microsoft YaHei',
|
||||
simsun: 'SimSun',
|
||||
simhei: 'SimHei',
|
||||
kaiti: 'Kaiti',
|
||||
fangsong: 'FangSong',
|
||||
nsimsun: 'NSimSun',
|
||||
stxinwei: 'STXinwei',
|
||||
stxingkai: 'STXingkai',
|
||||
stliti: 'STLiti',
|
||||
},
|
||||
'shortcut-panel': {
|
||||
title: '단축키',
|
||||
|
||||
@@ -47,22 +47,20 @@ const locale: typeof enUS = {
|
||||
more: 'Больше',
|
||||
},
|
||||
fontFamily: {
|
||||
TimesNewRoman: 'Times New Roman',
|
||||
Arial: 'Arial',
|
||||
Tahoma: 'Tahoma',
|
||||
Verdana: 'Verdana',
|
||||
MicrosoftYaHei: 'Microsoft YaHei',
|
||||
SimSun: 'SimSun',
|
||||
SimHei: 'SimHei',
|
||||
Kaiti: 'Kaiti',
|
||||
FangSong: 'FangSong',
|
||||
NSimSun: 'NSimSun',
|
||||
STXinwei: 'STXinwei',
|
||||
STXingkai: 'STXingkai',
|
||||
STLiti: 'STLiti',
|
||||
HanaleiFill: 'HanaleiFill',
|
||||
Anton: 'Anton',
|
||||
Pacifico: 'Pacifico',
|
||||
'not-supported': 'В системе не найден такой шрифт, используется шрифт по умолчанию.',
|
||||
arial: 'Arial',
|
||||
'times-new-roman': 'Times New Roman',
|
||||
tahoma: 'Tahoma',
|
||||
verdana: 'Verdana',
|
||||
'microsoft-yahei': 'Microsoft YaHei',
|
||||
simsun: 'SimSun',
|
||||
simhei: 'SimHei',
|
||||
kaiti: 'Kaiti',
|
||||
fangsong: 'FangSong',
|
||||
nsimsun: 'NSimSun',
|
||||
stxinwei: 'STXinwei',
|
||||
stxingkai: 'STXingkai',
|
||||
stliti: 'STLiti',
|
||||
},
|
||||
'shortcut-panel': {
|
||||
title: 'Сочетания клавиш',
|
||||
|
||||
@@ -47,22 +47,20 @@ const locale: typeof enUS = {
|
||||
more: 'Thêm',
|
||||
},
|
||||
fontFamily: {
|
||||
TimesNewRoman: 'Times New Roman',
|
||||
Arial: 'Arial',
|
||||
Tahoma: 'Tahoma',
|
||||
Verdana: 'Verdana',
|
||||
MicrosoftYaHei: 'Microsoft YaHei',
|
||||
SimSun: 'SimSun',
|
||||
SimHei: 'SimHei',
|
||||
Kaiti: 'Kaiti',
|
||||
FangSong: 'FangSong',
|
||||
NSimSun: 'NSimSun',
|
||||
STXinwei: 'STXinwei',
|
||||
STXingkai: 'STXingkai',
|
||||
STLiti: 'STLiti',
|
||||
HanaleiFill: 'HanaleiFill',
|
||||
Anton: 'Anton',
|
||||
Pacifico: 'Pacifico',
|
||||
'not-supported': 'Không tìm thấy phông chữ này trong hệ thống, sử dụng phông chữ mặc định.',
|
||||
arial: 'Arial',
|
||||
'times-new-roman': 'Times New Roman',
|
||||
tahoma: 'Tahoma',
|
||||
verdana: 'Verdana',
|
||||
'microsoft-yahei': 'Microsoft YaHei',
|
||||
simsun: 'SimSun',
|
||||
simhei: 'SimHei',
|
||||
kaiti: 'Kaiti',
|
||||
fangsong: 'FangSong',
|
||||
nsimsun: 'NSimSun',
|
||||
stxinwei: 'STXinwei',
|
||||
stxingkai: 'STXingkai',
|
||||
stliti: 'STLiti',
|
||||
},
|
||||
'shortcut-panel': {
|
||||
title: 'Bảng phím tắt',
|
||||
|
||||
@@ -47,22 +47,20 @@ const locale: typeof enUS = {
|
||||
more: '更多',
|
||||
},
|
||||
fontFamily: {
|
||||
TimesNewRoman: 'Times New Roman',
|
||||
Arial: 'Arial',
|
||||
Tahoma: 'Tahoma',
|
||||
Verdana: 'Verdana',
|
||||
MicrosoftYaHei: '微软雅黑',
|
||||
SimSun: '宋体',
|
||||
SimHei: '黑体',
|
||||
Kaiti: '楷体',
|
||||
FangSong: '仿宋',
|
||||
NSimSun: '新宋体',
|
||||
STXinwei: '华文新魏',
|
||||
STXingkai: '华文行楷',
|
||||
STLiti: '华文隶书',
|
||||
HanaleiFill: 'HanaleiFill',
|
||||
Anton: 'Anton',
|
||||
Pacifico: 'Pacifico',
|
||||
'not-supported': '系统中未找到该字体,使用默认字体。',
|
||||
arial: 'Arial',
|
||||
'times-new-roman': 'Times New Roman',
|
||||
tahoma: 'Tahoma',
|
||||
verdana: 'Verdana',
|
||||
'microsoft-yahei': '微软雅黑',
|
||||
simsun: '宋体',
|
||||
simhei: '黑体',
|
||||
kaiti: '楷体',
|
||||
fangsong: '仿宋',
|
||||
nsimsun: '新宋体',
|
||||
stxinwei: '华文新魏',
|
||||
stxingkai: '华文行楷',
|
||||
stliti: '华文隶书',
|
||||
},
|
||||
'shortcut-panel': {
|
||||
title: '快捷键面板',
|
||||
|
||||
@@ -47,22 +47,20 @@ const locale: typeof enUS = {
|
||||
more: '更多',
|
||||
},
|
||||
fontFamily: {
|
||||
TimesNewRoman: 'Times New Roman',
|
||||
Arial: 'Arial',
|
||||
Tahoma: 'Tahoma',
|
||||
Verdana: 'Verdana',
|
||||
MicrosoftYaHei: '微軟雅黑',
|
||||
SimSun: '宋體',
|
||||
SimHei: '黑體',
|
||||
Kaiti: '楷體',
|
||||
FangSong: '仿宋',
|
||||
NSimSun: '新宋體',
|
||||
STXinwei: '華文新魏',
|
||||
STXingkai: '華文行楷',
|
||||
STLiti: '華文隸書',
|
||||
HanaleiFill: 'HanaleiFill',
|
||||
Anton: 'Anton',
|
||||
Pacifico: 'Pacifico',
|
||||
'not-supported': '系統中未找到該字體,使用預設字體。',
|
||||
arial: 'Arial',
|
||||
'times-new-roman': 'Times New Roman',
|
||||
tahoma: 'Tahoma',
|
||||
verdana: 'Verdana',
|
||||
'microsoft-yahei': '微軟雅黑',
|
||||
simsun: '宋體',
|
||||
simhei: '黑體',
|
||||
kaiti: '楷體',
|
||||
fangsong: '仿宋',
|
||||
nsimsun: '新宋體',
|
||||
stxinwei: '華文新魏',
|
||||
stxingkai: '華文行楷',
|
||||
stliti: '華文隸書',
|
||||
},
|
||||
'shortcut-panel': {
|
||||
title: '快捷鍵面板',
|
||||
|
||||
@@ -33,6 +33,7 @@ import { ContextMenuService, IContextMenuService } from './services/contextmenu/
|
||||
import { DesktopDialogService } from './services/dialog/desktop-dialog.service';
|
||||
import { IDialogService } from './services/dialog/dialog.service';
|
||||
import { CanvasFloatDomService } from './services/dom/canvas-dom-layer.service';
|
||||
import { FontService, IFontService } from './services/font.service';
|
||||
import { DesktopGalleryService } from './services/gallery/desktop-gallery.service';
|
||||
import { IGalleryService } from './services/gallery/gallery.service';
|
||||
import { DesktopGlobalZoneService } from './services/global-zone/desktop-global-zone.service';
|
||||
@@ -119,6 +120,7 @@ export class UniverUIPlugin extends Plugin {
|
||||
[IBeforeCloseService, { useClass: DesktopBeforeCloseService }],
|
||||
[ILocalFileService, { useClass: DesktopLocalFileService }],
|
||||
[ICanvasPopupService, { useClass: CanvasPopupService }],
|
||||
[IFontService, { useClass: FontService }],
|
||||
[CanvasFloatDomService],
|
||||
[IUIController, {
|
||||
useFactory: (injector: Injector) => injector.createInstance(DesktopUIController, this._config),
|
||||
|
||||
@@ -0,0 +1,255 @@
|
||||
/**
|
||||
* Copyright 2023-present DreamNum Co., Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { IDisposable } from '@univerjs/core';
|
||||
import type { IUniverUIConfig } from '../controllers/config.schema';
|
||||
import { createIdentifier, IConfigService } from '@univerjs/core';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { UI_PLUGIN_CONFIG_KEY } from '../controllers/config.schema';
|
||||
|
||||
export const IFontService = createIdentifier<IFontService>('univer.font-service');
|
||||
|
||||
/**
|
||||
* Font configuration interface
|
||||
*/
|
||||
export interface IFontConfig {
|
||||
/**
|
||||
* Unique identifier, usually also the preferred value for CSS font-family
|
||||
* @example 'Microsoft YaHei'
|
||||
*/
|
||||
value: string;
|
||||
|
||||
/**
|
||||
* Translation key for i18n
|
||||
* @example 'font.microsoft_yahei'
|
||||
*/
|
||||
label: string;
|
||||
|
||||
/**
|
||||
* Font category for UI grouping (optional)
|
||||
*/
|
||||
category?: 'sans-serif' | 'serif' | 'monospace' | 'display' | 'handwriting';
|
||||
|
||||
/**
|
||||
* Mark whether the font is user-added
|
||||
* (Used to distinguish built-in fonts to prevent accidental deletion of core fonts)
|
||||
*/
|
||||
isCustom?: boolean;
|
||||
}
|
||||
|
||||
const DEFAULT_FONT_LIST: IFontConfig[] = [{
|
||||
value: 'Arial',
|
||||
label: 'fontFamily.arial',
|
||||
category: 'sans-serif',
|
||||
}, {
|
||||
value: 'Times New Roman',
|
||||
label: 'fontFamily.times-new-roman',
|
||||
category: 'serif',
|
||||
}, {
|
||||
value: 'Tahoma',
|
||||
label: 'fontFamily.tahoma',
|
||||
category: 'sans-serif',
|
||||
}, {
|
||||
value: 'Verdana',
|
||||
label: 'fontFamily.verdana',
|
||||
category: 'sans-serif',
|
||||
}, {
|
||||
value: 'Microsoft YaHei',
|
||||
label: 'fontFamily.microsoft-yahei',
|
||||
category: 'sans-serif',
|
||||
}, {
|
||||
value: 'SimSun',
|
||||
label: 'fontFamily.simsun',
|
||||
category: 'serif',
|
||||
}, {
|
||||
value: 'SimHei',
|
||||
label: 'fontFamily.simhei',
|
||||
category: 'sans-serif',
|
||||
}, {
|
||||
value: 'Kaiti',
|
||||
label: 'fontFamily.kaiti',
|
||||
category: 'serif',
|
||||
}, {
|
||||
value: 'FangSong',
|
||||
label: 'fontFamily.fangsong',
|
||||
category: 'serif',
|
||||
}, {
|
||||
value: 'NSimSun',
|
||||
label: 'fontFamily.nsimsun',
|
||||
category: 'serif',
|
||||
}, {
|
||||
value: 'STXinwei',
|
||||
label: 'fontFamily.stxinwei',
|
||||
category: 'serif',
|
||||
}, {
|
||||
value: 'STXingkai',
|
||||
label: 'fontFamily.stxingkai',
|
||||
category: 'serif',
|
||||
}, {
|
||||
value: 'STLiti',
|
||||
label: 'fontFamily.stliti',
|
||||
category: 'serif',
|
||||
}];
|
||||
|
||||
export interface IFontService {
|
||||
/**
|
||||
* The data stream of the font list
|
||||
* UI components should subscribe to this stream to render dropdown lists
|
||||
* When the list changes (add, delete, update), a new value is automatically emitted
|
||||
*/
|
||||
readonly fonts$: BehaviorSubject<IFontConfig[]>;
|
||||
|
||||
/**
|
||||
* Get a snapshot of the current font list (synchronously)
|
||||
* Suitable for scenarios where subscribing to the stream is not needed,
|
||||
* or when obtaining the current state during logic processing
|
||||
*/
|
||||
getFonts(): IFontConfig[];
|
||||
|
||||
/**
|
||||
* Get a single font configuration by value
|
||||
*/
|
||||
getFontByValue(value: string): IFontConfig | undefined;
|
||||
|
||||
/**
|
||||
* Check if the current browser environment supports the font
|
||||
* (Based on document.fonts.check or Canvas fallback)
|
||||
*/
|
||||
isFontSupported(fontValue: string): boolean;
|
||||
|
||||
/**
|
||||
* Add a new font
|
||||
* @throws Error if the font value already exists
|
||||
*/
|
||||
addFont(font: IFontConfig): void;
|
||||
|
||||
/**
|
||||
* Update an existing font configuration
|
||||
* Supports partial updates (e.g., only updating stack or label)
|
||||
* @param value The unique identifier of the font to update
|
||||
* @param updates The fields to update
|
||||
*/
|
||||
updateFont(value: string, updates: Partial<Omit<IFontConfig, 'value'>>): void;
|
||||
|
||||
/**
|
||||
* Remove a font
|
||||
* @param value The identifier of the font to remove
|
||||
* @returns boolean Whether the removal was successful (e.g., built-in fonts may not be allowed to be removed)
|
||||
*/
|
||||
removeFont(value: string): boolean;
|
||||
|
||||
/**
|
||||
* Reset to the default built-in font list
|
||||
* (Used for the "Restore Defaults" feature)
|
||||
*/
|
||||
resetToDefaults(): void;
|
||||
}
|
||||
|
||||
export class FontService implements IFontService, IDisposable {
|
||||
readonly fonts$: BehaviorSubject<IFontConfig[]> = new BehaviorSubject<IFontConfig[]>([...DEFAULT_FONT_LIST]);
|
||||
|
||||
constructor(@IConfigService protected readonly _configService: IConfigService) {
|
||||
const config = this._configService.getConfig<IUniverUIConfig>(UI_PLUGIN_CONFIG_KEY);
|
||||
const { customFontFamily = [] } = config ?? {};
|
||||
if (customFontFamily.length) {
|
||||
customFontFamily.forEach((font) => this.addFont({
|
||||
...font,
|
||||
isCustom: true,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.resetToDefaults();
|
||||
this.fonts$.complete();
|
||||
}
|
||||
|
||||
getFonts(): IFontConfig[] {
|
||||
return this.fonts$.getValue();
|
||||
}
|
||||
|
||||
getFontByValue(value: string): IFontConfig | undefined {
|
||||
return this.getFonts().find((font) => font.value === value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current browser environment supports the font
|
||||
* @param fontValue
|
||||
* @returns boolean Whether the font is supported
|
||||
*/
|
||||
isFontSupported(fontValue: string): boolean {
|
||||
const canvas = document.createElement('canvas');
|
||||
const context = canvas.getContext('2d');
|
||||
if (!context) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const testString = 'abcdefghijklmnopqrstuvwxyz0123456789';
|
||||
context.font = '12px monospace';
|
||||
const baselineWidth = context.measureText(testString).width;
|
||||
|
||||
context.font = `12px "${fontValue}", monospace`;
|
||||
const newWidth = context.measureText(testString).width;
|
||||
|
||||
return newWidth !== baselineWidth;
|
||||
}
|
||||
|
||||
addFont(font: IFontConfig): void {
|
||||
const existingFont = this.getFontByValue(font.value);
|
||||
if (existingFont) {
|
||||
throw new Error(`[FontService]: Font with value "${font.value}" already exists.`);
|
||||
}
|
||||
|
||||
const updatedFonts = [...this.getFonts(), font].sort();
|
||||
this.fonts$.next(updatedFonts);
|
||||
}
|
||||
|
||||
updateFont(value: string, updates: Partial<Omit<IFontConfig, 'value'>>): void {
|
||||
const fonts = this.getFonts();
|
||||
const fontIndex = fonts.findIndex((font) => font.value === value);
|
||||
if (fontIndex === -1) {
|
||||
throw new Error(`Font with value "${value}" not found.`);
|
||||
}
|
||||
|
||||
const updatedFont = { ...fonts[fontIndex], ...updates };
|
||||
const updatedFonts = [...fonts];
|
||||
updatedFonts[fontIndex] = updatedFont;
|
||||
|
||||
this.fonts$.next(updatedFonts);
|
||||
}
|
||||
|
||||
removeFont(value: string): boolean {
|
||||
const fonts = this.getFonts();
|
||||
const fontIndex = fonts.findIndex((font) => font.value === value);
|
||||
if (fontIndex === -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const fontToRemove = fonts[fontIndex];
|
||||
if (!fontToRemove.isCustom) {
|
||||
// Prevent removal of built-in fonts
|
||||
return false;
|
||||
}
|
||||
|
||||
const updatedFonts = fonts.filter((font) => font.value !== value);
|
||||
this.fonts$.next(updatedFonts);
|
||||
return true;
|
||||
}
|
||||
|
||||
resetToDefaults(): void {
|
||||
this.fonts$.next([...DEFAULT_FONT_LIST]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user