nimiq-branding-cli 1.1.0 → 1.2.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.
Files changed (74) hide show
  1. package/.audit/report.json +71 -0
  2. package/.audit/report.md +33 -0
  3. package/AUDIT.md +60 -0
  4. package/LINT.md +158 -0
  5. package/README.md +47 -4
  6. package/align/canonical.json +44 -0
  7. package/audit/learnings.json +51 -0
  8. package/bin/nq.js +90 -5
  9. package/hooks/ci-additions.md +53 -0
  10. package/hooks/pre-commit +10 -0
  11. package/hooks/session-start.sh +3 -0
  12. package/hooks/stack-align.yml +75 -0
  13. package/package.json +4 -4
  14. package/registry/SKILL-BLOCK.md +20 -0
  15. package/registry/components/account-header/meta.json +11 -1
  16. package/registry/components/account-list/meta.json +9 -1
  17. package/registry/components/account-ring/meta.json +9 -1
  18. package/registry/components/address-display/html/address-display.css +17 -13
  19. package/registry/components/address-display/html/demo.html +8 -10
  20. package/registry/components/address-display/meta.json +37 -7
  21. package/registry/components/address-display/vue/AddressDisplay.vue +11 -9
  22. package/registry/components/address-input/meta.json +53 -10
  23. package/registry/components/amount/meta.json +60 -11
  24. package/registry/components/amount-input/meta.json +55 -10
  25. package/registry/components/amount-with-fee/meta.json +58 -11
  26. package/registry/components/app-showcase-card/meta.json +17 -4
  27. package/registry/components/backup-banner/meta.json +29 -5
  28. package/registry/components/balance-distribution/meta.json +25 -5
  29. package/registry/components/buttons/meta.json +38 -7
  30. package/registry/components/card/meta.json +20 -4
  31. package/registry/components/close-button/meta.json +19 -4
  32. package/registry/components/consensus-icon/meta.json +26 -5
  33. package/registry/components/copyable/meta.json +25 -5
  34. package/registry/components/fiat-amount/meta.json +49 -9
  35. package/registry/components/flag-hex/html/demo.html +55 -0
  36. package/registry/components/flag-hex/html/flag-hex.css +21 -0
  37. package/registry/components/flag-hex/html/flag-hex.html +38 -0
  38. package/registry/components/flag-hex/meta.json +43 -0
  39. package/registry/components/flag-hex/vue/FlagHex.vue +98 -0
  40. package/registry/components/hero-section/meta.json +9 -4
  41. package/registry/components/honeycomb-band/meta.json +47 -9
  42. package/registry/components/identicon/meta.json +8 -1
  43. package/registry/components/label-input/meta.json +49 -9
  44. package/registry/components/loading-spinner/meta.json +19 -4
  45. package/registry/components/page-body/meta.json +23 -5
  46. package/registry/components/page-footer/meta.json +22 -5
  47. package/registry/components/page-header/meta.json +43 -8
  48. package/registry/components/payment-info-line/meta.json +10 -1
  49. package/registry/components/price-chart/meta.json +67 -11
  50. package/registry/components/qr-code/meta.json +22 -5
  51. package/registry/components/search-bar/meta.json +25 -5
  52. package/registry/components/select-bar/meta.json +37 -7
  53. package/registry/components/slider-toggle/meta.json +45 -8
  54. package/registry/components/small-page/meta.json +19 -4
  55. package/registry/components/status-alert/meta.json +37 -7
  56. package/registry/components/status-screen/meta.json +70 -13
  57. package/registry/components/swap-balance-bar/meta.json +8 -1
  58. package/registry/components/timer/meta.json +54 -10
  59. package/registry/components/toast-notification/meta.json +49 -9
  60. package/registry/components/tooltip/meta.json +69 -13
  61. package/registry/components/transaction-list/meta.json +9 -1
  62. package/registry/index.json +10 -0
  63. package/schemas/nimiq-stack.v1.json +103 -0
  64. package/scripts/align.mjs +435 -0
  65. package/scripts/apply-safe-bump.mjs +47 -0
  66. package/scripts/audit.mjs +247 -0
  67. package/scripts/bootstrap-provenance.mjs +126 -0
  68. package/scripts/hooks.mjs +152 -0
  69. package/scripts/lint.mjs +333 -0
  70. package/scripts/scaffold.mjs +391 -0
  71. package/scripts/sync-skill.mjs +84 -0
  72. package/test/align.test.mjs +166 -0
  73. package/test/scaffold.test.mjs +103 -0
  74. package/upstream-pins.json +35 -0
@@ -2,24 +2,69 @@
2
2
  "name": "amount-input",
3
3
  "purpose": "Large centered amount entry field that auto-fits its width and shrinks its font to the available space, with the currency ticker (NIM, BTC, ...) rendered beside the value.",
4
4
  "category": "form",
