@exegia/corpora-ui 0.26.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-lib/components/icons/__tests__/icons.test.d.ts +1 -0
- package/dist-lib/components/icons/file-badge-cfm.d.ts +7 -0
- package/dist-lib/components/icons/file-badge-corpus.d.ts +7 -0
- package/dist-lib/components/icons/file-badge-pdf.d.ts +7 -0
- package/dist-lib/components/icons/file-badge-tei.d.ts +7 -0
- package/dist-lib/components/icons/file-badge-tf.d.ts +7 -0
- package/dist-lib/components/icons/file-badge-txt.d.ts +7 -0
- package/dist-lib/components/icons/file-badge-xml.d.ts +7 -0
- package/dist-lib/components/icons/file-wordmark-cfm.d.ts +7 -0
- package/dist-lib/components/icons/file-wordmark-corpus.d.ts +7 -0
- package/dist-lib/components/icons/file-wordmark-pdf.d.ts +7 -0
- package/dist-lib/components/icons/file-wordmark-tei.d.ts +7 -0
- package/dist-lib/components/icons/file-wordmark-tf.d.ts +7 -0
- package/dist-lib/components/icons/file-wordmark-txt.d.ts +7 -0
- package/dist-lib/components/icons/file-wordmark-xml.d.ts +7 -0
- package/dist-lib/components/icons/index.d.ts +15 -0
- package/dist-lib/components/icons/types.d.ts +7 -0
- package/dist-lib/index.d.ts +1 -0
- package/dist-lib/index.js +8201 -995
- package/dist-lib/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/icons/README.md +91 -0
- package/src/components/icons/__tests__/icons.test.tsx +58 -0
- package/src/components/icons/file-badge-cfm.tsx +615 -0
- package/src/components/icons/file-badge-corpus.tsx +604 -0
- package/src/components/icons/file-badge-pdf.tsx +570 -0
- package/src/components/icons/file-badge-tei.tsx +524 -0
- package/src/components/icons/file-badge-tf.tsx +620 -0
- package/src/components/icons/file-badge-txt.tsx +607 -0
- package/src/components/icons/file-badge-xml.tsx +576 -0
- package/src/components/icons/file-wordmark-cfm.tsx +424 -0
- package/src/components/icons/file-wordmark-corpus.tsx +454 -0
- package/src/components/icons/file-wordmark-pdf.tsx +470 -0
- package/src/components/icons/file-wordmark-tei.tsx +424 -0
- package/src/components/icons/file-wordmark-tf.tsx +406 -0
- package/src/components/icons/file-wordmark-txt.tsx +421 -0
- package/src/components/icons/file-wordmark-xml.tsx +424 -0
- package/src/components/icons/index.ts +16 -0
- package/src/components/icons/types.ts +8 -0
- package/src/index.ts +3 -0
package/package.json
CHANGED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Corpora file icons
|
|
2
|
+
|
|
3
|
+
Fourteen React SVG components covering seven file formats in two visual families.
|
|
4
|
+
Every icon carries **both** a light and a dark artwork layer and picks one with
|
|
5
|
+
Tailwind's `dark` variant — no props, no context, no JavaScript.
|
|
6
|
+
|
|
7
|
+
Generated from `exegia-prod.sketch` → page `icons`, then simplified (dead defs
|
|
8
|
+
removed, light/dark-identical defs shared, ids stripped). Do not hand-edit the
|
|
9
|
+
`.tsx` files; regenerate them from Sketch instead (see
|
|
10
|
+
[Regenerating](#regenerating)).
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { FileBadgeTei, FileWordmarkPdf } from '@/components/icons';
|
|
16
|
+
|
|
17
|
+
<FileBadgeTei /> // 64×64, follows the app's dark class
|
|
18
|
+
<FileBadgeTei size={128} /> // any size
|
|
19
|
+
<FileWordmarkPdf title={null} /> // decorative: aria-hidden, no accessible name
|
|
20
|
+
<FileBadgeTei title="TEI source file" /> // custom accessible name
|
|
21
|
+
<FileBadgeTei className="shrink-0" /> // merged with the internal class
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
All remaining props are forwarded to the root `<svg>`.
|
|
25
|
+
|
|
26
|
+
## Components
|
|
27
|
+
|
|
28
|
+
| Format | Badge | Wordmark |
|
|
29
|
+
| --- | --- | --- |
|
|
30
|
+
| TEI | `FileBadgeTei` | `FileWordmarkTei` |
|
|
31
|
+
| XML | `FileBadgeXml` | `FileWordmarkXml` |
|
|
32
|
+
| TXT | `FileBadgeTxt` | `FileWordmarkTxt` |
|
|
33
|
+
| TF | `FileBadgeTf` | `FileWordmarkTf` |
|
|
34
|
+
| CFM | `FileBadgeCfm` | `FileWordmarkCfm` |
|
|
35
|
+
| PDF | `FileBadgePdf` | `FileWordmarkPdf` |
|
|
36
|
+
| Corpus | `FileBadgeCorpus` | `FileWordmarkCorpus` |
|
|
37
|
+
|
|
38
|
+
**Badge** — colour-coded pill overlapping the left edge of the sheet.
|
|
39
|
+
**Wordmark** — `.EXT` set along the bottom of the sheet.
|
|
40
|
+
|
|
41
|
+
## Theming
|
|
42
|
+
|
|
43
|
+
Each icon renders two `<g data-theme-layer>` groups and shows exactly one via
|
|
44
|
+
Tailwind's `dark` variant: the light layer is `dark:hidden`, the dark layer
|
|
45
|
+
`hidden dark:inline`. Whatever drives `dark:` in the app drives the icons —
|
|
46
|
+
here that is `@custom-variant dark (&:is(.dark *))` in `index.css`, so the
|
|
47
|
+
icons follow the `.dark` class exactly like every other component, with no
|
|
48
|
+
inline stylesheet and no media query of their own.
|
|
49
|
+
|
|
50
|
+
To force a theme on one subtree, scope the class:
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
<div className="dark">
|
|
54
|
+
<FileBadgeTei /> {/* dark artwork regardless of the app theme */}
|
|
55
|
+
</div>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Because the switch is pure CSS it is SSR-safe and cannot flash the wrong theme
|
|
59
|
+
on hydration. The `data-theme-layer` attributes stay on the groups as styling
|
|
60
|
+
and test hooks.
|
|
61
|
+
|
|
62
|
+
## Notes
|
|
63
|
+
|
|
64
|
+
- **Text is outlined.** Labels are vector paths, not live `<text>`, so the
|
|
65
|
+
icons do not depend on *TikTok Sans Display* being installed.
|
|
66
|
+
- **IDs are namespaced** per component and per theme layer (`tei-badge-l-…`),
|
|
67
|
+
so gradients and filters never collide when several icons share a page.
|
|
68
|
+
Only referenced defs carry ids; decorative group ids were stripped.
|
|
69
|
+
- **Both layers ship in every component,** but defs that are identical in
|
|
70
|
+
both themes (sheet geometry, badge plates, label glyphs) exist once and are
|
|
71
|
+
referenced from both layers — a `<defs>` entry resolves regardless of which
|
|
72
|
+
layer it sits in, hidden or not. Theme-specific gradients and filters stay
|
|
73
|
+
per layer, so the two themes remain pixel-faithful to Sketch.
|
|
74
|
+
- **Filter regions were widened** to the SVG default (`-50% / 200%`). Sketch
|
|
75
|
+
exports tight regions such as `height="76.2%"` that clip real geometry in
|
|
76
|
+
spec-compliant renderers — the third sheet line disappears without this.
|
|
77
|
+
|
|
78
|
+
## Regenerating
|
|
79
|
+
|
|
80
|
+
1. In Sketch, edit the symbols on the `icons` page of `exegia-prod`.
|
|
81
|
+
2. Re-export each symbol to SVG, and export each label inside an exact-size
|
|
82
|
+
bounding box to PDF (the PDF round-trip is what outlines the type).
|
|
83
|
+
3. Run the generator, which splices the outlined labels into the SVG, namespaces
|
|
84
|
+
the IDs, widens the filter regions and emits the `.tsx` files.
|
|
85
|
+
4. Run `bun scripts/simplify-icons.mjs` (from `react/`), which swaps the layer
|
|
86
|
+
switching onto Tailwind's `dark` variant, drops dead and duplicated defs,
|
|
87
|
+
strips unreferenced ids and default-value attributes, and verifies that
|
|
88
|
+
every remaining `url(#…)` / `href="#…"` reference resolves.
|
|
89
|
+
|
|
90
|
+
Colours are driven by the `file/*` swatches in the Sketch document, so a palette
|
|
91
|
+
change there propagates to every symbol before export.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test"
|
|
2
|
+
import { render } from "@testing-library/react"
|
|
3
|
+
|
|
4
|
+
import * as icons from ".."
|
|
5
|
+
|
|
6
|
+
const components = Object.entries(icons).filter(
|
|
7
|
+
([name]) => name.startsWith("FileBadge") || name.startsWith("FileWordmark")
|
|
8
|
+
) as [string, (props: Record<string, unknown>) => React.ReactElement][]
|
|
9
|
+
|
|
10
|
+
describe("file icons", () => {
|
|
11
|
+
test("exports all fourteen components", () => {
|
|
12
|
+
expect(components).toHaveLength(14)
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
for (const [name, Icon] of components) {
|
|
16
|
+
test(`${name} renders both theme layers on Tailwind's dark variant`, () => {
|
|
17
|
+
const { container } = render(<Icon />)
|
|
18
|
+
const svg = container.querySelector("svg")
|
|
19
|
+
expect(svg?.getAttribute("width")).toBe("64")
|
|
20
|
+
expect(svg?.getAttribute("role")).toBe("img")
|
|
21
|
+
|
|
22
|
+
const light = svg?.querySelector('[data-theme-layer="light"]')
|
|
23
|
+
const dark = svg?.querySelector('[data-theme-layer="dark"]')
|
|
24
|
+
expect(light?.getAttribute("class")).toBe("dark:hidden")
|
|
25
|
+
expect(dark?.getAttribute("class")).toBe("hidden dark:inline")
|
|
26
|
+
// No inline stylesheet — switching belongs to the app's Tailwind build.
|
|
27
|
+
expect(svg?.querySelector("style")).toBeNull()
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
test(`${name}'s internal references all resolve`, () => {
|
|
31
|
+
const { container } = render(<Icon />)
|
|
32
|
+
const svg = container.querySelector("svg")!
|
|
33
|
+
const ids = new Set(
|
|
34
|
+
[...svg.querySelectorAll("[id]")].map((el) => el.getAttribute("id"))
|
|
35
|
+
)
|
|
36
|
+
const refs = [
|
|
37
|
+
...[...svg.querySelectorAll("use")].map((el) =>
|
|
38
|
+
el.getAttribute("href")?.slice(1)
|
|
39
|
+
),
|
|
40
|
+
...[...svg.outerHTML.matchAll(/url\(#([^)]+)\)/g)].map((m) => m[1]),
|
|
41
|
+
]
|
|
42
|
+
expect(refs.length).toBeGreaterThan(0)
|
|
43
|
+
for (const ref of refs) expect(ids.has(ref ?? "")).toBe(true)
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
test("title becomes the accessible name; null marks decorative", () => {
|
|
48
|
+
const named = render(<icons.FileBadgeTei title="TEI source" />)
|
|
49
|
+
expect(
|
|
50
|
+
named.container.querySelector("svg")?.getAttribute("aria-label")
|
|
51
|
+
).toBe("TEI source")
|
|
52
|
+
|
|
53
|
+
const decorative = render(<icons.FileWordmarkPdf title={null} />)
|
|
54
|
+
const svg = decorative.container.querySelector("svg")
|
|
55
|
+
expect(svg?.getAttribute("role")).toBe("presentation")
|
|
56
|
+
expect(svg?.getAttribute("aria-hidden")).toBe("true")
|
|
57
|
+
})
|
|
58
|
+
})
|