mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-06 16:08:05 +00:00
Support custom editor font weights in steps of 50 (#74)
JetBrains Mono at 500 looks heavier than PyCharm's rendering, and 450 was rounded up to 500. Adds a Custom option with an input to the Main and Bold font weight rows; weights are clamped to 100–900 and rounded to the nearest 50 (the terminal, which follows the editor weights, gets the same steps). Verified in the app: Custom → 450 shows the input and the preview renders at 450. Maintainer follow-up: formatted the dialog test. Related: #32 https://claude.ai/code/session_01VUYsdXA2nkF5v6zsC93dpn
This commit is contained in:
@@ -128,6 +128,26 @@ describe("Settings dialog", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("edits and saves independent custom font weights", async () => {
|
||||
const dialog = await openDialog("editor.font");
|
||||
for (const [label, value] of [
|
||||
["Main font weight", "449"],
|
||||
["Bold font weight", "650"],
|
||||
]) {
|
||||
fireEvent.click(within(dialog).getByRole("button", { name: label }));
|
||||
fireEvent.click(screen.getByRole("option", { name: "Custom" }));
|
||||
fireEvent.change(within(dialog).getByLabelText(`${label} custom value`), { target: { value } });
|
||||
}
|
||||
const preview = within(dialog).getByLabelText("Font preview");
|
||||
expect(preview.style.getPropertyValue("--fw-code")).toBe("450");
|
||||
expect(preview.style.getPropertyValue("--fw-code-bold")).toBe("650");
|
||||
await act(async () => fireEvent.click(within(dialog).getByRole("button", { name: "Apply" })));
|
||||
expect(settingsSet.mock.calls).toEqual([
|
||||
["global", "editor.boldFontWeight", "650"],
|
||||
["global", "editor.fontWeight", "450"],
|
||||
]);
|
||||
});
|
||||
|
||||
it("Cancel discards staged edits", async () => {
|
||||
const dialog = await openDialog("editor.codeStyle.other");
|
||||
fireEvent.change(within(dialog).getByLabelText("Tab size"), { target: { value: "2" } });
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useMemo, useState } from "react";
|
||||
import { Checkbox, type SelectOption, T } from "@/ui";
|
||||
import { monoFontFamily } from "@/platform/fonts";
|
||||
import { NumberInput, Row, SearchLabel, Select } from "../../components/Form";
|
||||
import { useLabelMatch, useSetting } from "../../components/context";
|
||||
import { useLabelMatch, usePageContext, useSetting } from "../../components/context";
|
||||
import { FONT_WEIGHTS, fontWeightOf, fontWeightVars } from "@/platform/editorSettings";
|
||||
import { LIMITS } from "../../model/schema";
|
||||
import { editorPage } from "./kit";
|
||||
@@ -135,7 +135,32 @@ function FallbackRow() {
|
||||
);
|
||||
}
|
||||
|
||||
const WEIGHT_OPTIONS: SelectOption[] = FONT_WEIGHTS.map(([w, name]) => ({ value: String(w), label: name, detail: String(w) }));
|
||||
const WEIGHT_OPTIONS: SelectOption[] = [
|
||||
...FONT_WEIGHTS.map(([w, name]) => ({ value: String(w), label: name, detail: String(w) })),
|
||||
{ value: "custom", label: "Custom" },
|
||||
];
|
||||
|
||||
function WeightRow({ label, value, onChange, defaultWeight, hint }: { label: string; value: number; onChange: (value: number) => void; defaultWeight: number; hint?: string }) {
|
||||
const [customSelected, setCustomSelected] = useState(false);
|
||||
const weight = fontWeightOf(value, defaultWeight);
|
||||
const custom = customSelected || !FONT_WEIGHTS.some(([w]) => w === weight);
|
||||
return (
|
||||
<Row label={label} hint={hint}>
|
||||
<Select
|
||||
value={custom ? "custom" : String(weight)}
|
||||
options={WEIGHT_OPTIONS}
|
||||
onChange={(v) => {
|
||||
setCustomSelected(v === "custom");
|
||||
if (v !== "custom") onChange(Number(v));
|
||||
}}
|
||||
aria-label={label}
|
||||
/>
|
||||
{custom && (
|
||||
<NumberInput value={weight} onChange={(n) => onChange(fontWeightOf(n, defaultWeight))} min={100} max={900} step={50} integer aria-label={`${label} custom value`} />
|
||||
)}
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* IDEA's Main / Bold font weight. IDEA lists the weights the family ships; the
|
||||
@@ -143,26 +168,13 @@ const WEIGHT_OPTIONS: SelectOption[] = FONT_WEIGHTS.map(([w, name]) => ({ value:
|
||||
* standard names (the WebView picks the nearest face or synthesises bold).
|
||||
*/
|
||||
function WeightRows() {
|
||||
const { scope } = usePageContext();
|
||||
const [main, setMain] = useSetting<number>("editor.fontWeight");
|
||||
const [bold, setBold] = useSetting<number>("editor.boldFontWeight");
|
||||
return (
|
||||
<>
|
||||
<Row label="Main font weight">
|
||||
<Select
|
||||
value={String(fontWeightOf(main, 400))}
|
||||
options={WEIGHT_OPTIONS}
|
||||
onChange={(v) => setMain(Number(v))}
|
||||
aria-label="Main font weight"
|
||||
/>
|
||||
</Row>
|
||||
<Row label="Bold font weight" hint="Used wherever the color scheme shows text in bold">
|
||||
<Select
|
||||
value={String(fontWeightOf(bold, 700))}
|
||||
options={WEIGHT_OPTIONS}
|
||||
onChange={(v) => setBold(Number(v))}
|
||||
aria-label="Bold font weight"
|
||||
/>
|
||||
</Row>
|
||||
<WeightRow key={`${scope}-main`} label="Main font weight" value={main} onChange={setMain} defaultWeight={400} />
|
||||
<WeightRow key={`${scope}-bold`} label="Bold font weight" value={bold} onChange={setBold} defaultWeight={700} hint="Used wherever the color scheme shows text in bold" />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -60,9 +60,10 @@ describe("color schemes", () => {
|
||||
const d = validateEditorExtras({});
|
||||
expect([d.fontWeight, d.boldFontWeight]).toEqual([400, 700]);
|
||||
const v = validateEditorExtras({ fontWeight: 349, boldFontWeight: 1200 });
|
||||
expect([v.fontWeight, v.boldFontWeight]).toEqual([300, 900]);
|
||||
expect([v.fontWeight, v.boldFontWeight]).toEqual([350, 900]);
|
||||
expect(validateEditorExtras({ fontWeight: "bold" }).fontWeight).toBe(400);
|
||||
expect(fontWeightVars(500, undefined)).toEqual({ "--fw-code": "500", "--fw-code-bold": "700" });
|
||||
expect(fontWeightVars(450, 650)).toEqual({ "--fw-code": "450", "--fw-code-bold": "650" });
|
||||
});
|
||||
|
||||
it("coerces editor settings to their defaults' shape", () => {
|
||||
|
||||
@@ -205,10 +205,10 @@ export const FONT_WEIGHTS: ReadonlyArray<readonly [number, string]> = [
|
||||
[900, "Black"],
|
||||
];
|
||||
|
||||
/** Nearest CSS weight step (100–900); `def` for anything that is not a number. */
|
||||
/** CSS weight from 100 to 900, rounded to the nearest 50. */
|
||||
export function fontWeightOf(raw: unknown, def: number): number {
|
||||
if (typeof raw !== "number" || !Number.isFinite(raw)) return def;
|
||||
return Math.min(900, Math.max(100, Math.round(raw / 100) * 100));
|
||||
return Math.min(900, Math.max(100, Math.round(raw / 50) * 50));
|
||||
}
|
||||
|
||||
/** `--fw-code` / `--fw-code-bold`: what editor-font text and its bold runs render with. */
|
||||
|
||||
Reference in New Issue
Block a user