--- import * as ArticleMod from '../content/article.mdx'; import Hero from '../components/Hero.astro'; import Footer from '../components/Footer.astro'; import ThemeToggle from '../components/ThemeToggle.astro'; import Seo from '../components/Seo.astro'; import TableOfContents from '../components/TableOfContents.astro'; // Default OG image served from public/ const ogDefaultUrl = '/thumb.auto.jpg'; import 'katex/dist/katex.min.css'; import '../styles/global.css'; const articleFM = (ArticleMod as any).frontmatter ?? {}; const Article = (ArticleMod as any).default; // Clean version without
for metadata, SEO, citations const docTitle = (articleFM?.title ?? 'Untitled article') .replace(//gi, ' ') .replace(/\\n/g, ' ') .replace(/\n/g, ' ') .replace(/\s+/g, ' ') .trim(); // HTML version with
for Hero H1 display only const docTitleHtml = (articleFM?.title ?? 'Untitled article') .replace(/\\n/g, '
') .replace(/\n/g, '
'); const subtitle = articleFM?.subtitle ?? ''; const description = articleFM?.description ?? ''; // Accept authors as string[] or array of objects { name, url, affiliations? } const rawAuthors = (articleFM as any)?.authors ?? []; type Affiliation = { id: number; name: string; url?: string }; type Author = { name: string; url?: string; affiliationIndices?: number[] }; // Normalize affiliations from frontmatter: supports strings or objects { id?, name, url? } const rawAffils = (articleFM as any)?.affiliations ?? (articleFM as any)?.affiliation ?? []; const normalizedAffiliations: Affiliation[] = (() => { const seen: Map = new Map(); const list: Affiliation[] = []; const pushUnique = (name: string, url?: string) => { const key = `${String(name).trim()}|${url ? String(url).trim() : ''}`; if (seen.has(key)) return seen.get(key)!; const id = list.length + 1; list.push({ id, name: String(name).trim(), url: url ? String(url) : undefined }); seen.set(key, id); return id; }; const input = Array.isArray(rawAffils) ? rawAffils : (rawAffils ? [rawAffils] : []); for (const a of input) { if (typeof a === 'string') { pushUnique(a); } else if (a && typeof a === 'object') { const name = a.name ?? a.label ?? a.text ?? a.affiliation ?? ''; if (!String(name).trim()) continue; const url = a.url || a.link; // Respect provided numeric id for display stability if present and sequential; otherwise reassign pushUnique(String(name), url ? String(url) : undefined); } } return list; })(); // Helper: ensure an affiliation exists and return its id const ensureAffiliation = (val: any): number | undefined => { if (val == null) return undefined; if (typeof val === 'number' && Number.isFinite(val) && val > 0) { return Math.floor(val); } const name = typeof val === 'string' ? val : (val?.name ?? val?.label ?? val?.text ?? val?.affiliation); if (!name || !String(name).trim()) return undefined; const existing = normalizedAffiliations.find(a => a.name === String(name).trim()); if (existing) return existing.id; const id = normalizedAffiliations.length + 1; normalizedAffiliations.push({ id, name: String(name).trim(), url: val?.url || val?.link }); return id; }; // Normalize authors and map affiliations -> indices (Distill-like) const normalizedAuthors: Author[] = (Array.isArray(rawAuthors) ? rawAuthors : []) .map((a: any) => { if (typeof a === 'string') { return { name: a } as Author; } const name = String(a?.name || '').trim(); const url = a?.url || a?.link; let indices: number[] | undefined = undefined; const raw = a?.affiliations ?? a?.affiliation ?? a?.affils; if (raw != null) { const entries = Array.isArray(raw) ? raw : [raw]; const ids = entries.map(ensureAffiliation).filter((x): x is number => typeof x === 'number'); const unique = Array.from(new Set(ids)).sort((x, y) => x - y); if (unique.length) indices = unique; } return { name, url, affiliationIndices: indices } as Author; }) .filter((a: Author) => a.name && a.name.trim().length > 0); const authorNames: string[] = normalizedAuthors.map(a => a.name); const published = articleFM?.published ?? undefined; const tags = articleFM?.tags ?? []; // Prefer seoThumbImage from frontmatter if provided const fmOg = articleFM?.seoThumbImage as string | undefined; const imageAbs: string = fmOg && fmOg.startsWith('http') ? fmOg : (Astro.site ? new URL((fmOg ?? ogDefaultUrl), Astro.site).toString() : (fmOg ?? ogDefaultUrl)); // ---- Build citation text & BibTeX from frontmatter ---- const stripHtml = (text: string) => String(text || '').replace(/<[^>]*>/g, ''); // Use docTitle (already cleaned) and strip any remaining HTML for BibTeX const titleFlat = stripHtml(docTitle); const extractYear = (val: string | undefined): number | undefined => { if (!val) return undefined; const d = new Date(val); if (!Number.isNaN(d.getTime())) return d.getFullYear(); const m = String(val).match(/(19|20)\d{2}/); return m ? Number(m[0]) : undefined; }; const year = extractYear(published); const citationAuthorsText = authorNames.join(', '); const citationText = `${citationAuthorsText}${year ? ` (${year})` : ''}. "${titleFlat}".`; const authorsBib = authorNames.join(' and '); const keyAuthor = (authorNames[0] || 'article').split(/\s+/).slice(-1)[0].toLowerCase(); const keyTitle = titleFlat.toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_|_$/g, ''); const bibKey = `${keyAuthor}${year ?? ''}_${keyTitle}`; const doi = (ArticleMod as any)?.frontmatter?.doi ? String((ArticleMod as any).frontmatter.doi) : undefined; // Extract arXiv information from DOI if it's an arXiv URL const extractArxivInfo = (doiStr: string | undefined) => { if (!doiStr) return { eprint: undefined, primaryClass: undefined }; // Check if it's an arXiv URL (like https://arxiv.org/abs/2510.17269) const arxivMatch = doiStr.match(/arxiv\.org\/(?:abs|pdf)\/(\d{4}\.\d+)(?:v\d+)?/); if (arxivMatch) { return { eprint: arxivMatch[1], primaryClass: 'cs.CV' // You mentioned primaryClass={cs.CV} in your request }; } return { eprint: undefined, primaryClass: undefined }; }; const { eprint: arxivEprint, primaryClass: arxivClass } = extractArxivInfo(doi); // Build BibTeX with proper formatting let bibtexFields = [ `title={${titleFlat}}`, `author={${authorsBib}}` ]; if (year) bibtexFields.push(`year={${year}}`); if (doi) bibtexFields.push(`doi={${doi}}`); if (arxivEprint) { bibtexFields.push(`eprint={${arxivEprint}}`); bibtexFields.push(`archivePrefix={arXiv}`); bibtexFields.push(`primaryClass={${arxivClass}}`); } const bibtex = `@misc{${bibKey},\n ${bibtexFields.join(',\n ')}\n}`; const envCollapse = false; const tableOfContentAutoCollapse = Boolean( (articleFM as any)?.tableOfContentAutoCollapse ?? (articleFM as any)?.tableOfContentsAutoCollapse ?? envCollapse ); // Licence note (HTML allowed) const licence = (articleFM as any)?.licence ?? (articleFM as any)?.license ?? (articleFM as any)?.licenseNote; ---