@qilin-agent/client-ui-theme 3.1.5 → 3.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -6,7 +6,94 @@ window.__ModuleLoader__.load({
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
7
  let react_jsx_runtime = require("react/jsx-runtime");
8
8
  let _qilin_agent_client_ui_primitives = require("@qilin-agent/client-ui-primitives");
9
+ let react = require("react");
9
10
  let _qilin_agent_client_store = require("@qilin-agent/client-store");
11
+ //#region ../../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs
12
+ function r(e) {
13
+ var t, f, n = "";
14
+ if ("string" == typeof e || "number" == typeof e) n += e;
15
+ else if ("object" == typeof e) if (Array.isArray(e)) {
16
+ var o = e.length;
17
+ for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
18
+ } else for (f in e) e[f] && (n && (n += " "), n += f);
19
+ return n;
20
+ }
21
+ function clsx() {
22
+ for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
23
+ return n;
24
+ }
25
+ //#endregion
26
+ //#region \0qilin-css:/home/runner/work/QiLin/QiLin/packages/client/ui-theme/src/client/AppearanceRow.module.css.mjs
27
+ const css$3 = ".BphuTq_group{border-bottom:.5px solid var(--qilin-alias-border-l2);flex-direction:column;gap:8px;padding:16px 0;display:flex}.BphuTq_title{color:var(--qilin-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}.BphuTq_cubeRow{flex-wrap:wrap;align-items:stretch;gap:8px;display:flex}.BphuTq_themeCube{box-sizing:border-box;border:.5px solid var(--qilin-alias-border-l4);border-radius:var(--qilin-radius-xl);font:inherit;color:var(--qilin-alias-label-primary);cursor:pointer;background:0 0;flex-direction:column;flex:180px;justify-content:center;align-items:center;gap:4px;padding:20px 32px;font-size:14px;line-height:22px;display:flex}.BphuTq_themeCube:hover:not(.BphuTq_selected){background:var(--qilin-alias-interactive-bg-hover)}.BphuTq_selected{background:var(--qilin-alias-bg-module-platform);border-color:var(--qilin-static-neutral-bluish-400)}";
28
+ const tagId$3 = "@qilin-agent/client-ui-theme/AppearanceRow.module.css";
29
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
30
+ const tag = document.createElement("style");
31
+ tag.dataset.plugin = "@qilin-agent/client-ui-theme";
32
+ tag.dataset.pluginCss = tagId$3;
33
+ tag.textContent = css$3;
34
+ document.head.appendChild(tag);
35
+ }
36
+ var AppearanceRow_module_css_default = {
37
+ "cubeRow": "BphuTq_cubeRow",
38
+ "group": "BphuTq_group",
39
+ "selected": "BphuTq_selected",
40
+ "themeCube": "BphuTq_themeCube",
41
+ "title": "BphuTq_title"
42
+ };
43
+ //#endregion
44
+ //#region lib/types/client/AppearanceRow.js
45
+ /**
46
+ * Appearance preference row registered into the General section item slot
47
+ * (figma 501:30012 'Frame 2117131228'): title + three preference cubes.
48
+ * Registered by this package — the theme feature owns its own settings
49
+ * surface. Selection follows the persisted preference, never the resolved
50
+ * active theme.
51
+ */
52
+ /** Cube order and icons (figma 501:30015-30017: Light, Dark, System). */
53
+ const CUBES = [
54
+ {
55
+ id: "light",
56
+ labelKey: "appearance.light",
57
+ Icon: _qilin_agent_client_ui_primitives.IconLightOutline16
58
+ },
59
+ {
60
+ id: "dark",
61
+ labelKey: "appearance.dark",
62
+ Icon: _qilin_agent_client_ui_primitives.IconDarkOutline16
63
+ },
64
+ {
65
+ id: "system",
66
+ labelKey: "appearance.system",
67
+ Icon: _qilin_agent_client_ui_primitives.IconFollowsystemOutline16
68
+ }
69
+ ];
70
+ /**
71
+ * Render the Appearance row.
72
+ * @param props - composed slot props.
73
+ * @returns the row element tree.
74
+ */
75
+ function AppearanceRow({ t, setTheme, useStore }) {
76
+ const preference = useStore((s) => s.preference);
77
+ return (0, react_jsx_runtime.jsxs)("div", {
78
+ className: AppearanceRow_module_css_default.group,
79
+ children: [(0, react_jsx_runtime.jsx)("div", {
80
+ className: AppearanceRow_module_css_default.title,
81
+ children: t("appearance.title")
82
+ }), (0, react_jsx_runtime.jsx)("div", {
83
+ className: AppearanceRow_module_css_default.cubeRow,
84
+ children: CUBES.map(({ id, labelKey, Icon }) => (0, react_jsx_runtime.jsxs)("button", {
85
+ type: "button",
86
+ className: clsx(AppearanceRow_module_css_default.themeCube, preference === id && AppearanceRow_module_css_default.selected),
87
+ "aria-pressed": preference === id,
88
+ onClick: () => {
89
+ setTheme(id);
90
+ },
91
+ children: [(0, react_jsx_runtime.jsx)(Icon, {}), t(labelKey)]
92
+ }, id))
93
+ })]
94
+ });
95
+ }
96
+ //#endregion
10
97
  //#region ../../../vendor/cosmokit/src/misc.ts
11
98
  /** Return true when a value is `null` or `undefined`. */
12
99
  function isNullable(value) {
@@ -914,10 +1001,129 @@ window.__ModuleLoader__.load({
914
1001
  const FONT_SIZE_FIELD = "fontSize";
915
1002
  /** Default preference when the user-settings document has no override. */
916
1003
  const DEFAULT_PREFERENCE = "system";
1004
+ /** Independently configurable font roles. */
1005
+ const FONT_ROLES = [
1006
+ "text",
1007
+ "code",
1008
+ "terminal"
1009
+ ];
1010
+ /**
1011
+ * Font sizes by role. `text` is the conversation content size; `code` is the
1012
+ * code-block size (inline code stays 1px larger); `terminal` is the sidebar
1013
+ * terminal cell font size.
1014
+ */
1015
+ const FONT_SIZE_SPECS = {
1016
+ text: {
1017
+ field: FONT_SIZE_FIELD,
1018
+ variable: "--qilin-content-font-size",
1019
+ min: 10,
1020
+ max: 22,
1021
+ default: 14
1022
+ },
1023
+ code: {
1024
+ field: "codeFontSize",
1025
+ variable: "--qilin-code-font-size",
1026
+ min: 10,
1027
+ max: 16,
1028
+ default: 11
1029
+ },
1030
+ terminal: {
1031
+ field: "terminalFontSize",
1032
+ variable: "--qilin-terminal-font-size",
1033
+ min: 10,
1034
+ max: 20,
1035
+ default: 13
1036
+ }
1037
+ };
1038
+ /** Default font sizes by role. */
1039
+ const DEFAULT_FONT_SIZES = Object.freeze({
1040
+ text: FONT_SIZE_SPECS.text.default,
1041
+ code: FONT_SIZE_SPECS.code.default,
1042
+ terminal: FONT_SIZE_SPECS.terminal.default
1043
+ });
1044
+ /** Settings field carrying each role's font-family list. */
1045
+ const FONT_FAMILY_FIELDS = {
1046
+ text: "textFontFamily",
1047
+ code: "codeFontFamily",
1048
+ terminal: "terminalFontFamily"
1049
+ };
1050
+ /**
1051
+ * Body variable carrying one role's normalized font list; the token sheet
1052
+ * places it ahead of that role's built-in stack.
1053
+ * @param kind - font role.
1054
+ * @returns the CSS custom property name.
1055
+ */
1056
+ function fontFamilyVariable(kind) {
1057
+ return `--qilin-font-family-${kind}`;
1058
+ }
1059
+ /**
1060
+ * Integer px schema for one role's font size.
1061
+ * @param spec - the role's range and default.
1062
+ * @returns the validated number schema.
1063
+ */
1064
+ function fontSizeSchema(spec) {
1065
+ return Schema.number().step(1).min(spec.min).max(spec.max).default(spec.default);
1066
+ }
1067
+ /**
1068
+ * Collect every role's size from a settings section.
1069
+ * @param section - accepted theme settings.
1070
+ * @returns integer px sizes by role.
1071
+ */
1072
+ function sectionFontSizes(section) {
1073
+ return Object.freeze({
1074
+ text: section.fontSize,
1075
+ code: section.codeFontSize,
1076
+ terminal: section.terminalFontSize
1077
+ });
1078
+ }
1079
+ /**
1080
+ * Whether one value is an accepted size for a role.
1081
+ * @param role - font role.
1082
+ * @param px - candidate size.
1083
+ * @returns true for an integer within the role's range.
1084
+ */
1085
+ function isFontSize(role, px) {
1086
+ const spec = FONT_SIZE_SPECS[role];
1087
+ return Number.isInteger(px) && px >= spec.min && px <= spec.max;
1088
+ }
917
1089
  Schema.object({
918
1090
  [THEME_PREFERENCE_FIELD]: Schema.union([...THEME_PREFERENCES]).default(DEFAULT_PREFERENCE),
919
- [FONT_SIZE_FIELD]: Schema.number().step(1).min(10).max(22).default(14)
1091
+ [FONT_SIZE_FIELD]: fontSizeSchema(FONT_SIZE_SPECS.text),
1092
+ [FONT_SIZE_SPECS.code.field]: fontSizeSchema(FONT_SIZE_SPECS.code),
1093
+ [FONT_SIZE_SPECS.terminal.field]: fontSizeSchema(FONT_SIZE_SPECS.terminal),
1094
+ [FONT_FAMILY_FIELDS.text]: Schema.string().default(""),
1095
+ [FONT_FAMILY_FIELDS.code]: Schema.string().default(""),
1096
+ [FONT_FAMILY_FIELDS.terminal]: Schema.string().default("")
920
1097
  });
1098
+ /** CSS Fonts generic and system family keywords, which must stay unquoted. */
1099
+ const GENERIC_FAMILIES = new Set([
1100
+ "serif",
1101
+ "sans-serif",
1102
+ "monospace",
1103
+ "cursive",
1104
+ "fantasy",
1105
+ "system-ui",
1106
+ "ui-serif",
1107
+ "ui-sans-serif",
1108
+ "ui-monospace",
1109
+ "ui-rounded",
1110
+ "emoji",
1111
+ "math",
1112
+ "fangsong",
1113
+ "-apple-system",
1114
+ "blinkmacsystemfont"
1115
+ ]);
1116
+ /**
1117
+ * Normalize user input into a CSS font-family list. Names are comma separated;
1118
+ * quotes, backslashes, angle brackets, and control characters are dropped, and
1119
+ * every non-generic name is double-quoted, so the result is always a valid list
1120
+ * safe to embed in inline CSS and boot scripts. Normalizing a result returns it unchanged.
1121
+ * @param value - user-entered or stored font list.
1122
+ * @returns the normalized list, or `''` when no family name remains.
1123
+ */
1124
+ function normalizeFontFamily(value) {
1125
+ return value.split(",").map((name) => name.replace(/["'\\<>\u0000-\u001f\u007f]/gu, "").replace(/\s+/gu, " ").trim()).filter((name) => name !== "").map((name) => GENERIC_FAMILIES.has(name.toLowerCase()) ? name : `"${name}"`).join(", ");
1126
+ }
921
1127
  /**
922
1128
  * Narrow one wire or registry value to a persistable preference.
923
1129
  * @param value - value crossing the settings or registry boundary.
@@ -927,9 +1133,33 @@ window.__ModuleLoader__.load({
927
1133
  return THEME_PREFERENCES.some((preference) => preference === value);
928
1134
  }
929
1135
  //#endregion
930
- //#region \0qilin-css:/home/runner/work/QiLin/QiLin/packages/client/ui-theme/src/client/settings-row.module.css.mjs
931
- const css$1 = "._6SOBEq_row{border-bottom:.5px solid var(--qilin-alias-border-l2);align-items:center;gap:8px;padding:16px 0;display:flex}._6SOBEq_rowText{flex-direction:column;flex:1;gap:4px;min-width:0;padding-right:48px;display:flex}._6SOBEq_title{color:var(--qilin-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}._6SOBEq_desc{color:var(--qilin-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}._6SOBEq_control{align-items:center;gap:8px;display:inline-flex}._6SOBEq_stepper{border-radius:var(--qilin-radius-md);background:var(--qilin-alias-bg-module-platform);justify-content:center;align-items:center;min-width:72px;height:36px;display:inline-flex;position:relative}._6SOBEq_value{text-align:center;font-variant-numeric:tabular-nums;min-width:18px;color:var(--qilin-alias-label-primary);font-size:14px;line-height:22px}._6SOBEq_unit{color:var(--qilin-alias-label-secondary);font-size:14px;line-height:22px}._6SOBEq_arrows{opacity:0;flex-direction:column;gap:2px;display:flex;position:absolute;right:8px}._6SOBEq_stepper:hover ._6SOBEq_arrows,._6SOBEq_stepper:focus-within ._6SOBEq_arrows{opacity:1}._6SOBEq_arrow{background:color-mix(in srgb, var(--qilin-alias-bg-layer-1) 75%, transparent);width:17px;height:12px;color:var(--qilin-alias-label-primary);cursor:pointer;border:none;border-radius:3px;justify-content:center;align-items:center;padding:0;display:inline-flex}._6SOBEq_arrow:hover:not(:disabled){background:var(--qilin-alias-bg-layer-1)}._6SOBEq_arrow:disabled{color:var(--qilin-alias-label-caption);cursor:default}";
932
- const tagId$1 = "@qilin-agent/client-ui-theme/settings-row.module.css";
1136
+ //#region \0qilin-css:/home/runner/work/QiLin/QiLin/packages/client/ui-theme/src/client/FontSizeRow.module.css.mjs
1137
+ const css$2 = ".nKTALG_row{border-bottom:.5px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:16px 0;display:flex}.nKTALG_rowText{flex-direction:column;flex:1;gap:4px;min-width:0;padding-right:48px;display:flex}.nKTALG_title{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}.nKTALG_desc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}.nKTALG_control{align-items:center;gap:8px;display:inline-flex}.nKTALG_stepper{border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-module-platform);justify-content:center;align-items:center;min-width:72px;height:36px;display:inline-flex;position:relative}.nKTALG_value{text-align:center;font-variant-numeric:tabular-nums;min-width:18px;color:var(--dsw-alias-label-primary);font-size:14px;line-height:22px}.nKTALG_unit{color:var(--dsw-alias-label-secondary);font-size:14px;line-height:22px}.nKTALG_arrows{opacity:0;flex-direction:column;gap:2px;display:flex;position:absolute;right:8px}.nKTALG_stepper:hover .nKTALG_arrows,.nKTALG_stepper:focus-within .nKTALG_arrows{opacity:1}.nKTALG_arrow{border-radius:var(--dsw-radius-xs);background:color-mix(in srgb, var(--dsw-alias-bg-layer-1) 75%, transparent);width:17px;height:12px;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.nKTALG_arrow:hover:not(:disabled){background:var(--dsw-alias-bg-layer-1)}.nKTALG_arrow:disabled{color:var(--dsw-alias-label-caption);cursor:default}.nKTALG_expander{border-radius:var(--dsw-radius-xs);width:24px;height:24px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.nKTALG_expander:hover{background:var(--dsw-alias-interactive-bg-hover)}.nKTALG_expander svg{transition:transform var(--ds-transition-duration-fast) var(--ds-ease-in-out)}.nKTALG_expander[aria-expanded=true] svg{transform:rotate(180deg)}";
1138
+ const tagId$2 = "@qilin-agent/client-ui-theme/FontSizeRow.module.css";
1139
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
1140
+ const tag = document.createElement("style");
1141
+ tag.dataset.plugin = "@qilin-agent/client-ui-theme";
1142
+ tag.dataset.pluginCss = tagId$2;
1143
+ tag.textContent = css$2;
1144
+ document.head.appendChild(tag);
1145
+ }
1146
+ var FontSizeRow_module_css_default = {
1147
+ "arrow": "nKTALG_arrow",
1148
+ "arrows": "nKTALG_arrows",
1149
+ "control": "nKTALG_control",
1150
+ "desc": "nKTALG_desc",
1151
+ "expander": "nKTALG_expander",
1152
+ "row": "nKTALG_row",
1153
+ "rowText": "nKTALG_rowText",
1154
+ "stepper": "nKTALG_stepper",
1155
+ "title": "nKTALG_title",
1156
+ "unit": "nKTALG_unit",
1157
+ "value": "nKTALG_value"
1158
+ };
1159
+ //#endregion
1160
+ //#region \0qilin-css:/home/runner/work/QiLin/QiLin/packages/client/ui-theme/src/client/FontFamilyRow.module.css.mjs
1161
+ const css$1 = ".UWCkQq_field{flex:0 240px;min-width:0}";
1162
+ const tagId$1 = "@qilin-agent/client-ui-theme/FontFamilyRow.module.css";
933
1163
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
934
1164
  const tag = document.createElement("style");
935
1165
  tag.dataset.plugin = "@qilin-agent/client-ui-theme";
@@ -937,27 +1167,65 @@ window.__ModuleLoader__.load({
937
1167
  tag.textContent = css$1;
938
1168
  document.head.appendChild(tag);
939
1169
  }
940
- var settings_row_module_css_default = {
941
- "arrow": "_6SOBEq_arrow",
942
- "arrows": "_6SOBEq_arrows",
943
- "control": "_6SOBEq_control",
944
- "desc": "_6SOBEq_desc",
945
- "row": "_6SOBEq_row",
946
- "rowText": "_6SOBEq_rowText",
947
- "stepper": "_6SOBEq_stepper",
948
- "title": "_6SOBEq_title",
949
- "unit": "_6SOBEq_unit",
950
- "value": "_6SOBEq_value"
951
- };
1170
+ var FontFamilyRow_module_css_default = { "field": "UWCkQq_field" };
1171
+ //#endregion
1172
+ //#region lib/types/client/FontFamilyRow.js
1173
+ /**
1174
+ * Font-family preference row rendered inside the font settings group, once
1175
+ * per font role: title + role description + a text field holding the
1176
+ * comma-separated family list. Blur or Enter normalizes and commits the list;
1177
+ * an empty field restores the built-in stack. The field shows the persisted
1178
+ * list and resets whenever that list changes.
1179
+ */
1180
+ /**
1181
+ * Render one font-family row.
1182
+ * @param props - composed slot props.
1183
+ * @returns the row element tree.
1184
+ */
1185
+ function FontFamilyRow({ t, role, setFontFamily, useStore }) {
1186
+ const value = useStore((s) => s.fontFamilies[role]);
1187
+ const title = t(`fontFamily.${role}.title`);
1188
+ const commit = (input) => {
1189
+ input.value = normalizeFontFamily(input.value);
1190
+ setFontFamily(input.value);
1191
+ };
1192
+ return (0, react_jsx_runtime.jsxs)("div", {
1193
+ className: FontSizeRow_module_css_default.row,
1194
+ children: [(0, react_jsx_runtime.jsxs)("div", {
1195
+ className: FontSizeRow_module_css_default.rowText,
1196
+ children: [(0, react_jsx_runtime.jsx)("div", {
1197
+ className: FontSizeRow_module_css_default.title,
1198
+ children: title
1199
+ }), (0, react_jsx_runtime.jsx)("div", {
1200
+ className: FontSizeRow_module_css_default.desc,
1201
+ children: t(`fontFamily.${role}.description`)
1202
+ })]
1203
+ }), (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.Input, {
1204
+ className: FontFamilyRow_module_css_default.field,
1205
+ defaultValue: value,
1206
+ placeholder: t("fontFamily.placeholder"),
1207
+ "aria-label": title,
1208
+ spellCheck: false,
1209
+ autoComplete: "off",
1210
+ onBlur: (event) => {
1211
+ commit(event.currentTarget);
1212
+ },
1213
+ maxLength: 200,
1214
+ onKeyDown: (event) => {
1215
+ if (event.nativeEvent.isComposing || event.nativeEvent.keyCode === 229) return;
1216
+ if (event.key === "Enter") event.currentTarget.blur();
1217
+ }
1218
+ }, value)]
1219
+ });
1220
+ }
952
1221
  //#endregion
953
1222
  //#region lib/types/client/FontSizeRow.js
954
1223
  /**
955
- * Font-size preference row registered into the General section item slot:
956
- * title + body-text-only description + stepper pill (centered value; hover
1224
+ * Font-size preference row: title + role description + stepper pill (centered value; hover
957
1225
  * reveals the up/down arrow column anchored to the pill's right edge) + a px
958
- * unit label after the pill. Registered by this package — the theme feature
959
- * owns the content font-size setting the same way it owns the appearance
960
- * preference. The displayed value follows the persisted setting, never the
1226
+ * unit label after the pill. The text row is registered into the General
1227
+ * section item slot; the code and terminal rows render inside the font
1228
+ * settings group. The displayed value follows the persisted setting, never the
961
1229
  * click echo.
962
1230
  */
963
1231
  /**
@@ -965,74 +1233,73 @@ window.__ModuleLoader__.load({
965
1233
  * @param props - composed slot props.
966
1234
  * @returns the row element tree.
967
1235
  */
968
- function FontSizeRow({ t, setFontSize, useStore }) {
969
- const fontSize = useStore((s) => s.fontSize);
1236
+ function FontSizeRow({ t, role, setFontSize, useStore, expander }) {
1237
+ const fontSize = useStore((s) => s.fontSizes[role]);
1238
+ const { min, max } = FONT_SIZE_SPECS[role];
970
1239
  return (0, react_jsx_runtime.jsxs)("div", {
971
- className: settings_row_module_css_default.row,
1240
+ className: FontSizeRow_module_css_default.row,
972
1241
  children: [(0, react_jsx_runtime.jsxs)("div", {
973
- className: settings_row_module_css_default.rowText,
1242
+ className: FontSizeRow_module_css_default.rowText,
974
1243
  children: [(0, react_jsx_runtime.jsx)("div", {
975
- className: settings_row_module_css_default.title,
976
- children: t("fontSize.title")
1244
+ className: FontSizeRow_module_css_default.title,
1245
+ children: t(`fontSize.${role}.title`)
977
1246
  }), (0, react_jsx_runtime.jsx)("div", {
978
- className: settings_row_module_css_default.desc,
979
- children: t("fontSize.description")
1247
+ className: FontSizeRow_module_css_default.desc,
1248
+ children: t(`fontSize.${role}.description`)
980
1249
  })]
981
1250
  }), (0, react_jsx_runtime.jsxs)("div", {
982
- className: settings_row_module_css_default.control,
983
- children: [(0, react_jsx_runtime.jsxs)("div", {
984
- className: settings_row_module_css_default.stepper,
985
- children: [(0, react_jsx_runtime.jsx)("span", {
986
- className: settings_row_module_css_default.value,
987
- children: fontSize
988
- }), (0, react_jsx_runtime.jsxs)("span", {
989
- className: settings_row_module_css_default.arrows,
990
- children: [(0, react_jsx_runtime.jsx)("button", {
991
- type: "button",
992
- className: settings_row_module_css_default.arrow,
993
- "aria-label": t("fontSize.increase"),
994
- disabled: fontSize >= 22,
995
- onClick: () => {
996
- setFontSize(fontSize + 1);
997
- },
998
- children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconChevronUpOutline14, { size: 9 })
999
- }), (0, react_jsx_runtime.jsx)("button", {
1000
- type: "button",
1001
- className: settings_row_module_css_default.arrow,
1002
- "aria-label": t("fontSize.decrease"),
1003
- disabled: fontSize <= 10,
1004
- onClick: () => {
1005
- setFontSize(fontSize - 1);
1006
- },
1007
- children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconChevronDownOutline14, { size: 9 })
1251
+ className: FontSizeRow_module_css_default.control,
1252
+ children: [
1253
+ (0, react_jsx_runtime.jsxs)("div", {
1254
+ className: FontSizeRow_module_css_default.stepper,
1255
+ children: [(0, react_jsx_runtime.jsx)("span", {
1256
+ className: FontSizeRow_module_css_default.value,
1257
+ children: fontSize
1258
+ }), (0, react_jsx_runtime.jsxs)("span", {
1259
+ className: FontSizeRow_module_css_default.arrows,
1260
+ children: [(0, react_jsx_runtime.jsx)("button", {
1261
+ type: "button",
1262
+ className: FontSizeRow_module_css_default.arrow,
1263
+ "aria-label": t(`fontSize.${role}.increase`),
1264
+ disabled: fontSize >= max,
1265
+ onClick: () => {
1266
+ setFontSize(fontSize + 1);
1267
+ },
1268
+ children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconChevronUpOutline14, { size: 9 })
1269
+ }), (0, react_jsx_runtime.jsx)("button", {
1270
+ type: "button",
1271
+ className: FontSizeRow_module_css_default.arrow,
1272
+ "aria-label": t(`fontSize.${role}.decrease`),
1273
+ disabled: fontSize <= min,
1274
+ onClick: () => {
1275
+ setFontSize(fontSize - 1);
1276
+ },
1277
+ children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconChevronDownOutline14, { size: 9 })
1278
+ })]
1008
1279
  })]
1009
- })]
1010
- }), (0, react_jsx_runtime.jsx)("span", {
1011
- className: settings_row_module_css_default.unit,
1012
- children: t("fontSize.unit")
1013
- })]
1280
+ }),
1281
+ (0, react_jsx_runtime.jsx)("span", {
1282
+ className: FontSizeRow_module_css_default.unit,
1283
+ children: t("fontSize.unit")
1284
+ }),
1285
+ expander !== void 0 && (0, react_jsx_runtime.jsx)("button", {
1286
+ type: "button",
1287
+ className: FontSizeRow_module_css_default.expander,
1288
+ "aria-label": t("fontSize.more"),
1289
+ title: t("fontSize.more"),
1290
+ "aria-expanded": expander.open,
1291
+ "aria-controls": expander.controls,
1292
+ onClick: expander.onToggle,
1293
+ children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconChevronDownOutline14, { size: 12 })
1294
+ })
1295
+ ]
1014
1296
  })]
1015
1297
  });
1016
1298
  }
1017
1299
  //#endregion
1018
- //#region ../../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs
1019
- function r(e) {
1020
- var t, f, n = "";
1021
- if ("string" == typeof e || "number" == typeof e) n += e;
1022
- else if ("object" == typeof e) if (Array.isArray(e)) {
1023
- var o = e.length;
1024
- for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
1025
- } else for (f in e) e[f] && (n && (n += " "), n += f);
1026
- return n;
1027
- }
1028
- function clsx() {
1029
- for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
1030
- return n;
1031
- }
1032
- //#endregion
1033
- //#region \0qilin-css:/home/runner/work/QiLin/QiLin/packages/client/ui-theme/src/client/AppearanceRow.module.css.mjs
1034
- const css = ".BphuTq_group{border-bottom:.5px solid var(--qilin-alias-border-l2);flex-direction:column;gap:8px;padding:16px 0;display:flex}.BphuTq_title{color:var(--qilin-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}.BphuTq_cubeRow{flex-wrap:wrap;align-items:stretch;gap:8px;display:flex}.BphuTq_themeCube{box-sizing:border-box;border:.5px solid var(--qilin-alias-border-l4);border-radius:var(--qilin-radius-xl);font:inherit;color:var(--qilin-alias-label-primary);cursor:pointer;background:0 0;flex-direction:column;flex:180px;justify-content:center;align-items:center;gap:4px;padding:20px 32px;font-size:14px;line-height:22px;display:flex}.BphuTq_themeCube:hover:not(.BphuTq_selected){background:var(--qilin-alias-interactive-bg-hover)}.BphuTq_selected{background:var(--qilin-alias-bg-module-platform);border-color:var(--qilin-static-neutral-bluish-400)}";
1035
- const tagId = "@qilin-agent/client-ui-theme/AppearanceRow.module.css";
1300
+ //#region \0qilin-css:/home/runner/work/QiLin/QiLin/packages/client/ui-theme/src/client/FontSettingsGroup.module.css.mjs
1301
+ const css = "._1IoJOW_group:last-child>:last-child,._1IoJOW_group:last-child>:last-child>:last-child{border-bottom:0}";
1302
+ const tagId = "@qilin-agent/client-ui-theme/FontSettingsGroup.module.css";
1036
1303
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
1037
1304
  const tag = document.createElement("style");
1038
1305
  tag.dataset.plugin = "@qilin-agent/client-ui-theme";
@@ -1040,72 +1307,64 @@ window.__ModuleLoader__.load({
1040
1307
  tag.textContent = css;
1041
1308
  document.head.appendChild(tag);
1042
1309
  }
1043
- var AppearanceRow_module_css_default = {
1044
- "cubeRow": "BphuTq_cubeRow",
1045
- "group": "BphuTq_group",
1046
- "selected": "BphuTq_selected",
1047
- "themeCube": "BphuTq_themeCube",
1048
- "title": "BphuTq_title"
1049
- };
1310
+ var FontSettingsGroup_module_css_default = { "group": "_1IoJOW_group" };
1050
1311
  //#endregion
1051
- //#region lib/types/client/AppearanceRow.js
1312
+ //#region lib/types/client/FontSettingsGroup.js
1052
1313
  /**
1053
- * Appearance preference row registered into the General section item slot
1054
- * (figma 501:30012 'Frame 2117131228'): title + three preference cubes.
1055
- * Registered by this package — the theme feature owns its own settings
1056
- * surface. Selection follows the persisted preference, never the resolved
1057
- * active theme.
1314
+ * Font settings registered into the General section item slot: the text
1315
+ * font-size row, whose disclosure button expands a region holding the font
1316
+ * row for each role and the code and terminal size rows. The region starts
1317
+ * collapsed on every mount.
1058
1318
  */
1059
- /** Cube order and icons (figma 501:30015-30017: Light, Dark, System). */
1060
- const CUBES = [
1061
- {
1062
- id: "light",
1063
- labelKey: "appearance.light",
1064
- Icon: _qilin_agent_client_ui_primitives.IconLightOutline16
1065
- },
1066
- {
1067
- id: "dark",
1068
- labelKey: "appearance.dark",
1069
- Icon: _qilin_agent_client_ui_primitives.IconDarkOutline16
1070
- },
1071
- {
1072
- id: "system",
1073
- labelKey: "appearance.system",
1074
- Icon: _qilin_agent_client_ui_primitives.IconFollowsystemOutline16
1075
- }
1076
- ];
1077
1319
  /**
1078
- * Render the Appearance row.
1320
+ * Render the text font-size row and its expandable font settings.
1079
1321
  * @param props - composed slot props.
1080
- * @returns the row element tree.
1322
+ * @returns the text size row and, when expanded, the font rows.
1081
1323
  */
1082
- function AppearanceRow({ t, setTheme, useStore }) {
1083
- const preference = useStore((s) => s.preference);
1324
+ function FontSettingsGroup({ setFontFamily, setFontSize, ...shared }) {
1325
+ const [open, setOpen] = (0, react.useState)(false);
1326
+ const regionId = (0, react.useId)();
1327
+ const family = (role) => (0, react_jsx_runtime.jsx)(FontFamilyRow, {
1328
+ ...shared,
1329
+ role,
1330
+ setFontFamily: (value) => {
1331
+ setFontFamily(role, value);
1332
+ }
1333
+ });
1334
+ const size = (role, expander) => (0, react_jsx_runtime.jsx)(FontSizeRow, {
1335
+ ...shared,
1336
+ role,
1337
+ expander,
1338
+ setFontSize: (px) => {
1339
+ setFontSize(role, px);
1340
+ }
1341
+ });
1084
1342
  return (0, react_jsx_runtime.jsxs)("div", {
1085
- className: AppearanceRow_module_css_default.group,
1086
- children: [(0, react_jsx_runtime.jsx)("div", {
1087
- className: AppearanceRow_module_css_default.title,
1088
- children: t("appearance.title")
1089
- }), (0, react_jsx_runtime.jsx)("div", {
1090
- className: AppearanceRow_module_css_default.cubeRow,
1091
- children: CUBES.map(({ id, labelKey, Icon }) => (0, react_jsx_runtime.jsxs)("button", {
1092
- type: "button",
1093
- className: clsx(AppearanceRow_module_css_default.themeCube, preference === id && AppearanceRow_module_css_default.selected),
1094
- "aria-pressed": preference === id,
1095
- onClick: () => {
1096
- setTheme(id);
1097
- },
1098
- children: [(0, react_jsx_runtime.jsx)(Icon, {}), t(labelKey)]
1099
- }, id))
1343
+ className: FontSettingsGroup_module_css_default.group,
1344
+ children: [size("text", {
1345
+ open,
1346
+ controls: regionId,
1347
+ onToggle: () => {
1348
+ setOpen((value) => !value);
1349
+ }
1350
+ }), open && (0, react_jsx_runtime.jsxs)("div", {
1351
+ id: regionId,
1352
+ children: [
1353
+ family("text"),
1354
+ family("code"),
1355
+ size("code"),
1356
+ family("terminal"),
1357
+ size("terminal")
1358
+ ]
1100
1359
  })]
1101
1360
  });
1102
1361
  }
1103
1362
  //#endregion
1104
1363
  //#region lib/types/client/settings-store.js
1105
1364
  /**
1106
- * Appearance and typography settings-row slot stores: mirrors of the theme
1107
- * service snapshot. The plugin's apply-world change listener is the only
1108
- * writer; the rows read their fields via props.useStore.
1365
+ * Appearance and font row slot stores: mirrors of the theme service
1366
+ * snapshot. The plugin's apply-world change listener is the only writer; the
1367
+ * row components read via props.useStore.
1109
1368
  */
1110
1369
  /**
1111
1370
  * Declares the Appearance row state and write surface.
@@ -1114,7 +1373,7 @@ window.__ModuleLoader__.load({
1114
1373
  function createAppearanceRowStore() {
1115
1374
  return (0, _qilin_agent_client_store.defineStore)({
1116
1375
  init: () => ({
1117
- preference: DEFAULT_PREFERENCE,
1376
+ preference: "system",
1118
1377
  revision: -1
1119
1378
  }),
1120
1379
  actions: { sync: (d, preference, revision) => {
@@ -1125,25 +1384,81 @@ window.__ModuleLoader__.load({
1125
1384
  });
1126
1385
  }
1127
1386
  /**
1128
- * Declares the shared typography-row state and write surface.
1387
+ * Declares the font rows' state and write surface.
1129
1388
  * @returns the store handle.
1130
1389
  */
1131
- function createTypographyRowStore() {
1390
+ function createFontRowStore() {
1132
1391
  return (0, _qilin_agent_client_store.defineStore)({
1133
1392
  init: () => ({
1134
- fontSize: 14,
1393
+ fontSizes: DEFAULT_FONT_SIZES,
1394
+ fontFamilies: {
1395
+ text: "",
1396
+ code: "",
1397
+ terminal: ""
1398
+ },
1135
1399
  revision: -1
1136
1400
  }),
1137
- actions: { sync: (d, fontSize, revision) => {
1401
+ actions: { sync: (d, fontSizes, fontFamilies, revision) => {
1138
1402
  if (revision <= d.revision) return;
1139
- d.fontSize = fontSize;
1403
+ d.fontSizes = fontSizes;
1404
+ d.fontFamilies = fontFamilies;
1140
1405
  d.revision = revision;
1141
1406
  } }
1142
1407
  });
1143
1408
  }
1144
1409
  //#endregion
1410
+ //#region lib/types/client/font-size-shortcuts.js
1411
+ /** Desktop keyboard shortcuts that step all three font sizes together. */
1412
+ /**
1413
+ * Register the desktop font-size keys and consume their gestures.
1414
+ * The web client keeps the browser's own zoom for these keys, so the
1415
+ * registration exists only where the keyboard service reports the desktop
1416
+ * runtime.
1417
+ * @param ctx - client cordis context owning the registration effects.
1418
+ * @param namespace - locale namespace carrying the shortcut labels (this package's own).
1419
+ * @param adjust - applies one +1 or -1 px step to every font-size role.
1420
+ */
1421
+ function installFontSizeShortcuts(ctx, namespace, adjust) {
1422
+ ctx.inject(["shortcuts", "locale"], (scope) => {
1423
+ if (scope.shortcuts.runtime !== "desktop") return;
1424
+ const t = scope.locale.bind(namespace);
1425
+ for (const [direction, code, label] of [[
1426
+ "increase",
1427
+ "Equal",
1428
+ "fontSize.text.increase"
1429
+ ], [
1430
+ "decrease",
1431
+ "Minus",
1432
+ "fontSize.text.decrease"
1433
+ ]]) {
1434
+ const binding = {
1435
+ code,
1436
+ modifiers: ["primary"]
1437
+ };
1438
+ const bindings = direction === "increase" ? [binding, {
1439
+ code,
1440
+ modifiers: ["primary", "shift"]
1441
+ }] : [binding];
1442
+ scope.effect(() => scope.shortcuts.registerFixed({
1443
+ id: `fontSize.${direction}`,
1444
+ label: () => t(label),
1445
+ keys: scope.shortcuts.describeBinding(binding).keys,
1446
+ bindings,
1447
+ group: "application"
1448
+ }), `ui-theme: ${direction} font size reference`);
1449
+ }
1450
+ scope.effect(() => scope.shortcuts.observeFixedInput((input) => {
1451
+ if (input.type === "reset") return;
1452
+ const { gesture, context } = input;
1453
+ if (gesture.composing || gesture.defaultPrevented || gesture.repeat || context.region === "terminal" || gesture.alt || (scope.shortcuts.platform === "macos" ? !gesture.meta || gesture.control : !gesture.control || gesture.meta) || gesture.code !== "Equal" && gesture.code !== "Minus" || gesture.code === "Minus" && gesture.shift) return;
1454
+ input.consume();
1455
+ adjust(gesture.code === "Equal" ? 1 : -1);
1456
+ }), "ui-theme: font size input");
1457
+ });
1458
+ }
1459
+ //#endregion
1145
1460
  //#region \0qilin-inline-css:/home/runner/work/QiLin/QiLin/packages/client/ui-theme/src/styles/base.css.mjs
1146
- var base_css_default = ":root{--qilin-font-family:-apple-system, BlinkMacSystemFont, \"Segoe UI\", \"PingFang SC\", \"Hiragino Sans GB\", \"Microsoft YaHei\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;--ds-font-family-code:\"SF Mono\", \"JetBrains Mono\", \"Fira Code\", Consolas, \"Liberation Mono\", Menlo, Courier, \"PingFang SC\", \"Microsoft YaHei\";--ds-ease-in-out:cubic-bezier(.4, 0, .2, 1);--ds-transition-duration:.2s;--ds-transition-duration-fast:.1s;--ds-transition-duration-slow:.3s;--qilin-radius-xs:4px;--qilin-radius-sm:8px;--qilin-radius-md:12px;--qilin-radius-lg:16px;--qilin-radius-xl:20px;--qilin-radius-panel:28px}[data-dsh-automatic-focus]:focus,[data-dsh-automatic-focus]:focus:focus-visible{outline:none}";
1461
+ var base_css_default = ":root{--qilin-font-family-text-default:-apple-system, BlinkMacSystemFont, \"Segoe UI\", \"PingFang SC\", \"Hiragino Sans GB\", \"Microsoft YaHei\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;--qilin-font-family:var(--qilin-font-family-text,var(--qilin-font-family-text-default)), var(--qilin-font-family-text-default);--qilin-font-family-code-default:\"SF Mono\", \"JetBrains Mono\", \"Fira Code\", Consolas, \"Liberation Mono\", Menlo, Courier, \"PingFang SC\", \"Microsoft YaHei\";--ds-font-family-code:var(--qilin-font-family-code,var(--qilin-font-family-code-default)), var(--qilin-font-family-code-default);--ds-ease-in-out:cubic-bezier(.4, 0, .2, 1);--ds-transition-duration:.2s;--ds-transition-duration-fast:.1s;--ds-transition-duration-slow:.3s;--qilin-radius-xs:4px;--qilin-radius-sm:8px;--qilin-radius-md:12px;--qilin-radius-lg:16px;--qilin-radius-xl:20px;--qilin-radius-panel:28px}[data-dsh-automatic-focus]:focus,[data-dsh-automatic-focus]:focus:focus-visible{outline:none}";
1147
1462
  //#endregion
1148
1463
  //#region \0qilin-inline-css:/home/runner/work/QiLin/QiLin/packages/client/ui-theme/src/styles/corner-shape.css.mjs
1149
1464
  var corner_shape_css_default = "@supports (corner-shape:superellipse(1.5)){:root{--qilin-corner-shape:superellipse(1.5)}*,:before,:after{corner-shape:var(--qilin-corner-shape)}}";
@@ -1161,7 +1476,7 @@ window.__ModuleLoader__.load({
1161
1476
  var scrollbar_css_default = "body{--qilin-scrollbar-thumb:var(--qilin-alias-scrollbar-bg-l1);--qilin-scrollbar-thumb-hover:var(--qilin-alias-scrollbar-hover-l1);--qilin-scrollbar-thumb-border:0px;--qilin-scrollbar-track-margin:0px;--qilin-scrollbar-width:8px}@supports not selector(::-webkit-scrollbar){body,body *{scrollbar-width:thin;scrollbar-color:var(--qilin-scrollbar-thumb) transparent}}::-webkit-scrollbar{width:var(--qilin-scrollbar-width);height:var(--qilin-scrollbar-width)}::-webkit-scrollbar-track{margin-block:var(--qilin-scrollbar-track-margin);background:0 0}::-webkit-scrollbar-thumb{border:var(--qilin-scrollbar-thumb-border) solid transparent;corner-shape:round;background:var(--qilin-scrollbar-thumb);background-clip:content-box;border-radius:999px}::-webkit-scrollbar-thumb:hover{background-color:var(--qilin-scrollbar-thumb-hover)}::-webkit-scrollbar-corner{background:0 0}";
1162
1477
  //#endregion
1163
1478
  //#region \0qilin-inline-css:/home/runner/work/QiLin/QiLin/packages/client/ui-theme/src/styles/gradient-shadow-text.css.mjs
1164
- var gradient_shadow_text_css_default = "body{--qilin-linear-gradient-think:linear-gradient(180deg, #fff 20.19%, #fff0 100%);--qilin-linear-think-select:linear-gradient(180deg, #f5f6f7 20.19%, #f5f6f700 100%);--qilin-shadow-lv1:0 2px 4px 0 #0000000d;--qilin-shadow-lv1-blur:0 4px 12px 0 #00000005;--qilin-shadow-lv2:0 4px 12px 0 #00000005, 0 2px 8px 0 #0000000a;--qilin-shadow-lv3:0 0 1px 0 #0003, 0 0 4px 0 #00000005, 0 12px 32px 0 #00000014;--qilin-elevation-stroke-color:var(--qilin-alias-border-l4);--qilin-mask-blur:blur(2px)}body,body *{--qilin-elevation-stroke:0 0 0 .5px var(--qilin-elevation-stroke-color);--qilin-elevation-panel:var(--qilin-elevation-stroke), 0 3px 8px 0 #00000008, 0 0 16px 0 #00000005;--qilin-elevation-prominent:var(--qilin-elevation-stroke), 0 3px 8px 0 #0000000a, 0 0 20px 0 #0000000d;--qilin-elevation-soft:var(--qilin-elevation-stroke), 0 4px 16px 0 #00000008, 0 0 24px 0 #00000008}body[data-ds-dark-theme]{--qilin-linear-gradient-think:linear-gradient(180deg, #151517 20.19%, #15151700 100%);--qilin-linear-think-select:linear-gradient(180deg, #232325 20.19%, #23232500 100%)}body{--qilin-content-font-delta:calc(var(--qilin-content-font-size,14px) - 14px);--qilin-content-font-size-secondary:min(calc(var(--qilin-content-font-size,14px) - 1px), max(13px, calc(var(--qilin-content-font-size,14px) - 2px)));--qilin-content-font-delta-secondary:calc(var(--qilin-content-font-size-secondary) - 13px);--qilin-font-markdown-h1:700 calc(21px + var(--qilin-content-font-delta)) / calc(30px + var(--qilin-content-font-delta)) var(--qilin-font-family);--qilin-font-markdown-h1-font-family:var(--qilin-font-family);--qilin-font-markdown-h1-font-weight:700;--qilin-font-markdown-h1-line-height:calc(30px + var(--qilin-content-font-delta));--qilin-font-markdown-h1-font-size:calc(21px + var(--qilin-content-font-delta));--qilin-font-markdown-h1-font-style:normal;--qilin-font-markdown-h2:700 calc(19px + var(--qilin-content-font-delta)) / calc(28px + var(--qilin-content-font-delta)) var(--qilin-font-family);--qilin-font-markdown-h2-font-family:var(--qilin-font-family);--qilin-font-markdown-h2-font-weight:700;--qilin-font-markdown-h2-line-height:calc(28px + var(--qilin-content-font-delta));--qilin-font-markdown-h2-font-size:calc(19px + var(--qilin-content-font-delta));--qilin-font-markdown-h2-font-style:normal;--qilin-font-markdown-h3:700 calc(18px + var(--qilin-content-font-delta)) / calc(26px + var(--qilin-content-font-delta)) var(--qilin-font-family);--qilin-font-markdown-h3-font-family:var(--qilin-font-family);--qilin-font-markdown-h3-font-weight:700;--qilin-font-markdown-h3-line-height:calc(26px + var(--qilin-content-font-delta));--qilin-font-markdown-h3-font-size:calc(18px + var(--qilin-content-font-delta));--qilin-font-markdown-h3-font-style:normal;--qilin-font-markdown-h4:600 var(--qilin-content-font-size,14px) / calc(24px + var(--qilin-content-font-delta)) var(--qilin-font-family);--qilin-font-markdown-h4-font-family:var(--qilin-font-family);--qilin-font-markdown-h4-font-weight:600;--qilin-font-markdown-h4-line-height:calc(24px + var(--qilin-content-font-delta));--qilin-font-markdown-h4-font-size:var(--qilin-content-font-size,14px);--qilin-font-markdown-h4-font-style:normal;--qilin-font-markdown-base:var(--qilin-content-font-size,14px) / calc(24px + var(--qilin-content-font-delta)) var(--qilin-font-family);--qilin-font-markdown-base-font-family:var(--qilin-font-family);--qilin-font-markdown-base-font-weight:400;--qilin-font-markdown-base-line-height:calc(24px + var(--qilin-content-font-delta));--qilin-font-markdown-base-font-size:var(--qilin-content-font-size,14px);--qilin-font-markdown-base-font-style:normal;--qilin-font-markdown-base-strong:600 var(--qilin-content-font-size,14px) / calc(24px + var(--qilin-content-font-delta)) var(--qilin-font-family);--qilin-font-markdown-base-strong-font-family:var(--qilin-font-family);--qilin-font-markdown-base-strong-font-weight:600;--qilin-font-markdown-base-strong-line-height:calc(24px + var(--qilin-content-font-delta));--qilin-font-markdown-base-strong-font-size:var(--qilin-content-font-size,14px);--qilin-font-markdown-base-strong-font-style:normal;--qilin-font-markdown-base-italic:italic var(--qilin-content-font-size,14px) / calc(24px + var(--qilin-content-font-delta)) var(--qilin-font-family);--qilin-font-markdown-base-italic-font-family:var(--qilin-font-family);--qilin-font-markdown-base-italic-font-weight:400;--qilin-font-markdown-base-italic-line-height:calc(24px + var(--qilin-content-font-delta));--qilin-font-markdown-base-italic-font-size:var(--qilin-content-font-size,14px);--qilin-font-markdown-base-italic-font-style:italic;--qilin-font-markdown-base-strong-italic:italic 600 var(--qilin-content-font-size,14px) / calc(24px + var(--qilin-content-font-delta)) var(--qilin-font-family);--qilin-font-markdown-base-strong-italic-font-family:var(--qilin-font-family);--qilin-font-markdown-base-strong-italic-font-weight:600;--qilin-font-markdown-base-strong-italic-line-height:calc(24px + var(--qilin-content-font-delta));--qilin-font-markdown-base-strong-italic-font-size:var(--qilin-content-font-size,14px);--qilin-font-markdown-base-strong-italic-font-style:italic;--qilin-font-markdown-table:var(--qilin-content-font-size-secondary,13px)/calc(22px + var(--qilin-content-font-delta-secondary,0px)) var(--qilin-font-family);--qilin-font-markdown-table-font-family:var(--qilin-font-family);--qilin-font-markdown-table-font-weight:400;--qilin-font-markdown-table-line-height:calc(22px + var(--qilin-content-font-delta-secondary,0px));--qilin-font-markdown-table-font-size:var(--qilin-content-font-size-secondary,13px);--qilin-font-markdown-table-font-style:normal;--qilin-font-markdown-table-head:500 var(--qilin-content-font-size-secondary,13px)/calc(22px + var(--qilin-content-font-delta-secondary,0px)) var(--qilin-font-family);--qilin-font-markdown-table-head-font-family:var(--qilin-font-family);--qilin-font-markdown-table-head-font-weight:500;--qilin-font-markdown-table-head-line-height:calc(22px + var(--qilin-content-font-delta-secondary,0px));--qilin-font-markdown-table-head-font-size:var(--qilin-content-font-size-secondary,13px);--qilin-font-markdown-table-head-font-style:normal;--qilin-font-markdown-small:12px/20px var(--qilin-font-family);--qilin-font-markdown-small-font-family:var(--qilin-font-family);--qilin-font-markdown-small-font-weight:400;--qilin-font-markdown-small-line-height:20px;--qilin-font-markdown-small-font-size:12px;--qilin-font-markdown-small-font-style:normal;--qilin-font-markdown-small-strong:600 12px/20px var(--qilin-font-family);--qilin-font-markdown-small-strong-font-family:var(--qilin-font-family);--qilin-font-markdown-small-strong-font-weight:600;--qilin-font-markdown-small-strong-line-height:20px;--qilin-font-markdown-small-strong-font-size:12px;--qilin-font-markdown-small-strong-font-style:normal;--qilin-font-markdown-small-italic:italic 12px/20px var(--qilin-font-family);--qilin-font-markdown-small-italic-font-family:var(--qilin-font-family);--qilin-font-markdown-small-italic-font-weight:400;--qilin-font-markdown-small-italic-line-height:20px;--qilin-font-markdown-small-italic-font-size:12px;--qilin-font-markdown-small-italic-font-style:italic;--qilin-font-markdown-small-strong-italic:italic 600 12px/20px var(--qilin-font-family);--qilin-font-markdown-small-strong-italic-font-family:var(--qilin-font-family);--qilin-font-markdown-small-strong-italic-font-weight:600;--qilin-font-markdown-small-strong-italic-line-height:20px;--qilin-font-markdown-small-strong-italic-font-size:12px;--qilin-font-markdown-small-strong-italic-font-style:italic;--qilin-font-markdown-code:12px/19px var(--ds-font-family-code);--qilin-font-markdown-code-font-family:var(--ds-font-family-code);--qilin-font-markdown-code-font-weight:400;--qilin-font-markdown-code-line-height:19px;--qilin-font-markdown-code-font-size:12px;--qilin-font-markdown-code-font-style:normal;--qilin-font-markdown-code-block:11px/19px var(--ds-font-family-code);--qilin-font-markdown-code-block-font-family:var(--ds-font-family-code);--qilin-font-markdown-code-block-font-weight:400;--qilin-font-markdown-code-block-line-height:19px;--qilin-font-markdown-code-block-font-size:11px;--qilin-font-markdown-code-block-font-style:normal;--qilin-font-markdown-code-block-small:11px/16px var(--ds-font-family-code);--qilin-font-markdown-code-block-small-font-family:var(--ds-font-family-code);--qilin-font-markdown-code-block-small-font-weight:400;--qilin-font-markdown-code-block-small-line-height:16px;--qilin-font-markdown-code-block-small-font-size:11px;--qilin-font-markdown-code-block-small-font-style:normal;--qilin-font-xl-24:600 24px/32px var(--qilin-font-family);--qilin-font-xl-24-font-family:var(--qilin-font-family);--qilin-font-xl-24-font-weight:600;--qilin-font-xl-24-line-height:32px;--qilin-font-xl-24-font-size:24px;--qilin-font-xl-24-font-style:normal;--qilin-font-l-20:500 20px/28px var(--qilin-font-family);--qilin-font-l-20-font-family:var(--qilin-font-family);--qilin-font-l-20-font-weight:500;--qilin-font-l-20-line-height:28px;--qilin-font-l-20-font-size:20px;--qilin-font-l-20-font-style:normal;--qilin-font-m-18:500 16px/28px var(--qilin-font-family);--qilin-font-m-18-font-family:var(--qilin-font-family);--qilin-font-m-18-font-weight:500;--qilin-font-m-18-line-height:28px;--qilin-font-m-18-font-size:16px;--qilin-font-m-18-font-style:normal;--qilin-font-base-16:16px/24px var(--qilin-font-family);--qilin-font-base-16-font-family:var(--qilin-font-family);--qilin-font-base-16-font-weight:400;--qilin-font-base-16-line-height:24px;--qilin-font-base-16-font-size:16px;--qilin-font-base-16-font-style:normal;--qilin-font-base-strong-16:500 16px/24px var(--qilin-font-family);--qilin-font-base-strong-16-font-family:var(--qilin-font-family);--qilin-font-base-strong-16-font-weight:500;--qilin-font-base-strong-16-line-height:24px;--qilin-font-base-strong-16-font-size:16px;--qilin-font-base-strong-16-font-style:normal;--qilin-font-s-14:14px/22px var(--qilin-font-family);--qilin-font-s-14-font-family:var(--qilin-font-family);--qilin-font-s-14-font-weight:400;--qilin-font-s-14-line-height:22px;--qilin-font-s-14-font-size:14px;--qilin-font-s-14-font-style:normal;--qilin-font-s-strong-14:500 14px/22px var(--qilin-font-family);--qilin-font-s-strong-14-font-family:var(--qilin-font-family);--qilin-font-s-strong-14-font-weight:500;--qilin-font-s-strong-14-line-height:22px;--qilin-font-s-strong-14-font-size:14px;--qilin-font-s-strong-14-font-style:normal;--qilin-font-xs-13:13px/20px var(--qilin-font-family);--qilin-font-xs-13-font-family:var(--qilin-font-family);--qilin-font-xs-13-font-weight:400;--qilin-font-xs-13-line-height:20px;--qilin-font-xs-13-font-size:13px;--qilin-font-xs-13-font-style:normal;--qilin-font-xs-strong-13:500 13px/20px var(--qilin-font-family);--qilin-font-xs-strong-13-font-family:var(--qilin-font-family);--qilin-font-xs-strong-13-font-weight:500;--qilin-font-xs-strong-13-line-height:20px;--qilin-font-xs-strong-13-font-size:13px;--qilin-font-xs-strong-13-font-style:normal;--qilin-font-xxs-12:12px/18px var(--qilin-font-family);--qilin-font-xxs-12-font-family:var(--qilin-font-family);--qilin-font-xxs-12-font-weight:400;--qilin-font-xxs-12-line-height:18px;--qilin-font-xxs-12-font-size:12px;--qilin-font-xxs-12-font-style:normal;--qilin-font-xxs-strong-12:500 12px/18px var(--qilin-font-family);--qilin-font-xxs-strong-12-font-family:var(--qilin-font-family);--qilin-font-xxs-strong-12-font-weight:500;--qilin-font-xxs-strong-12-line-height:18px;--qilin-font-xxs-strong-12-font-size:12px;--qilin-font-xxs-strong-12-font-style:normal;--qilin-font-xxxs-11:11px/14px var(--qilin-font-family);--qilin-font-xxxs-11-font-family:var(--qilin-font-family);--qilin-font-xxxs-11-font-weight:400;--qilin-font-xxxs-11-line-height:14px;--qilin-font-xxxs-11-font-size:11px;--qilin-font-xxxs-11-font-style:normal;--qilin-font-xxxs-strong-11:500 11px/14px var(--qilin-font-family);--qilin-font-xxxs-strong-11-font-family:var(--qilin-font-family);--qilin-font-xxxs-strong-11-font-weight:500;--qilin-font-xxxs-strong-11-line-height:14px;--qilin-font-xxxs-strong-11-font-size:11px;--qilin-font-xxxs-strong-11-font-style:normal}";
1479
+ var gradient_shadow_text_css_default = "body{--qilin-linear-gradient-think:linear-gradient(180deg, #fff 20.19%, #fff0 100%);--qilin-linear-think-select:linear-gradient(180deg, #f5f6f7 20.19%, #f5f6f700 100%);--qilin-shadow-lv1:0 2px 4px 0 #0000000d;--qilin-shadow-lv1-blur:0 4px 12px 0 #00000005;--qilin-shadow-lv2:0 4px 12px 0 #00000005, 0 2px 8px 0 #0000000a;--qilin-shadow-lv3:0 0 1px 0 #0003, 0 0 4px 0 #00000005, 0 12px 32px 0 #00000014;--qilin-elevation-stroke-color:var(--qilin-alias-border-l4);--qilin-mask-blur:blur(2px)}body,body *{--qilin-elevation-stroke:0 0 0 .5px var(--qilin-elevation-stroke-color);--qilin-elevation-panel:var(--qilin-elevation-stroke), 0 3px 8px 0 #00000008, 0 0 16px 0 #00000005;--qilin-elevation-prominent:var(--qilin-elevation-stroke), 0 3px 8px 0 #0000000a, 0 0 20px 0 #0000000d;--qilin-elevation-soft:var(--qilin-elevation-stroke), 0 4px 16px 0 #00000008, 0 0 24px 0 #00000008}body[data-ds-dark-theme]{--qilin-linear-gradient-think:linear-gradient(180deg, #151517 20.19%, #15151700 100%);--qilin-linear-think-select:linear-gradient(180deg, #232325 20.19%, #23232500 100%)}body{--qilin-content-font-delta:calc(var(--qilin-content-font-size,14px) - 14px);--qilin-content-font-size-secondary:min(calc(var(--qilin-content-font-size,14px) - 1px), max(13px, calc(var(--qilin-content-font-size,14px) - 2px)));--qilin-content-font-delta-secondary:calc(var(--qilin-content-font-size-secondary) - 13px);--qilin-font-markdown-h1:700 calc(21px + var(--qilin-content-font-delta)) / calc(30px + var(--qilin-content-font-delta)) var(--qilin-font-family);--qilin-font-markdown-h1-font-family:var(--qilin-font-family);--qilin-font-markdown-h1-font-weight:700;--qilin-font-markdown-h1-line-height:calc(30px + var(--qilin-content-font-delta));--qilin-font-markdown-h1-font-size:calc(21px + var(--qilin-content-font-delta));--qilin-font-markdown-h1-font-style:normal;--qilin-font-markdown-h2:700 calc(19px + var(--qilin-content-font-delta)) / calc(28px + var(--qilin-content-font-delta)) var(--qilin-font-family);--qilin-font-markdown-h2-font-family:var(--qilin-font-family);--qilin-font-markdown-h2-font-weight:700;--qilin-font-markdown-h2-line-height:calc(28px + var(--qilin-content-font-delta));--qilin-font-markdown-h2-font-size:calc(19px + var(--qilin-content-font-delta));--qilin-font-markdown-h2-font-style:normal;--qilin-font-markdown-h3:700 calc(18px + var(--qilin-content-font-delta)) / calc(26px + var(--qilin-content-font-delta)) var(--qilin-font-family);--qilin-font-markdown-h3-font-family:var(--qilin-font-family);--qilin-font-markdown-h3-font-weight:700;--qilin-font-markdown-h3-line-height:calc(26px + var(--qilin-content-font-delta));--qilin-font-markdown-h3-font-size:calc(18px + var(--qilin-content-font-delta));--qilin-font-markdown-h3-font-style:normal;--qilin-font-markdown-h4:600 var(--qilin-content-font-size,14px) / calc(24px + var(--qilin-content-font-delta)) var(--qilin-font-family);--qilin-font-markdown-h4-font-family:var(--qilin-font-family);--qilin-font-markdown-h4-font-weight:600;--qilin-font-markdown-h4-line-height:calc(24px + var(--qilin-content-font-delta));--qilin-font-markdown-h4-font-size:var(--qilin-content-font-size,14px);--qilin-font-markdown-h4-font-style:normal;--qilin-font-markdown-base:var(--qilin-content-font-size,14px) / calc(24px + var(--qilin-content-font-delta)) var(--qilin-font-family);--qilin-font-markdown-base-font-family:var(--qilin-font-family);--qilin-font-markdown-base-font-weight:400;--qilin-font-markdown-base-line-height:calc(24px + var(--qilin-content-font-delta));--qilin-font-markdown-base-font-size:var(--qilin-content-font-size,14px);--qilin-font-markdown-base-font-style:normal;--qilin-font-markdown-base-strong:600 var(--qilin-content-font-size,14px) / calc(24px + var(--qilin-content-font-delta)) var(--qilin-font-family);--qilin-font-markdown-base-strong-font-family:var(--qilin-font-family);--qilin-font-markdown-base-strong-font-weight:600;--qilin-font-markdown-base-strong-line-height:calc(24px + var(--qilin-content-font-delta));--qilin-font-markdown-base-strong-font-size:var(--qilin-content-font-size,14px);--qilin-font-markdown-base-strong-font-style:normal;--qilin-font-markdown-base-italic:italic var(--qilin-content-font-size,14px) / calc(24px + var(--qilin-content-font-delta)) var(--qilin-font-family);--qilin-font-markdown-base-italic-font-family:var(--qilin-font-family);--qilin-font-markdown-base-italic-font-weight:400;--qilin-font-markdown-base-italic-line-height:calc(24px + var(--qilin-content-font-delta));--qilin-font-markdown-base-italic-font-size:var(--qilin-content-font-size,14px);--qilin-font-markdown-base-italic-font-style:italic;--qilin-font-markdown-base-strong-italic:italic 600 var(--qilin-content-font-size,14px) / calc(24px + var(--qilin-content-font-delta)) var(--qilin-font-family);--qilin-font-markdown-base-strong-italic-font-family:var(--qilin-font-family);--qilin-font-markdown-base-strong-italic-font-weight:600;--qilin-font-markdown-base-strong-italic-line-height:calc(24px + var(--qilin-content-font-delta));--qilin-font-markdown-base-strong-italic-font-size:var(--qilin-content-font-size,14px);--qilin-font-markdown-base-strong-italic-font-style:italic;--qilin-font-markdown-table:var(--qilin-content-font-size-secondary,13px)/calc(22px + var(--qilin-content-font-delta-secondary,0px)) var(--qilin-font-family);--qilin-font-markdown-table-font-family:var(--qilin-font-family);--qilin-font-markdown-table-font-weight:400;--qilin-font-markdown-table-line-height:calc(22px + var(--qilin-content-font-delta-secondary,0px));--qilin-font-markdown-table-font-size:var(--qilin-content-font-size-secondary,13px);--qilin-font-markdown-table-font-style:normal;--qilin-font-markdown-table-head:500 var(--qilin-content-font-size-secondary,13px)/calc(22px + var(--qilin-content-font-delta-secondary,0px)) var(--qilin-font-family);--qilin-font-markdown-table-head-font-family:var(--qilin-font-family);--qilin-font-markdown-table-head-font-weight:500;--qilin-font-markdown-table-head-line-height:calc(22px + var(--qilin-content-font-delta-secondary,0px));--qilin-font-markdown-table-head-font-size:var(--qilin-content-font-size-secondary,13px);--qilin-font-markdown-table-head-font-style:normal;--qilin-font-markdown-small:12px/20px var(--qilin-font-family);--qilin-font-markdown-small-font-family:var(--qilin-font-family);--qilin-font-markdown-small-font-weight:400;--qilin-font-markdown-small-line-height:20px;--qilin-font-markdown-small-font-size:12px;--qilin-font-markdown-small-font-style:normal;--qilin-font-markdown-small-strong:600 12px/20px var(--qilin-font-family);--qilin-font-markdown-small-strong-font-family:var(--qilin-font-family);--qilin-font-markdown-small-strong-font-weight:600;--qilin-font-markdown-small-strong-line-height:20px;--qilin-font-markdown-small-strong-font-size:12px;--qilin-font-markdown-small-strong-font-style:normal;--qilin-font-markdown-small-italic:italic 12px/20px var(--qilin-font-family);--qilin-font-markdown-small-italic-font-family:var(--qilin-font-family);--qilin-font-markdown-small-italic-font-weight:400;--qilin-font-markdown-small-italic-line-height:20px;--qilin-font-markdown-small-italic-font-size:12px;--qilin-font-markdown-small-italic-font-style:italic;--qilin-font-markdown-small-strong-italic:italic 600 12px/20px var(--qilin-font-family);--qilin-font-markdown-small-strong-italic-font-family:var(--qilin-font-family);--qilin-font-markdown-small-strong-italic-font-weight:600;--qilin-font-markdown-small-strong-italic-line-height:20px;--qilin-font-markdown-small-strong-italic-font-size:12px;--qilin-font-markdown-small-strong-italic-font-style:italic;--qilin-code-font-delta:calc(var(--qilin-code-font-size,11px) - 11px);--qilin-font-markdown-code:calc(12px + var(--qilin-code-font-delta)) / calc(19px + var(--qilin-code-font-delta)) var(--ds-font-family-code);--qilin-font-markdown-code-font-family:var(--ds-font-family-code);--qilin-font-markdown-code-font-weight:400;--qilin-font-markdown-code-line-height:calc(19px + var(--qilin-code-font-delta));--qilin-font-markdown-code-font-size:calc(12px + var(--qilin-code-font-delta));--qilin-font-markdown-code-font-style:normal;--qilin-font-markdown-code-block:var(--qilin-code-font-size,11px) / calc(19px + var(--qilin-code-font-delta)) var(--ds-font-family-code);--qilin-font-markdown-code-block-font-family:var(--ds-font-family-code);--qilin-font-markdown-code-block-font-weight:400;--qilin-font-markdown-code-block-line-height:calc(19px + var(--qilin-code-font-delta));--qilin-font-markdown-code-block-font-size:var(--qilin-code-font-size,11px);--qilin-font-markdown-code-block-font-style:normal;--qilin-font-markdown-code-block-small:var(--qilin-code-font-size,11px) / calc(16px + var(--qilin-code-font-delta)) var(--ds-font-family-code);--qilin-font-markdown-code-block-small-font-family:var(--ds-font-family-code);--qilin-font-markdown-code-block-small-font-weight:400;--qilin-font-markdown-code-block-small-line-height:calc(16px + var(--qilin-code-font-delta));--qilin-font-markdown-code-block-small-font-size:var(--qilin-code-font-size,11px);--qilin-font-markdown-code-block-small-font-style:normal;--qilin-font-xl-24:600 24px/32px var(--qilin-font-family);--qilin-font-xl-24-font-family:var(--qilin-font-family);--qilin-font-xl-24-font-weight:600;--qilin-font-xl-24-line-height:32px;--qilin-font-xl-24-font-size:24px;--qilin-font-xl-24-font-style:normal;--qilin-font-l-20:500 20px/28px var(--qilin-font-family);--qilin-font-l-20-font-family:var(--qilin-font-family);--qilin-font-l-20-font-weight:500;--qilin-font-l-20-line-height:28px;--qilin-font-l-20-font-size:20px;--qilin-font-l-20-font-style:normal;--qilin-font-m-18:500 16px/28px var(--qilin-font-family);--qilin-font-m-18-font-family:var(--qilin-font-family);--qilin-font-m-18-font-weight:500;--qilin-font-m-18-line-height:28px;--qilin-font-m-18-font-size:16px;--qilin-font-m-18-font-style:normal;--qilin-font-base-16:16px/24px var(--qilin-font-family);--qilin-font-base-16-font-family:var(--qilin-font-family);--qilin-font-base-16-font-weight:400;--qilin-font-base-16-line-height:24px;--qilin-font-base-16-font-size:16px;--qilin-font-base-16-font-style:normal;--qilin-font-base-strong-16:500 16px/24px var(--qilin-font-family);--qilin-font-base-strong-16-font-family:var(--qilin-font-family);--qilin-font-base-strong-16-font-weight:500;--qilin-font-base-strong-16-line-height:24px;--qilin-font-base-strong-16-font-size:16px;--qilin-font-base-strong-16-font-style:normal;--qilin-font-s-14:14px/22px var(--qilin-font-family);--qilin-font-s-14-font-family:var(--qilin-font-family);--qilin-font-s-14-font-weight:400;--qilin-font-s-14-line-height:22px;--qilin-font-s-14-font-size:14px;--qilin-font-s-14-font-style:normal;--qilin-font-s-strong-14:500 14px/22px var(--qilin-font-family);--qilin-font-s-strong-14-font-family:var(--qilin-font-family);--qilin-font-s-strong-14-font-weight:500;--qilin-font-s-strong-14-line-height:22px;--qilin-font-s-strong-14-font-size:14px;--qilin-font-s-strong-14-font-style:normal;--qilin-font-xs-13:13px/20px var(--qilin-font-family);--qilin-font-xs-13-font-family:var(--qilin-font-family);--qilin-font-xs-13-font-weight:400;--qilin-font-xs-13-line-height:20px;--qilin-font-xs-13-font-size:13px;--qilin-font-xs-13-font-style:normal;--qilin-font-xs-strong-13:500 13px/20px var(--qilin-font-family);--qilin-font-xs-strong-13-font-family:var(--qilin-font-family);--qilin-font-xs-strong-13-font-weight:500;--qilin-font-xs-strong-13-line-height:20px;--qilin-font-xs-strong-13-font-size:13px;--qilin-font-xs-strong-13-font-style:normal;--qilin-font-xxs-12:12px/18px var(--qilin-font-family);--qilin-font-xxs-12-font-family:var(--qilin-font-family);--qilin-font-xxs-12-font-weight:400;--qilin-font-xxs-12-line-height:18px;--qilin-font-xxs-12-font-size:12px;--qilin-font-xxs-12-font-style:normal;--qilin-font-xxs-strong-12:500 12px/18px var(--qilin-font-family);--qilin-font-xxs-strong-12-font-family:var(--qilin-font-family);--qilin-font-xxs-strong-12-font-weight:500;--qilin-font-xxs-strong-12-line-height:18px;--qilin-font-xxs-strong-12-font-size:12px;--qilin-font-xxs-strong-12-font-style:normal;--qilin-font-xxxs-11:11px/14px var(--qilin-font-family);--qilin-font-xxxs-11-font-family:var(--qilin-font-family);--qilin-font-xxxs-11-font-weight:400;--qilin-font-xxxs-11-line-height:14px;--qilin-font-xxxs-11-font-size:11px;--qilin-font-xxxs-11-font-style:normal;--qilin-font-xxxs-strong-11:500 11px/14px var(--qilin-font-family);--qilin-font-xxxs-strong-11-font-family:var(--qilin-font-family);--qilin-font-xxxs-strong-11-font-weight:500;--qilin-font-xxxs-strong-11-line-height:14px;--qilin-font-xxxs-strong-11-font-size:11px;--qilin-font-xxxs-strong-11-font-style:normal}";
1165
1480
  //#endregion
1166
1481
  //#region \0qilin-inline-css:/home/runner/work/QiLin/QiLin/packages/client/ui-theme/src/styles/shiki.css.mjs
1167
1482
  var shiki_css_default = ":root{--shiki-foreground:var(--qilin-alias-label-primary);--shiki-background:var(--qilin-alias-markdown-code-block);--shiki-token-constant:#1c7ed6;--shiki-token-string:#2f9e44;--shiki-token-comment:#868e96;--shiki-token-keyword:#d6336c;--shiki-token-parameter:#e8590c;--shiki-token-function:#6741d9;--shiki-token-string-expression:#2b8a3e;--shiki-token-punctuation:#495057;--shiki-token-link:#1971c2}body[data-ds-dark-theme]{--shiki-token-constant:#4dabf7;--shiki-token-string:#69db7c;--shiki-token-comment:#adb5bd;--shiki-token-keyword:#faa2c1;--shiki-token-parameter:#ffa94d;--shiki-token-function:#b197fc;--shiki-token-string-expression:#8ce99a;--shiki-token-punctuation:#ced4da;--shiki-token-link:#74c0fc}";
@@ -1197,18 +1512,34 @@ window.__ModuleLoader__.load({
1197
1512
  }
1198
1513
  //#endregion
1199
1514
  //#region lib/types/client/locales.js
1200
- /** `settings.theme` namespace dictionaries (the Appearance, font-size, and line-spacing rows' copy). */
1515
+ /** `settings.theme` namespace dictionaries (the Appearance and font settings rows' copy). */
1201
1516
  /** Simplified Chinese dictionary (the key-set source of truth). */
1202
1517
  const zh = {
1203
1518
  "appearance.title": "外观",
1204
1519
  "appearance.light": "浅色",
1205
1520
  "appearance.dark": "深色",
1206
1521
  "appearance.system": "跟随系统",
1207
- "fontSize.title": "字号大小",
1208
- "fontSize.description": "仅影响会话内容的字号",
1522
+ "fontSize.text.title": "字号大小",
1523
+ "fontSize.text.description": "仅影响会话内容的字号",
1524
+ "fontSize.text.increase": "增大字号",
1525
+ "fontSize.text.decrease": "减小字号",
1526
+ "fontSize.code.title": "代码字号",
1527
+ "fontSize.code.description": "用于代码块、行内代码与工具输出",
1528
+ "fontSize.code.increase": "增大代码字号",
1529
+ "fontSize.code.decrease": "减小代码字号",
1530
+ "fontSize.terminal.title": "终端字号",
1531
+ "fontSize.terminal.description": "用于侧栏终端",
1532
+ "fontSize.terminal.increase": "增大终端字号",
1533
+ "fontSize.terminal.decrease": "减小终端字号",
1209
1534
  "fontSize.unit": "px",
1210
- "fontSize.increase": "增大字号",
1211
- "fontSize.decrease": "减小字号"
1535
+ "fontFamily.text.title": "正文字体",
1536
+ "fontFamily.text.description": "用于界面与会话正文。多个字体用逗号分隔,留空使用默认字体",
1537
+ "fontFamily.code.title": "代码字体",
1538
+ "fontFamily.code.description": "用于代码块、行内代码与工具输出。多个字体用逗号分隔,留空使用默认字体",
1539
+ "fontFamily.terminal.title": "终端字体",
1540
+ "fontFamily.terminal.description": "用于侧栏终端。多个字体用逗号分隔,留空使用默认字体",
1541
+ "fontFamily.placeholder": "默认",
1542
+ "fontSize.more": "更多字体设置"
1212
1543
  };
1213
1544
  /** English dictionary, checked complete against the zh key set. */
1214
1545
  const en = {
@@ -1216,11 +1547,27 @@ window.__ModuleLoader__.load({
1216
1547
  "appearance.light": "Light",
1217
1548
  "appearance.dark": "Dark",
1218
1549
  "appearance.system": "System",
1219
- "fontSize.title": "Font size",
1220
- "fontSize.description": "Only affects conversation content",
1550
+ "fontSize.text.title": "Font size",
1551
+ "fontSize.text.description": "Only affects conversation content",
1552
+ "fontSize.text.increase": "Increase font size",
1553
+ "fontSize.text.decrease": "Decrease font size",
1554
+ "fontSize.code.title": "Code font size",
1555
+ "fontSize.code.description": "Used for code blocks, inline code, and tool output",
1556
+ "fontSize.code.increase": "Increase code font size",
1557
+ "fontSize.code.decrease": "Decrease code font size",
1558
+ "fontSize.terminal.title": "Terminal font size",
1559
+ "fontSize.terminal.description": "Used for the sidebar terminal",
1560
+ "fontSize.terminal.increase": "Increase terminal font size",
1561
+ "fontSize.terminal.decrease": "Decrease terminal font size",
1221
1562
  "fontSize.unit": "px",
1222
- "fontSize.increase": "Increase font size",
1223
- "fontSize.decrease": "Decrease font size"
1563
+ "fontFamily.text.title": "Text font",
1564
+ "fontFamily.text.description": "Used for the interface and conversation text. Separate fonts with commas; leave empty for the default",
1565
+ "fontFamily.code.title": "Code font",
1566
+ "fontFamily.code.description": "Used for code blocks, inline code, and tool output. Separate fonts with commas; leave empty for the default",
1567
+ "fontFamily.terminal.title": "Terminal font",
1568
+ "fontFamily.terminal.description": "Used for the sidebar terminal. Separate fonts with commas; leave empty for the default",
1569
+ "fontFamily.placeholder": "Default",
1570
+ "fontSize.more": "More font settings"
1224
1571
  };
1225
1572
  //#endregion
1226
1573
  //#region lib/types/client/index.js
@@ -1237,95 +1584,102 @@ window.__ModuleLoader__.load({
1237
1584
  })]);
1238
1585
  const BUILTIN_INSPECT_TOKENS = Object.freeze([
1239
1586
  {
1240
- name: "--qilin-alias-bg-base",
1587
+ name: "--dsw-alias-bg-base",
1241
1588
  description: "Application base background.",
1242
1589
  valueType: "CSS color",
1243
1590
  requiresLightAndDark: true,
1244
- cssVariable: "--qilin-alias-bg-base"
1591
+ cssVariable: "--dsw-alias-bg-base"
1245
1592
  },
1246
1593
  {
1247
- name: "--qilin-alias-bg-layer-1",
1594
+ name: "--dsw-alias-bg-layer-1",
1248
1595
  description: "Primary raised surface background.",
1249
1596
  valueType: "CSS color",
1250
1597
  requiresLightAndDark: true,
1251
- cssVariable: "--qilin-alias-bg-layer-1"
1598
+ cssVariable: "--dsw-alias-bg-layer-1"
1252
1599
  },
1253
1600
  {
1254
- name: "--qilin-alias-bg-layer-2",
1601
+ name: "--dsw-alias-bg-layer-2",
1255
1602
  description: "Secondary nested surface background.",
1256
1603
  valueType: "CSS color",
1257
1604
  requiresLightAndDark: true,
1258
- cssVariable: "--qilin-alias-bg-layer-2"
1605
+ cssVariable: "--dsw-alias-bg-layer-2"
1259
1606
  },
1260
1607
  {
1261
- name: "--qilin-alias-bg-overlay",
1608
+ name: "--dsw-alias-bg-overlay",
1262
1609
  description: "Overlay and popover background.",
1263
1610
  valueType: "CSS color",
1264
1611
  requiresLightAndDark: true,
1265
- cssVariable: "--qilin-alias-bg-overlay"
1612
+ cssVariable: "--dsw-alias-bg-overlay"
1266
1613
  },
1267
1614
  {
1268
- name: "--qilin-alias-border-l1",
1615
+ name: "--dsw-alias-border-l1",
1269
1616
  description: "Primary subtle border.",
1270
1617
  valueType: "CSS color",
1271
1618
  requiresLightAndDark: true,
1272
- cssVariable: "--qilin-alias-border-l1"
1619
+ cssVariable: "--dsw-alias-border-l1"
1273
1620
  },
1274
1621
  {
1275
- name: "--qilin-alias-border-l2",
1622
+ name: "--dsw-alias-border-l2",
1276
1623
  description: "Secondary stronger border.",
1277
1624
  valueType: "CSS color",
1278
1625
  requiresLightAndDark: true,
1279
- cssVariable: "--qilin-alias-border-l2"
1626
+ cssVariable: "--dsw-alias-border-l2"
1280
1627
  },
1281
1628
  {
1282
- name: "--qilin-alias-brand-primary",
1629
+ name: "--dsw-alias-brand-primary",
1283
1630
  description: "Primary brand accent.",
1284
1631
  valueType: "CSS color",
1285
1632
  requiresLightAndDark: true,
1286
- cssVariable: "--qilin-alias-brand-primary"
1633
+ cssVariable: "--dsw-alias-brand-primary"
1287
1634
  },
1288
1635
  {
1289
- name: "--qilin-alias-label-primary",
1636
+ name: "--dsw-alias-label-primary",
1290
1637
  description: "Primary text color.",
1291
1638
  valueType: "CSS color",
1292
1639
  requiresLightAndDark: true,
1293
- cssVariable: "--qilin-alias-label-primary"
1640
+ cssVariable: "--dsw-alias-label-primary"
1294
1641
  },
1295
1642
  {
1296
- name: "--qilin-alias-label-secondary",
1643
+ name: "--dsw-alias-label-secondary",
1297
1644
  description: "Secondary text color.",
1298
1645
  valueType: "CSS color",
1299
1646
  requiresLightAndDark: true,
1300
- cssVariable: "--qilin-alias-label-secondary"
1647
+ cssVariable: "--dsw-alias-label-secondary"
1301
1648
  },
1302
1649
  {
1303
- name: "--qilin-alias-state-error-primary",
1650
+ name: "--dsw-alias-state-error-primary",
1304
1651
  description: "Primary error state color.",
1305
1652
  valueType: "CSS color",
1306
1653
  requiresLightAndDark: true,
1307
- cssVariable: "--qilin-alias-state-error-primary"
1654
+ cssVariable: "--dsw-alias-state-error-primary"
1308
1655
  },
1309
1656
  {
1310
- name: "--qilin-alias-state-success-primary",
1657
+ name: "--dsw-alias-state-idle-primary",
1658
+ description: "Primary inactive state color.",
1659
+ valueType: "CSS color",
1660
+ requiresLightAndDark: true,
1661
+ cssVariable: "--dsw-alias-state-idle-primary"
1662
+ },
1663
+ {
1664
+ name: "--dsw-alias-state-success-primary",
1311
1665
  description: "Primary success state color.",
1312
1666
  valueType: "CSS color",
1313
1667
  requiresLightAndDark: true,
1314
- cssVariable: "--qilin-alias-state-success-primary"
1668
+ cssVariable: "--dsw-alias-state-success-primary"
1315
1669
  },
1316
1670
  {
1317
- name: "--qilin-alias-state-warn-primary",
1671
+ name: "--dsw-alias-state-warn-primary",
1318
1672
  description: "Primary warning state color.",
1319
1673
  valueType: "CSS color",
1320
1674
  requiresLightAndDark: true,
1321
- cssVariable: "--qilin-alias-state-warn-primary"
1675
+ cssVariable: "--dsw-alias-state-warn-primary"
1322
1676
  },
1323
1677
  {
1324
- name: "--qilin-specific-sidebar-fill",
1678
+ name: "--dsw-specific-sidebar-fill",
1325
1679
  description: "Sidebar column and title-row background.",
1326
1680
  valueType: "CSS color",
1327
1681
  requiresLightAndDark: true,
1328
- cssVariable: "--qilin-specific-sidebar-fill"
1682
+ cssVariable: "--dsw-specific-sidebar-fill"
1329
1683
  }
1330
1684
  ]);
1331
1685
  /**
@@ -1344,8 +1698,11 @@ window.__ModuleLoader__.load({
1344
1698
  host;
1345
1699
  themes = [...BUILTIN_THEMES];
1346
1700
  preference;
1347
- fontSize = bootstrapFontSize();
1701
+ fontSizes = bootstrapFontSizes();
1702
+ fontFamilies = bootstrapFontFamilies();
1348
1703
  revision = 0;
1704
+ /** Own settings writes not yet settled; adoption waits for zero so a Host echo of an earlier write cannot revert a later local change. */
1705
+ pendingWrites = 0;
1349
1706
  snapshot;
1350
1707
  media;
1351
1708
  /** Override layers by source; seq (monotonic) is the stacking order. */
@@ -1379,6 +1736,9 @@ window.__ModuleLoader__.load({
1379
1736
  this.adopt();
1380
1737
  }), "ui-theme: settings scope adoption");
1381
1738
  this.adopt();
1739
+ installFontSizeShortcuts(ctx, SETTINGS_NS, (delta) => {
1740
+ this.adjustFontSizes(delta);
1741
+ });
1382
1742
  }
1383
1743
  /**
1384
1744
  * Read the current immutable theme snapshot.
@@ -1407,29 +1767,87 @@ window.__ModuleLoader__.load({
1407
1767
  if (id !== "system" && !this.themes.some((t) => t.id === id)) throw new Error(`theme "${id}" is not registered`);
1408
1768
  if (this.preference === id) return;
1409
1769
  this.preference = id;
1410
- if (isThemePreference(id)) this.host.set(THEME_PREFERENCE_FIELD, id);
1770
+ if (isThemePreference(id)) this.write(() => this.host.set(THEME_PREFERENCE_FIELD, id));
1771
+ this.publish();
1772
+ }
1773
+ /**
1774
+ * Change one role's font size — the only font-size write entry. Accepted
1775
+ * values are written through the settings scope and emit `theme/change`.
1776
+ * @param role - font role.
1777
+ * @param px - integer px within the role's `FONT_SIZE_SPECS` range; out-of-range or fractional values throw.
1778
+ */
1779
+ setFontSize(role, px) {
1780
+ const spec = FONT_SIZE_SPECS[role];
1781
+ if (!isFontSize(role, px)) throw new Error(`${role} font size ${px} is outside ${spec.min}..${spec.max}`);
1782
+ if (this.fontSizes[role] === px) return;
1783
+ this.fontSizes = Object.freeze({
1784
+ ...this.fontSizes,
1785
+ [role]: px
1786
+ });
1787
+ this.write(() => this.host.set(spec.field, px));
1788
+ this.publish();
1789
+ }
1790
+ /**
1791
+ * Step all font sizes within their own ranges and save changed fields in one mutation.
1792
+ * Emits one `theme/change`; no write or event occurs when every role is at its limit.
1793
+ * @param delta - one pixel to add or remove from each role's current size.
1794
+ */
1795
+ adjustFontSizes(delta) {
1796
+ const fontSizes = { ...this.fontSizes };
1797
+ const fields = {};
1798
+ for (const role of FONT_ROLES) {
1799
+ const { field, min, max } = FONT_SIZE_SPECS[role];
1800
+ const px = Math.max(min, Math.min(max, fontSizes[role] + delta));
1801
+ if (px === fontSizes[role]) continue;
1802
+ fontSizes[role] = px;
1803
+ fields[field] = px;
1804
+ }
1805
+ const ops = Object.entries(fields).map(([field, value]) => ({
1806
+ op: "set",
1807
+ path: [field],
1808
+ value
1809
+ }));
1810
+ if (ops.length === 0) return;
1811
+ this.fontSizes = Object.freeze(fontSizes);
1812
+ this.write(() => this.host.mutate(ops));
1411
1813
  this.publish();
1412
1814
  }
1413
1815
  /**
1414
- * Change the conversation content font size — the only font-size write
1415
- * entry. Accepted values are written through the settings scope and emit
1416
- * `theme/change`.
1417
- * @param px - integer px within FONT_SIZE_MIN..FONT_SIZE_MAX; out-of-range or fractional values throw.
1816
+ * Change one role's font list — the only font-family write entry. The value
1817
+ * is normalized, written through the settings scope, and emits `theme/change`
1818
+ * when the normalized list differs.
1819
+ * @param role - font role.
1820
+ * @param value - comma-separated family names; a value without names restores the built-in stack.
1418
1821
  */
1419
- setFontSize(px) {
1420
- if (!Number.isInteger(px) || px < 10 || px > 22) throw new Error(`font size ${px} is outside 10..22`);
1421
- if (this.fontSize === px) return;
1422
- this.fontSize = px;
1423
- this.host.set(FONT_SIZE_FIELD, px);
1822
+ setFontFamily(role, value) {
1823
+ const list = normalizeFontFamily(value);
1824
+ if (this.fontFamilies[role] === list) return;
1825
+ this.fontFamilies = Object.freeze({
1826
+ ...this.fontFamilies,
1827
+ [role]: list
1828
+ });
1829
+ this.write(() => this.host.set(FONT_FAMILY_FIELDS[role], list));
1424
1830
  this.publish();
1425
1831
  }
1832
+ /** Queue one settings write, then adopt the durable section once no own write remains. */
1833
+ write(operation) {
1834
+ this.pendingWrites += 1;
1835
+ operation().finally(() => {
1836
+ this.pendingWrites -= 1;
1837
+ this.adopt();
1838
+ });
1839
+ }
1426
1840
  /** Adopt the scope's accepted durable preference without writing it back. */
1427
1841
  adopt() {
1842
+ if (this.pendingWrites > 0) return;
1428
1843
  const section = this.host.getSnapshot().value;
1429
1844
  if (section === void 0) return;
1430
- if (this.preference === section.preference && this.fontSize === section.fontSize) return;
1845
+ const fontFamilies = durableFontFamilies(section);
1846
+ const fontSizes = sectionFontSizes(section);
1847
+ if (this.preference === section.preference && FONT_ROLES.every((role) => this.fontSizes[role] === fontSizes[role] && this.fontFamilies[role] === fontFamilies[role])) return;
1431
1848
  this.preference = section.preference;
1432
- this.fontSize = section.fontSize;
1849
+ this.fontSizes = fontSizes;
1850
+ this.fontFamilies = fontFamilies;
1433
1851
  this.publish();
1434
1852
  }
1435
1853
  /**
@@ -1488,7 +1906,8 @@ window.__ModuleLoader__.load({
1488
1906
  if (active === void 0) throw new Error(`theme registry lost "${resolvedId}"`);
1489
1907
  return Object.freeze({
1490
1908
  preference: this.preference,
1491
- fontSize: this.fontSize,
1909
+ fontSizes: this.fontSizes,
1910
+ fontFamilies: this.fontFamilies,
1492
1911
  active: this.composeActive(active),
1493
1912
  themes: Object.freeze([...this.themes]),
1494
1913
  revision: this.revision
@@ -1516,18 +1935,47 @@ window.__ModuleLoader__.load({
1516
1935
  }
1517
1936
  };
1518
1937
  /**
1519
- * Read the font size the Host boot script wrote on `body` before any plugin
1938
+ * Read the font sizes the Host boot script wrote on `body` before any plugin
1520
1939
  * ran, so the initial snapshot matches first paint and ui-layout's presenter
1521
- * does not flash the schema default while the settings read is in flight.
1522
- * Non-browser runs and mounts without the boot script fall back to the
1523
- * schema default; the durable settings adoption still lands afterwards.
1940
+ * does not flash the schema defaults while the settings read is in flight.
1941
+ * Non-browser runs, mounts without the boot script, and out-of-range values
1942
+ * fall back to each role's default; the durable settings adoption still lands afterwards.
1524
1943
  */
1525
- function bootstrapFontSize() {
1944
+ function bootstrapFontSizes() {
1526
1945
  /* v8 ignore next -- needs a documentless run (node e2e booting the client tree), not constructible under jsdom */
1527
- if (typeof document === "undefined") return 14;
1528
- const raw = document.body.style.getPropertyValue("--qilin-content-font-size");
1529
- const parsed = Number.parseInt(raw, 10);
1530
- return Number.isInteger(parsed) && parsed >= 10 && parsed <= 22 ? parsed : 14;
1946
+ if (typeof document === "undefined") return DEFAULT_FONT_SIZES;
1947
+ const read = (role) => {
1948
+ const parsed = Number.parseInt(document.body.style.getPropertyValue(FONT_SIZE_SPECS[role].variable), 10);
1949
+ return isFontSize(role, parsed) ? parsed : FONT_SIZE_SPECS[role].default;
1950
+ };
1951
+ return Object.freeze({
1952
+ text: read("text"),
1953
+ code: read("code"),
1954
+ terminal: read("terminal")
1955
+ });
1956
+ }
1957
+ /** Font lists the Host boot script wrote on `body`, read for the same first-paint reason as {@link bootstrapFontSizes}. */
1958
+ function bootstrapFontFamilies() {
1959
+ /* v8 ignore next -- needs a documentless run (node e2e booting the client tree), not constructible under jsdom */
1960
+ if (typeof document === "undefined") return Object.freeze({
1961
+ text: "",
1962
+ code: "",
1963
+ terminal: ""
1964
+ });
1965
+ const style = document.body.style;
1966
+ return Object.freeze({
1967
+ text: normalizeFontFamily(style.getPropertyValue(fontFamilyVariable("text"))),
1968
+ code: normalizeFontFamily(style.getPropertyValue(fontFamilyVariable("code"))),
1969
+ terminal: normalizeFontFamily(style.getPropertyValue(fontFamilyVariable("terminal")))
1970
+ });
1971
+ }
1972
+ /** Normalized font lists from one accepted settings section (hand-edited documents may hold raw input). */
1973
+ function durableFontFamilies(section) {
1974
+ return Object.freeze({
1975
+ text: normalizeFontFamily(section.textFontFamily),
1976
+ code: normalizeFontFamily(section.codeFontFamily),
1977
+ terminal: normalizeFontFamily(section.terminalFontFamily)
1978
+ });
1531
1979
  }
1532
1980
  /**
1533
1981
  * Runtime shape check for one override layer (model-authored callers pass
@@ -1569,8 +2017,8 @@ window.__ModuleLoader__.load({
1569
2017
  ];
1570
2018
  /**
1571
2019
  * Client plugin body: provide the theme service and register the
1572
- * feature-owned Appearance, font-size, and line-spacing preference rows into
1573
- * the General section's item slot (a feature owns its settings surface).
2020
+ * feature-owned Appearance and font settings rows into the General section's item
2021
+ * slot (a feature owns its settings surface).
1574
2022
  * @param ctx - client cordis context.
1575
2023
  */
1576
2024
  function apply(ctx) {
@@ -1581,18 +2029,17 @@ window.__ModuleLoader__.load({
1581
2029
  zh,
1582
2030
  en
1583
2031
  }), "ui-theme: settings row dictionaries");
1584
- const typographyStore = createTypographyRowStore();
1585
- const appearanceStore = createAppearanceRowStore();
1586
- let appearanceBound;
1587
- let fontSizeBound;
2032
+ const store = createAppearanceRowStore();
2033
+ let bound;
2034
+ const fontStore = createFontRowStore();
2035
+ let fontBound;
1588
2036
  const sync = (snapshot) => {
1589
- const { preference, fontSize, revision } = snapshot;
1590
- appearanceBound?.sync(preference, revision);
1591
- fontSizeBound?.sync(fontSize, revision);
2037
+ bound?.sync(snapshot.preference, snapshot.revision);
2038
+ fontBound?.sync(snapshot.fontSizes, snapshot.fontFamilies, snapshot.revision);
1592
2039
  };
1593
2040
  ctx.on("theme/change", sync);
1594
- const appearanceInjected = (actions) => {
1595
- appearanceBound = actions;
2041
+ const injected = (actions) => {
2042
+ bound = actions;
1596
2043
  sync(theme.getTheme());
1597
2044
  return { setTheme: (id) => {
1598
2045
  theme.setTheme(id);
@@ -1602,25 +2049,29 @@ window.__ModuleLoader__.load({
1602
2049
  name: "settings.general.item",
1603
2050
  id: "appearance",
1604
2051
  order: 10,
1605
- store: appearanceStore,
2052
+ store,
1606
2053
  locale: SETTINGS_NS,
1607
- inject: appearanceInjected
2054
+ inject: injected
1608
2055
  }, AppearanceRow));
1609
- const fontSizeInjected = (actions) => {
1610
- fontSizeBound = actions;
1611
- sync(theme.getTheme());
1612
- return { setFontSize: (px) => {
1613
- theme.setFontSize(px);
1614
- } };
1615
- };
1616
2056
  ctx.slots.inject("settings.general.item", () => ctx.slots.register({
1617
2057
  name: "settings.general.item",
1618
2058
  id: "font-size",
1619
2059
  order: 11,
1620
- store: typographyStore,
2060
+ store: fontStore,
1621
2061
  locale: SETTINGS_NS,
1622
- inject: fontSizeInjected
1623
- }, FontSizeRow));
2062
+ inject: (actions) => {
2063
+ fontBound = actions;
2064
+ sync(theme.getTheme());
2065
+ return {
2066
+ setFontFamily: (role, value) => {
2067
+ theme.setFontFamily(role, value);
2068
+ },
2069
+ setFontSize: (role, px) => {
2070
+ theme.setFontSize(role, px);
2071
+ }
2072
+ };
2073
+ }
2074
+ }, FontSettingsGroup));
1624
2075
  }
1625
2076
  //#endregion
1626
2077
  exports.SETTINGS_NS = SETTINGS_NS;