5
- "variants": ["vue", "html"],
5
+ "variants": [
6
+ "vue",
7
+ "html"
8
+ ],
6
9
  "props": [
7
- { "name": "value", "type": "number", "default": null, "description": "Amount in the currency's smallest unit (Luna for NIM, i.e. value / 10^decimals is displayed)." },
8
- { "name": "maxFontSize", "type": "number", "default": 8, "description": "Maximum font size in rem; the font shrinks below this when the value would overflow the available width." },
9
- { "name": "placeholder", "type": "string", "default": "0", "description": "Placeholder shown when empty." },
10
- { "name": "vanishing", "type": "boolean", "default": false, "description": "Removes the input's inset border (nq-input .vanishing style)." },
11
- { "name": "decimals", "type": "number", "default": 5, "description": "Number of decimals the entered value is parsed with (5 for NIM/Luna)." },
12
- { "name": "currency", "type": "string", "default": "nim", "description": "Currency code; rendered as ticker (nim→NIM, tnim→tNIM, mbtc→mBTC, tbtc→tBTC, usdc.e→USDC.e, else uppercased) and applied as a class on the ticker span." }
10
+ {
11
+ "name": "value",
12
+ "type": "number",
13
+ "default": null,
14
+ "description": "Amount in the currency's smallest unit (Luna for NIM, i.e. value / 10^decimals is displayed)."
15
+ },
16
+ {
17
+ "name": "maxFontSize",
18
+ "type": "number",
19
+ "default": 8,
20
+ "description": "Maximum font size in rem; the font shrinks below this when the value would overflow the available width."
21
+ },
22
+ {
23
+ "name": "placeholder",
24
+ "type": "string",
25
+ "default": "0",
26
+ "description": "Placeholder shown when empty."
27
+ },
28
+ {
29
+ "name": "vanishing",
30
+ "type": "boolean",
31
+ "default": false,
32
+ "description": "Removes the input's inset border (nq-input .vanishing style)."
33
+ },
34
+ {
35
+ "name": "decimals",
36
+ "type": "number",
37
+ "default": 5,
38
+ "description": "Number of decimals the entered value is parsed with (5 for NIM/Luna)."
39
+ },
40
+ {
41
+ "name": "currency",
42
+ "type": "string",
43
+ "default": "nim",
44
+ "description": "Currency code; rendered as ticker (nim→NIM, tnim→tNIM, mbtc→mBTC, tbtc→tBTC, usdc.e→USDC.e, else uppercased) and applied as a class on the ticker span."
45
+ }
46
+ ],
47
+ "cssFiles": [
48
+ "css/legacy/nimiq-style.min.css"
13
49
  ],
14
- "cssFiles": ["css/legacy/nimiq-style.min.css"],
15
50
  "dependsOn": [],
16
51
  "npmDeps": [],
17
52
  "verified": true,
18
53
  "verify": {
19
- "viewport": { "width": 600, "height": 400 },
54
+ "viewport": {
55
+ "width": 600,
56
+ "height": 400
57
+ },
20
58
  "selector": ".amount-input",
21
59
  "maxDiffPct": 0.5,
22
60
  "settleMs": 250
23
61
  },
24
- "notes": "Sample state: '100.00' NIM entered, unfocused, maxFontSize 8rem. The component's width/font-size auto-fit is inherently JS-driven (upstream measures hidden width-finder spans on every input); truth.html and demo.html both include a minimal script that replicates mounted()+updateWidth() once after fonts load — deterministic for a fixed value. Truth emulates Vue's [data-v-*] scoping on the component CSS because scoped attribute selectors are what let the upstream `input` rule (padding 0 .25rem) beat .nq-input's specificity."
62
+ "notes": "Sample state: '100.00' NIM entered, unfocused, maxFontSize 8rem. The component's width/font-size auto-fit is inherently JS-driven (upstream measures hidden width-finder spans on every input); truth.html and demo.html both include a minimal script that replicates mounted()+updateWidth() once after fonts load — deterministic for a fixed value. Truth emulates Vue's [data-v-*] scoping on the component CSS because scoped attribute selectors are what let the upstream `input` rule (padding 0 .25rem) beat .nq-input's specificity.",
63
+ "source": {
64
+ "repo": "vue-components",
65
+ "ref": "3c5b972",
66
+ "files": [
67
+ "vue-components:src/components/AmountInput.vue"
68
+ ]
69
+ }
25
70
  }
@@ -2,24 +2,71 @@
2
2
  "name": "amount-with-fee",
3
3
  "purpose": "Large centered amount entry field (auto-sizing AmountInput with currency ticker) plus a secondary line that shows either an 'Insufficient balance' error, an approximate fiat value and/or the network fee. Used in send-transaction flows.",
4
4
  "category": "payment",
5
- "variants": ["vue", "html"],
5
+ "variants": [
6
+ "vue",
7
+ "html"
8
+ ],
6
9
  "props": [
7
- { "name": "value", "type": "{ amount: number, fee: number, isValid: boolean }", "default": "{ amount: 0, fee: 0, isValid: false }", "description": "v-model object: amount and fee in the currency's smallest unit (luna); isValid is computed and emitted back (amount > 0 && amount + fee <= availableBalance)." },
8
- { "name": "availableBalance", "type": "number", "default": 0, "description": "Spendable balance in the smallest unit; entering more shows the insufficient-balance error and red styling." },
9
- { "name": "fiatAmount", "type": "number | null", "description": "Optional fiat value of the entered amount; shown as '~<FiatAmount>' when set together with fiatCurrency." },
10
- { "name": "fiatCurrency", "type": "string | null", "description": "Fiat currency code for fiatAmount (e.g. 'eur')." },
11
- { "name": "currency", "type": "string", "default": "nim", "description": "Crypto currency code; rendered uppercase as the ticker (special-cased: tnim→tNIM, mbtc→mBTC, tbtc→tBTC, usdc.e→USDC.e)." },
12
- { "name": "currencyDecimals", "type": "number", "default": 5, "description": "Decimals of the currency's smallest unit (5 for NIM/luna, 8 for BTC/sat)." }
10
+ {
11
+ "name": "value",
12
+ "type": "{ amount: number, fee: number, isValid: boolean }",
13
+ "default": "{ amount: 0, fee: 0, isValid: false }",
14
+ "description": "v-model object: amount and fee in the currency's smallest unit (luna); isValid is computed and emitted back (amount > 0 && amount + fee <= availableBalance)."
15
+ },
16
+ {
17
+ "name": "availableBalance",
18
+ "type": "number",
19
+ "default": 0,
20
+ "description": "Spendable balance in the smallest unit; entering more shows the insufficient-balance error and red styling."
21
+ },
22
+ {
23
+ "name": "fiatAmount",
24
+ "type": "number | null",
25
+ "description": "Optional fiat value of the entered amount; shown as '~<FiatAmount>' when set together with fiatCurrency."
26
+ },
27
+ {
28
+ "name": "fiatCurrency",
29
+ "type": "string | null",
30
+ "description": "Fiat currency code for fiatAmount (e.g. 'eur')."
31
+ },
32
+ {
33
+ "name": "currency",
34
+ "type": "string",
35
+ "default": "nim",
36
+ "description": "Crypto currency code; rendered uppercase as the ticker (special-cased: tnim→tNIM, mbtc→mBTC, tbtc→tBTC, usdc.e→USDC.e)."
37
+ },
38
+ {
39
+ "name": "currencyDecimals",
40
+ "type": "number",
41
+ "default": 5,
42
+ "description": "Decimals of the currency's smallest unit (5 for NIM/luna, 8 for BTC/sat)."
43
+ }
44
+ ],
45
+ "cssFiles": [
46
+ "css/legacy/nimiq-style.min.css"
47
+ ],
48
+ "dependsOn": [
49
+ "amount",
50
+ "fiat-amount"
13
51
  ],
