Skip to content

Commit 5fc0a78

Browse files
ayaka14732Copilot
andauthored
UI Updates (#7)
* UI Update * Use CSS variable for font lists * Memoize tableRows computation to prevent unnecessary re-renders (#8) * Initial plan * Memoize tableRows computation with useMemo Co-authored-by: ayaka14732 <68557794+ayaka14732@users.noreply.github.com> * Delete package-lock.json --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: ayaka14732 <68557794+ayaka14732@users.noreply.github.com> Co-authored-by: Ayaka Mikazuki <ayaka@mail.shn.hk> --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
1 parent ec7f1b9 commit 5fc0a78

File tree

4 files changed

+46
-32
lines changed

4 files changed

+46
-32
lines changed

src/app/NotoTraditionalNushu.css

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/app/index.css

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,6 @@
22
@import "./scrollbar.css";
33
@import "./CharisSIL.css";
44
@import "./SBBWeb.css";
5-
@import "./NotoTraditionalNushu.css";
6-
7-
/* Swiss SBB Modern Style - Design Tokens
8-
* Movement: Contemporary Swiss Design (2020s SBB branding)
9-
* Principles: Bold, efficient, high-energy, functional clarity
10-
* Color: SBB Red (#EB0000) dominant, white, light grays
11-
* Layout: Minimal spacing, sharp edges, strong visual hierarchy
12-
* Typography: Bold sans-serif, high contrast
13-
*/
145

156
@theme inline {
167
--radius-sm: 0px;
@@ -100,6 +91,13 @@
10091
--chart-3: oklch(0.45 0.2 27);
10192
--chart-4: oklch(0.35 0.18 27);
10293
--chart-5: oklch(0.25 0.15 27);
94+
95+
/* Font */
96+
--font-sans: "SBB", "Helvetica Neue", Helvetica, Arial;
97+
--font-cjk-sans:
98+
"Source Han Sans HC", "Source Han Sans K", "Noto Sans CJK KR", "Source Han Sans SC", "Noto Sans CJK SC",
99+
"Source Han Sans", "Noto Sans CJK JP", "Source Han Sans TC", "Noto Sans CJK TC", "Noto Sans KR", "Noto Sans SC",
100+
"Noto Sans TC";
103101
}
104102

105103
.dark {
@@ -193,13 +191,26 @@
193191
}
194192
}
195193

196-
/* Language-specific font styles */
194+
:lang(zh-HK) {
195+
font-family: var(--font-sans), var(--font-cjk-sans), sans-serif, sans-serif;
196+
/* Not yet enabled:
197+
font-language-override: "KOR"; */
198+
}
199+
197200
:lang(zh-Latn),
198201
:lang(zh-Cyrl) {
199-
font-family: "Charis SIL", serif;
202+
font-family: "Charis SIL", var(--font-cjk-sans), sans-serif, sans-serif;
200203
font-style: italic;
201204
}
202205

203206
:lang(zh-Latn-fonipa) {
204207
font-style: normal;
205208
}
209+
210+
:lang(zh-Phag) {
211+
font-family: "Noto Sans PhagsPa", var(--font-sans), var(--font-cjk-sans), sans-serif, sans-serif;
212+
}
213+
214+
:lang(zh-Nshu) {
215+
font-family: "Noto Traditional Nushu", var(--font-sans), var(--font-cjk-sans), sans-serif, sans-serif;
216+
}

src/app/layout.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ export default function RootLayout({
3333
return (
3434
<html lang="zh-HK">
3535
<head>
36+
<link rel="preconnect" href="https://fonts.googleapis.com" />
37+
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
38+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Noto+Sans+PhagsPa&display=swap" />
3639
<link
3740
rel="stylesheet"
3841
href="https://cdn.jsdelivr.net/gh/nushu-script/NotoTraditionalNushu@woff-v1.0/index.css"

src/components/Query.tsx

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
"use client";
22

3-
import React from "react";
3+
import React, { useState, useMemo } from "react";
44

55
import { queryCharacters } from "@/lib/api";
66
import { buildTableRows, parse特殊語言字音 } from "@/lib/dataProcessor";
77
import { CharacterResultItem, ProcessedLanguage, TableRow, UserSettings } from "@/types";
8-
import { useState, useEffect } from "react";
98
import { useApp } from "@/contexts/AppContext";
109
import { getTranslation } from "@/lib/i18n";
1110
import LanguageDetailModal from "@/components/LanguageDetailModal";
@@ -52,6 +51,16 @@ const SpecialCharReadingFragments = ({
5251
);
5352
};
5453

54+
function renderTextWithStrong(text: string) {
55+
const parts = text.split("*");
56+
return <>{parts.map((part, index) => (index % 2 === 1 ? <strong key={index}>{part}</strong> : part))}</>;
57+
}
58+
59+
// TODO: This is a workaround. Fix this in the backend instead.
60+
const removeSpaceBetweenTwoChineseChars = (text: string): string => {
61+
return text.replace(/(?<=[\u4e00-\u9fff])\s+(?=[\u4e00-\u9fff])/g, "");
62+
};
63+
5564
const CharReadingBox = ({
5665
字音,
5766
langAbbr,
@@ -64,6 +73,7 @@ const CharReadingBox = ({
6473
settings: UserSettings;
6574
}) => {
6675
const isSpecialLanguage = langAbbr === "廣韻" || langAbbr === "中原音韻" || langAbbr === "東干甘肅話";
76+
const is八思巴字 = langAbbr === "蒙古字韻";
6777
const is女書 = langAbbr === "江永上江墟";
6878

6979
if (typeof 字音 === "string") {
@@ -101,8 +111,10 @@ const CharReadingBox = ({
101111
<span lang="zh-Latn-fonipa">{音標}</span>
102112
)}
103113
{注釋 && (
104-
<span lang={is女書 ? "zh-Nshu" : "zh-HK"} className="ml-1 text-xs text-muted-foreground">
105-
{注釋}
114+
<span
115+
lang={is女書 ? "zh-Nshu" : is八思巴字 ? "zh-Phag" : "zh-HK"}
116+
className="ml-1 text-xs text-muted-foreground">
117+
{renderTextWithStrong(removeSpaceBetweenTwoChineseChars(注釋))}
106118
</span>
107119
)}
108120
</div>
@@ -130,7 +142,6 @@ const Query = () => {
130142
setQueryResults: setContextQueryResults,
131143
} = useApp();
132144
const t = getTranslation(language);
133-
const [tableRows, setTableRows] = useState<TableRow[]>([]);
134145
const [isQuerying, setIsQuerying] = useState(false);
135146
const [error, setError] = useState<string | null>(null);
136147
const [hasQueried, setHasQueried] = useState(!!contextQueryResults);
@@ -147,11 +158,6 @@ const Query = () => {
147158
const response = await queryCharacters(queryInput.trim());
148159
const results = response.data;
149160
setContextQueryResults(results);
150-
151-
// Build table rows
152-
const rows = buildTableRows(results, processedLanguages, settings.selectedLanguages);
153-
console.log("Table rows built:", rows.length);
154-
setTableRows(rows);
155161
} catch (err) {
156162
// Show specific error message
157163
if (err instanceof Error) {
@@ -171,12 +177,11 @@ const Query = () => {
171177
}
172178
};
173179

174-
// Rebuild table rows when contextQueryResults or settings change
175-
useEffect(() => {
176-
if (contextQueryResults && contextQueryResults.length > 0) {
177-
const rows = buildTableRows(contextQueryResults, processedLanguages, settings.selectedLanguages);
178-
setTableRows(rows);
180+
const tableRows = useMemo(() => {
181+
if (contextQueryResults === null) {
182+
return null;
179183
}
184+
return buildTableRows(contextQueryResults, processedLanguages, settings.selectedLanguages);
180185
}, [contextQueryResults, processedLanguages, settings.selectedLanguages]);
181186

182187
return (
@@ -206,7 +211,7 @@ const Query = () => {
206211
</div>
207212

208213
{/* Results Table Section */}
209-
{contextQueryResults !== null && tableRows.length > 0 && (
214+
{contextQueryResults !== null && tableRows !== null && tableRows.length > 0 && (
210215
<div className="p-4 flex justify-center">
211216
<div className="overflow-x-auto shadow-sm">
212217
<table className="border-collapse border border-border bg-card">

0 commit comments

Comments
 (0)