From 0652aa19eab54a335ee6dd9c66ae811e162a54c3 Mon Sep 17 00:00:00 2001 From: Atul Varma Date: Sun, 14 Feb 2021 12:32:55 -0500 Subject: [PATCH] Add rudimentary about page. --- lib/browser-main.tsx | 274 +++++----------------------------- lib/pages/about-page.tsx | 8 + lib/pages/vocabulary-page.tsx | 241 ++++++++++++++++++++++++++++++ 3 files changed, 290 insertions(+), 233 deletions(-) create mode 100644 lib/pages/about-page.tsx create mode 100644 lib/pages/vocabulary-page.tsx diff --git a/lib/browser-main.tsx b/lib/browser-main.tsx index a1cb536..54e8ab8 100644 --- a/lib/browser-main.tsx +++ b/lib/browser-main.tsx @@ -1,252 +1,60 @@ -import React, { useState } from "react"; +import React from "react"; import ReactDOM from "react-dom"; -import { Point, BBox } from "../vendor/bezier-js"; -import { dilateBoundingBox, getBoundingBoxSize } from "./bounding-box"; -import { FILL_REPLACEMENT_COLOR, STROKE_REPLACEMENT_COLOR } from "./colors"; -import * as colors from "./colors"; -import { PointWithNormal, Specs } from "./specs"; +import { AboutPage } from "./pages/about-page"; +import { VocabularyPage } from "./pages/vocabulary-page"; -import _SvgVocabulary from "./svg-vocabulary.json"; -import type { SvgSymbolData, SvgSymbolElement } from "./vocabulary"; +const Pages = { + vocabulary: VocabularyPage, + about: AboutPage, +}; + +type PageName = keyof typeof Pages; + +const pageNames = Object.keys(Pages) as PageName[]; const APP_ID = "app"; const appEl = document.getElementById(APP_ID); -const SvgVocabulary: SvgSymbolData[] = _SvgVocabulary as any; - if (!appEl) { throw new Error(`Unable to find #${APP_ID}!`); } -type SvgSymbolContext = { - stroke: string; - fill: string; - showSpecs: boolean; -}; - -type SvgSymbolProps = { - data: SvgSymbolData; - scale?: number; -} & SvgSymbolContext; - -const px = (value: number) => `${value}px`; - -function getColor( - ctx: SvgSymbolContext, - color: string | undefined -): string | undefined { - switch (color) { - case STROKE_REPLACEMENT_COLOR: - return ctx.stroke; - case FILL_REPLACEMENT_COLOR: - return ctx.fill; - } - return color; -} - -function reactifySvgSymbolElement( - ctx: SvgSymbolContext, - el: SvgSymbolElement, - key: number -): JSX.Element { - let { fill, stroke } = el.props; - fill = getColor(ctx, fill); - stroke = getColor(ctx, stroke); - return React.createElement( - el.tagName, - { - ...el.props, - id: undefined, - fill, - stroke, - key, - }, - el.children.map(reactifySvgSymbolElement.bind(null, ctx)) - ); -} - -const ATTACHMENT_POINT_RADIUS = 20; - -const ATTACHMENT_POINT_NORMAL_LENGTH = 50; - -const ATTACHMENT_POINT_NORMAL_STROKE = 4; - -const AttachmentPoints: React.FC<{ - color: string; - points: PointWithNormal[]; -}> = (props) => ( - <> - {props.points.map((pwn, i) => { - const { x, y } = pwn.point; - const x2 = x + pwn.normal.x * ATTACHMENT_POINT_NORMAL_LENGTH; - const y2 = y + pwn.normal.y * ATTACHMENT_POINT_NORMAL_LENGTH; - return ( - - - - - ); - })} - -); - -const BoundingBoxes: React.FC<{ fill: string; bboxes: BBox[] }> = (props) => ( - <> - {props.bboxes.map((b, i) => { - const [width, height] = getBoundingBoxSize(b); - return ( - - ); - })} - -); - -const SvgSymbolSpecs: React.FC<{ specs: Specs }> = ({ specs }) => { - return ( - <> - {specs.tail && ( - - )} - {specs.leg && ( - - )} - {specs.arm && ( - - )} - {specs.horn && ( - - )} - {specs.crown && ( - - )} - {specs.nesting && ( - - )} - - ); -}; - -const BBOX_DILATION = 50; - -const SvgSymbol: React.FC = (props) => { - const d = props.data; - const bbox = dilateBoundingBox(d.bbox, BBOX_DILATION); - const scale = props.scale || 1; - const [width, height] = getBoundingBoxSize(bbox); - - return ( - - {props.data.layers.map(reactifySvgSymbolElement.bind(null, props))} - {props.showSpecs && d.specs && } - - ); -}; - -const App: React.FC<{}> = () => { - const [stroke, setStroke] = useState("#000000"); - const [fill, setFill] = useState("#ffffff"); - const [showSpecs, setShowSpecs] = useState(false); +const App: React.FC<{}> = (props) => { + const page = new URLSearchParams(window.location.search); + const currPageName = toPageName(page.get("p") || "", "vocabulary"); + const PageComponent = Pages[currPageName]; return ( <> -

Mystic Symbolic Vocabulary

-

- - setStroke(e.target.value)} - id="stroke" - />{" "} - - setFill(e.target.value)} - id="fill" - />{" "} - -

- {SvgVocabulary.map((symbolData) => ( -
-
- {symbolData.name} -
-
- -
-
- ))} +
+ +
+
+

Other pages

+
    + {pageNames.map((pageName) => ( +
  • + {currPageName === pageName ? ( + pageName + ) : ( + {pageName} + )} +
  • + ))} +
+
); }; ReactDOM.render(, appEl); + +function isPageName(page: string): page is PageName { + return pageNames.includes(page as any); +} + +function toPageName(page: string, defaultValue: PageName): PageName { + if (isPageName(page)) return page; + return defaultValue; +} diff --git a/lib/pages/about-page.tsx b/lib/pages/about-page.tsx new file mode 100644 index 0000000..5eb89a1 --- /dev/null +++ b/lib/pages/about-page.tsx @@ -0,0 +1,8 @@ +import React from "react"; + +export const AboutPage: React.FC<{}> = () => ( + <> +

About

+

This is an about page.

+ +); diff --git a/lib/pages/vocabulary-page.tsx b/lib/pages/vocabulary-page.tsx new file mode 100644 index 0000000..933741e --- /dev/null +++ b/lib/pages/vocabulary-page.tsx @@ -0,0 +1,241 @@ +import React, { useState } from "react"; +import { BBox } from "../../vendor/bezier-js"; +import { dilateBoundingBox, getBoundingBoxSize } from "../bounding-box"; +import { FILL_REPLACEMENT_COLOR, STROKE_REPLACEMENT_COLOR } from "../colors"; +import * as colors from "../colors"; +import { PointWithNormal, Specs } from "../specs"; + +import _SvgVocabulary from "../svg-vocabulary.json"; +import type { SvgSymbolData, SvgSymbolElement } from "../vocabulary"; + +const SvgVocabulary: SvgSymbolData[] = _SvgVocabulary as any; + +type SvgSymbolContext = { + stroke: string; + fill: string; + showSpecs: boolean; +}; + +type SvgSymbolProps = { + data: SvgSymbolData; + scale?: number; +} & SvgSymbolContext; + +const px = (value: number) => `${value}px`; + +function getColor( + ctx: SvgSymbolContext, + color: string | undefined +): string | undefined { + switch (color) { + case STROKE_REPLACEMENT_COLOR: + return ctx.stroke; + case FILL_REPLACEMENT_COLOR: + return ctx.fill; + } + return color; +} + +function reactifySvgSymbolElement( + ctx: SvgSymbolContext, + el: SvgSymbolElement, + key: number +): JSX.Element { + let { fill, stroke } = el.props; + fill = getColor(ctx, fill); + stroke = getColor(ctx, stroke); + return React.createElement( + el.tagName, + { + ...el.props, + id: undefined, + fill, + stroke, + key, + }, + el.children.map(reactifySvgSymbolElement.bind(null, ctx)) + ); +} + +const ATTACHMENT_POINT_RADIUS = 20; + +const ATTACHMENT_POINT_NORMAL_LENGTH = 50; + +const ATTACHMENT_POINT_NORMAL_STROKE = 4; + +const AttachmentPoints: React.FC<{ + color: string; + points: PointWithNormal[]; +}> = (props) => ( + <> + {props.points.map((pwn, i) => { + const { x, y } = pwn.point; + const x2 = x + pwn.normal.x * ATTACHMENT_POINT_NORMAL_LENGTH; + const y2 = y + pwn.normal.y * ATTACHMENT_POINT_NORMAL_LENGTH; + return ( + + + + + ); + })} + +); + +const BoundingBoxes: React.FC<{ fill: string; bboxes: BBox[] }> = (props) => ( + <> + {props.bboxes.map((b, i) => { + const [width, height] = getBoundingBoxSize(b); + return ( + + ); + })} + +); + +const SvgSymbolSpecs: React.FC<{ specs: Specs }> = ({ specs }) => { + return ( + <> + {specs.tail && ( + + )} + {specs.leg && ( + + )} + {specs.arm && ( + + )} + {specs.horn && ( + + )} + {specs.crown && ( + + )} + {specs.nesting && ( + + )} + + ); +}; + +const BBOX_DILATION = 50; + +const SvgSymbol: React.FC = (props) => { + const d = props.data; + const bbox = dilateBoundingBox(d.bbox, BBOX_DILATION); + const scale = props.scale || 1; + const [width, height] = getBoundingBoxSize(bbox); + + return ( + + {props.data.layers.map(reactifySvgSymbolElement.bind(null, props))} + {props.showSpecs && d.specs && } + + ); +}; + +export const VocabularyPage: React.FC<{}> = () => { + const [stroke, setStroke] = useState("#000000"); + const [fill, setFill] = useState("#ffffff"); + const [showSpecs, setShowSpecs] = useState(false); + + return ( + <> +

Mystic Symbolic Vocabulary

+

+ + setStroke(e.target.value)} + id="stroke" + />{" "} + + setFill(e.target.value)} + id="fill" + />{" "} + +

+ {SvgVocabulary.map((symbolData) => ( +
+
+ {symbolData.name} +
+
+ +
+
+ ))} + + ); +};