diff --git a/README.md b/README.md index dc0db4c..4a9a439 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ docker run -d --name rawmark \ - 笔记以普通 `.md` 文件保存在 `数据目录/vault/`,粘贴、上传和导入的图片统一存放在笔记同级的 `assets/`,链接使用 `./assets/文件名`,同目录相同内容去重。笔记跨目录移动时图片跟随,仍被其他笔记引用的原图保留;删除单篇笔记不会删除共享图片。旧 `笔记名.assets/` 仍可读取、移动与恢复;外部修改会实时同步到网页。 - 知识工具:标准 Markdown 链接构成图谱,支持正文 `#标签` 与 YAML `tags`。笔记或文件夹在应用内改名、移动时维护入链和相对出链;公式和代码示例不参与关系提取。 - 日记与模板:默认日记路径为 `Daily/YYYY-MM-DD.md`(本地日期),已有日记直接打开;模板为 `Templates/` 下的普通 Markdown,支持 `{{date}}`、`{{time}}`、`{{title}}`,资源链接按新笔记位置调整。可在设置中修改目录和日记模板。 -- 外观:浅色玻璃工作台与深色模式,字体资源随应用本地提供;代码块使用 highlight.js,固定采用官网的 Atom One Dark 配色,与页面明暗模式独立;界面字号默认 14px,可输入 14–20px 并单独重置,与编辑器及阅读字号独立;排版、玻璃透明度、选中文本工具栏均可在设置中调整并即时保存。 +- 外观:浅色玻璃工作台与深色模式,默认字体为 Maple Mono Normal NL NF CN v7.9(界面、正文与代码),字体资源随应用本地提供;代码块使用 highlight.js,固定采用官网的 Atom One Dark 配色,与页面明暗模式独立;界面字号默认 14px,可输入 14–20px 并单独重置,与编辑器及阅读字号独立;排版、玻璃透明度、选中文本工具栏均可在设置中调整并即时保存。 - 选区格式:电脑与触屏选中文字后提供外观、加粗、斜体、下划线、删除线、高亮和链接。外观可设置配色、字体、局部字号与效果;下划线及外观以受限的标准 HTML 行内标签保存在 Markdown 中,源码与导出保留标签,其他软件的显示取决于其 HTML 支持。清除样式只重置局部外观;底部不再显示格式栏。 - 图片管理:侧栏默认隐藏 `assets` 和 `笔记名.assets`;右键文件夹选择「图片管理」,查看当前目录及直属附件目录的图片,支持检索、排序、网格/列表、批量上传、引用查看及预览、重命名、移动、替换。可切换整个知识库;清理孤立图片须确认候选,服务端再次核对全库引用后移入回收站,可恢复。上传至所选目录的 `assets/`,相同内容自动去重。根目录可在侧栏空白处右键或通过命令面板打开。图片改名/移动会更新笔记中的本地引用;替换保留路径,选择相同扩展名的图片(最大 50 MB),旧图片不进回收站。 - `--user` 让容器以宿主机用户身份读写数据目录;不指定时容器以 UID 65532 运行,需要该用户对目录有写权限。 @@ -69,3 +69,5 @@ scripts/dev.sh --host # 前端监听所有网卡,手机访问 http://<电脑 cd web && npm run typecheck && npm test go vet -tags dev ./... && go test ./internal/... ``` + +字体资源已入库,普通构建无需下载或转换。重新生成时,在独立 Python 环境安装 `fonttools[woff]`,下载 [v7.9 指定字体包](https://github.com/subframe7536/maple-font/releases/download/v7.9/MapleMonoNormalNL-NF-CN.zip),运行 `python3 scripts/prepare-maple-font.py /path/to/MapleMonoNormalNL-NF-CN.zip`;生成 WOFF2 与 `maple-font.css`,保留上游许可。 diff --git a/scripts/prepare-maple-font.py b/scripts/prepare-maple-font.py new file mode 100644 index 0000000..13fdde4 --- /dev/null +++ b/scripts/prepare-maple-font.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +"""从指定 v7.9 ZIP 重建本地字体:python3 scripts/prepare-maple-font.py /path/to/MapleMonoNormalNL-NF-CN.zip。 +仅重建字体时需要 fonttools[woff];应用构建直接使用已入库的 WOFF2。 +来源:https://github.com/subframe7536/maple-font/releases/tag/v7.9 +""" +import io +from pathlib import Path +import sys +import zipfile + +from fontTools import subset +from fontTools.ttLib import TTFont + +root = Path(__file__).resolve().parents[1] / 'web/src/themes' +output = root / 'fonts/maple' +output.mkdir(exist_ok=True) +family = 'Maple Mono Normal NL NF CN' +css = ['/* Maple Mono v7.9;由 scripts/prepare-maple-font.py 生成,授权见 fonts/maple/LICENSE.txt。 */'] +with zipfile.ZipFile(sys.argv[1]) as archive: + (output / 'LICENSE.txt').write_bytes(archive.read('LICENSE.txt')) + for variant, weight, style in [('Regular', 400, 'normal'), ('Bold', 700, 'normal'), ('Italic', 400, 'italic'), ('BoldItalic', 700, 'italic')]: + data = archive.read('MapleMonoNormalNL-NF-CN-' + variant + '.ttf') + source = TTFont(io.BytesIO(data)) + points = sorted(source.getBestCmap()) + # 按 Unicode 区间分片,中文和 Nerd Font 不强制随拉丁文字一起下载。 + for block in sorted({cp // 4096 for cp in points}): + unicodes = [cp for cp in points if cp // 4096 == block] + font = TTFont(io.BytesIO(data), recalcTimestamp=False) + options = subset.Options() + options.flavor = 'woff2' + subsetter = subset.Subsetter(options=options) + subsetter.populate(unicodes=unicodes) + subsetter.subset(font) + font.flavor = 'woff2' + name = f'{variant.lower()}-{block:02x}.woff2' + font.save(output / name) + css.append(f"@font-face {{ font-family: '{family}'; font-style: {style}; font-weight: {weight}; font-display: swap; src: url('./fonts/maple/{name}') format('woff2'); unicode-range: U+{block * 4096:X}-{(block + 1) * 4096 - 1:X}; }}") +(root / 'maple-font.css').write_text('\n'.join(css) + '\n') diff --git a/web/src/themes/base.css b/web/src/themes/base.css index 822e342..aa7c6c9 100644 --- a/web/src/themes/base.css +++ b/web/src/themes/base.css @@ -1,13 +1,14 @@ @import './fonts.css'; @import 'highlight.js/styles/atom-one-dark.css'; +@import './maple-font.css'; /* 基础主题。--rm-* 变量继续作为主题接口,字体在本地加载。 */ :root { color-scheme: light; --rm-sidebar-width: 288px; - --rm-font-text: 'Manrope', 'PingFang SC', 'Microsoft YaHei', sans-serif; - --rm-font-heading: 'Noto Serif SC', 'Source Han Serif SC', serif; - --rm-font-mono: 'JetBrains Mono', ui-monospace, monospace; + --rm-font-text: 'Maple Mono Normal NL NF CN', monospace; + --rm-font-heading: var(--rm-font-editor, var(--rm-font-text)); + --rm-font-mono: 'Maple Mono Normal NL NF CN', monospace; --rm-font-size: 16px; /* 界面排版独立于正文;辅助文字随界面缩放,但不小于 13px。 */ --rm-ui-font-size: 14px; diff --git a/web/src/themes/fonts/maple/LICENSE.txt b/web/src/themes/fonts/maple/LICENSE.txt new file mode 100644 index 0000000..65ea530 --- /dev/null +++ b/web/src/themes/fonts/maple/LICENSE.txt @@ -0,0 +1,93 @@ +Copyright 2022 The Maple Mono Project Authors (https://github.com/subframe7536/maple-font) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://openfontlicense.org + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/web/src/themes/fonts/maple/bold-00.woff2 b/web/src/themes/fonts/maple/bold-00.woff2 new file mode 100644 index 0000000..a559102 Binary files /dev/null and b/web/src/themes/fonts/maple/bold-00.woff2 differ diff --git a/web/src/themes/fonts/maple/bold-01.woff2 b/web/src/themes/fonts/maple/bold-01.woff2 new file mode 100644 index 0000000..eeea011 Binary files /dev/null and b/web/src/themes/fonts/maple/bold-01.woff2 differ diff --git a/web/src/themes/fonts/maple/bold-02.woff2 b/web/src/themes/fonts/maple/bold-02.woff2 new file mode 100644 index 0000000..0e1c7c7 Binary files /dev/null and b/web/src/themes/fonts/maple/bold-02.woff2 differ diff --git a/web/src/themes/fonts/maple/bold-03.woff2 b/web/src/themes/fonts/maple/bold-03.woff2 new file mode 100644 index 0000000..1a01dc2 Binary files /dev/null and b/web/src/themes/fonts/maple/bold-03.woff2 differ diff --git a/web/src/themes/fonts/maple/bold-04.woff2 b/web/src/themes/fonts/maple/bold-04.woff2 new file mode 100644 index 0000000..1c1bc67 Binary files /dev/null and b/web/src/themes/fonts/maple/bold-04.woff2 differ diff --git a/web/src/themes/fonts/maple/bold-05.woff2 b/web/src/themes/fonts/maple/bold-05.woff2 new file mode 100644 index 0000000..3e47874 Binary files /dev/null and b/web/src/themes/fonts/maple/bold-05.woff2 differ diff --git a/web/src/themes/fonts/maple/bold-06.woff2 b/web/src/themes/fonts/maple/bold-06.woff2 new file mode 100644 index 0000000..90e2ca1 Binary files /dev/null and b/web/src/themes/fonts/maple/bold-06.woff2 differ diff --git a/web/src/themes/fonts/maple/bold-07.woff2 b/web/src/themes/fonts/maple/bold-07.woff2 new file mode 100644 index 0000000..b63ea33 Binary files /dev/null and b/web/src/themes/fonts/maple/bold-07.woff2 differ diff --git a/web/src/themes/fonts/maple/bold-08.woff2 b/web/src/themes/fonts/maple/bold-08.woff2 new file mode 100644 index 0000000..43ade9f Binary files /dev/null and b/web/src/themes/fonts/maple/bold-08.woff2 differ diff --git a/web/src/themes/fonts/maple/bold-09.woff2 b/web/src/themes/fonts/maple/bold-09.woff2 new file mode 100644 index 0000000..142f7ec Binary files /dev/null and b/web/src/themes/fonts/maple/bold-09.woff2 differ diff --git a/web/src/themes/fonts/maple/bold-0e.woff2 b/web/src/themes/fonts/maple/bold-0e.woff2 new file mode 100644 index 0000000..6857b44 Binary files /dev/null and b/web/src/themes/fonts/maple/bold-0e.woff2 differ diff --git a/web/src/themes/fonts/maple/bold-0f.woff2 b/web/src/themes/fonts/maple/bold-0f.woff2 new file mode 100644 index 0000000..1d6627a Binary files /dev/null and b/web/src/themes/fonts/maple/bold-0f.woff2 differ diff --git a/web/src/themes/fonts/maple/bold-1f.woff2 b/web/src/themes/fonts/maple/bold-1f.woff2 new file mode 100644 index 0000000..69af934 Binary files /dev/null and b/web/src/themes/fonts/maple/bold-1f.woff2 differ diff --git a/web/src/themes/fonts/maple/bold-f0.woff2 b/web/src/themes/fonts/maple/bold-f0.woff2 new file mode 100644 index 0000000..cb70a1b Binary files /dev/null and b/web/src/themes/fonts/maple/bold-f0.woff2 differ diff --git a/web/src/themes/fonts/maple/bold-f1.woff2 b/web/src/themes/fonts/maple/bold-f1.woff2 new file mode 100644 index 0000000..fcaa025 Binary files /dev/null and b/web/src/themes/fonts/maple/bold-f1.woff2 differ diff --git a/web/src/themes/fonts/maple/bolditalic-00.woff2 b/web/src/themes/fonts/maple/bolditalic-00.woff2 new file mode 100644 index 0000000..55a76d4 Binary files /dev/null and b/web/src/themes/fonts/maple/bolditalic-00.woff2 differ diff --git a/web/src/themes/fonts/maple/bolditalic-01.woff2 b/web/src/themes/fonts/maple/bolditalic-01.woff2 new file mode 100644 index 0000000..fe288f0 Binary files /dev/null and b/web/src/themes/fonts/maple/bolditalic-01.woff2 differ diff --git a/web/src/themes/fonts/maple/bolditalic-02.woff2 b/web/src/themes/fonts/maple/bolditalic-02.woff2 new file mode 100644 index 0000000..ebcb0fc Binary files /dev/null and b/web/src/themes/fonts/maple/bolditalic-02.woff2 differ diff --git a/web/src/themes/fonts/maple/bolditalic-03.woff2 b/web/src/themes/fonts/maple/bolditalic-03.woff2 new file mode 100644 index 0000000..370ea3f Binary files /dev/null and b/web/src/themes/fonts/maple/bolditalic-03.woff2 differ diff --git a/web/src/themes/fonts/maple/bolditalic-04.woff2 b/web/src/themes/fonts/maple/bolditalic-04.woff2 new file mode 100644 index 0000000..72bc135 Binary files /dev/null and b/web/src/themes/fonts/maple/bolditalic-04.woff2 differ diff --git a/web/src/themes/fonts/maple/bolditalic-05.woff2 b/web/src/themes/fonts/maple/bolditalic-05.woff2 new file mode 100644 index 0000000..5f847d4 Binary files /dev/null and b/web/src/themes/fonts/maple/bolditalic-05.woff2 differ diff --git a/web/src/themes/fonts/maple/bolditalic-06.woff2 b/web/src/themes/fonts/maple/bolditalic-06.woff2 new file mode 100644 index 0000000..889cd0e Binary files /dev/null and b/web/src/themes/fonts/maple/bolditalic-06.woff2 differ diff --git a/web/src/themes/fonts/maple/bolditalic-07.woff2 b/web/src/themes/fonts/maple/bolditalic-07.woff2 new file mode 100644 index 0000000..8f642f3 Binary files /dev/null and b/web/src/themes/fonts/maple/bolditalic-07.woff2 differ diff --git a/web/src/themes/fonts/maple/bolditalic-08.woff2 b/web/src/themes/fonts/maple/bolditalic-08.woff2 new file mode 100644 index 0000000..13631ad Binary files /dev/null and b/web/src/themes/fonts/maple/bolditalic-08.woff2 differ diff --git a/web/src/themes/fonts/maple/bolditalic-09.woff2 b/web/src/themes/fonts/maple/bolditalic-09.woff2 new file mode 100644 index 0000000..86eb27d Binary files /dev/null and b/web/src/themes/fonts/maple/bolditalic-09.woff2 differ diff --git a/web/src/themes/fonts/maple/bolditalic-0e.woff2 b/web/src/themes/fonts/maple/bolditalic-0e.woff2 new file mode 100644 index 0000000..30b62e8 Binary files /dev/null and b/web/src/themes/fonts/maple/bolditalic-0e.woff2 differ diff --git a/web/src/themes/fonts/maple/bolditalic-0f.woff2 b/web/src/themes/fonts/maple/bolditalic-0f.woff2 new file mode 100644 index 0000000..b2dba80 Binary files /dev/null and b/web/src/themes/fonts/maple/bolditalic-0f.woff2 differ diff --git a/web/src/themes/fonts/maple/bolditalic-1f.woff2 b/web/src/themes/fonts/maple/bolditalic-1f.woff2 new file mode 100644 index 0000000..8585e77 Binary files /dev/null and b/web/src/themes/fonts/maple/bolditalic-1f.woff2 differ diff --git a/web/src/themes/fonts/maple/bolditalic-f0.woff2 b/web/src/themes/fonts/maple/bolditalic-f0.woff2 new file mode 100644 index 0000000..884214b Binary files /dev/null and b/web/src/themes/fonts/maple/bolditalic-f0.woff2 differ diff --git a/web/src/themes/fonts/maple/bolditalic-f1.woff2 b/web/src/themes/fonts/maple/bolditalic-f1.woff2 new file mode 100644 index 0000000..e6e2a8a Binary files /dev/null and b/web/src/themes/fonts/maple/bolditalic-f1.woff2 differ diff --git a/web/src/themes/fonts/maple/italic-00.woff2 b/web/src/themes/fonts/maple/italic-00.woff2 new file mode 100644 index 0000000..e1fb092 Binary files /dev/null and b/web/src/themes/fonts/maple/italic-00.woff2 differ diff --git a/web/src/themes/fonts/maple/italic-01.woff2 b/web/src/themes/fonts/maple/italic-01.woff2 new file mode 100644 index 0000000..5d74a78 Binary files /dev/null and b/web/src/themes/fonts/maple/italic-01.woff2 differ diff --git a/web/src/themes/fonts/maple/italic-02.woff2 b/web/src/themes/fonts/maple/italic-02.woff2 new file mode 100644 index 0000000..7a52811 Binary files /dev/null and b/web/src/themes/fonts/maple/italic-02.woff2 differ diff --git a/web/src/themes/fonts/maple/italic-03.woff2 b/web/src/themes/fonts/maple/italic-03.woff2 new file mode 100644 index 0000000..7661240 Binary files /dev/null and b/web/src/themes/fonts/maple/italic-03.woff2 differ diff --git a/web/src/themes/fonts/maple/italic-04.woff2 b/web/src/themes/fonts/maple/italic-04.woff2 new file mode 100644 index 0000000..7baef04 Binary files /dev/null and b/web/src/themes/fonts/maple/italic-04.woff2 differ diff --git a/web/src/themes/fonts/maple/italic-05.woff2 b/web/src/themes/fonts/maple/italic-05.woff2 new file mode 100644 index 0000000..2fe5bf5 Binary files /dev/null and b/web/src/themes/fonts/maple/italic-05.woff2 differ diff --git a/web/src/themes/fonts/maple/italic-06.woff2 b/web/src/themes/fonts/maple/italic-06.woff2 new file mode 100644 index 0000000..37047d0 Binary files /dev/null and b/web/src/themes/fonts/maple/italic-06.woff2 differ diff --git a/web/src/themes/fonts/maple/italic-07.woff2 b/web/src/themes/fonts/maple/italic-07.woff2 new file mode 100644 index 0000000..327c12f Binary files /dev/null and b/web/src/themes/fonts/maple/italic-07.woff2 differ diff --git a/web/src/themes/fonts/maple/italic-08.woff2 b/web/src/themes/fonts/maple/italic-08.woff2 new file mode 100644 index 0000000..8f1f943 Binary files /dev/null and b/web/src/themes/fonts/maple/italic-08.woff2 differ diff --git a/web/src/themes/fonts/maple/italic-09.woff2 b/web/src/themes/fonts/maple/italic-09.woff2 new file mode 100644 index 0000000..b6c9d1a Binary files /dev/null and b/web/src/themes/fonts/maple/italic-09.woff2 differ diff --git a/web/src/themes/fonts/maple/italic-0e.woff2 b/web/src/themes/fonts/maple/italic-0e.woff2 new file mode 100644 index 0000000..ca146e9 Binary files /dev/null and b/web/src/themes/fonts/maple/italic-0e.woff2 differ diff --git a/web/src/themes/fonts/maple/italic-0f.woff2 b/web/src/themes/fonts/maple/italic-0f.woff2 new file mode 100644 index 0000000..4593a80 Binary files /dev/null and b/web/src/themes/fonts/maple/italic-0f.woff2 differ diff --git a/web/src/themes/fonts/maple/italic-1f.woff2 b/web/src/themes/fonts/maple/italic-1f.woff2 new file mode 100644 index 0000000..1d89ece Binary files /dev/null and b/web/src/themes/fonts/maple/italic-1f.woff2 differ diff --git a/web/src/themes/fonts/maple/italic-f0.woff2 b/web/src/themes/fonts/maple/italic-f0.woff2 new file mode 100644 index 0000000..6266641 Binary files /dev/null and b/web/src/themes/fonts/maple/italic-f0.woff2 differ diff --git a/web/src/themes/fonts/maple/italic-f1.woff2 b/web/src/themes/fonts/maple/italic-f1.woff2 new file mode 100644 index 0000000..61817d4 Binary files /dev/null and b/web/src/themes/fonts/maple/italic-f1.woff2 differ diff --git a/web/src/themes/fonts/maple/regular-00.woff2 b/web/src/themes/fonts/maple/regular-00.woff2 new file mode 100644 index 0000000..5c4242c Binary files /dev/null and b/web/src/themes/fonts/maple/regular-00.woff2 differ diff --git a/web/src/themes/fonts/maple/regular-01.woff2 b/web/src/themes/fonts/maple/regular-01.woff2 new file mode 100644 index 0000000..15e45d5 Binary files /dev/null and b/web/src/themes/fonts/maple/regular-01.woff2 differ diff --git a/web/src/themes/fonts/maple/regular-02.woff2 b/web/src/themes/fonts/maple/regular-02.woff2 new file mode 100644 index 0000000..c97a53f Binary files /dev/null and b/web/src/themes/fonts/maple/regular-02.woff2 differ diff --git a/web/src/themes/fonts/maple/regular-03.woff2 b/web/src/themes/fonts/maple/regular-03.woff2 new file mode 100644 index 0000000..aa1de9c Binary files /dev/null and b/web/src/themes/fonts/maple/regular-03.woff2 differ diff --git a/web/src/themes/fonts/maple/regular-04.woff2 b/web/src/themes/fonts/maple/regular-04.woff2 new file mode 100644 index 0000000..8c3a61e Binary files /dev/null and b/web/src/themes/fonts/maple/regular-04.woff2 differ diff --git a/web/src/themes/fonts/maple/regular-05.woff2 b/web/src/themes/fonts/maple/regular-05.woff2 new file mode 100644 index 0000000..f7f859b Binary files /dev/null and b/web/src/themes/fonts/maple/regular-05.woff2 differ diff --git a/web/src/themes/fonts/maple/regular-06.woff2 b/web/src/themes/fonts/maple/regular-06.woff2 new file mode 100644 index 0000000..497c48c Binary files /dev/null and b/web/src/themes/fonts/maple/regular-06.woff2 differ diff --git a/web/src/themes/fonts/maple/regular-07.woff2 b/web/src/themes/fonts/maple/regular-07.woff2 new file mode 100644 index 0000000..9ee7af6 Binary files /dev/null and b/web/src/themes/fonts/maple/regular-07.woff2 differ diff --git a/web/src/themes/fonts/maple/regular-08.woff2 b/web/src/themes/fonts/maple/regular-08.woff2 new file mode 100644 index 0000000..542483f Binary files /dev/null and b/web/src/themes/fonts/maple/regular-08.woff2 differ diff --git a/web/src/themes/fonts/maple/regular-09.woff2 b/web/src/themes/fonts/maple/regular-09.woff2 new file mode 100644 index 0000000..26b5f48 Binary files /dev/null and b/web/src/themes/fonts/maple/regular-09.woff2 differ diff --git a/web/src/themes/fonts/maple/regular-0e.woff2 b/web/src/themes/fonts/maple/regular-0e.woff2 new file mode 100644 index 0000000..e288cc3 Binary files /dev/null and b/web/src/themes/fonts/maple/regular-0e.woff2 differ diff --git a/web/src/themes/fonts/maple/regular-0f.woff2 b/web/src/themes/fonts/maple/regular-0f.woff2 new file mode 100644 index 0000000..530bfb0 Binary files /dev/null and b/web/src/themes/fonts/maple/regular-0f.woff2 differ diff --git a/web/src/themes/fonts/maple/regular-1f.woff2 b/web/src/themes/fonts/maple/regular-1f.woff2 new file mode 100644 index 0000000..e8e0aae Binary files /dev/null and b/web/src/themes/fonts/maple/regular-1f.woff2 differ diff --git a/web/src/themes/fonts/maple/regular-f0.woff2 b/web/src/themes/fonts/maple/regular-f0.woff2 new file mode 100644 index 0000000..f0ee78c Binary files /dev/null and b/web/src/themes/fonts/maple/regular-f0.woff2 differ diff --git a/web/src/themes/fonts/maple/regular-f1.woff2 b/web/src/themes/fonts/maple/regular-f1.woff2 new file mode 100644 index 0000000..d7304d1 Binary files /dev/null and b/web/src/themes/fonts/maple/regular-f1.woff2 differ diff --git a/web/src/themes/maple-font.css b/web/src/themes/maple-font.css new file mode 100644 index 0000000..60ff0dd --- /dev/null +++ b/web/src/themes/maple-font.css @@ -0,0 +1,61 @@ +/* Maple Mono v7.9;由 scripts/prepare-maple-font.py 生成,授权见 fonts/maple/LICENSE.txt。 */ +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 400; font-display: swap; src: url('./fonts/maple/regular-00.woff2') format('woff2'); unicode-range: U+0-FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 400; font-display: swap; src: url('./fonts/maple/regular-01.woff2') format('woff2'); unicode-range: U+1000-1FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 400; font-display: swap; src: url('./fonts/maple/regular-02.woff2') format('woff2'); unicode-range: U+2000-2FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 400; font-display: swap; src: url('./fonts/maple/regular-03.woff2') format('woff2'); unicode-range: U+3000-3FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 400; font-display: swap; src: url('./fonts/maple/regular-04.woff2') format('woff2'); unicode-range: U+4000-4FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 400; font-display: swap; src: url('./fonts/maple/regular-05.woff2') format('woff2'); unicode-range: U+5000-5FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 400; font-display: swap; src: url('./fonts/maple/regular-06.woff2') format('woff2'); unicode-range: U+6000-6FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 400; font-display: swap; src: url('./fonts/maple/regular-07.woff2') format('woff2'); unicode-range: U+7000-7FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 400; font-display: swap; src: url('./fonts/maple/regular-08.woff2') format('woff2'); unicode-range: U+8000-8FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 400; font-display: swap; src: url('./fonts/maple/regular-09.woff2') format('woff2'); unicode-range: U+9000-9FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 400; font-display: swap; src: url('./fonts/maple/regular-0e.woff2') format('woff2'); unicode-range: U+E000-EFFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 400; font-display: swap; src: url('./fonts/maple/regular-0f.woff2') format('woff2'); unicode-range: U+F000-FFFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 400; font-display: swap; src: url('./fonts/maple/regular-1f.woff2') format('woff2'); unicode-range: U+1F000-1FFFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 400; font-display: swap; src: url('./fonts/maple/regular-f0.woff2') format('woff2'); unicode-range: U+F0000-F0FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 400; font-display: swap; src: url('./fonts/maple/regular-f1.woff2') format('woff2'); unicode-range: U+F1000-F1FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 700; font-display: swap; src: url('./fonts/maple/bold-00.woff2') format('woff2'); unicode-range: U+0-FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 700; font-display: swap; src: url('./fonts/maple/bold-01.woff2') format('woff2'); unicode-range: U+1000-1FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 700; font-display: swap; src: url('./fonts/maple/bold-02.woff2') format('woff2'); unicode-range: U+2000-2FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 700; font-display: swap; src: url('./fonts/maple/bold-03.woff2') format('woff2'); unicode-range: U+3000-3FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 700; font-display: swap; src: url('./fonts/maple/bold-04.woff2') format('woff2'); unicode-range: U+4000-4FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 700; font-display: swap; src: url('./fonts/maple/bold-05.woff2') format('woff2'); unicode-range: U+5000-5FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 700; font-display: swap; src: url('./fonts/maple/bold-06.woff2') format('woff2'); unicode-range: U+6000-6FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 700; font-display: swap; src: url('./fonts/maple/bold-07.woff2') format('woff2'); unicode-range: U+7000-7FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 700; font-display: swap; src: url('./fonts/maple/bold-08.woff2') format('woff2'); unicode-range: U+8000-8FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 700; font-display: swap; src: url('./fonts/maple/bold-09.woff2') format('woff2'); unicode-range: U+9000-9FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 700; font-display: swap; src: url('./fonts/maple/bold-0e.woff2') format('woff2'); unicode-range: U+E000-EFFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 700; font-display: swap; src: url('./fonts/maple/bold-0f.woff2') format('woff2'); unicode-range: U+F000-FFFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 700; font-display: swap; src: url('./fonts/maple/bold-1f.woff2') format('woff2'); unicode-range: U+1F000-1FFFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 700; font-display: swap; src: url('./fonts/maple/bold-f0.woff2') format('woff2'); unicode-range: U+F0000-F0FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: normal; font-weight: 700; font-display: swap; src: url('./fonts/maple/bold-f1.woff2') format('woff2'); unicode-range: U+F1000-F1FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 400; font-display: swap; src: url('./fonts/maple/italic-00.woff2') format('woff2'); unicode-range: U+0-FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 400; font-display: swap; src: url('./fonts/maple/italic-01.woff2') format('woff2'); unicode-range: U+1000-1FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 400; font-display: swap; src: url('./fonts/maple/italic-02.woff2') format('woff2'); unicode-range: U+2000-2FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 400; font-display: swap; src: url('./fonts/maple/italic-03.woff2') format('woff2'); unicode-range: U+3000-3FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 400; font-display: swap; src: url('./fonts/maple/italic-04.woff2') format('woff2'); unicode-range: U+4000-4FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 400; font-display: swap; src: url('./fonts/maple/italic-05.woff2') format('woff2'); unicode-range: U+5000-5FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 400; font-display: swap; src: url('./fonts/maple/italic-06.woff2') format('woff2'); unicode-range: U+6000-6FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 400; font-display: swap; src: url('./fonts/maple/italic-07.woff2') format('woff2'); unicode-range: U+7000-7FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 400; font-display: swap; src: url('./fonts/maple/italic-08.woff2') format('woff2'); unicode-range: U+8000-8FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 400; font-display: swap; src: url('./fonts/maple/italic-09.woff2') format('woff2'); unicode-range: U+9000-9FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 400; font-display: swap; src: url('./fonts/maple/italic-0e.woff2') format('woff2'); unicode-range: U+E000-EFFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 400; font-display: swap; src: url('./fonts/maple/italic-0f.woff2') format('woff2'); unicode-range: U+F000-FFFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 400; font-display: swap; src: url('./fonts/maple/italic-1f.woff2') format('woff2'); unicode-range: U+1F000-1FFFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 400; font-display: swap; src: url('./fonts/maple/italic-f0.woff2') format('woff2'); unicode-range: U+F0000-F0FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 400; font-display: swap; src: url('./fonts/maple/italic-f1.woff2') format('woff2'); unicode-range: U+F1000-F1FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 700; font-display: swap; src: url('./fonts/maple/bolditalic-00.woff2') format('woff2'); unicode-range: U+0-FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 700; font-display: swap; src: url('./fonts/maple/bolditalic-01.woff2') format('woff2'); unicode-range: U+1000-1FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 700; font-display: swap; src: url('./fonts/maple/bolditalic-02.woff2') format('woff2'); unicode-range: U+2000-2FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 700; font-display: swap; src: url('./fonts/maple/bolditalic-03.woff2') format('woff2'); unicode-range: U+3000-3FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 700; font-display: swap; src: url('./fonts/maple/bolditalic-04.woff2') format('woff2'); unicode-range: U+4000-4FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 700; font-display: swap; src: url('./fonts/maple/bolditalic-05.woff2') format('woff2'); unicode-range: U+5000-5FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 700; font-display: swap; src: url('./fonts/maple/bolditalic-06.woff2') format('woff2'); unicode-range: U+6000-6FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 700; font-display: swap; src: url('./fonts/maple/bolditalic-07.woff2') format('woff2'); unicode-range: U+7000-7FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 700; font-display: swap; src: url('./fonts/maple/bolditalic-08.woff2') format('woff2'); unicode-range: U+8000-8FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 700; font-display: swap; src: url('./fonts/maple/bolditalic-09.woff2') format('woff2'); unicode-range: U+9000-9FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 700; font-display: swap; src: url('./fonts/maple/bolditalic-0e.woff2') format('woff2'); unicode-range: U+E000-EFFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 700; font-display: swap; src: url('./fonts/maple/bolditalic-0f.woff2') format('woff2'); unicode-range: U+F000-FFFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 700; font-display: swap; src: url('./fonts/maple/bolditalic-1f.woff2') format('woff2'); unicode-range: U+1F000-1FFFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 700; font-display: swap; src: url('./fonts/maple/bolditalic-f0.woff2') format('woff2'); unicode-range: U+F0000-F0FFF; } +@font-face { font-family: 'Maple Mono Normal NL NF CN'; font-style: italic; font-weight: 700; font-display: swap; src: url('./fonts/maple/bolditalic-f1.woff2') format('woff2'); unicode-range: U+F1000-F1FFF; } diff --git a/web/src/themes/typography.test.ts b/web/src/themes/typography.test.ts index d79e142..cf103f7 100644 --- a/web/src/themes/typography.test.ts +++ b/web/src/themes/typography.test.ts @@ -31,3 +31,13 @@ describe('界面与正文排版设置', () => { expect(style.getPropertyValue('--rm-font-size')).toBe('24px') }) }) + +it('缺省或无效字体统一使用 Maple,保留用户已有的显式选择', () => { + expect(sanitizeDisplaySettings({})).toMatchObject({ textFont: 'maple', codeFont: 'maple' }) + expect(sanitizeDisplaySettings({ textFont: 'unknown', codeFont: 'unknown' })).toMatchObject({ textFont: 'maple', codeFont: 'maple' }) + for (const textFont of ['sans', 'serif', 'system', 'maple']) expect(sanitizeDisplaySettings({ textFont }).textFont).toBe(textFont) + for (const codeFont of ['jetbrains', 'system', 'maple']) expect(sanitizeDisplaySettings({ codeFont }).codeFont).toBe(codeFont) + applyDisplaySettings(DISPLAY_DEFAULTS) + expect(document.documentElement.style.getPropertyValue('--rm-font-editor')).toContain('Maple Mono Normal NL NF CN') + expect(document.documentElement.style.getPropertyValue('--rm-font-mono')).toContain('Maple Mono Normal NL NF CN') +}) diff --git a/web/src/themes/typography.ts b/web/src/themes/typography.ts index 2092987..592653e 100644 --- a/web/src/themes/typography.ts +++ b/web/src/themes/typography.ts @@ -1,15 +1,18 @@ // 编辑器排版设置;账户、快捷键等设置不进入此模块。 +const maple = { label: 'Maple Mono Normal NL NF CN', css: "'Maple Mono Normal NL NF CN', monospace" } export const TEXT_FONTS = { + maple, sans: { label: 'Manrope · 清晰无衬线', css: "'Manrope', 'PingFang SC', 'Microsoft YaHei', sans-serif" }, serif: { label: 'Noto Serif SC · 思源宋体', css: "'Noto Serif SC', 'Source Han Serif SC', serif" }, system: { label: '系统字体', css: 'system-ui, sans-serif' }, } export const CODE_FONTS = { + maple, jetbrains: { label: 'JetBrains Mono', css: "'JetBrains Mono', ui-monospace, monospace" }, system: { label: '系统等宽字体', css: 'ui-monospace, monospace' }, } export const UI_FONT_SIZE = { min: 14, max: 20, default: 14 } -export const DISPLAY_DEFAULTS = { uiFontSize: UI_FONT_SIZE.default, fontSize: 16, contentWidth: 760, textFont: 'sans' as keyof typeof TEXT_FONTS, codeFont: 'jetbrains' as keyof typeof CODE_FONTS, lineHeight: 1.75, paragraphSpacing: 16, glassOpacity: .75 } +export const DISPLAY_DEFAULTS = { uiFontSize: UI_FONT_SIZE.default, fontSize: 16, contentWidth: 760, textFont: 'maple' as keyof typeof TEXT_FONTS, codeFont: 'maple' as keyof typeof CODE_FONTS, lineHeight: 1.75, paragraphSpacing: 16, glassOpacity: .75 } export type DisplaySettings = typeof DISPLAY_DEFAULTS export function sanitizeDisplaySettings(raw: Record): DisplaySettings { const ranged = (key: 'lineHeight' | 'paragraphSpacing' | 'glassOpacity', min: number, max: number) => typeof raw[key] === 'number' && Number.isFinite(raw[key]) && raw[key] >= min && raw[key] <= max ? raw[key] : DISPLAY_DEFAULTS[key] @@ -17,8 +20,8 @@ export function sanitizeDisplaySettings(raw: Record): DisplaySe uiFontSize: typeof raw.uiFontSize === 'number' && Number.isInteger(raw.uiFontSize) && raw.uiFontSize >= UI_FONT_SIZE.min && raw.uiFontSize <= UI_FONT_SIZE.max ? raw.uiFontSize : UI_FONT_SIZE.default, fontSize: typeof raw.fontSize === 'number' && Number.isFinite(raw.fontSize) && raw.fontSize > 0 ? raw.fontSize : 16, contentWidth: typeof raw.contentWidth === 'number' && [0, 680, 760, 960].includes(raw.contentWidth) ? raw.contentWidth : 760, - textFont: raw.textFont === 'serif' || raw.textFont === 'system' ? raw.textFont : 'sans', - codeFont: raw.codeFont === 'system' ? 'system' : 'jetbrains', + textFont: raw.textFont === 'sans' || raw.textFont === 'serif' || raw.textFont === 'system' ? raw.textFont : 'maple', + codeFont: raw.codeFont === 'jetbrains' || raw.codeFont === 'system' ? raw.codeFont : 'maple', lineHeight: ranged('lineHeight', 1.2, 2.5), paragraphSpacing: ranged('paragraphSpacing', 0, 40), glassOpacity: ranged('glassOpacity', .4, 1), } }