refactor: remove emoji icons and normalize dashes in client UI.
This commit is contained in:
@@ -13,7 +13,7 @@ async function safeFetch(url, options = {}) {
|
|||||||
try {
|
try {
|
||||||
res = await fetch(url, options);
|
res = await fetch(url, options);
|
||||||
} catch (networkErr) {
|
} catch (networkErr) {
|
||||||
const err = new Error(`Network error — is the server running? (${networkErr.message})`);
|
const err = new Error(`Network error - is the server running? (${networkErr.message})`);
|
||||||
err.cause = networkErr;
|
err.cause = networkErr;
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,9 +86,7 @@ export default function StandardModal({ standard, onClose }) {
|
|||||||
ref={closeBtnRef}
|
ref={closeBtnRef}
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
aria-label={t("modal.closeLabel")}
|
aria-label={t("modal.closeLabel")}
|
||||||
>
|
/>
|
||||||
✕
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Standard detail */}
|
{/* Standard detail */}
|
||||||
@@ -128,7 +126,6 @@ export default function StandardModal({ standard, onClose }) {
|
|||||||
{/* AI chat panel */}
|
{/* AI chat panel */}
|
||||||
<div className="modal-section ai-panel" aria-label={t("modal.askAI")}>
|
<div className="modal-section ai-panel" aria-label={t("modal.askAI")}>
|
||||||
<p className="modal-section-title">
|
<p className="modal-section-title">
|
||||||
<span className="ai-label-icon" aria-hidden="true">✦</span>
|
|
||||||
{t("modal.askAI")}
|
{t("modal.askAI")}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -136,15 +133,11 @@ export default function StandardModal({ standard, onClose }) {
|
|||||||
<div className="chat-log" aria-live="polite" aria-label={t("modal.conversation")}>
|
<div className="chat-log" aria-live="polite" aria-label={t("modal.conversation")}>
|
||||||
{messages.map((m, i) => (
|
{messages.map((m, i) => (
|
||||||
<div key={i} className={`chat-bubble chat-bubble--${m.role}`}>
|
<div key={i} className={`chat-bubble chat-bubble--${m.role}`}>
|
||||||
{m.role === "ai" && (
|
|
||||||
<span className="bubble-label" aria-label={t("modal.aiResponse")}>✦</span>
|
|
||||||
)}
|
|
||||||
<p className="bubble-text">{m.text}</p>
|
<p className="bubble-text">{m.text}</p>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
{asking && (
|
{asking && (
|
||||||
<div className="chat-bubble chat-bubble--ai chat-bubble--loading" aria-label={t("modal.aiThinking")}>
|
<div className="chat-bubble chat-bubble--ai chat-bubble--loading" aria-label={t("modal.aiThinking")}>
|
||||||
<span className="bubble-label" aria-hidden="true">✦</span>
|
|
||||||
<span className="typing-dots">
|
<span className="typing-dots">
|
||||||
<span /><span /><span />
|
<span /><span /><span />
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -4,33 +4,6 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { fetchCategories } from "../api/standards";
|
import { fetchCategories } from "../api/standards";
|
||||||
import "./Categories.css";
|
import "./Categories.css";
|
||||||
|
|
||||||
const CATEGORY_ICONS = {
|
|
||||||
"Adhesives": "🧲",
|
|
||||||
"Bitumen and Tar Products": "🛣️",
|
|
||||||
"Builder's Hardware": "🔩",
|
|
||||||
"Building Limes": "🪨",
|
|
||||||
"Cement and Concrete": "🏗️",
|
|
||||||
"Concrete Reinforcement": "⚙️",
|
|
||||||
"Doors, Windows and Shutters": "🚪",
|
|
||||||
"Electrical Installations": "⚡",
|
|
||||||
"Floor, Wall, Roof Coverings and Finishes": "🏛️",
|
|
||||||
"Gypsum Building Materials": "🏺",
|
|
||||||
"Light Metal and Their Alloys": "🔧",
|
|
||||||
"Paints, Varnishes and Allied Products": "🎨",
|
|
||||||
"Pipes and Fittings": "🔧",
|
|
||||||
"Sanitary Appliances and Water Fittings": "🚿",
|
|
||||||
"Stones": "🪨",
|
|
||||||
"Structural Shapes": "📐",
|
|
||||||
"Structural Steels": "🏗️",
|
|
||||||
"Thermal Insulation Materials": "🌡️",
|
|
||||||
"Threaded Fasteners and Rivets": "🔩",
|
|
||||||
"Timber": "🪵",
|
|
||||||
"Water Proofing and Damp Proofing Materials": "💧",
|
|
||||||
"Welding Electrodes and Wires": "🔌",
|
|
||||||
"Wire Ropes and Wire Products": "🪢",
|
|
||||||
"Wood Products": "🪵",
|
|
||||||
"Wood Products for Building": "🏠",
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function Categories() {
|
export default function Categories() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -76,9 +49,6 @@ export default function Categories() {
|
|||||||
role="listitem"
|
role="listitem"
|
||||||
onClick={() => navigate(`/standards?category=${encodeURIComponent(cat.name)}`)}
|
onClick={() => navigate(`/standards?category=${encodeURIComponent(cat.name)}`)}
|
||||||
>
|
>
|
||||||
<span className="cat-page-icon" aria-hidden="true">
|
|
||||||
{CATEGORY_ICONS[cat.name] || "📋"}
|
|
||||||
</span>
|
|
||||||
<span className="cat-page-name">{cat.name}</span>
|
<span className="cat-page-name">{cat.name}</span>
|
||||||
<span className="cat-page-count">{t("categories.standardCount", { count: cat.count })}</span>
|
<span className="cat-page-count">{t("categories.standardCount", { count: cat.count })}</span>
|
||||||
<span className="cat-page-arrow" aria-hidden="true">→</span>
|
<span className="cat-page-arrow" aria-hidden="true">→</span>
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ export default function Home() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const PILLARS = [
|
const PILLARS = [
|
||||||
{ icon: "⚡", titleKey: "home.pillar_instantRetrieval_title", bodyKey: "home.pillar_instantRetrieval_body" },
|
{ titleKey: "home.pillar_instantRetrieval_title", bodyKey: "home.pillar_instantRetrieval_body" },
|
||||||
{ icon: "📐", titleKey: "home.pillar_sectionDetail_title", bodyKey: "home.pillar_sectionDetail_body" },
|
{ titleKey: "home.pillar_sectionDetail_title", bodyKey: "home.pillar_sectionDetail_body" },
|
||||||
{ icon: "🗂", titleKey: "home.pillar_categories_title", bodyKey: "home.pillar_categories_body" },
|
{ titleKey: "home.pillar_categories_title", bodyKey: "home.pillar_categories_body" },
|
||||||
{ icon: "🔒", titleKey: "home.pillar_officialSource_title", bodyKey: "home.pillar_officialSource_body" },
|
{ titleKey: "home.pillar_officialSource_title", bodyKey: "home.pillar_officialSource_body" },
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -116,9 +116,8 @@ export default function Home() {
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div className="feature-pillars" role="list">
|
<div className="feature-pillars" role="list">
|
||||||
{PILLARS.map(({ icon, titleKey, bodyKey }) => (
|
{PILLARS.map(({ titleKey, bodyKey }) => (
|
||||||
<div className="pillar" role="listitem" key={titleKey}>
|
<div className="pillar" role="listitem" key={titleKey}>
|
||||||
<span className="pillar-icon" aria-hidden="true">{icon}</span>
|
|
||||||
<h3 className="pillar-title">{t(titleKey)}</h3>
|
<h3 className="pillar-title">{t(titleKey)}</h3>
|
||||||
<p className="pillar-body">{t(bodyKey)}</p>
|
<p className="pillar-body">{t(bodyKey)}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -128,8 +128,8 @@ export default function Recommend() {
|
|||||||
{loading && (
|
{loading && (
|
||||||
<div className="loading-state" aria-label={t("common.loading")}>
|
<div className="loading-state" aria-label={t("common.loading")}>
|
||||||
<div className="loading-steps">
|
<div className="loading-steps">
|
||||||
<LoadingStep icon="🔍" label={t("recommend.loadingRetrieval")} />
|
<LoadingStep label={t("recommend.loadingRetrieval")} />
|
||||||
<LoadingStep icon="✦" label={t("recommend.loadingAI")} delay />
|
<LoadingStep label={t("recommend.loadingAI")} delay />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -232,10 +232,9 @@ function LatencyBadge({ label, ms, accent, bold }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function LoadingStep({ icon, label, delay }) {
|
function LoadingStep({ label, delay }) {
|
||||||
return (
|
return (
|
||||||
<div className={`loading-step${delay ? " loading-step--delay" : ""}`}>
|
<div className={`loading-step${delay ? " loading-step--delay" : ""}`}>
|
||||||
<span className="loading-step-icon" aria-hidden="true">{icon}</span>
|
|
||||||
<span>{label}</span>
|
<span>{label}</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -251,7 +250,7 @@ function SearchIcon() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function SpinIcon() {
|
function SpinIcon() {
|
||||||
return <span className="spin-icon" aria-hidden="true">⟳</span>;
|
return <span className="spin-icon" aria-hidden="true" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function standardsFullRecord(s) {
|
function standardsFullRecord(s) {
|
||||||
|
|||||||
@@ -98,9 +98,7 @@ export default function Standards() {
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={handleClearSearch}
|
onClick={handleClearSearch}
|
||||||
aria-label={t("standards.clearSearch")}
|
aria-label={t("standards.clearSearch")}
|
||||||
>
|
/>
|
||||||
✕
|
|
||||||
</button>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="filter-row">
|
<div className="filter-row">
|
||||||
@@ -131,7 +129,7 @@ export default function Standards() {
|
|||||||
{loading
|
{loading
|
||||||
? t("standards.searching")
|
? t("standards.searching")
|
||||||
: t("standards.found", { count: meta.total })}
|
: t("standards.found", { count: meta.total })}
|
||||||
{!loading && meta.total > 0 && ` — ${t("standards.page", { page: meta.page, total: meta.totalPages })}`}
|
{!loading && meta.total > 0 && ` -- ${t("standards.page", { page: meta.page, total: meta.totalPages })}`}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user