Skip to content

Commit

Permalink
refactor: dynamic generation font and CSS rules
Browse files Browse the repository at this point in the history
  • Loading branch information
kirklin committed Aug 30, 2023
1 parent 37913ef commit 9dc4eda
Show file tree
Hide file tree
Showing 2 changed files with 206 additions and 122 deletions.
301 changes: 198 additions & 103 deletions src/defaultChineseFonts.ts
Original file line number Diff line number Diff line change
@@ -1,111 +1,206 @@
const macosSimplifiedChinese = ["-apple-system", "BlinkMacSystemFont", "PingFang SC", "Hiragino Sans GB", "Heiti SC"];
const macosTraditionalChinese = ["-apple-system", "BlinkMacSystemFont", "PingFang SC"];
const windowsSimplifiedChinese = ["Microsoft YaHei"];
const windowsTraditionalChinese = ["Microsoft Jhenghei"];
const linuxSimplifiedChinese = ["system-ui", "Ubuntu", "Droid Sans", "Source Han Sans SC", "Source Han Sans CN", "Source Han Sans"];
const linuxTraditionalChinese = ["system-ui", "Ubuntu", "Droid Sans", "Source Han Sans TC", "Source Han Sans TW", "Source Han Sans"];

export type FontType = "chinese" | "helvetica" | "italics" | "song" | "imitation-song" | "new-song" | "li";
/**
* Generates a list of fonts for the specified character type and font type, with optional fallback font.
* 根据指定的字符类型和字体类型生成字体列表,可以选择性地指定回退字体。
*
* @param characterType - The type of characters to consider: "simplified" or "traditional".
* 要考虑的字符类型:"simplified"(简体)或 "traditional"(繁体)。
* @param fontType - The type of font to generate the list for: "chinese", "helvetica", "italics", "song", "imitation-song", "new-song", or "li".
* 要生成列表的字体类型:"chinese"、"helvetica"、"italics"、"song"、"imitation-song"、"new-song" 或 "li"。
* @param fallbackFont - The fallback font to use if the desired font type is not available. Pass `null` for no fallback.
* 如果所需字体类型不可用,则使用的回退字体。传递 `null` 表示没有回退字体。
* @param declareEnglishFont - Whether to declare an English font.
* 是否声明英文字体。
*
* @returns {string[]} An array of font names based on the specified criteria.
* 基于指定条件的字体名称数组。
*/
export function generateFontList(
characterType: "simplified" | "traditional",
fontType: FontType,
fallbackFont: string | null = "sans-serif",
declareEnglishFont: boolean = true,
): string[] {
const fontList: string[] = [];

// Add English font declaration if required
if (declareEnglishFont) {
fontList.push(`Punctuation ${fontType.charAt(0).toUpperCase() + fontType.slice(1)}`);
fontList.push("Arial");
}

// Determine the appropriate font list based on the character type
if (characterType === "simplified") {
const chineseFonts = [macosSimplifiedChinese, windowsSimplifiedChinese, linuxSimplifiedChinese].flat();
// Select the font list based on the font type
switch (fontType) {
case "chinese":
fontList.push(...chineseFonts);
break;
// 黑体
case "helvetica":
fontList.push("PingFang SC", "Heiti SC", "Microsoft YaHei", "Source Han Sans SC", "Source Han Sans CN", "Noto Sans CJK SC",
"WenQuanYi Micro Hei", "WenQuanYi Zen Hei", "SimHei", "WenQuanYi Zen Hei Sharp");
break;
// 楷体
case "italics":
fontList.push("Kaiti SC", "STKaiti",
"AR PL UKai CN", "AR PL UKai HK", "AR PL UKai TW", "AR PL UKai TW MBE", "AR PL KaitiM GB",
"KaiTi", "KaiTi_GB2312", "DFKai-SB");
fontList.push(...chineseFonts);
break;
// 宋体
case "song":
fontList.push("Songti SC", "Noto Serif CJK SC",
"Source Han Serif SC",
"Source Han Serif CN",
"STSong",
"AR PL New Sung",
"AR PL SungtiL GB",
"NSimSun",
"SimSun",
"WenQuanYi Bitmap Song",
"AR PL UMing CN",
"PMingLiU",
"MingLiU",
);
fontList.push(...chineseFonts);
break;
// 仿宋体
case "imitation-song":
fontList.push("STFangsong", "FangSong", "FangSong_GB2312");
fontList.push(...chineseFonts);
break;
// 新宋体
case "new-song":
fontList.push("SimSun-ExtB", "NSimSun");
fontList.push(...chineseFonts);
break;
// 隶书
case "li":
fontList.push("LiSu", "STLiti");
fontList.push(...chineseFonts);
break;
default:
fontList.push(...chineseFonts);
}
} else {
const chineseFonts = [macosTraditionalChinese, windowsTraditionalChinese, linuxTraditionalChinese].flat();
// Select the font list based on the font type
switch (fontType) {
case "chinese":
fontList.push(...chineseFonts);
break;
// 黑体
case "helvetica":
fontList.push("PingFang SC", "Heiti SC", "Microsoft YaHei", "Source Han Sans SC", "Source Han Sans CN", "Noto Sans CJK SC",
"WenQuanYi Micro Hei", "WenQuanYi Zen Hei", "SimHei", "WenQuanYi Zen Hei Sharp");
break;
// 楷体
case "italics":
fontList.push("Kaiti SC", "STKaiti",
"AR PL UKai CN", "AR PL UKai HK", "AR PL UKai TW", "AR PL UKai TW MBE", "AR PL KaitiM GB",
"KaiTi", "KaiTi_GB2312", "DFKai-SB", "TW-Kai");
fontList.push(...chineseFonts);
break;
// 宋体
case "song":
fontList.push("Songti SC", "Noto Serif CJK SC",
"Source Han Serif SC",
"Source Han Serif CN",
"STSong",
"AR PL New Sung",
"AR PL SungtiL GB",
"NSimSun",
"SimSun",
"TW-Sung",
"WenQuanYi Bitmap Song",
"AR PL UMing CN",
"AR PL UMing HK",
"AR PL UMing TW",
"AR PL UMing TW MBE",
"PMingLiU",
"MingLiU",
);
fontList.push(...chineseFonts);
break;
// 仿宋体
case "imitation-song":
fontList.push("STFangsong", "FangSong", "FangSong_GB2312");
fontList.push(...chineseFonts);
break;
// 新宋体
case "new-song":
fontList.push("SimSun-ExtB", "NSimSun");
fontList.push(...chineseFonts);
break;
// 隶书
case "li":
fontList.push("LiSu", "STLiti");
fontList.push(...chineseFonts);
break;
default:
fontList.push(...chineseFonts);
}
}

// Add fallback font if specified
if (fallbackFont !== null) {
fontList.push(fallbackFont);
}

return fontList;
}

