diff --git a/src/pages/learn/[...slug].astro b/src/pages/learn/[...slug].astro index 3f06c00..e8ae66b 100644 --- a/src/pages/learn/[...slug].astro +++ b/src/pages/learn/[...slug].astro @@ -14,11 +14,21 @@ import type { WidgetQuestion } from '../../components/quiz/study/LearnQuizWidget import { buildCitationIndex } from '../../lib/citations/index'; export async function getStaticPaths() { + // Slugs handled by static hub pages under src/pages/learn/. Excluding them here + // prevents a duplicate-route build error; the article content still lives in + // the collection and is referenced by the corresponding hub (e.g. Hub 5). + // Declared inside getStaticPaths because Astro hoists this function into its + // own module scope and outer consts are not accessible. + const STATIC_HUB_SLUGS = new Set([ + 'identification/treatments', + ]); const entries = await getCollection('learn'); - return entries.map(entry => ({ - params: { slug: entry.id }, - props: { entry, allEntries: entries }, - })); + return entries + .filter((entry) => !STATIC_HUB_SLUGS.has(entry.id)) + .map((entry) => ({ + params: { slug: entry.id }, + props: { entry, allEntries: entries }, + })); } interface Props { diff --git a/src/pages/learn/equipment/index.astro b/src/pages/learn/equipment/index.astro new file mode 100644 index 0000000..1bccd0e --- /dev/null +++ b/src/pages/learn/equipment/index.astro @@ -0,0 +1,277 @@ +--- +import { getCollection } from 'astro:content'; +import BaseLayout from '../../../layouts/BaseLayout.astro'; +import { Card, CardTitle, CardDescription } from '../../../components/ui/Card'; +import { IconBox } from '../../../components/ui/IconBox'; +import { Container } from '../../../components/ui/Container'; +import { DifficultyBadge } from '../../../components/ui/DifficultyBadge'; +import { Breadcrumb } from '../../../components/docs'; + +const learnEntries = await getCollection('learn'); + +interface EquipmentTopic { + id: string; + title: string; + description: string; + href: string; + difficulty?: 'beginner' | 'intermediate' | 'advanced'; +} + +const equipmentTopics: EquipmentTopic[] = learnEntries + .filter((e) => e.data.category === 'equipment') + .map((e) => ({ + id: e.id, + title: e.data.title, + description: e.data.description, + href: `/learn/${e.id}`, + difficulty: e.data.difficulty as EquipmentTopic['difficulty'], + })) + .sort((a, b) => { + if (a.id === 'equipment/overview') return -1; + if (b.id === 'equipment/overview') return 1; + if (a.id === 'equipment/refractometer') return -1; + if (b.id === 'equipment/refractometer') return 1; + return a.title.localeCompare(b.title); + }); + +const learningResourceSchema = { + '@context': 'https://schema.org', + '@type': 'LearningResource', + name: 'How to Use a Refractometer and Other Gemstone Testing Equipment', + alternateName: [ + 'Gemmological Equipment Guide', + 'Refractometer Tutorial', + 'FGA Equipment Module', + ], + description: + 'Comprehensive guide to gemmological testing equipment: refractometer, polariscope, dichroscope, spectroscope, microscope, UV lamp, and advanced laboratory instruments.', + url: 'https://gemmology.dev/learn/equipment/', + learningResourceType: 'Guide', + educationalLevel: 'beginner', + inLanguage: 'en', + isAccessibleForFree: true, + audience: { + '@type': 'EducationalAudience', + educationalRole: 'student', + }, + about: [ + 'Refractometer operation', + 'Polariscope use', + 'Dichroscope use', + 'Spectroscope operation', + 'Gemmological microscope technique', + 'UV fluorescence inspection', + 'Specific gravity measurement', + ], + teaches: equipmentTopics.map((t) => t.title), + hasPart: equipmentTopics.map((t) => ({ + '@type': 'LearningResource', + name: t.title, + url: `https://gemmology.dev${t.href}/`, + learningResourceType: 'Article', + })), +}; + +const breadcrumbSchema = { + '@context': 'https://schema.org', + '@type': 'BreadcrumbList', + itemListElement: [ + { '@type': 'ListItem', position: 1, name: 'Home', item: 'https://gemmology.dev' }, + { '@type': 'ListItem', position: 2, name: 'Learn', item: 'https://gemmology.dev/learn/' }, + { + '@type': 'ListItem', + position: 3, + name: 'Equipment', + item: 'https://gemmology.dev/learn/equipment/', + }, + ], +}; + +const breadcrumbItems = [ + { label: 'Learn', href: '/learn' }, + { label: 'Equipment' }, +]; + +const refractometerRows = [ + { + step: 1, + instruction: 'Clean the prism with the supplied solvent and a soft tissue. Any residue affects the half-shadow boundary.', + }, + { + step: 2, + instruction: 'Apply one small drop of contact fluid (refractive index 1.79–1.81; di-iodomethane saturated with sulphur) directly to the prism.', + }, + { + step: 3, + instruction: 'Place the stone polished-table-side-down so it rests fully in the fluid. The table must lie flat — wedge thin stones with a small fluid pool.', + }, + { + step: 4, + instruction: 'View through the eyepiece under sodium (589 nm) or filtered white light. Adjust the eyepiece focus until the scale and shadow boundary are crisp.', + }, + { + step: 5, + instruction: 'Rotate the stone through 180° in 45° increments. Singly refractive stones show one stationary shadow; doubly refractive stones show two boundaries that move (the birefringence).', + }, + { + step: 6, + instruction: 'Record the highest and lowest readings to ±0.002. The difference is the birefringence; the midpoint is the spot reading.', + }, + { + step: 7, + instruction: 'Cabochons and rough surfaces use the spot method: a tiny droplet on the prism contacts only the dome. Read the point at which the bright field switches to dark.', + }, +]; + +const iconPaths: Record = { + microscope: + 'M9 3h6m-6 0v6m6-6v6m-3 0v3m0 0a6 6 0 100 12 6 6 0 000-12zm0 0V9m-3 12h6', + beaker: + 'M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z', +}; +--- + + +