Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,11 @@ export class GlyphCatalogOverlay {
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText(
fitCanvasText(context, cell.glyph.name, cell.nameRect.width - 2 * LABEL_HORIZONTAL_INSET),
fitCanvasText(
context,
cell.glyph.displayName,
cell.nameRect.width - 2 * LABEL_HORIZONTAL_INSET,
),
cell.nameRect.x + cell.nameRect.width / 2,
cell.nameRect.y + cell.nameRect.height / 2,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ function catalog(count: number): GlyphCatalogItem[] {
return Array.from({ length: count }, (_, index) => ({
id: `glyph-${index}` as GlyphId,
name: `name-${index}` as GlyphName,
displayName: `name-${index}`,
unicode: index,
}));
}
Expand Down
17 changes: 11 additions & 6 deletions apps/desktop/src/renderer/src/context/GlyphCatalogProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useMemo, useState, type ReactNode } from "react";
import type { GlyphCategory, GlyphCategoryCatalog } from "@shift/glyph-info";
import type { GlyphCategory, GlyphCategoryCatalog, GlyphInfo } from "@shift/glyph-info";
import type { GlyphName, GlyphRecord } from "@shift/types";
import { useSignalState } from "@/lib/signals";
import { useEditor } from "@/workspace/WorkspaceContext";
Expand All @@ -24,8 +24,8 @@ const useGlyphCatalogState = (): GlyphCatalogState => {
const [selectedSubCategoryKey, setSelectedSubCategoryKey] = useState<string | null>(null);

const availableGlyphs = useMemo(
() => glyphRecords.map(glyphCatalogItemFromRecord),
[glyphRecords],
() => glyphRecords.map((record) => glyphCatalogItemFromRecord(record, glyphInfo)),
[glyphInfo, glyphRecords],
);

const availableUnicodes = useMemo(
Expand Down Expand Up @@ -54,7 +54,9 @@ const useGlyphCatalogState = (): GlyphCatalogState => {
return availableGlyphs.filter((glyph) => {
const unicodeMatched = glyph.unicode !== null && categoryFilteredUnicodes.has(glyph.unicode);
const nameMatched =
normalizedQuery !== "" && glyph.name.toLowerCase().includes(normalizedQuery);
normalizedQuery !== "" &&
(glyph.name.toLowerCase().includes(normalizedQuery) ||
glyph.displayName.toLowerCase().includes(normalizedQuery));

if (filteringByCategory) return unicodeMatched;
if (normalizedQuery !== "") return unicodeMatched || nameMatched;
Expand Down Expand Up @@ -100,10 +102,13 @@ const useGlyphCatalogState = (): GlyphCatalogState => {
};
};

function glyphCatalogItemFromRecord(record: GlyphRecord): GlyphCatalogItem {
function glyphCatalogItemFromRecord(record: GlyphRecord, glyphInfo: GlyphInfo): GlyphCatalogItem {
const unicode = record.unicodes[0] ?? null;

return {
id: record.id,
name: record.name,
unicode: record.unicodes[0] ?? null,
displayName: glyphInfo.resolveGlyphName(record.name, unicode),
unicode,
};
}
1 change: 1 addition & 0 deletions apps/desktop/src/renderer/src/types/glyphCatalog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export type GlyphCatalogCellArea = "preview" | "name";
export interface GlyphCatalogItem {
readonly id: GlyphId;
readonly name: GlyphName;
readonly displayName: string;
readonly unicode: number | null;
}

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"test:unit": "pnpm turbo run test --filter='!shift-bridge'",
"test:integration": "pnpm test:native && cargo test --workspace",
"test:lint": "pnpm --filter @shift/desktop run lint:check",
"test:perf": "pnpm --filter @shift/desktop exec vitest bench --run",
"test:perf": "pnpm generate:glyph-info && pnpm --filter @shift/desktop exec vitest bench --run",
"test:playwright": "pnpm --filter @shift/desktop test:e2e",
"test:watch": "turbo run test:watch",
"test:native": "turbo run test --filter=shift-bridge",
Expand Down
19 changes: 19 additions & 0 deletions packages/glyph-info/src/GlyphInfo.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,25 @@ describe("getGlyphName", () => {
});
});

describe("resolveGlyphName", () => {
it("maps legacy aliases from the glyph database", () => {
expect(db.resolveGlyphName("afii10072")).toBe("zhe-cy");
expect(db.resolveGlyphName("afii10081")).toBe("pe-cy");
});

it("uses the assigned codepoint when the authored name is noncanonical", () => {
expect(db.resolveGlyphName("custom-zhe", 0x0436)).toBe("zhe-cy");
});

it("maps production names and preserves dot suffixes", () => {
expect(db.resolveGlyphName("uni01C9.sc")).toBe("lj.sc");
});

it("preserves unknown authored names", () => {
expect(db.resolveGlyphName("custom.unencoded")).toBe("custom.unencoded");
});
});

describe("getAllGlyph", () => {
it("returns many entries", () => {
const all = db.getAllGlyph();
Expand Down
31 changes: 30 additions & 1 deletion packages/glyph-info/src/GlyphInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ function toSortedCategorySummaries(
export class GlyphInfo {
#glyphData: Map<number, Glyph>;
#glyphDataByName: Map<string, Glyph>;
#glyphDataByAlias: Map<string, Glyph>;
#decomposed: Map<number, number[]>;
#usedBy: Map<number, number[]>;
#charsets: CharsetDefinition[];
Expand All @@ -135,6 +136,19 @@ export class GlyphInfo {
constructor(resources: GlyphInfoResources) {
this.#glyphData = new Map(resources.glyphData.map((g) => [g.codepoint, g]));
this.#glyphDataByName = new Map(resources.glyphData.map((g) => [g.name, g]));
this.#glyphDataByAlias = new Map(this.#glyphDataByName);
for (const glyph of resources.glyphData) {
if (glyph.production && !this.#glyphDataByAlias.has(glyph.production)) {
this.#glyphDataByAlias.set(glyph.production, glyph);
}

for (const alias of glyph.altNames?.split(",") ?? []) {
const name = alias.trim();
if (name && !this.#glyphDataByAlias.has(name)) {
this.#glyphDataByAlias.set(name, glyph);
}
}
}

this.#decomposed = new Map(
Object.entries(resources.decomposition.decomposed).map(([k, v]) => [Number(k), v]),
Expand Down Expand Up @@ -169,11 +183,26 @@ export class GlyphInfo {
return data.name;
}

/** Look up the full metadata record for a production glyph name. */
/** Look up the full metadata record for a canonical glyph name. */
getGlyphByName(name: string): Glyph | null {
return this.#glyphDataByName.get(name) ?? null;
}

/**
* Resolve an authored glyph name to the canonical glyph database name.
* Dot suffixes are preserved, and unknown names pass through unchanged.
*/
resolveGlyphName(name: string, codepoint?: number | null): string {
const suffixStart = name.indexOf(".");
const baseName = suffixStart > 0 ? name.slice(0, suffixStart) : name;
const suffix = suffixStart > 0 ? name.slice(suffixStart) : "";
const glyph =
(codepoint === null || codepoint === undefined ? null : this.#glyphData.get(codepoint)) ??
this.#glyphDataByAlias.get(baseName);

return glyph ? `${glyph.name}${suffix}` : name;
}

getAllGlyph(): Glyph[] {
return Array.from(this.#glyphData.values());
}
Expand Down