export const defaultChineseFonts = {
"chinese": [
"Punctuation SC",
"Helvetica Neue",
"Helvetica",
"Arial",
"Microsoft Yahei",
"Hiragino Sans GB",
"Heiti SC",
"WenQuanYi Micro Hei",
"sans-serif",
],

"chinese": generateFontList("simplified", "chinese"),
// 黑体
"helvetica": [
"Punctuation SC",
"-apple-system",
"Noto Sans",
"Helvetica Neue",
"Helvetica",
"Nimbus Sans L",
"Arial",
"Liberation Sans",
"PingFang SC",
"Hiragino Sans GB",
"Noto Sans CJK SC",
"Source Han Sans SC",
"Source Han Sans CN",
"Microsoft YaHei",
"Wenquanyi Micro Hei",
"WenQuanYi Zen Hei",
"ST Heiti",
"SimHei",
"WenQuanYi Zen Hei Sharp",
"sans-serif",
],
"helvetica": generateFontList("simplified", "helvetica"),
// 楷体
"italics": [
"Punctuation SC",
"Baskerville",
"Georgia",
"Liberation Serif",
"Kaiti SC",
"STKaiti",
"AR PL UKai CN",
"AR PL UKai HK",
"AR PL UKai TW",
"AR PL UKai TW MBE",
"AR PL KaitiM GB",
"KaiTi",
"KaiTi_GB2312",
"DFKai-SB",
"TW-Kai",
"serif",
],
"italics": generateFontList("simplified", "italics"),
// 宋体
"song": [
"Punctuation SC",
"Georgia",
"Nimbus Roman No9 L",
"Songti SC",
"Noto Serif CJK SC",
"Source Han Serif SC",
"Source Han Serif CN",
"STSong",
"AR PL New Sung",
"AR PL SungtiL GB",
"NSimSun",
"SimSun",
"TW-Sung",
"WenQuanYi Bitmap Song",
"AR PL UMing CN",
"AR PL UMing HK",
"AR PL UMing TW",
"AR PL UMing TW MBE",
"PMingLiU",
"MingLiU",
"serif",
],
"song": generateFontList("simplified", "song"),
// 仿宋体
"imitation-song": [
"Punctuation SC",
"Baskerville",
"Times New Roman",
"Liberation Serif",
"STFangsong",
"FangSong",
"FangSong_GB2312",
"CWTEX-F",
"serif",
],
"imitation-song": generateFontList("simplified", "imitation-song"),
// 新宋体
"new-song": [
"Punctuation SC",
"SimSun-ExtB",
"NSimSun",
"Microsoft YaHei UI",
"Microsoft YaHei UI Light",
"Microsoft YaHei UI Bold",
"serif",
],
"new-song": generateFontList("simplified", "new-song"),
// 隶书
"li": [
"Punctuation SC",
"LiSu",
"YouYuan",
"STXingkai",
"Xingkai SC",
"PMingLiU-ExtB",
"serif",
],
"li": generateFontList("simplified", "li"),
};