14
- "cssFiles": ["css/legacy/nimiq-style.min.css"],
15
- "dependsOn": ["amount", "fiat-amount"],
16
52
  "npmDeps": [],
17
53
  "verified": true,
18
54
  "verify": {
19
- "viewport": { "width": 600, "height": 400 },
55
+ "viewport": {
56
+ "width": 600,
57
+ "height": 400
58
+ },
20
59
  "selector": ".amount-with-fee",
21
60
  "maxDiffPct": 0.5,
22
61
  "settleMs": 250
23
62
  },
24
- "notes": "Sample state: amount 10000000 luna (input shows '100'), fee 0, availableBalance 50000000, no fiat — valid, so the fee-section renders empty (min-height 2rem placeholder). Both truth and demo replicate AmountInput's JS width behavior: the input's inline width is set to the rendered width of a hidden measuring span (text + 1.25rem padding) after fonts load; the upstream font-shrink logic (maxFontSize) only kicks in for values wider than the container and is not exercised by the sample. The slot/error/fiat/fee branches are documented in the snippet. Vue port ships AmountWithFee.vue + AmountInput.vue (AmountInput is not a standalone registry component); Amount.vue and FiatAmount.vue are imported from sibling registry components 'amount' and 'fiat-amount' (copy them next to AmountWithFee.vue, see dependsOn). $t is stubbed as identity."
63
+ "notes": "Sample state: amount 10000000 luna (input shows '100'), fee 0, availableBalance 50000000, no fiat — valid, so the fee-section renders empty (min-height 2rem placeholder). Both truth and demo replicate AmountInput's JS width behavior: the input's inline width is set to the rendered width of a hidden measuring span (text + 1.25rem padding) after fonts load; the upstream font-shrink logic (maxFontSize) only kicks in for values wider than the container and is not exercised by the sample. The slot/error/fiat/fee branches are documented in the snippet. Vue port ships AmountWithFee.vue + AmountInput.vue (AmountInput is not a standalone registry component); Amount.vue and FiatAmount.vue are imported from sibling registry components 'amount' and 'fiat-amount' (copy them next to AmountWithFee.vue, see dependsOn). $t is stubbed as identity.",
64
+ "source": {
65
+ "repo": "vue-components",
66
+ "ref": "3c5b972",
67
+ "files": [
68
+ "vue-components:src/components/AmountWithFee.vue",
69
+ "vue-components:src/components/AmountInput.vue"
70
+ ]
71
+ }
25
72
  }
@@ -2,9 +2,14 @@
2
2
  "name": "app-showcase-card",
3
3
  "purpose": "nimiq.com 'THE APPS' marketing card: light-gray rounded card with gold app-icon chip (official white Nimiq signet), title, 2-line gray subtitle and the REAL Nimiq Pay phone screenshot clipped at the card edge. .wide modifier puts the bare gold signet + copy left and the REAL Nimiq Wallet desktop screenshot bleeding off the bottom-right.",
4
4
  "category": "marketing",
5
- "variants": ["default", "wide"],
5
+ "variants": [
6
+ "default",
7
+ "wide"
8
+ ],
6
9
  "props": [],
