@ghxstship/xos-icons 0.0.0-stage → 4.16.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/LICENSE +21 -0
- package/README.md +28 -2
- package/THIRD_PARTY_NOTICES +50 -0
- package/package.json +28 -4
- package/registry/a09.txt +5 -0
- package/registry/a128.txt +2 -0
- package/registry/a15.txt +14 -0
- package/registry/a35.txt +23 -0
- package/registry/a36.txt +2 -0
- package/registry/a61.txt +4 -0
- package/registry/assets.txt +11 -0
- package/registry/atlas.txt +38 -0
- package/registry/b3.txt +3 -0
- package/registry/gateway.txt +21 -0
- package/registry/logistics-hospitality.txt +9 -0
- package/registry/marketing.txt +7 -0
- package/registry/ui.txt +98 -0
- package/registry/views-help.txt +32 -0
- package/scripts/generate-registry.mjs +138 -0
- package/src/glyphs.ts +78 -0
- package/src/index.ts +8 -0
- package/src/map.json +71 -0
- package/src/names.generated.ts +227 -0
- package/src/names.ts +40 -0
- package/src/registry.generated.ts +452 -0
- package/src/registry.ts +24 -0
- package/src/sprite.d.ts +6 -0
- package/src/sprite.generated.svg +222 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 GHXSTSHIP Industries LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,29 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @ghxstship/xos-icons
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
XOS glyph map and icon registry: the Lucide icon for every department, phase and record kind, the record state glyph shapes, and the closed set of icons XOS draws by name.
|
|
4
|
+
|
|
5
|
+
This is `@xos/icons` from the Atlas repository at release v4.16.0, published under the `@ghxstship` scope.
|
|
6
|
+
The archive holds the package's TypeScript source as the release tag does.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
The source imports its sibling packages as `@xos/*`, so install it under its workspace name with an npm alias, at an exact version:
|
|
11
|
+
|
|
12
|
+
```json
|
|
13
|
+
{
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@xos/icons": "npm:@ghxstship/xos-icons@4.16.0"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Build
|
|
21
|
+
|
|
22
|
+
The package ships TypeScript, so the consuming build transpiles it.
|
|
23
|
+
|
|
24
|
+
- In Next.js, list both names of every installed package in `transpilePackages`, for example `"@xos/icons"` and `"@ghxstship/xos-icons"`. pnpm resolves an alias to the published name, so the alias alone is not enough.
|
|
25
|
+
- The source imports its own files with `.ts` and `.tsx` extensions, so the consumer's `tsconfig.json` sets `allowImportingTsExtensions` (with `noEmit` and bundler module resolution).
|
|
26
|
+
|
|
27
|
+
## License
|
|
28
|
+
|
|
29
|
+
MIT. See `LICENSE` and `THIRD_PARTY_NOTICES`.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
Third-party notices for @xos/icons
|
|
2
|
+
|
|
3
|
+
The icon sprite, the glyph registry and the icon components in this package draw icons from lucide-react 1.53.0.
|
|
4
|
+
Its license follows in full.
|
|
5
|
+
|
|
6
|
+
----------------------------------------------------------------------
|
|
7
|
+
|
|
8
|
+
ISC License
|
|
9
|
+
|
|
10
|
+
Copyright (c) 2026 Lucide Icons and Contributors
|
|
11
|
+
|
|
12
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
13
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
14
|
+
copyright notice and this permission notice appear in all copies.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
17
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
19
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
20
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
21
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
22
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
The following Lucide icons are derived from the Feather project:
|
|
27
|
+
|
|
28
|
+
airplay, alert-circle, alert-octagon, alert-triangle, aperture, arrow-down-circle, arrow-down-left, arrow-down-right, arrow-down, arrow-left-circle, arrow-left, arrow-right-circle, arrow-right, arrow-up-circle, arrow-up-left, arrow-up-right, arrow-up, at-sign, calendar, cast, check, chevron-down, chevron-left, chevron-right, chevron-up, chevrons-down, chevrons-left, chevrons-right, chevrons-up, circle, clipboard, clock, code, columns, command, compass, corner-down-left, corner-down-right, corner-left-down, corner-left-up, corner-right-down, corner-right-up, corner-up-left, corner-up-right, crosshair, database, divide-circle, divide-square, dollar-sign, download, external-link, feather, frown, hash, headphones, help-circle, info, italic, key, layout, life-buoy, link-2, link, loader, lock, log-in, log-out, maximize, meh, minimize, minimize-2, minus-circle, minus-square, minus, monitor, moon, more-horizontal, more-vertical, move, music, navigation-2, navigation, octagon, pause-circle, percent, plus-circle, plus-square, plus, power, radio, rss, search, server, share, shopping-bag, sidebar, smartphone, smile, square, table-2, tablet, target, terminal, trash-2, trash, triangle, tv, type, upload, x-circle, x-octagon, x-square, x, zoom-in, zoom-out
|
|
29
|
+
|
|
30
|
+
The MIT License (MIT) (for the icons listed above)
|
|
31
|
+
|
|
32
|
+
Copyright (c) 2013-present Cole Bemis
|
|
33
|
+
|
|
34
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
35
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
36
|
+
in the Software without restriction, including without limitation the rights
|
|
37
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
38
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
39
|
+
furnished to do so, subject to the following conditions:
|
|
40
|
+
|
|
41
|
+
The above copyright notice and this permission notice shall be included in all
|
|
42
|
+
copies or substantial portions of the Software.
|
|
43
|
+
|
|
44
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
45
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
46
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
47
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
48
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
49
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
50
|
+
SOFTWARE.
|
package/package.json
CHANGED
|
@@ -1,6 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ghxstship/xos-icons",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "4.16.0",
|
|
4
|
+
"description": "XOS glyph map and icon registry: the Lucide icon for every department, phase and record kind, the record state glyph shapes, and the closed set of icons XOS draws by name.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.ts",
|
|
9
|
+
"./glyphs": "./src/glyphs.ts",
|
|
10
|
+
"./names": "./src/names.ts",
|
|
11
|
+
"./sprite.svg": {
|
|
12
|
+
"types": "./src/sprite.d.ts",
|
|
13
|
+
"default": "./src/sprite.generated.svg"
|
|
14
|
+
},
|
|
15
|
+
"./map.json": "./src/map.json"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"lucide-react": "1.53.0"
|
|
19
|
+
},
|
|
20
|
+
"sideEffects": false,
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/ghxstship/atlas.git",
|
|
24
|
+
"directory": "packages/icons"
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public",
|
|
28
|
+
"provenance": false
|
|
29
|
+
}
|
|
30
|
+
}
|
package/registry/a09.txt
ADDED
package/registry/a15.txt
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Icons the Finance and Reports pages (A15) draw by name that no other registry lists: toolbar
|
|
2
|
+
# actions and empty states. One lucide-react name per line.
|
|
3
|
+
ArrowRightLeft
|
|
4
|
+
Banknote
|
|
5
|
+
ClipboardPaste
|
|
6
|
+
FilePlus2
|
|
7
|
+
FileSpreadsheet
|
|
8
|
+
Handshake
|
|
9
|
+
Package
|
|
10
|
+
BarChart3
|
|
11
|
+
Gauge
|
|
12
|
+
Grid3x3
|
|
13
|
+
ShoppingCart
|
|
14
|
+
FileCheck
|
package/registry/a35.txt
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Icons Atlas pages draw by name that were missing from the registry, so they rendered as blank
|
|
2
|
+
# boxes (A35, RRR-79): found by the accessibility sweep (Folder, ListPlus, ListVideo, Table2) and by a
|
|
3
|
+
# scan of every icon="..." prop in Atlas, Gateway and @xos/ui. One lucide-react name per line.
|
|
4
|
+
Award
|
|
5
|
+
CheckCircle2
|
|
6
|
+
CloudLightning
|
|
7
|
+
Copy
|
|
8
|
+
FileOutput
|
|
9
|
+
Filter
|
|
10
|
+
Folder
|
|
11
|
+
FolderOpen
|
|
12
|
+
LayoutTemplate
|
|
13
|
+
Link
|
|
14
|
+
ListPlus
|
|
15
|
+
ListVideo
|
|
16
|
+
PackageSearch
|
|
17
|
+
Palmtree
|
|
18
|
+
Scale
|
|
19
|
+
ScrollText
|
|
20
|
+
ShieldAlert
|
|
21
|
+
Siren
|
|
22
|
+
Table2
|
|
23
|
+
UserMinus
|
package/registry/a36.txt
ADDED
package/registry/a61.txt
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Icons the Atlas shell draws by name: sidebar items, chrome actions and shell states (A06).
|
|
2
|
+
Activity
|
|
3
|
+
BookOpen
|
|
4
|
+
Boxes
|
|
5
|
+
Briefcase
|
|
6
|
+
CalendarDays
|
|
7
|
+
ChartColumn
|
|
8
|
+
Circle
|
|
9
|
+
CircleCheck
|
|
10
|
+
CircleUserRound
|
|
11
|
+
Clapperboard
|
|
12
|
+
FileText
|
|
13
|
+
Folder
|
|
14
|
+
FolderKanban
|
|
15
|
+
GripVertical
|
|
16
|
+
HardHat
|
|
17
|
+
House
|
|
18
|
+
IdCard
|
|
19
|
+
Inbox
|
|
20
|
+
Landmark
|
|
21
|
+
Library
|
|
22
|
+
List
|
|
23
|
+
ListChecks
|
|
24
|
+
LogOut
|
|
25
|
+
MapPin
|
|
26
|
+
Menu
|
|
27
|
+
PackageCheck
|
|
28
|
+
Search
|
|
29
|
+
SearchX
|
|
30
|
+
Settings
|
|
31
|
+
ShieldCheck
|
|
32
|
+
ShoppingCart
|
|
33
|
+
Star
|
|
34
|
+
Store
|
|
35
|
+
Truck
|
|
36
|
+
UserRound
|
|
37
|
+
Users
|
|
38
|
+
UtensilsCrossed
|
package/registry/b3.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Icons the Gateway app draws by name that no other registry lists: destinations, engagement
|
|
2
|
+
# tabs, empty states and actions (A27). One lucide-react name per line.
|
|
3
|
+
ArrowLeftRight
|
|
4
|
+
BedDouble
|
|
5
|
+
BellPlus
|
|
6
|
+
BookmarkCheck
|
|
7
|
+
BriefcaseBusiness
|
|
8
|
+
CircleUser
|
|
9
|
+
FileBarChart
|
|
10
|
+
FileCheck
|
|
11
|
+
FileDiff
|
|
12
|
+
Flag
|
|
13
|
+
FolderLock
|
|
14
|
+
Gavel
|
|
15
|
+
Gift
|
|
16
|
+
ListMusic
|
|
17
|
+
ListOrdered
|
|
18
|
+
Mail
|
|
19
|
+
MailCheck
|
|
20
|
+
MessagesSquare
|
|
21
|
+
Receipt
|
package/registry/ui.txt
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Icons packages/ui draws by name: component chrome, feedback tones, pickers and the Icon aliases
|
|
2
|
+
# (more, alert, check-circle, pin, home, undo). Owner: A05. One lucide-react name per line.
|
|
3
|
+
# Canon glyphs (departments, phases, record kinds) come from src/map.json and are not repeated here.
|
|
4
|
+
AlarmClock
|
|
5
|
+
ArrowDown
|
|
6
|
+
ArrowLeft
|
|
7
|
+
ArrowRight
|
|
8
|
+
ArrowUp
|
|
9
|
+
ArrowUpRight
|
|
10
|
+
AudioLines
|
|
11
|
+
BadgeCheck
|
|
12
|
+
Bell
|
|
13
|
+
Bold
|
|
14
|
+
Bookmark
|
|
15
|
+
Building2
|
|
16
|
+
Calendar
|
|
17
|
+
CalendarClock
|
|
18
|
+
CalendarPlus
|
|
19
|
+
CalendarRange
|
|
20
|
+
ChartColumn
|
|
21
|
+
Check
|
|
22
|
+
ChevronDown
|
|
23
|
+
ChevronLeft
|
|
24
|
+
ChevronRight
|
|
25
|
+
ChevronsUpDown
|
|
26
|
+
Circle
|
|
27
|
+
CircleAlert
|
|
28
|
+
CircleCheck
|
|
29
|
+
CircleHelp
|
|
30
|
+
CircleX
|
|
31
|
+
Clock
|
|
32
|
+
Compass
|
|
33
|
+
Download
|
|
34
|
+
Ellipsis
|
|
35
|
+
ExternalLink
|
|
36
|
+
Eye
|
|
37
|
+
File
|
|
38
|
+
FileText
|
|
39
|
+
FolderKanban
|
|
40
|
+
Globe
|
|
41
|
+
Hash
|
|
42
|
+
House
|
|
43
|
+
Image
|
|
44
|
+
Inbox
|
|
45
|
+
Info
|
|
46
|
+
Italic
|
|
47
|
+
Landmark
|
|
48
|
+
LayoutGrid
|
|
49
|
+
LifeBuoy
|
|
50
|
+
Link2
|
|
51
|
+
List
|
|
52
|
+
ListFilter
|
|
53
|
+
Lock
|
|
54
|
+
Map
|
|
55
|
+
MapPin
|
|
56
|
+
Maximize2
|
|
57
|
+
Megaphone
|
|
58
|
+
Menu
|
|
59
|
+
MessageSquare
|
|
60
|
+
Minus
|
|
61
|
+
Navigation
|
|
62
|
+
OctagonAlert
|
|
63
|
+
Paperclip
|
|
64
|
+
Pencil
|
|
65
|
+
Play
|
|
66
|
+
Plus
|
|
67
|
+
Radio
|
|
68
|
+
RefreshCw
|
|
69
|
+
ScanLine
|
|
70
|
+
Search
|
|
71
|
+
SearchX
|
|
72
|
+
Send
|
|
73
|
+
Shapes
|
|
74
|
+
SlidersHorizontal
|
|
75
|
+
Sparkles
|
|
76
|
+
Star
|
|
77
|
+
Sun
|
|
78
|
+
SunMedium
|
|
79
|
+
Table
|
|
80
|
+
ThumbsUp
|
|
81
|
+
Trash2
|
|
82
|
+
TriangleAlert
|
|
83
|
+
Undo2
|
|
84
|
+
Upload
|
|
85
|
+
User
|
|
86
|
+
UserPlus
|
|
87
|
+
Wallet
|
|
88
|
+
WifiOff
|
|
89
|
+
ZoomIn
|
|
90
|
+
ZoomOut
|
|
91
|
+
Camera
|
|
92
|
+
Coffee
|
|
93
|
+
Flashlight
|
|
94
|
+
Nfc
|
|
95
|
+
PenLine
|
|
96
|
+
Phone
|
|
97
|
+
Smartphone
|
|
98
|
+
X
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Icons A31 (Views, Help and Support) draws by name: the saved views menu, the view registry's view
|
|
2
|
+
# types (packages/schemas/views.yaml), the help panel, tours, tips and support. One lucide-react name
|
|
3
|
+
# per line.
|
|
4
|
+
Bookmark
|
|
5
|
+
BookmarkPlus
|
|
6
|
+
CalendarRange
|
|
7
|
+
ChartColumn
|
|
8
|
+
ChartGantt
|
|
9
|
+
Columns3
|
|
10
|
+
Grid3x3
|
|
11
|
+
Inbox
|
|
12
|
+
LayoutGrid
|
|
13
|
+
List
|
|
14
|
+
ListTree
|
|
15
|
+
Map
|
|
16
|
+
MapPinned
|
|
17
|
+
Network
|
|
18
|
+
PanelLeft
|
|
19
|
+
Pin
|
|
20
|
+
PinOff
|
|
21
|
+
RefreshCw
|
|
22
|
+
Rss
|
|
23
|
+
Share2
|
|
24
|
+
Sheet
|
|
25
|
+
Table
|
|
26
|
+
Trash2
|
|
27
|
+
Users
|
|
28
|
+
ArrowLeft
|
|
29
|
+
BookOpen
|
|
30
|
+
CircleHelp
|
|
31
|
+
LifeBuoy
|
|
32
|
+
Play
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Writes src/names.generated.ts, src/registry.generated.ts and src/sprite.generated.svg: the closed set of lucide-react icons XOS draws by name, imported
|
|
3
|
+
* one by one so bundlers keep only these icons (RRR-70). Sources are every registry/<owner>.txt
|
|
4
|
+
* (one PascalCase lucide-react name per line, `#` starts a comment) plus every glyph in src/map.json.
|
|
5
|
+
* Each owner keeps its own list, so parallel branches never conflict in a shared file (ADR 0021);
|
|
6
|
+
* on a conflict in the generated file, rerun this script.
|
|
7
|
+
*
|
|
8
|
+
* Usage: node scripts/generate-registry.mjs [--check]
|
|
9
|
+
* With --check, writes nothing and exits 1 when the generated file is out of date or a name does
|
|
10
|
+
* not exist in the pinned lucide-react.
|
|
11
|
+
*/
|
|
12
|
+
import { readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
13
|
+
import { createRequire } from "node:module";
|
|
14
|
+
import { dirname, join } from "node:path";
|
|
15
|
+
import { fileURLToPath } from "node:url";
|
|
16
|
+
import * as prettier from "prettier";
|
|
17
|
+
|
|
18
|
+
const root = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
19
|
+
const lucide = createRequire(import.meta.url)("lucide-react");
|
|
20
|
+
|
|
21
|
+
const owners = new Map();
|
|
22
|
+
function add(name, owner) {
|
|
23
|
+
if (!owners.has(name)) owners.set(name, new Set());
|
|
24
|
+
owners.get(name).add(owner);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const map = JSON.parse(readFileSync(join(root, "src/map.json"), "utf8"));
|
|
28
|
+
for (const table of [map.departments, map.phases, map.recordKinds]) {
|
|
29
|
+
for (const name of Object.values(table)) add(name, "map.json");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const registryDir = join(root, "registry");
|
|
33
|
+
for (const file of readdirSync(registryDir)
|
|
34
|
+
.filter((f) => f.endsWith(".txt"))
|
|
35
|
+
.sort()) {
|
|
36
|
+
const lines = readFileSync(join(registryDir, file), "utf8").split(/\r?\n/);
|
|
37
|
+
for (const raw of lines) {
|
|
38
|
+
const name = raw.replace(/#.*/, "").trim();
|
|
39
|
+
if (name) add(name, file);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const problems = [];
|
|
44
|
+
for (const [name, from] of owners) {
|
|
45
|
+
const where = [...from].join(", ");
|
|
46
|
+
if (!/^[A-Z][A-Za-z0-9]*$/.test(name)) {
|
|
47
|
+
problems.push(`${name} (${where}) is not a PascalCase lucide-react name`);
|
|
48
|
+
} else if (name.startsWith("Lucide") || name.endsWith("Icon") || name === "Icon") {
|
|
49
|
+
problems.push(`${name} (${where}) is an alias form; list the base name`);
|
|
50
|
+
} else if (typeof lucide[name] !== "object" && typeof lucide[name] !== "function") {
|
|
51
|
+
problems.push(`${name} (${where}) does not exist in lucide-react ${map.library.version}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (problems.length > 0) {
|
|
55
|
+
console.error(`Icon registry has ${problems.length} invalid names:\n ${problems.join("\n ")}`);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const names = [...owners.keys()].sort();
|
|
60
|
+
const header = `/* Generated by scripts/generate-registry.mjs from registry/*.txt and src/map.json. Do not edit; run \`pnpm --filter @xos/icons generate:registry\`. */`;
|
|
61
|
+
|
|
62
|
+
const namesSource = `${header}
|
|
63
|
+
|
|
64
|
+
/** Every icon name XOS draws by name, sorted. Imports nothing, so a bundle that only checks names stays small. */
|
|
65
|
+
export const registeredIconNames = ${JSON.stringify(names)} as const;
|
|
66
|
+
|
|
67
|
+
export type RegisteredIconName = (typeof registeredIconNames)[number];
|
|
68
|
+
`;
|
|
69
|
+
|
|
70
|
+
const registrySource = `${header}
|
|
71
|
+
import type { LucideIcon } from "lucide-react";
|
|
72
|
+
import { ${names.map((n) => `${n} as Lucide${n}`).join(", ")} } from "lucide-react";
|
|
73
|
+
import { registeredIconNames, type RegisteredIconName } from "./names.generated.ts";
|
|
74
|
+
|
|
75
|
+
export { registeredIconNames, type RegisteredIconName };
|
|
76
|
+
|
|
77
|
+
/** The lucide-react component for each registered name. Only these icons reach a bundle. */
|
|
78
|
+
export const iconRegistry: Readonly<Record<RegisteredIconName, LucideIcon>> = /* @__PURE__ */ Object.freeze({ ${names
|
|
79
|
+
.map((n) => `${n}: Lucide${n}`)
|
|
80
|
+
.join(", ")} });
|
|
81
|
+
`;
|
|
82
|
+
|
|
83
|
+
/** XML attribute text: lucide's path data never needs more than these escapes. */
|
|
84
|
+
function attr(value) {
|
|
85
|
+
return String(value).replaceAll("&", "&").replaceAll('"', """).replaceAll("<", "<");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* The web icon sprite (ADR 0027): one <symbol> per registered icon, drawn from the same pinned
|
|
90
|
+
* lucide-react data as the components. Symbols carry only geometry, so the referencing <svg> sets
|
|
91
|
+
* stroke, size and color for each use.
|
|
92
|
+
*/
|
|
93
|
+
function symbol(name) {
|
|
94
|
+
const data = lucide[name].render({}, null).props.icon;
|
|
95
|
+
const size = data.size ?? 24;
|
|
96
|
+
const children = data.node
|
|
97
|
+
.map(([tag, attrs]) => {
|
|
98
|
+
const text = Object.entries(attrs)
|
|
99
|
+
.filter(([k]) => k !== "key")
|
|
100
|
+
.map(([k, v]) => ` ${k}="${attr(v)}"`)
|
|
101
|
+
.join("");
|
|
102
|
+
return `<${tag}${text}/>`;
|
|
103
|
+
})
|
|
104
|
+
.join("");
|
|
105
|
+
return `<symbol id="${name}" viewBox="0 0 ${size} ${size}">${children}</symbol>`;
|
|
106
|
+
}
|
|
107
|
+
// Width and height let Next.js read the file as a static image import; uses ignore them.
|
|
108
|
+
const sprite = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">\n${names.map(symbol).join("\n")}\n</svg>\n`;
|
|
109
|
+
|
|
110
|
+
const outputs = [];
|
|
111
|
+
for (const [file, source] of [
|
|
112
|
+
["src/names.generated.ts", namesSource],
|
|
113
|
+
["src/registry.generated.ts", registrySource],
|
|
114
|
+
]) {
|
|
115
|
+
const path = join(root, file);
|
|
116
|
+
const config = (await prettier.resolveConfig(path)) ?? {};
|
|
117
|
+
outputs.push([file, await prettier.format(source, { ...config, filepath: path })]);
|
|
118
|
+
}
|
|
119
|
+
outputs.push(["src/sprite.generated.svg", sprite]);
|
|
120
|
+
|
|
121
|
+
if (process.argv.includes("--check")) {
|
|
122
|
+
const stale = outputs.filter(([file, output]) => {
|
|
123
|
+
try {
|
|
124
|
+
return readFileSync(join(root, file), "utf8") !== output;
|
|
125
|
+
} catch {
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
if (stale.length > 0) {
|
|
130
|
+
console.error(
|
|
131
|
+
`${stale.map(([file]) => file).join(", ")} out of date. Run pnpm --filter @xos/icons generate:registry.`,
|
|
132
|
+
);
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
} else {
|
|
136
|
+
for (const [file, output] of outputs) writeFileSync(join(root, file), output);
|
|
137
|
+
console.log(`Wrote ${names.length} icons to the names, registry and sprite files in src/.`);
|
|
138
|
+
}
|
package/src/glyphs.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import map from "./map.json" with { type: "json" };
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* XOS glyph map (design handoff, section 2): the lucide-react icon for each department, phase and
|
|
5
|
+
* record kind, keyed by canon code, and the shape each record state draws. src/map.json is the
|
|
6
|
+
* single source; every Lucide name in it resolves in the pinned lucide-react.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export type DepartmentCode = keyof typeof map.departments;
|
|
10
|
+
export type PhaseCode = keyof typeof map.phases;
|
|
11
|
+
export type RecordKind = keyof typeof map.recordKinds;
|
|
12
|
+
export type RecordState = keyof typeof map.stateIcons;
|
|
13
|
+
|
|
14
|
+
/** A Lucide component name used by an XOS glyph, in PascalCase (`Hammer`). */
|
|
15
|
+
export type GlyphIconName =
|
|
16
|
+
| (typeof map.departments)[DepartmentCode]
|
|
17
|
+
| (typeof map.phases)[PhaseCode]
|
|
18
|
+
| (typeof map.recordKinds)[RecordKind];
|
|
19
|
+
|
|
20
|
+
/** The shape a record state icon draws. State icons are custom (StateIcon), not Lucide. */
|
|
21
|
+
export type StateGlyph = (typeof map.stateIcons)[RecordState];
|
|
22
|
+
|
|
23
|
+
/** Icon library facts the glyphs are drawn with: package, pinned version, license and stroke width. */
|
|
24
|
+
export const iconLibrary: Readonly<typeof map.library> = map.library;
|
|
25
|
+
|
|
26
|
+
export const departmentCodes = Object.keys(map.departments) as DepartmentCode[];
|
|
27
|
+
export const phaseCodes = Object.keys(map.phases) as PhaseCode[];
|
|
28
|
+
export const recordKinds = Object.keys(map.recordKinds) as RecordKind[];
|
|
29
|
+
export const recordStates = Object.keys(map.stateIcons) as RecordState[];
|
|
30
|
+
|
|
31
|
+
function has<T extends object>(table: T, key: string): key is Extract<keyof T, string> {
|
|
32
|
+
return Object.hasOwn(table, key);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function isDepartmentCode(value: string): value is DepartmentCode {
|
|
36
|
+
return has(map.departments, value);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function isPhaseCode(value: string): value is PhaseCode {
|
|
40
|
+
return has(map.phases, value);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function isRecordKind(value: string): value is RecordKind {
|
|
44
|
+
return has(map.recordKinds, value);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function isRecordState(value: string): value is RecordState {
|
|
48
|
+
return has(map.stateIcons, value);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Lucide icon for a department code (`"4000"` is Tent). */
|
|
52
|
+
export function departmentIcon(code: DepartmentCode): GlyphIconName {
|
|
53
|
+
return map.departments[code];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Lucide icon for a phase code (`"BLD"` is Hammer). */
|
|
57
|
+
export function phaseIcon(code: PhaseCode): GlyphIconName {
|
|
58
|
+
return map.phases[code];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Lucide icon for a record kind (`"Task"` is SquareCheck). */
|
|
62
|
+
export function recordKindIcon(kind: RecordKind): GlyphIconName {
|
|
63
|
+
return map.recordKinds[kind];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Shape drawn by the record state icon (`"blocked"` is an octagon). */
|
|
67
|
+
export function stateGlyph(state: RecordState): StateGlyph {
|
|
68
|
+
return map.stateIcons[state];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Every distinct Lucide name the glyph map uses, sorted. */
|
|
72
|
+
export const glyphIconNames: readonly GlyphIconName[] = [
|
|
73
|
+
...new Set<GlyphIconName>([
|
|
74
|
+
...Object.values(map.departments),
|
|
75
|
+
...Object.values(map.phases),
|
|
76
|
+
...Object.values(map.recordKinds),
|
|
77
|
+
]),
|
|
78
|
+
].sort();
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @xos/icons: the glyph map, the icon names XOS draws, the lucide-react components behind them
|
|
3
|
+
* (native and server use) and the web sprite (`@xos/icons/sprite.svg`). Web bundles import the
|
|
4
|
+
* `glyphs` and `names` entries, which pull in no icon components (ADR 0027).
|
|
5
|
+
*/
|
|
6
|
+
export * from "./glyphs.ts";
|
|
7
|
+
export * from "./names.ts";
|
|
8
|
+
export * from "./registry.ts";
|