diff --git a/.gitignore b/.gitignore index ecdef5b..066147b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,6 @@ -static \ No newline at end of file +node_modules/ +.next/ +out/ +next-env.d.ts +tsconfig.tsbuildinfo +.DS_Store diff --git a/README.md b/README.md new file mode 100644 index 0000000..4e9f378 --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +# latex2js.com + +The website for [LaTeX2JS](https://github.com/Mathapedia/LaTeX2JS) — author interactive math equations and diagrams online using LaTeX and PSTricks. + +Built with Next.js (static export) on the same architecture as [constructive.io](https://constructive.io) and [danlynch.com](https://danlynch.com): + +- **JSON-LD knowledge graph** — `src/data/jsonld/` holds a flat graph of schema.org entities with namespaced `@id`s (`software:latex2js`, `org:constructive`, `person:danlynch`, …) shared across the site family. Pages slice per-page subgraphs via `jsonldjs` and the `
` component injects them as `application/ld+json`. +- **SEO registry** — `src/seo.ts` holds per-route titles/descriptions; canonicals are derived from typed routes. +- **Sitemap + robots.txt** — generated post-build from the exported HTML by `src/seo/seo.ts`. +- **llms.txt + markdown twins** — `scripts/generate-llm-markdown.ts` emits `out/llms.txt` and a `.md` twin for every example and installation page. +- **Content as data** — the interactive PSTricks examples live as `.tex` files in `content/examples/`, registered in `src/data/examples.ts`, and rendered client-side by [`@latex2js/react`](https://www.npmjs.com/package/@latex2js/react). + +## Develop + +```bash +pnpm install +pnpm dev # http://localhost:5007 +pnpm test # JSON-LD graph validation + registry tests +``` + +## Build & deploy + +```bash +pnpm build # next build + llms.txt/md twins + sitemap/robots into out/ +pnpm deploy:all # build, sync to s3://latex2js.com, extensionless copies, CloudFront invalidation +``` diff --git a/__tests__/helpers/jsonld-test-utils.ts b/__tests__/helpers/jsonld-test-utils.ts new file mode 100644 index 0000000..cee5100 --- /dev/null +++ b/__tests__/helpers/jsonld-test-utils.ts @@ -0,0 +1,97 @@ +/** + * JSON-LD Test Utilities + * + * Helper functions for testing JSON-LD output. + * Snapshots are kept lean by extracting only @id and @type properties. + */ + +import { type JsonLdGraph, type JsonLdEntity } from 'jsonldjs'; + +/** + * Extract only @id properties from entities for lean snapshots + */ +export function extractIds(entities: JsonLdEntity[]): string[] { + return entities + .map((e) => e['@id']) + .filter((id): id is string => typeof id === 'string') + .sort(); +} + +/** + * Extract @id and @type for more detailed snapshots + */ +export function extractIdsAndTypes(entities: JsonLdEntity[]): { id: string; type: string | string[] }[] { + return entities + .map((e) => ({ + id: e['@id'], + type: e['@type'] as string | string[], + })) + .filter((e): e is { id: string; type: string | string[] } => typeof e.id === 'string') + .sort((a, b) => a.id.localeCompare(b.id)); +} + +/** + * Group entities by @type + */ +export function groupByType(entities: JsonLdEntity[]): Record', - claim: () => '
Be sure to checkout the example apps on Github here!
-
-
-Be sure to checkout the example apps on Github here!
-
-
- Be sure to checkout the example apps on Github here!
-
-
-
- This project is the frontend only version of the code that originated from Mathapedia to enable real-time, dynamic authorship of mathematical ebooks
- - - $$\frac{\delta}{\delta u} \int_{birth}^{death} f(life) du = \mbox{your life}$$ - -You will also find installation instructions here.
- -- Get inspired, and make sure you see the PSTricks examples here! -
- -- To get started, check out the example apps - on Github, or view source. Play in the sandbox here. -
- -There's also quite a bit of documentation here
- -- If you've built anything cool with LaTeX2JS, please share! -
- -You will also find installation instructions here.
- -- Get inspired, and make sure you see the PSTricks examples here! -
- -- To get started, check out the example apps - on Github, or view source. Play in the sandbox here. -
- -There's also quite a bit of documentation here
- -- If you've built anything cool with LaTeX2JS, please share! -
- -
-
-
-
-
- Proud to support the best! Click below to find the installation for your favorite library/framework:
- -
- Vue Installation
-
-
- React Installation
-
-
- HTML5 Installation
-
-
-
-
-
-
-
-
-
+ {code}
+
+ );
+}
diff --git a/src/components/common/head.tsx b/src/components/common/head.tsx
new file mode 100644
index 0000000..e4e30d2
--- /dev/null
+++ b/src/components/common/head.tsx
@@ -0,0 +1,64 @@
+import NextHead from 'next/head';
+import { createJsonLdBuilder, type JsonLdConfig } from 'jsonldjs';
+import { NextSeo } from 'next-seo';
+
+import { seoConfig } from '@/seo';
+import { siteConfig } from '@/config';
+
+interface HeadProps {
+ title: string;
+ description: string;
+ route: `/${string}`;
+ images?: {
+ url: string;
+ alt: string;
+ width?: number;
+ height?: number;
+ }[];
+ noindex?: boolean;
+ nofollow?: boolean;
+ canonicalUrl?: string;
+ jsonLdConfig?: JsonLdConfig;
+}
+
+export function Head({
+ title,
+ description,
+ route,
+ images,
+ nofollow = false,
+ noindex = false,
+ canonicalUrl = '',
+ jsonLdConfig,
+}: HeadProps) {
+ const defaultCanonical = `${siteConfig.site.canonical}${route}`;
+
+ const graph = {
+ ...seoConfig.openGraph,
+ images: images || seoConfig.openGraph.images,
+ url: defaultCanonical,
+ title,
+ description,
+ };
+
+ const jsonLdContent = jsonLdConfig ? createJsonLdBuilder().mergeConfig(jsonLdConfig).build() : null;
+
+ return (
+ <>
+ This page could not be found.
++ + Back to LaTeX2JS + +
++ + ← All examples + +
+{example.description}
+ {example.interactive && ( ++ This diagram is interactive — use your mouse or touch to play with it. +
+ )} + ++ Interactive PSTricks diagrams rendered live in the browser by LaTeX2JS — each with its LaTeX source. Be sure to + check out the{' '} + + example apps on GitHub + + ! +
+ +{example.description}
+ {example.interactive && ( +Interactive
+ )} + ++ Author interactive math equations and diagrams online using LaTeX and PSTricks +
++ This project is the frontend-only version of the code that originated from{' '} + + Mathapedia + {' '} + to enable real-time, dynamic authorship of mathematical ebooks. +
+Proud to support the best
++ Install LaTeX2JS for{' '} + + React + + ,{' '} + + Vue + + , or{' '} + + plain HTML5 + + . +
++ Get inspired, and make sure you see{' '} + + the PSTricks examples here + + ! +
++ Check out the{' '} + + example apps on GitHub + + , or play in the{' '} + + sandbox + + . +
++ There is also quite a bit of documentation{' '} + + here + + . +
++ + ← All installation guides + +
+ ++ {index + 1}. {step.text} +
+ {step.code && ( ++ LaTeX2JS ships adapters for the frameworks you already use. Pick yours: +
+ ++ Write LaTeX and PSTricks, then render it live. Powered by LaTeX2JS and MathJax. +
+ + + + ++ The source has a syntax error; showing the last valid render. +
+ )} + {rendered ? ( + /* Remount on each render so LaTeX2JS reprocesses the new source. */ ++ The preview appears here and updates as you type — start from an{' '} + + example + {' '} + if you'd like something to take apart. +
+ )} +