7
- "cssFiles": ["app-showcase-card.css"],
10
+ "cssFiles": [
11
+ "app-showcase-card.css"
12
+ ],
8
13
  "assetFiles": [
9
14
  "img/nimiq-pay-preview.webp",
10
15
  "img/nimiq-wallet-preview.webp",
@@ -15,10 +20,18 @@
15
20
  "npmDeps": [],
16
21
  "verified": true,
17
22
  "verify": {
18
- "viewport": { "width": 860, "height": 1000 },
23
+ "viewport": {
24
+ "width": 860,
25
+ "height": 1000
26
+ },
19
27
  "selector": ".stage",
20
28
  "maxDiffPct": 0.5,
21
29
  "settleMs": 250
22
30
  },
23
- "notes": "MARKETING component, layout screenshot-calibrated against references/screenshots/nimiq-com/home-card-component.png (standard 'Pay App' card) and home-desktop-full.png THE APPS section (wide 'Nimiq wallet' card). Device mocks are the REAL team-shipped product screenshots (default, not optional): standard card renders assets/img/nimiq-pay-preview.webp (490x916 Nimiq Pay phone shot incl. its own rounded frame, clipped by the card's overflow:hidden bottom edge like the live site) and the wide card renders assets/img/nimiq-wallet-preview.webp (1734x1164 Nimiq Wallet desktop shot, absolutely positioned so it bleeds off the right + bottom card edges). Both originate from nimiq.com's Prismic CDN (raw sweep copies: references/assets/nimiq-com/prismic/Zt7oXRoQrfVKl2hA_NimiqPayPreview.webp and Zt7oXhoQrfVKl2hB_NimiqWalletPreview.webp). Hexagon marks are the official signet SVGs from the team logo pack: white signet (assets/logos/official/white/nimiq_signet_white_base_size.svg) inside the gold chip with the 'Pay' label, and the colored gold signet (assets/logos/official/colored/nimiq_signet_rgb_base_size.svg) shown bare in the wide card exactly like the live site. The chip's gold radial gradient uses the same stops as the official colored signet (#EC991C -> #E9B213). The old CSS-built phone/window mocks and clip-path hexagons were deleted. Snippet references assets as ../../../../assets/<subpath>; nq add copies them into consumer projects at ./nimiq/assets/<subpath>. Self-contained px units (marketing pages don't use the legacy html{font-size:8px} framework); Mulish via Google Fonts. Static markup, no script."
31
+ "notes": "MARKETING component, layout screenshot-calibrated against references/screenshots/nimiq-com/home-card-component.png (standard 'Pay App' card) and home-desktop-full.png THE APPS section (wide 'Nimiq wallet' card). Device mocks are the REAL team-shipped product screenshots (default, not optional): standard card renders assets/img/nimiq-pay-preview.webp (490x916 Nimiq Pay phone shot incl. its own rounded frame, clipped by the card's overflow:hidden bottom edge like the live site) and the wide card renders assets/img/nimiq-wallet-preview.webp (1734x1164 Nimiq Wallet desktop shot, absolutely positioned so it bleeds off the right + bottom card edges). Both originate from nimiq.com's Prismic CDN (raw sweep copies: references/assets/nimiq-com/prismic/Zt7oXRoQrfVKl2hA_NimiqPayPreview.webp and Zt7oXhoQrfVKl2hB_NimiqWalletPreview.webp). Hexagon marks are the official signet SVGs from the team logo pack: white signet (assets/logos/official/white/nimiq_signet_white_base_size.svg) inside the gold chip with the 'Pay' label, and the colored gold signet (assets/logos/official/colored/nimiq_signet_rgb_base_size.svg) shown bare in the wide card exactly like the live site. The chip's gold radial gradient uses the same stops as the official colored signet (#EC991C -> #E9B213). The old CSS-built phone/window mocks and clip-path hexagons were deleted. Snippet references assets as ../../../../assets/<subpath>; nq add copies them into consumer projects at ./nimiq/assets/<subpath>. Self-contained px units (marketing pages don't use the legacy html{font-size:8px} framework); Mulish via Google Fonts. Static markup, no script.",
32
+ "source": {
33
+ "repo": "nimiq-com",
34
+ "ref": null,
35
+ "files": []
36
+ }
24
37
  }
@@ -2,14 +2,38 @@
2
2
  "name": "backup-banner",
3
3
  "purpose": "The wallet's persistent orange warning banner — \"There is no 'forgot password'\" with a Backup→ pill — shown until the account's recovery words are exported.",
4
4
  "category": "feedback",
5
- "variants": ["vue", "html"],
5
+ "variants": [
6
+ "vue",
7
+ "html"
8
+ ],
6
9
  "props": [
7
- { "name": "variant", "type": "'words' | 'file'", "description": "words = orange text on white with tonal inset border (recovery words not backed up); file = solid orange gradient (login file not saved)" }
10
+ {
11
+ "name": "variant",
12
+ "type": "'words' | 'file'",
13
+ "description": "words = orange text on white with tonal inset border (recovery words not backed up); file = solid orange gradient (login file not saved)"
14
+ }
15
+ ],
16
+ "cssFiles": [
17
+ "css/legacy/nimiq-style.min.css"
8
18
  ],
9
- "cssFiles": ["css/legacy/nimiq-style.min.css"],
10
19
  "dependsOn": [],
11
20
  "npmDeps": [],
12
21
  "verified": true,
13
- "verify": { "viewport": { "width": 600, "height": 130 }, "selector": ".words", "maxDiffPct": 0.5, "settleMs": 250 },
14
- "notes": "Source: upstream/wallet/src/components/layouts/AccountOverview.vue (.backup-warning block, SCSS expanded; .words variant). Needs wallet theme vars --body-size:2rem and --text-10:rgba(31,35,72,0.1) (from wallet themes.scss) — the snippet CSS defines them on the component root. AlertTriangleIcon + ArrowRightSmallIcon inlined from @nimiq/style icons. .nq-button-pill.orange comes from the legacy framework. Hover slides the arrow right 0.25rem. Verify selector is .words so it crops the same element in truth (.backup-warning.words) and demo (.backup-banner.words). Upstream click handlers (router push to Backup / hub backup()) are app wiring; the Vue port emits 'action'."
22
+ "verify": {
23
+ "viewport": {
24
+ "width": 600,
25
+ "height": 130
26
+ },
27
+ "selector": ".words",
28
+ "maxDiffPct": 0.5,
29
+ "settleMs": 250
30
+ },
31
+ "notes": "Source: upstream/wallet/src/components/layouts/AccountOverview.vue (.backup-warning block, SCSS expanded; .words variant). Needs wallet theme vars --body-size:2rem and --text-10:rgba(31,35,72,0.1) (from wallet themes.scss) — the snippet CSS defines them on the component root. AlertTriangleIcon + ArrowRightSmallIcon inlined from @nimiq/style icons. .nq-button-pill.orange comes from the legacy framework. Hover slides the arrow right 0.25rem. Verify selector is .words so it crops the same element in truth (.backup-warning.words) and demo (.backup-banner.words). Upstream click handlers (router push to Backup / hub backup()) are app wiring; the Vue port emits 'action'.",
32
+ "source": {
33
+ "repo": "wallet",
34
+ "ref": "656ed56",
35
+ "files": [
36
+ "wallet:src/components/layouts/AccountOverview.vue"
37
+ ]
38
+ }
15
39
  }
@@ -2,19 +2,39 @@
2
2
  "name": "balance-distribution",
