diff --git a/src/components/advanced/AdvancedTools.tsx b/src/components/advanced/AdvancedTools.tsx index 48c7814..f0daed0 100644 --- a/src/components/advanced/AdvancedTools.tsx +++ b/src/components/advanced/AdvancedTools.tsx @@ -45,22 +45,22 @@ export function AdvancedTools() { diff --git a/src/components/gallery/FamilyModal.tsx b/src/components/gallery/FamilyModal.tsx index 4004d7d..2f8d220 100644 --- a/src/components/gallery/FamilyModal.tsx +++ b/src/components/gallery/FamilyModal.tsx @@ -6,6 +6,7 @@ import { Button } from '../ui/Button'; import { useFamilyExpressions } from '../../hooks/useFamilies'; import type { MineralFamily, MineralExpression } from '../../lib/db'; import { sanitizeSvg } from '../../lib/sanitize-svg'; +import { formatLabel } from '../../lib/format-label'; import { clsx } from 'clsx'; interface FamilyModalProps { @@ -297,7 +298,7 @@ export function FamilyModal({ family, onClose }: FamilyModalProps) { {family.growth_method && (
Growth Method - {family.growth_method.replace(/_/g, ' ')} + {formatLabel(family.growth_method)}
)} {family.manufacturer && ( diff --git a/src/components/gallery/FilterBar.tsx b/src/components/gallery/FilterBar.tsx index 8510ac5..4f3ce33 100644 --- a/src/components/gallery/FilterBar.tsx +++ b/src/components/gallery/FilterBar.tsx @@ -57,7 +57,12 @@ export function FilterBar({
+ onSearchChange(e.target.value)} diff --git a/src/components/identification/HardnessReference.tsx b/src/components/identification/HardnessReference.tsx index 11c553d..b13344a 100644 --- a/src/components/identification/HardnessReference.tsx +++ b/src/components/identification/HardnessReference.tsx @@ -243,7 +243,7 @@ export function HardnessReference() { href="/learn/fundamentals/physical-properties" className="text-amber-600 hover:text-amber-700 underline" > - Learn more about hardness, toughness, and gem durability → + Learn more about hardness, toughness, and gem durability
diff --git a/src/components/lab/ChelseaFilter.tsx b/src/components/lab/ChelseaFilter.tsx index 1144570..c6809fc 100644 --- a/src/components/lab/ChelseaFilter.tsx +++ b/src/components/lab/ChelseaFilter.tsx @@ -196,7 +196,7 @@ export function ChelseaFilter() { href="/learn/equipment/other-tools" className="text-crystal-700 hover:text-crystal-700 underline" > - Learn more about the Chelsea filter and its limitations → + Learn more about the Chelsea filter and its limitations
diff --git a/src/components/lab/HeavyLiquidReference.tsx b/src/components/lab/HeavyLiquidReference.tsx index 3c2d87c..e378b59 100644 --- a/src/components/lab/HeavyLiquidReference.tsx +++ b/src/components/lab/HeavyLiquidReference.tsx @@ -242,7 +242,7 @@ export function HeavyLiquidReference() { href="/learn/equipment/other-tools" className="text-crystal-700 hover:text-crystal-700 underline" > - Learn more about heavy liquids and SG measurement → + Learn more about heavy liquids and SG measurement diff --git a/src/components/lab/SpectroscopeCalculator.tsx b/src/components/lab/SpectroscopeCalculator.tsx index 0ed495a..4c6a8a2 100644 --- a/src/components/lab/SpectroscopeCalculator.tsx +++ b/src/components/lab/SpectroscopeCalculator.tsx @@ -195,7 +195,7 @@ export function SpectroscopeCalculator() { href="/learn/equipment/spectroscope" className="text-crystal-700 hover:text-crystal-700 underline" > - Learn spectroscope technique and absorption spectrum interpretation → + Learn spectroscope technique and absorption spectrum interpretation diff --git a/src/components/layout/Footer.astro b/src/components/layout/Footer.astro index 348f0fa..d22b0eb 100644 --- a/src/components/layout/Footer.astro +++ b/src/components/layout/Footer.astro @@ -101,7 +101,7 @@ const showPackages = path.startsWith('/docs'); © {currentYear} gemmology.dev. Code under MIT, content under CC BY-SA 4.0.

- Built for the FGA community + Built for the FGA community

diff --git a/src/components/minerals/CounterpartsSection.astro b/src/components/minerals/CounterpartsSection.astro index a4cec4b..e945674 100644 --- a/src/components/minerals/CounterpartsSection.astro +++ b/src/components/minerals/CounterpartsSection.astro @@ -5,6 +5,7 @@ */ import type { Mineral } from '../../lib/db-server'; import { cleanCrystalSvg, isValidSvg } from '../../lib/svg-utils'; +import { formatLabel } from '../../lib/format-label'; interface Props { /** The current mineral being viewed */ @@ -21,6 +22,10 @@ const isNatural = !mineral.origin || mineral.origin === 'natural'; const hasCounterparts = counterparts.length > 0; const hasNaturalCounterpart = !!naturalCounterpart; +// Strip the parenthetical expression label (e.g. "Diamond (Octahedron)" → "Diamond") +// — synthetics list is family-scoped, so the expression name is misleading. +const familyName = mineral.name.replace(/\s*\([^)]*\)\s*$/, '').trim(); + // Don't render if nothing to show if (!hasCounterparts && !hasNaturalCounterpart) return; @@ -39,7 +44,7 @@ const originStyles: Record = {

{isNatural - ? `Known synthetic and simulant versions of ${mineral.name}` + ? `Known synthetic and simulant versions of ${familyName}` : `The natural gem this ${mineral.origin} imitates` }

@@ -79,7 +84,7 @@ const originStyles: Record = { {cp.growth_method && ( -
{cp.growth_method.replace(/_/g, ' ')}
+
{formatLabel(cp.growth_method)}
)} @@ -140,7 +145,7 @@ const originStyles: Record = { href="/gallery?origin=synthetic" class="text-sm text-sky-600 hover:text-sky-700 font-medium" > - View all synthetic gems → + View all synthetic gems )} diff --git a/src/components/minerals/RelatedMinerals.astro b/src/components/minerals/RelatedMinerals.astro index c5d20ca..f997e96 100644 --- a/src/components/minerals/RelatedMinerals.astro +++ b/src/components/minerals/RelatedMinerals.astro @@ -68,7 +68,7 @@ const { minerals, currentSystem } = Astro.props; href={`/gallery?system=${currentSystem.toLowerCase()}`} class="text-sm text-sky-600 hover:text-sky-700 font-medium" > - View all {currentSystem} minerals → + View all {currentSystem} minerals diff --git a/src/components/optical/DichroscopeResults.tsx b/src/components/optical/DichroscopeResults.tsx index ea39f3b..230c892 100644 --- a/src/components/optical/DichroscopeResults.tsx +++ b/src/components/optical/DichroscopeResults.tsx @@ -221,7 +221,7 @@ export function DichroscopeResults() { href="/learn/equipment/dichroscope" className="text-purple-600 hover:text-purple-700 underline" > - Learn dichroscope technique and see full pleochroism reference → + Learn dichroscope technique and see full pleochroism reference diff --git a/src/components/optical/OpticalTools.tsx b/src/components/optical/OpticalTools.tsx index b0ce3c2..cb79e4f 100644 --- a/src/components/optical/OpticalTools.tsx +++ b/src/components/optical/OpticalTools.tsx @@ -53,17 +53,17 @@ export function OpticalTools() { diff --git a/src/components/quiz/QuizPage.tsx b/src/components/quiz/QuizPage.tsx index 2665df9..03bc5e4 100644 --- a/src/components/quiz/QuizPage.tsx +++ b/src/components/quiz/QuizPage.tsx @@ -46,9 +46,9 @@ export function QuizPage({ learnEntries }: QuizPageProps) {
-

Quiz

+

Practice and Exam Mode

- Test your gemmology knowledge with questions from the learn content. + 756 questions across all FGA subject areas. Practise at your own pace, or sit a timed mock exam.

diff --git a/src/components/tools/ToolsHub.tsx b/src/components/tools/ToolsHub.tsx index 35b9843..760117a 100644 --- a/src/components/tools/ToolsHub.tsx +++ b/src/components/tools/ToolsHub.tsx @@ -67,7 +67,7 @@ export function ToolsHub() {

Tools

- Professional gemmological tools for calculations, conversions, and reference. + Calculators for the bench: SG by hydrostatic weighing, RI lookup, birefringence, critical angle, carat estimation, and unit conversion — alongside dichroscope, polariscope, and Chelsea-filter references.

diff --git a/src/lib/format-label.ts b/src/lib/format-label.ts new file mode 100644 index 0000000..22d4506 --- /dev/null +++ b/src/lib/format-label.ts @@ -0,0 +1,18 @@ +const ACRONYMS = new Set([ + 'CVD', 'HPHT', 'FTIR', 'HPLC', 'GIA', 'FGA', 'AGTA', + 'EDXRF', 'XRF', 'EDS', 'SEM', 'UV', 'IR', 'NIR', + 'YAG', 'GGG', 'CZ', 'IGI', 'AGS', 'SSEF', 'GRS', +]); + +export function formatLabel(value: string | null | undefined): string { + if (!value) return ''; + return value + .replace(/_/g, ' ') + .split(' ') + .map((word) => { + const upper = word.toUpperCase(); + if (ACRONYMS.has(upper)) return upper; + return word.charAt(0).toUpperCase() + word.slice(1); + }) + .join(' '); +} diff --git a/src/pages/404.astro b/src/pages/404.astro index 26010d2..b39d304 100644 --- a/src/pages/404.astro +++ b/src/pages/404.astro @@ -12,7 +12,7 @@ const { familyCount } = await getSiteStats(); const popularPages = [ { title: 'Crystal Gallery', href: '/gallery', description: `Explore ${familyCount} mineral crystal structures` }, { title: 'Learn Gemmology', href: '/learn', description: 'FGA curriculum and educational content' }, - { title: 'CDL Playground', href: '/playground', description: 'Interactive crystal visualization' }, + { title: 'Quiz', href: '/quiz', description: 'Practice and exam-mode questions across the FGA syllabus' }, { title: 'Documentation', href: '/docs', description: 'API reference and guides' }, ]; --- @@ -32,11 +32,11 @@ const popularPages = [

Lost in the lattice

- The page you're looking for doesn't exist or has been moved. Try one of the routes below or head back to the gallery. + This page doesn't crystallise. The URL you followed doesn't correspond to a known structure — it may have been moved or never existed.

- +
diff --git a/src/pages/gallery/index.astro b/src/pages/gallery/index.astro index 46290b1..09e2892 100644 --- a/src/pages/gallery/index.astro +++ b/src/pages/gallery/index.astro @@ -18,7 +18,7 @@ const initialOrigin = url.searchParams.get('origin') || ''; // Always point to base gallery URL as canonical to prevent duplicate content from filters const canonicalURL = 'https://gemmology.dev/gallery'; -const { familyCount } = await getSiteStats(); +const { familyCount, expressionCount } = await getSiteStats(); // SSG-fetch families + filter dropdowns at build time so the gallery first // paint does not block on sql.js + the 8 MB minerals.db. The wasm DB only @@ -33,14 +33,14 @@ const [initialFamilies, initialSystems, initialOrigins, initialGroups] = await P
= {

- Identify gems with - confidence + Crystal morphology, + rendered precisely.

- Study, practise, and reason about coloured gemstones with an open - FGA-aligned toolkit: a {familyCount}-mineral reference gallery, - interactive crystal morphology, gemmological calculators, and a - timed exam mode. + {familyCount} minerals with FGA-accurate crystallographic data, rendered live from open-source code. + Study, practise, and reason about coloured gemstones — gallery, calculators, quiz, and timed exam included.