@mohasinac/appkit 4.54.0 → 4.55.0-next.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/.build-stamp.json +5 -5
- package/dist/features/media/messages/en.json +67 -67
- package/dist/security/csp.d.ts +16 -1
- package/dist/security/csp.js +5 -3
- package/dist/seed/_helpers/category-parts-glossary-map.js +0 -2
- package/dist/seed/_helpers/category-parts.d.ts +1 -1
- package/dist/seed/_helpers/category-parts.js +6 -18
- package/dist/seed/products-catalogue-seed-data.d.ts +5 -5
- package/dist/seed/products-catalogue-seed-data.js +63936 -13803
- package/dist/styles.css +536 -381
- package/dist/tokens/themes/index.d.ts +3 -1
- package/dist/tokens/themes/index.js +11 -1
- package/dist/tokens/themes/technical-dark.d.ts +30 -0
- package/dist/tokens/themes/technical-dark.js +103 -0
- package/dist/tokens/themes/technical-light.d.ts +22 -0
- package/dist/tokens/themes/technical-light.js +89 -0
- package/dist/tokens/tokens.css +155 -0
- package/dist/ui/components/GatedPrice.style.css +43 -43
- package/dist/ui/components/QuickCreateModal.style.css +78 -78
- package/dist/ui/forms/FormShell.style.css +260 -260
- package/package.json +1 -1
package/dist/.build-stamp.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"stampVersion": 1,
|
|
3
|
-
"version": "4.
|
|
4
|
-
"head": "
|
|
5
|
-
"branch": "
|
|
6
|
-
"dirty":
|
|
7
|
-
"builtAt": "2026-10-
|
|
3
|
+
"version": "4.55.0-next.0",
|
|
4
|
+
"head": "549abc780f1aa0e87661e86d9c76718bfe3d6cb0",
|
|
5
|
+
"branch": "feat/mohasinac-site",
|
|
6
|
+
"dirty": true,
|
|
7
|
+
"builtAt": "2026-10-20T12:44:38.195Z"
|
|
8
8
|
}
|
|
@@ -1,67 +1,67 @@
|
|
|
1
|
-
{
|
|
2
|
-
"mediaEditor": {
|
|
3
|
-
"cropTitle": "Crop Image",
|
|
4
|
-
"cropInstruction": "Drag to reposition. Use the zoom slider or +/- keys to zoom.",
|
|
5
|
-
"cropPreviewAlt": "Preview",
|
|
6
|
-
"cropZoom": "Zoom",
|
|
7
|
-
"cropZoomIn": "Zoom in",
|
|
8
|
-
"cropZoomOut": "Zoom out",
|
|
9
|
-
"cropRotateLeft": "Rotate left 90°",
|
|
10
|
-
"cropRotateRight": "Rotate right 90°",
|
|
11
|
-
"cropFlipH": "Flip horizontally",
|
|
12
|
-
"cropFlipV": "Flip vertically",
|
|
13
|
-
"cropWarningTitle": "Low zoom",
|
|
14
|
-
"cropWarningMessage": "Zoom in for better quality.",
|
|
15
|
-
"cropPosition": "Position",
|
|
16
|
-
"cropReset": "Reset",
|
|
17
|
-
"cropSave": "Save Crop",
|
|
18
|
-
"cropCancel": "Cancel",
|
|
19
|
-
"trimTitle": "Trim Video",
|
|
20
|
-
"trimInstruction": "Set the start and end times, then click Trim.",
|
|
21
|
-
"trimStart": "Start",
|
|
22
|
-
"trimEnd": "End",
|
|
23
|
-
"trimDuration": "Duration: {duration}s",
|
|
24
|
-
"trimQuality": "Quality",
|
|
25
|
-
"trimQualityLow": "Low",
|
|
26
|
-
"trimQualityMedium": "Medium",
|
|
27
|
-
"trimQualityHigh": "High",
|
|
28
|
-
"trimSave": "Trim Video",
|
|
29
|
-
"trimSkip": "Skip",
|
|
30
|
-
"trimming": "Trimming…",
|
|
31
|
-
"thumbnailTitle": "Select Thumbnail",
|
|
32
|
-
"thumbnailInstruction": "Seek to the frame you want to use as the thumbnail.",
|
|
33
|
-
"thumbnailCapture": "Use This Frame",
|
|
34
|
-
"thumbnailSkip": "Skip",
|
|
35
|
-
"thumbnailCapturing": "Capturing…",
|
|
36
|
-
"thumbnailUploading": "Uploading…",
|
|
37
|
-
"cropSuccess": "Image cropped",
|
|
38
|
-
"trimSuccess": "Video trimmed",
|
|
39
|
-
"thumbnailSuccess": "Thumbnail saved",
|
|
40
|
-
"cropError": "Failed to crop image",
|
|
41
|
-
"trimError": "Failed to trim video",
|
|
42
|
-
"thumbnailError": "Failed to capture thumbnail",
|
|
43
|
-
"editImage": "Edit / Crop",
|
|
44
|
-
"editVideo": "Trim / Thumbnail"
|
|
45
|
-
},
|
|
46
|
-
"camera": {
|
|
47
|
-
"takePhoto": "Take Photo",
|
|
48
|
-
"startRecording": "Start Recording",
|
|
49
|
-
"stopRecording": "Stop Recording",
|
|
50
|
-
"flipCamera": "Flip Camera",
|
|
51
|
-
"switchToCamera": "Use Camera",
|
|
52
|
-
"switchToUpload": "Upload File",
|
|
53
|
-
"cameraError": "Camera unavailable",
|
|
54
|
-
"permissionDenied": "Camera permission denied. Please allow access in your browser settings.",
|
|
55
|
-
"notSupported": "Camera is not supported on this device",
|
|
56
|
-
"starting": "Starting camera..."
|
|
57
|
-
},
|
|
58
|
-
"upload": {
|
|
59
|
-
"change": "Change",
|
|
60
|
-
"remove": "Remove",
|
|
61
|
-
"clickToUpload": "Click to upload",
|
|
62
|
-
"uploading": "Uploading…",
|
|
63
|
-
"uploadingProgress": "Uploading {progress}%…",
|
|
64
|
-
"replaceFile": "Replace file",
|
|
65
|
-
"chooseFile": "Choose file to upload"
|
|
66
|
-
}
|
|
67
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"mediaEditor": {
|
|
3
|
+
"cropTitle": "Crop Image",
|
|
4
|
+
"cropInstruction": "Drag to reposition. Use the zoom slider or +/- keys to zoom.",
|
|
5
|
+
"cropPreviewAlt": "Preview",
|
|
6
|
+
"cropZoom": "Zoom",
|
|
7
|
+
"cropZoomIn": "Zoom in",
|
|
8
|
+
"cropZoomOut": "Zoom out",
|
|
9
|
+
"cropRotateLeft": "Rotate left 90°",
|
|
10
|
+
"cropRotateRight": "Rotate right 90°",
|
|
11
|
+
"cropFlipH": "Flip horizontally",
|
|
12
|
+
"cropFlipV": "Flip vertically",
|
|
13
|
+
"cropWarningTitle": "Low zoom",
|
|
14
|
+
"cropWarningMessage": "Zoom in for better quality.",
|
|
15
|
+
"cropPosition": "Position",
|
|
16
|
+
"cropReset": "Reset",
|
|
17
|
+
"cropSave": "Save Crop",
|
|
18
|
+
"cropCancel": "Cancel",
|
|
19
|
+
"trimTitle": "Trim Video",
|
|
20
|
+
"trimInstruction": "Set the start and end times, then click Trim.",
|
|
21
|
+
"trimStart": "Start",
|
|
22
|
+
"trimEnd": "End",
|
|
23
|
+
"trimDuration": "Duration: {duration}s",
|
|
24
|
+
"trimQuality": "Quality",
|
|
25
|
+
"trimQualityLow": "Low",
|
|
26
|
+
"trimQualityMedium": "Medium",
|
|
27
|
+
"trimQualityHigh": "High",
|
|
28
|
+
"trimSave": "Trim Video",
|
|
29
|
+
"trimSkip": "Skip",
|
|
30
|
+
"trimming": "Trimming…",
|
|
31
|
+
"thumbnailTitle": "Select Thumbnail",
|
|
32
|
+
"thumbnailInstruction": "Seek to the frame you want to use as the thumbnail.",
|
|
33
|
+
"thumbnailCapture": "Use This Frame",
|
|
34
|
+
"thumbnailSkip": "Skip",
|
|
35
|
+
"thumbnailCapturing": "Capturing…",
|
|
36
|
+
"thumbnailUploading": "Uploading…",
|
|
37
|
+
"cropSuccess": "Image cropped",
|
|
38
|
+
"trimSuccess": "Video trimmed",
|
|
39
|
+
"thumbnailSuccess": "Thumbnail saved",
|
|
40
|
+
"cropError": "Failed to crop image",
|
|
41
|
+
"trimError": "Failed to trim video",
|
|
42
|
+
"thumbnailError": "Failed to capture thumbnail",
|
|
43
|
+
"editImage": "Edit / Crop",
|
|
44
|
+
"editVideo": "Trim / Thumbnail"
|
|
45
|
+
},
|
|
46
|
+
"camera": {
|
|
47
|
+
"takePhoto": "Take Photo",
|
|
48
|
+
"startRecording": "Start Recording",
|
|
49
|
+
"stopRecording": "Stop Recording",
|
|
50
|
+
"flipCamera": "Flip Camera",
|
|
51
|
+
"switchToCamera": "Use Camera",
|
|
52
|
+
"switchToUpload": "Upload File",
|
|
53
|
+
"cameraError": "Camera unavailable",
|
|
54
|
+
"permissionDenied": "Camera permission denied. Please allow access in your browser settings.",
|
|
55
|
+
"notSupported": "Camera is not supported on this device",
|
|
56
|
+
"starting": "Starting camera..."
|
|
57
|
+
},
|
|
58
|
+
"upload": {
|
|
59
|
+
"change": "Change",
|
|
60
|
+
"remove": "Remove",
|
|
61
|
+
"clickToUpload": "Click to upload",
|
|
62
|
+
"uploading": "Uploading…",
|
|
63
|
+
"uploadingProgress": "Uploading {progress}%…",
|
|
64
|
+
"replaceFile": "Replace file",
|
|
65
|
+
"chooseFile": "Choose file to upload"
|
|
66
|
+
}
|
|
67
|
+
}
|
package/dist/security/csp.d.ts
CHANGED
|
@@ -12,5 +12,20 @@
|
|
|
12
12
|
*/
|
|
13
13
|
/** Generate a 16-byte base64 nonce for a single request. */
|
|
14
14
|
export declare function generateNonce(): string;
|
|
15
|
+
export interface BuildCSPOptions {
|
|
16
|
+
/**
|
|
17
|
+
* Add `'wasm-unsafe-eval'` to `script-src`, permitting
|
|
18
|
+
* `WebAssembly.compile`/`instantiate` from bytes.
|
|
19
|
+
*
|
|
20
|
+
* Required by any page that compiles WebAssembly at runtime — without it the
|
|
21
|
+
* production policy (`script-src 'self' 'nonce-…'`) blocks compilation
|
|
22
|
+
* outright, because WebAssembly compilation counts as script evaluation.
|
|
23
|
+
*
|
|
24
|
+
* Narrower than `'unsafe-eval'` on purpose: it unblocks WASM only and still
|
|
25
|
+
* forbids `eval` and `new Function` for JavaScript. Default `false`, so
|
|
26
|
+
* existing consumers are unaffected.
|
|
27
|
+
*/
|
|
28
|
+
wasm?: boolean;
|
|
29
|
+
}
|
|
15
30
|
/** Build the full CSP header value for the given nonce. */
|
|
16
|
-
export declare function buildCSP(nonce: string): string;
|
|
31
|
+
export declare function buildCSP(nonce: string, options?: BuildCSPOptions): string;
|
package/dist/security/csp.js
CHANGED
|
@@ -17,13 +17,15 @@ export function generateNonce() {
|
|
|
17
17
|
return btoa(String.fromCharCode(...bytes));
|
|
18
18
|
}
|
|
19
19
|
/** Build the full CSP header value for the given nonce. */
|
|
20
|
-
export function buildCSP(nonce) {
|
|
20
|
+
export function buildCSP(nonce, options = {}) {
|
|
21
21
|
const isDev = process.env.NODE_ENV === "development";
|
|
22
|
+
const wasm = options.wasm === true ? " 'wasm-unsafe-eval'" : "";
|
|
22
23
|
return [
|
|
23
24
|
"default-src 'self'",
|
|
24
25
|
isDev
|
|
25
|
-
?
|
|
26
|
-
|
|
26
|
+
? // 'unsafe-eval' already subsumes 'wasm-unsafe-eval' in dev.
|
|
27
|
+
"script-src 'self' 'unsafe-eval' 'unsafe-inline'"
|
|
28
|
+
: `script-src 'self' 'nonce-${nonce}'${wasm}`,
|
|
27
29
|
"style-src 'self' 'unsafe-inline'",
|
|
28
30
|
"img-src 'self' data: https: blob:",
|
|
29
31
|
"font-src 'self' data:",
|
|
@@ -637,7 +637,6 @@ export const PART_CATEGORY_TO_GLOSSARY_ID = {
|
|
|
637
637
|
"category-disc-knuckle": "disc--knuckle",
|
|
638
638
|
"category-disc-mobius": "disc--mobius",
|
|
639
639
|
"category-disc-outer": "disc--outer",
|
|
640
|
-
"category-disc-variable-per-combo": "disc--variable-per-combo",
|
|
641
640
|
"category-disc-vertical": "disc--vertical",
|
|
642
641
|
"category-disc-wheel": "disc--wheel",
|
|
643
642
|
"category-disc-wing": "disc--wing",
|
|
@@ -1769,7 +1768,6 @@ export const PART_CATEGORY_TO_GLOSSARY_ID = {
|
|
|
1769
1768
|
"category-performance-tip-spike": "performance-tip--spike",
|
|
1770
1769
|
"category-performance-tip-spiral": "performance-tip--spiral",
|
|
1771
1770
|
"category-performance-tip-trick": "performance-tip--trick",
|
|
1772
|
-
"category-performance-tip-variable-per-combo": "performance-tip--variable-per-combo",
|
|
1773
1771
|
"category-performance-tip-wide-defense": "performance-tip--wide-defense",
|
|
1774
1772
|
"category-performance-tip-xtreme": "performance-tip--xtreme",
|
|
1775
1773
|
"category-performance-tip-zeta": "performance-tip--zeta",
|
|
@@ -6,4 +6,4 @@ export declare const PART_LEAVES: Record<string, CategoryTreeNode[]>;
|
|
|
6
6
|
* SAME string by construction, so this map exists only to let a reader see that
|
|
7
7
|
* stated rather than inferred.
|
|
8
8
|
*/
|
|
9
|
-
export declare const PART_LEAF_COUNT =
|
|
9
|
+
export declare const PART_LEAF_COUNT = 2488;
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
* 🛑 The prose is ours, composed from facts (name, classification, printed
|
|
22
22
|
* code, weight, model count). No corpus sentence is reproduced.
|
|
23
23
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
24
|
+
* 2488 parts -> 2488 leaves across 26 part-type nodes.
|
|
25
|
+
* 665 needed a classification-qualified slug because the bare name
|
|
26
26
|
* collides across classifications; the rest keep the short URL.
|
|
27
27
|
*
|
|
28
28
|
* @tag domain:categories
|
|
@@ -1986,12 +1986,6 @@ export const PART_LEAVES = {
|
|
|
1986
1986
|
description: "Vanguard (Hasbro) — a disc (20.4 g). Loose examples, spares and pre-owned discs of this part are listed here.",
|
|
1987
1987
|
extra: { aliases: ["Vanguard (Hasbro)", "vanguard-hasbro", "Vn"] },
|
|
1988
1988
|
},
|
|
1989
|
-
{
|
|
1990
|
-
id: "category-disc-variable-per-combo",
|
|
1991
|
-
name: "variable per combo",
|
|
1992
|
-
description: "variable per combo — a disc (used by 1 model). Loose examples, spares and pre-owned discs of this part are listed here.",
|
|
1993
|
-
extra: { aliases: ["variable per combo"] },
|
|
1994
|
-
},
|
|
1995
1989
|
{
|
|
1996
1990
|
id: "category-disc-vertical",
|
|
1997
1991
|
name: "Vertical",
|
|
@@ -9482,12 +9476,6 @@ export const PART_LEAVES = {
|
|
|
9482
9476
|
description: "Twin Ball — a performance tip (0.7 g). Loose examples, spares and pre-owned performance tips of this part are listed here.",
|
|
9483
9477
|
extra: { aliases: ["Twin Ball", "twin-ball", "TB"] },
|
|
9484
9478
|
},
|
|
9485
|
-
{
|
|
9486
|
-
id: "category-performance-tip-variable-per-combo",
|
|
9487
|
-
name: "variable per combo",
|
|
9488
|
-
description: "variable per combo — a performance tip (used by 1 model). Loose examples, spares and pre-owned performance tips of this part are listed here.",
|
|
9489
|
-
extra: { aliases: ["variable per combo"] },
|
|
9490
|
-
},
|
|
9491
9479
|
{
|
|
9492
9480
|
id: "category-w2d",
|
|
9493
9481
|
name: "W2D",
|
|
@@ -11604,9 +11592,9 @@ export const PART_LEAVES = {
|
|
|
11604
11592
|
},
|
|
11605
11593
|
{
|
|
11606
11594
|
id: "category-custom-metal-change-w-upper-attack-support-parts",
|
|
11607
|
-
name: "Custom Metal Change (w
|
|
11608
|
-
description: "Custom Metal Change (w
|
|
11609
|
-
extra: { aliases: ["Custom Metal Change (w
|
|
11595
|
+
name: "Custom Metal Change (w/ Upper Attack Support Parts)",
|
|
11596
|
+
description: "Custom Metal Change (w/ Upper Attack Support Parts) — a blade base. Loose examples, spares and pre-owned blade bases of this part are listed here.",
|
|
11597
|
+
extra: { aliases: ["Custom Metal Change (w/ Upper Attack Support Parts)", "custom-metal-change-w-upper-attack-support-parts"] },
|
|
11610
11598
|
},
|
|
11611
11599
|
{
|
|
11612
11600
|
id: "category-customize-bearing-base",
|
|
@@ -15031,4 +15019,4 @@ export const PART_LEAVES = {
|
|
|
15031
15019
|
* SAME string by construction, so this map exists only to let a reader see that
|
|
15032
15020
|
* stated rather than inferred.
|
|
15033
15021
|
*/
|
|
15034
|
-
export const PART_LEAF_COUNT =
|
|
15022
|
+
export const PART_LEAF_COUNT = 2488;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* GENERATED by scripts/gen-catalogue-listings.mjs — do not edit by hand.
|
|
3
3
|
*
|
|
4
|
-
* One product listing per taxonomy leaf:
|
|
5
|
-
* models =
|
|
4
|
+
* One product listing per taxonomy leaf: 2488 parts + 221 complete
|
|
5
|
+
* models = 2974 rows. This is what makes `products` reproducible from
|
|
6
6
|
* committed data alone — see the generator's own header for the incident that
|
|
7
7
|
* made that matter (968 live documents with no committed source).
|
|
8
8
|
*
|
|
@@ -11,12 +11,12 @@
|
|
|
11
11
|
* — so a re-run of the generator, and a re-run of `appkit-seed load`, both
|
|
12
12
|
* reproduce the SAME 968 documents rather than minting duplicates.
|
|
13
13
|
*
|
|
14
|
-
*
|
|
14
|
+
* 2753 of 2488 part listings carry `partGlossaryId`, resolved through
|
|
15
15
|
* `PART_CATEGORY_TO_GLOSSARY_ID` (the pairing `gen-category-parts.mjs` already
|
|
16
|
-
* computes, emitted rather than re-derived).
|
|
16
|
+
* computes, emitted rather than re-derived). 600 of 221 model listings
|
|
17
17
|
* reuse the real wiki cover photo their category page already shows; the rest
|
|
18
18
|
* fall back to a deterministic coloured tile from `public/images/seed-tiles/`.
|
|
19
19
|
*/
|
|
20
20
|
import type { ProductDocument } from "../features/products/schemas/firestore";
|
|
21
21
|
export declare const productsCatalogueSeedData: Partial<ProductDocument>[];
|
|
22
|
-
export declare const CATALOGUE_LISTING_COUNT =
|
|
22
|
+
export declare const CATALOGUE_LISTING_COUNT = 2974;
|