3
3
  "purpose": "Sidebar balance-distribution donut from the Nimiq wallet: a ring made of one rounded SVG arc per currency (gold NIM, orange BTC, blue USDC, teal USDT), sized by each currency's share of the account's total fiat value, next to a bold white CURRENCY / percentage legend. Empty currencies get no arc and a dimmed legend row; hovering a row or arc highlights that currency. Lives on the navy wallet sidebar.",
4
4
  "category": "data-display",
5
- "variants": ["vue", "html"],
5
+ "variants": [
6
+ "vue",
7
+ "html"
8
+ ],
6
9
  "props": [
7
- { "name": "balances", "type": "Partial<Record<'nim' | 'btc' | 'usdc' | 'usdt', number>>", "default": "{ nim: 1, btc: 0 }", "description": "Fiat value per currency; each arc's length is the currency's share of the total. The keys decide which currencies appear (legend order: nim, btc, usdc, usdt; zero balances sort last). Upstream computes this from the Address/BtcAddress/PolygonAddress/Staking stores and Fiat exchange rates — the port exposes it as a prop." }
10
+ {
11
+ "name": "balances",
12
+ "type": "Partial<Record<'nim' | 'btc' | 'usdc' | 'usdt', number>>",
13
+ "default": "{ nim: 1, btc: 0 }",
14
+ "description": "Fiat value per currency; each arc's length is the currency's share of the total. The keys decide which currencies appear (legend order: nim, btc, usdc, usdt; zero balances sort last). Upstream computes this from the Address/BtcAddress/PolygonAddress/Staking stores and Fiat exchange rates — the port exposes it as a prop."
15
+ }
16
+ ],
17
+ "cssFiles": [
18
+ "css/legacy/nimiq-style.min.css"
8
19
  ],
9
- "cssFiles": ["css/legacy/nimiq-style.min.css"],
10
20
  "dependsOn": [],
11
21
  "npmDeps": [],
12
22
  "verified": true,
13
23
  "verify": {
14
- "viewport": { "width": 240, "height": 110 },
24
+ "viewport": {
25
+ "width": 240,
26
+ "height": 110
27
+ },
15
28
  "selector": ".balance-distribution",
16
29
  "maxDiffPct": 0.5,
17
30
  "settleMs": 250
18
31
  },
19
- "notes": "Source: upstream/wallet/src/components/BalanceDistribution.vue (scoped styles verbatim) + layouts/Sidebar.vue for context (navy --bg-secondary: var(--nimiq-blue) background, 2.5rem vertical margin, Swap pill rendered below it by the sidebar — the pill is a sibling Tooltip/button, not part of this component). Sample state per brief item 6: NIM 100% / BTC 0% — BTC has no balance so only the gold NIM arc renders, as a full circle without gap or line caps (SVG_SIZE 51, STROKE_WIDTH 4, RADIUS 23.5, dasharray '147.655 0', dashoffset = circleStart = 32.914); the BTC legend row is .inactive (children at opacity .3). Currency colors: --nimiq-gold from the legacy framework; --bitcoin-orange #F7931A / --usdc-blue #2775CA / --usdt-green #009393 from wallet themes.scss, defined on the component root in the snippet. The upstream enter/leave arc transitions (transition-group hooks) are ported in the Vue variant; the html snippet is the static render."
32
+ "notes": "Source: upstream/wallet/src/components/BalanceDistribution.vue (scoped styles verbatim) + layouts/Sidebar.vue for context (navy --bg-secondary: var(--nimiq-blue) background, 2.5rem vertical margin, Swap pill rendered below it by the sidebar — the pill is a sibling Tooltip/button, not part of this component). Sample state per brief item 6: NIM 100% / BTC 0% — BTC has no balance so only the gold NIM arc renders, as a full circle without gap or line caps (SVG_SIZE 51, STROKE_WIDTH 4, RADIUS 23.5, dasharray '147.655 0', dashoffset = circleStart = 32.914); the BTC legend row is .inactive (children at opacity .3). Currency colors: --nimiq-gold from the legacy framework; --bitcoin-orange #F7931A / --usdc-blue #2775CA / --usdt-green #009393 from wallet themes.scss, defined on the component root in the snippet. The upstream enter/leave arc transitions (transition-group hooks) are ported in the Vue variant; the html snippet is the static render.",
33
+ "source": {
34
+ "repo": "wallet",
35
+ "ref": "656ed56",
36
+ "files": [
37
+ "wallet:src/components/BalanceDistribution.vue"
38
+ ]
39
+ }
20
40
  }
@@ -2,21 +2,52 @@
2
2
  "name": "buttons",
3
3
  "purpose": "Primary Nimiq buttons (.nq-button) from the nimiq-style CSS framework: pill-shaped gradient buttons in blue (default), light-blue, green, orange, red, gold, plus disabled and inverse states.",
4
4
  "category": "form",
5
- "variants": ["vue", "html"],
5
+ "variants": [
6
+ "vue",
7
+ "html"
8
+ ],
6
9
  "props": [
7
- { "name": "color", "type": "'' | 'light-blue' | 'green' | 'orange' | 'red' | 'gold'", "default": "''", "description": "Color variant class added to .nq-button; empty = default Nimiq blue." },
8
- { "name": "inverse", "type": "boolean", "default": "false", "description": "White button with colored text, for use on colored backgrounds." },
9
- { "name": "disabled", "type": "boolean", "default": "false", "description": "Disabled state (gray, no shadow, not-allowed cursor)." }
10
+ {
11
+ "name": "color",
12
+ "type": "'' | 'light-blue' | 'green' | 'orange' | 'red' | 'gold'",
13
+ "default": "''",
14
+ "description": "Color variant class added to .nq-button; empty = default Nimiq blue."
15
+ },
16
+ {
17
+ "name": "inverse",
18
+ "type": "boolean",
19
+ "default": "false",
20
+ "description": "White button with colored text, for use on colored backgrounds."
21
+ },
22
+ {
23
+ "name": "disabled",
24
+ "type": "boolean",
25
+ "default": "false",
26
+ "description": "Disabled state (gray, no shadow, not-allowed cursor)."
27
+ }
28
+ ],
29
+ "cssFiles": [
30
+ "css/legacy/nimiq-style.min.css"
10
31
  ],