/**
* Generates a CSS @font-face rule for the specified font type.
* 根据指定的字体类型生成 CSS @font-face 规则。
*
* @param fontType - The type of font to generate the @font-face rule for.
* 要生成 @font-face 规则的字体类型。
*
* @returns {string} The generated @font-face CSS rule as a string.
* 生成的 @font-face CSS 规则作为字符串。
*/
export function generateFontFaceRule(fontType: FontType): string {
const fontList = defaultChineseFonts[fontType];
if (!fontList) {
throw new Error(`Font type "${fontType}" is not valid.`);
}

const fontName = `Punctuation ${fontType.charAt(0).toUpperCase() + fontType.slice(1)}`;
const filteredFontList = fontList.filter(font => font !== "Arial"); // Filtering out Arial
const fontSrc = filteredFontList.map(font => `local('${font}')`).join(", ");

return `
@font-face {
font-family: '${fontName}';
src: ${fontSrc};
unicode-range: U+201C, U+201D, U+2018, U+2019, U+2E3A, U+2014, U+2013, U+2026, U+00B7, U+007E, U+002F;
}
`;
}
27 changes: 8 additions & 19 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { toArray } from "@unocss/core";
import type { Preset } from "unocss";
import { defaultChineseFonts } from "./defaultChineseFonts";
import type { FontType } from "./defaultChineseFonts";
import { defaultChineseFonts, generateFontFaceRule } from "./defaultChineseFonts";
import type { ChineseFontsOptions } from "./types";

export * from "./types";
Expand Down Expand Up @@ -43,24 +44,12 @@ const presetChinese = (options: ChineseFontsOptions = {}): Preset => {
}
};
}
// TODO: Dynamically calculates and sets the font styles for specific Chinese characters based on the selected theme's fonts.
// TODO: 根据所选主题的字体动态计算并设置特定中文字符的字体样式。
preset.preflights = [
{
getCSS: () => `
@font-face {
font-family: 'Punctuation SC';
src: local('PingFang SC'), local('Noto Sans SC'), local('Noto Sans CJK SC'), local('Heiti SC'), local('Microsoft Yahei');
unicode-range: U+201C, U+201D, U+2018, U+2019, U+2E3A, U+2014, U+2013, U+2026, U+00B7, U+007E, U+002F; /* Unicode range for punctuation marks */
}
@font-face {
font-family: 'Punctuation TC';
src: local('PingFang TC'), local('Noto Sans TC'), local('Noto Sans CJK TC'), local('Heiti TC'), local('Microsoft JhengHei');
unicode-range: U+201C, U+201D, U+2018, U+2019, U+2E3A, U+2014, U+2013, U+2026, U+00B7, U+007E, U+002F; /* Unicode range for punctuation marks */
}
`,
},
];

const fontFacePreflights = Object.keys(defaultChineseFonts).map(fontType => ({
getCSS: () => generateFontFaceRule(<FontType>fontType),
}));

preset.preflights = fontFacePreflights;

return preset;
};
Expand Down

0 comments on commit 9dc4eda

Please sign in to comment.