11
- "cssFiles": ["css/legacy/nimiq-style.min.css"],
12
32
  "dependsOn": [],
13
33
  "npmDeps": [],
14
34
  "verified": true,
15
35
  "verify": {
16
- "viewport": { "width": 600, "height": 600 },
36
+ "viewport": {
37
+ "width": 600,
38
+ "height": 600
39
+ },
17
40
  "selector": "body",
18
41
  "maxDiffPct": 0.5,
19
42
  "settleMs": 250
20
43
  },
21
- "notes": "Pure CSS-framework component — all styling comes from .nq-button rules in legacy nimiq-style.min.css (gradient backgrounds via --nimiq-*-bg vars, 500px border-radius, uppercase bold text). No scoped CSS exists upstream. html/buttons.css is the upstream src/buttons.css extracted verbatim for standalone use (still requires the --nimiq-* CSS vars). Vue variant is a thin wrapper adding color/inverse/disabled classes."
44
+ "notes": "Pure CSS-framework component — all styling comes from .nq-button rules in legacy nimiq-style.min.css (gradient backgrounds via --nimiq-*-bg vars, 500px border-radius, uppercase bold text). No scoped CSS exists upstream. html/buttons.css is the upstream src/buttons.css extracted verbatim for standalone use (still requires the --nimiq-* CSS vars). Vue variant is a thin wrapper adding color/inverse/disabled classes.",
45
+ "source": {
46
+ "repo": "nimiq-style",
47
+ "ref": "21c10a1",
48
+ "files": [
49
+ "nimiq-style:src/buttons.css",
50
+ "nimiq-style:nimiq-style.min.css"
51
+ ]
52
+ }
22
53
  }
@@ -2,17 +2,33 @@
2
2
  "name": "card",
3
3
  "purpose": "Standard Nimiq card container (.nq-card) with header, body and footer sections; the base layout block of @nimiq/style used for grouping content.",
4
4
  "category": "layout",
5
- "variants": ["vue", "html"],
5
+ "variants": [
6
+ "vue",
7
+ "html"
8
+ ],
6
9
  "props": [],
7
- "cssFiles": ["css/legacy/nimiq-style.min.css"],
10
+ "cssFiles": [
11
+ "css/legacy/nimiq-style.min.css"
12
+ ],
8
13
  "dependsOn": [],
9
14
  "npmDeps": [],
10
15
  "verified": true,
11
16
  "verify": {
12
- "viewport": { "width": 600, "height": 420 },
17
+ "viewport": {
18
+ "width": 600,
19
+ "height": 420
20
+ },
13
21
  "selector": ".nq-card",
14
22
  "maxDiffPct": 0.5,
15
23
  "settleMs": 250
16
24
  },
17
- "notes": "Pure CSS-framework component: all styling comes from .nq-card, .nq-card-header, .nq-card-body, .nq-card-footer in legacy nimiq-style.min.css (white bg via --nimiq-card-bg, 1.25rem radius, shadow, --nimiq-blue text, max-width 75rem). Adjacent-sibling rules matter: .nq-card-header + .nq-card-body gets padding-top 1rem; .nq-card-body + .nq-card-footer gets padding-top 0. Sample state: nq-h1 header 'Card Title', nq-text body, footer with an nq-button. Vue variant is a slot-based convenience wrapper (header/default/footer slots), not an upstream vue-components port — upstream has no Card.vue; the card is markup-only in @nimiq/style demo.html."
25
+ "notes": "Pure CSS-framework component: all styling comes from .nq-card, .nq-card-header, .nq-card-body, .nq-card-footer in legacy nimiq-style.min.css (white bg via --nimiq-card-bg, 1.25rem radius, shadow, --nimiq-blue text, max-width 75rem). Adjacent-sibling rules matter: .nq-card-header + .nq-card-body gets padding-top 1rem; .nq-card-body + .nq-card-footer gets padding-top 0. Sample state: nq-h1 header 'Card Title', nq-text body, footer with an nq-button. Vue variant is a slot-based convenience wrapper (header/default/footer slots), not an upstream vue-components port — upstream has no Card.vue; the card is markup-only in @nimiq/style demo.html.",
26
+ "source": {
27
+ "repo": "nimiq-style",
28
+ "ref": "21c10a1",
29
+ "files": [
30
+ "nimiq-style:src/layout.css",
31
+ "nimiq-style:nimiq-style.min.css"
32
+ ]
33
+ }
18
34
  }
@@ -2,17 +2,32 @@
2
2
  "name": "close-button",
3
3
  "purpose": "Circled X dismiss button used on modals and overlays. A .nq-button-s stripped of its pill background, showing the Nimiq close icon at 20% opacity (40% on hover/focus/active), with a round hover halo and enlarged hit area.",
4
4
  "category": "form",
5
- "variants": ["vue", "html"],
5
+ "variants": [
6
+ "vue",
7
+ "html"
8
+ ],
6
9
  "props": [],
7
- "cssFiles": ["css/legacy/nimiq-style.min.css"],
10
+ "cssFiles": [
11
+ "css/legacy/nimiq-style.min.css"
12
+ ],
8
13
  "dependsOn": [],
9
14
  "npmDeps": [],
10
15
  "verified": true,
11
16
  "verify": {
12
- "viewport": { "width": 200, "height": 200 },
17
+ "viewport": {
18
+ "width": 200,
19
+ "height": 200
20
+ },
13
21
  "selector": ".close-button",
14
22
  "maxDiffPct": 0.5,
15
23
  "settleMs": 250
16
24
  },
17
- "notes": "Sample state: default resting state (icon at opacity .2, no .top-right positioning). Upstream scoped CSS targets the bare `button` element; the html snippet namespaces it under .close-button. CloseIcon (@nimiq/style close.svg, 24x24) is inlined with class nq-icon. Add class .top-right to absolutely pin it 2rem from the top-right of a positioned parent. Upstream emits a re-emitted 'click' (MouseEvent) and prevents mousedown default to avoid focus-stealing; no props. Requires nimiq-style for .nq-button-s, .nq-icon and --nimiq-ease."
25
+ "notes": "Sample state: default resting state (icon at opacity .2, no .top-right positioning). Upstream scoped CSS targets the bare `button` element; the html snippet namespaces it under .close-button. CloseIcon (@nimiq/style close.svg, 24x24) is inlined with class nq-icon. Add class .top-right to absolutely pin it 2rem from the top-right of a positioned parent. Upstream emits a re-emitted 'click' (MouseEvent) and prevents mousedown default to avoid focus-stealing; no props. Requires nimiq-style for .nq-button-s, .nq-icon and --nimiq-ease.",
26
+ "source": {
27
+ "repo": "vue-components",
28
+ "ref": "3c5b972",
29
+ "files": [
30
+ "vue-components:src/components/CloseButton.vue"
31
+ ]
32
+ }
18
33
  }
@@ -2,19 +2,40 @@
2
2
  "name": "consensus-icon",
3
3
  "purpose": "Network consensus indicator shown by every Nimiq light-client app: a globe icon that reflects the consensus state — animated globe sprite while syncing, globe with checkmark when consensus is established (green when its parent is :hover/:focus/.active), globe with alert triangle in orange when connecting or stalled.",
4
4
  "category": "feedback",
5
- "variants": ["vue", "html"],
5
+ "variants": [
6
+ "vue",
7
+ "html"
8
+ ],
6
9
  "props": [
7
- { "name": "consensus", "type": "'syncing' | 'established' | 'connecting' | 'stalled'", "default": "'syncing'", "description": "Consensus state. Upstream reads this live from the Network store; the port exposes it as a prop." }
10
+ {
11
+ "name": "consensus",
12
+ "type": "'syncing' | 'established' | 'connecting' | 'stalled'",
13
+ "default": "'syncing'",
14
+ "description": "Consensus state. Upstream reads this live from the Network store; the port exposes it as a prop."
15
+ }
16
+ ],
17
+ "cssFiles": [
18
+ "css/legacy/nimiq-style.min.css"
8
19
  ],
9
- "cssFiles": ["css/legacy/nimiq-style.min.css"],
10
20
  "dependsOn": [],
11
21
  "npmDeps": [],
12
22
  "verified": true,
13
23
  "verify": {
14
- "viewport": { "width": 120, "height": 100 },
24
+ "viewport": {
25
+ "width": 120,
26
+ "height": 100
27
+ },
15
28
  "selector": ".consensus-icon",
16
29
  "maxDiffPct": 0.5,
17
30
  "settleMs": 250
18
31
  },
19
- "notes": "Sample state: ESTABLISHED (WorldCheckIcon, static) wrapped in an .active parent so the upstream rule `.active > .established` colors it nimiq-green at full opacity — exactly how it appears on the wallet sidebar network button while the network page is open. At rest the icon inherits color from context (sidebar: white at 0.3 opacity). Container is 2.75rem (22px) with -0.125rem margin; the check SVG is 24x22 so it slightly overflows the box, as upstream. The SYNCING state animates a 10x3-frame sprite (consensus-sprite.svg, white strokes — needs a colored/dark background or the AccountOverview brightness/sepia filter); snippet + Vue port inline the sprite as a data URI so no asset file is needed. Selectors are namespaced under .consensus-icon and keyframes prefixed consensus-icon-* for showcase embedding."
32
+ "notes": "Sample state: ESTABLISHED (WorldCheckIcon, static) wrapped in an .active parent so the upstream rule `.active > .established` colors it nimiq-green at full opacity — exactly how it appears on the wallet sidebar network button while the network page is open. At rest the icon inherits color from context (sidebar: white at 0.3 opacity). Container is 2.75rem (22px) with -0.125rem margin; the check SVG is 24x22 so it slightly overflows the box, as upstream. The SYNCING state animates a 10x3-frame sprite (consensus-sprite.svg, white strokes — needs a colored/dark background or the AccountOverview brightness/sepia filter); snippet + Vue port inline the sprite as a data URI so no asset file is needed. Selectors are namespaced under .consensus-icon and keyframes prefixed consensus-icon-* for showcase embedding.",
33
+ "source": {
34
+ "repo": "wallet",
35
+ "ref": "656ed56",
36
+ "files": [
37
+ "wallet:src/components/ConsensusIcon.vue",
38
+ "wallet:src/components/icons/WorldCheckIcon.vue"
39
+ ]
40
+ }
20
41
  }
@@ -2,19 +2,39 @@
2
2
  "name": "copyable",
3
3
  "purpose": "Wrapper that makes a click on its content copy it (or a provided text) to the clipboard, with a light-blue hover/focus tint and an animated 'Copied' tooltip as feedback.",
4
4
  "category": "data-display",
5
- "variants": ["vue", "html"],
5
+ "variants": [
6
+ "vue",
7
+ "html"
8
+ ],
6
9
  "props": [
7
- { "name": "text", "type": "string", "required": false, "description": "A specific text to copy to the clipboard on click. Defaults to the element's own innerText (minus the tooltip label)." }
10
+ {
11
+ "name": "text",
12
+ "type": "string",
13
+ "required": false,
14
+ "description": "A specific text to copy to the clipboard on click. Defaults to the element's own innerText (minus the tooltip label)."
15
+ }
16
+ ],
17
+ "cssFiles": [
18
+ "css/legacy/nimiq-style.min.css"
8
19
  ],
9
- "cssFiles": ["css/legacy/nimiq-style.min.css"],
10
20
  "dependsOn": [],
11
21
  "npmDeps": [],
12
22
  "verified": true,
13
23
  "verify": {
14
- "viewport": { "width": 600, "height": 400 },
24
+ "viewport": {
25
+ "width": 600,
26
+ "height": 400
27
+ },
15
28
  "selector": ".copyable",
16
29
  "maxDiffPct": 0.5,
17
30
  "settleMs": 250
18
31
  },
19
- "notes": "Sample state: slot text 'NQ07 0000 ...' in resting (uncopied) state. The .background tint and .tooltip are opacity:0 at rest and only show on hover/focus/.copied. Tooltip label 'Copied' is the en-US i18n string. Clipboard.copy from @nimiq/utils is inlined verbatim in the Vue port (textarea + execCommand with selection restore). Upstream copies 800ms feedback (DISPLAY_TIME); keydown Space/Enter also triggers copy."
32
+ "notes": "Sample state: slot text 'NQ07 0000 ...' in resting (uncopied) state. The .background tint and .tooltip are opacity:0 at rest and only show on hover/focus/.copied. Tooltip label 'Copied' is the en-US i18n string. Clipboard.copy from @nimiq/utils is inlined verbatim in the Vue port (textarea + execCommand with selection restore). Upstream copies 800ms feedback (DISPLAY_TIME); keydown Space/Enter also triggers copy.",
33
+ "source": {
34
+ "repo": "vue-components",
35
+ "ref": "3c5b972",
36
+ "files": [
37
+ "vue-components:src/components/Copyable.vue"
38
+ ]
39
+ }
20
40
  }
@@ -2,23 +2,63 @@
2
2
  "name": "fiat-amount",
3
3
  "purpose": "Displays a fiat amount with an optimized currency symbol (e.g. $1234.56 instead of USD 1234.56) and adaptive decimal precision: decimals are extended until the rounded display deviates from the true amount by at most maxRelativeDeviation.",
4
4
  "category": "payment",
5
- "variants": ["vue", "html"],
5
+ "variants": [
6
+ "vue",
7
+ "html"
8
+ ],
6
9
  "props": [
7
- { "name": "amount", "type": "number", "required": true, "description": "The fiat amount to display." },
8
- { "name": "currency", "type": "string", "required": true, "description": "ISO 4217 currency code, e.g. 'USD', 'EUR'." },
9
- { "name": "maxRelativeDeviation", "type": "number", "default": 0.1, "description": "Max allowed relative deviation of the rounded display value; decimals extend until met." },
10
- { "name": "locale", "type": "string", "required": false, "description": "Formatting locale, e.g. 'en-US'. Defaults to a locale typical for the currency." },
11
- { "name": "hideDecimals", "type": "boolean", "default": false, "description": "Render without decimals. Takes precedence over maxRelativeDeviation." }
10
+ {
11
+ "name": "amount",
12
+ "type": "number",
13
+ "required": true,
14
+ "description": "The fiat amount to display."
15
+ },
16
+ {
17
+ "name": "currency",
18
+ "type": "string",
19
+ "required": true,
20
+ "description": "ISO 4217 currency code, e.g. 'USD', 'EUR'."
21
+ },
22
+ {
23
+ "name": "maxRelativeDeviation",
24
+ "type": "number",
25
+ "default": 0.1,
26
+ "description": "Max allowed relative deviation of the rounded display value; decimals extend until met."
27
+ },
28
+ {
29
+ "name": "locale",
30
+ "type": "string",
31
+ "required": false,
32
+ "description": "Formatting locale, e.g. 'en-US'. Defaults to a locale typical for the currency."
33
+ },
34
+ {
35
+ "name": "hideDecimals",
36
+ "type": "boolean",
37
+ "default": false,
38
+ "description": "Render without decimals. Takes precedence over maxRelativeDeviation."
39
+ }
40
+ ],
41
+ "cssFiles": [
42
+ "css/legacy/nimiq-style.min.css"
12
43
  ],
13
- "cssFiles": ["css/legacy/nimiq-style.min.css"],
14
44
  "dependsOn": [],
15
45
  "npmDeps": [],
16
46
  "verified": true,
17
47
  "verify": {
18
- "viewport": { "width": 600, "height": 400 },
48
+ "viewport": {
49
+ "width": 600,
50
+ "height": 400
51
+ },
19
52
  "selector": ".fiat-amount",
20
53
  "maxDiffPct": 0.5,
21
54
  "settleMs": 250
22
55
  },
23
- "notes": "Sample state: amount=1234.56, currency='USD', locale='en-US' (hardcoded so the render is machine-independent) -> '$1234.56'. The upstream component has NO <style> block; the span inherits font/color from the page (nimiq-style body text). CurrencyInfo and FormattableNumber from @nimiq/utils are inlined in the Vue port (symbol + decimals resolution incl. EXTRA_SYMBOLS/decimal-less lists, and integer grouping with narrow no-break space for >4 integer digits)."
56
+ "notes": "Sample state: amount=1234.56, currency='USD', locale='en-US' (hardcoded so the render is machine-independent) -> '$1234.56'. The upstream component has NO <style> block; the span inherits font/color from the page (nimiq-style body text). CurrencyInfo and FormattableNumber from @nimiq/utils are inlined in the Vue port (symbol + decimals resolution incl. EXTRA_SYMBOLS/decimal-less lists, and integer grouping with narrow no-break space for >4 integer digits).",
57
+ "source": {
58
+ "repo": "vue-components",
59
+ "ref": "3c5b972",
60
+ "files": [
61
+ "vue-components:src/components/FiatAmount.vue"
62
+ ]
63
+ }
24
64
  }