@trading-game/design-intelligence-layer 0.14.0 → 0.15.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/AGENTS.md +140 -1
- package/README.md +15 -6
- package/dist/index.cjs +506 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +186 -1
- package/dist/index.d.ts +186 -1
- package/dist/index.js +498 -0
- package/dist/index.js.map +1 -1
- package/guides/design-system-guide/trading-game-ds-guide.md +199 -33
- package/guides/rules/design-system-consuming-project.mdc +19 -11
- package/package.json +1 -1
- package/src/styles.css +22 -0
|
@@ -614,71 +614,237 @@ These are styling behaviors you can't discover from TypeScript types alone:
|
|
|
614
614
|
|
|
615
615
|
## 8.5 — Blocks Catalogue
|
|
616
616
|
|
|
617
|
-
> Blocks are fully composed UI sections built from design system primitives. They
|
|
618
|
-
> -
|
|
619
|
-
> -
|
|
620
|
-
> -
|
|
617
|
+
> Blocks are fully composed UI sections built from design system primitives. They are **exported from the package** the same as primitives — import them by name and pass data via props.
|
|
618
|
+
> - **Variants** (`layout` / `mode` / `status`) live on a single block, not separate components.
|
|
619
|
+
> - Each block ships with internal state where appropriate (e.g. `NavBarBlock` manages its own mobile-menu drawer).
|
|
620
|
+
> - Blocks appear in the **Blocks** tab of the playground for visual reference, with the demo importing the same exports a consumer would.
|
|
621
621
|
|
|
622
|
-
###
|
|
622
|
+
### `HeroBlock`
|
|
623
623
|
|
|
624
|
-
|
|
624
|
+
Marketing hero section with two layouts.
|
|
625
|
+
|
|
626
|
+
```tsx
|
|
627
|
+
import { HeroBlock } from "@trading-game/design-intelligence-layer"
|
|
628
|
+
|
|
629
|
+
<HeroBlock
|
|
630
|
+
layout="centered" // "centered" | "split"
|
|
631
|
+
tagline={{ label: "What's new", suffix: "v2.0" }}
|
|
632
|
+
heading="Solve your customer's main problem"
|
|
633
|
+
body="One or two sentences expanding on the value prop."
|
|
634
|
+
primaryCta={{ label: "Get started" }}
|
|
635
|
+
secondaryCta={{ label: "Learn more" }} // split layout only
|
|
636
|
+
/>
|
|
637
|
+
```
|
|
625
638
|
|
|
626
639
|
| Variant | Description |
|
|
627
640
|
|---------|-------------|
|
|
628
|
-
| Desktop |
|
|
629
|
-
|
|
|
630
|
-
| Mobile
|
|
641
|
+
| `centered` (Desktop) | Centred single-column: tagline pill + heading + body + single primary CTA with `ArrowRight` icon; no image |
|
|
642
|
+
| `split` (Desktop) | Two columns: tagline pill + heading + body + Get started / Learn more CTAs left; square image panel right |
|
|
643
|
+
| `split` (Mobile) | Single column stacked: text content centred above, image panel full-width below |
|
|
631
644
|
|
|
632
|
-
**Components used:** `Button` (
|
|
645
|
+
**Components used:** `Button` (default `sm`, `secondary sm`); `ArrowUpRight`, `ArrowRight` icons (lucide)
|
|
633
646
|
|
|
634
|
-
**Tokens used:** `bg-prominent`, `bg-
|
|
647
|
+
**Tokens used:** `bg-prominent`, `bg-subtle`, `border-border-subtle`, `text-on-prominent`, `text-on-subtle`, `bg-semantic-win`, `rounded-xl`, `rounded-full`, `px-layout-margin-inline`, `gap-layout-gutter`, `py-24`, `text-5xl`, `font-semibold`, `font-display`, `tracking-tight`, `text-lg`, `font-body`, `text-sm`, `shadow-sm`, `max-w-2xl`
|
|
635
648
|
|
|
636
649
|
---
|
|
637
650
|
|
|
638
|
-
###
|
|
651
|
+
### `AuthBlock`
|
|
652
|
+
|
|
653
|
+
Sign-in / sign-up form. Form fields are identical between modes; `mode` drives heading, terms copy, CTA label, and the footer cross-link.
|
|
654
|
+
|
|
655
|
+
```tsx
|
|
656
|
+
import { AuthBlock } from "@trading-game/design-intelligence-layer"
|
|
657
|
+
|
|
658
|
+
<AuthBlock
|
|
659
|
+
mode="sign-in" // "sign-in" | "sign-up"
|
|
660
|
+
logoSrc="/path/to/brand-icon.svg" // consumer-provided
|
|
661
|
+
providers={["google", "telegram", "x"]} // default: all three
|
|
662
|
+
onSubmit={({ email }) => { ... }}
|
|
663
|
+
crossLinkHref="/auth/signup"
|
|
664
|
+
/>
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
| Region | Content |
|
|
668
|
+
|--------|---------|
|
|
669
|
+
| Top | Brand logo + wordmark lockup |
|
|
670
|
+
| Heading | "Sign in" / "Sign up" (mode-driven) |
|
|
671
|
+
| Providers | Configurable OAuth buttons (Google, Telegram, X) |
|
|
672
|
+
| Body | "or" divider + email input + terms paragraph |
|
|
673
|
+
| Footer | Primary CTA + footer cross-link to the opposite mode |
|
|
674
|
+
|
|
675
|
+
**Components used:** `Button`, `Input`, `Link`
|
|
676
|
+
|
|
677
|
+
**Tokens used:** `text-on-prominent`, `text-on-subtle`, `bg-border-subtle`, `font-display`, `font-body`
|
|
678
|
+
|
|
679
|
+
---
|
|
639
680
|
|
|
640
|
-
|
|
681
|
+
### `FAQBlock`
|
|
682
|
+
|
|
683
|
+
Frequently-asked-questions section with optional help card.
|
|
684
|
+
|
|
685
|
+
```tsx
|
|
686
|
+
import { FAQBlock } from "@trading-game/design-intelligence-layer"
|
|
687
|
+
|
|
688
|
+
<FAQBlock
|
|
689
|
+
layout="desktop" // "desktop" | "mobile"
|
|
690
|
+
items={[{ value: "q1", question: "...", answer: "..." }, ...]}
|
|
691
|
+
intro={<>Optional intro paragraph with a <Link>link</Link>.</>}
|
|
692
|
+
helpCard={{ title: "Need more help?", body: "...", ctaLabel: "Contact us" }}
|
|
693
|
+
/>
|
|
694
|
+
```
|
|
641
695
|
|
|
642
696
|
| Variant | Description |
|
|
643
697
|
|---------|-------------|
|
|
644
|
-
|
|
|
645
|
-
|
|
|
646
|
-
| Type 2 — Desktop | Centred single-column: tagline pill + heading + body + single primary CTA with `ArrowRight` icon; no image |
|
|
698
|
+
| `desktop` | `text-5xl` heading, `gap-12`, help card padding `p-8` |
|
|
699
|
+
| `mobile` | `text-4xl` heading, `gap-10`, help card padding `p-6` |
|
|
647
700
|
|
|
648
|
-
**Components used:** `
|
|
701
|
+
**Components used:** `Accordion`, `AccordionItem`, `AccordionTrigger`, `AccordionContent`, `Button`
|
|
649
702
|
|
|
650
|
-
**Tokens used:** `
|
|
703
|
+
**Tokens used:** `text-on-prominent`, `text-on-subtle`, `bg-subtle`, `font-display`, `font-body`, `rounded-xl`
|
|
651
704
|
|
|
652
705
|
---
|
|
653
706
|
|
|
654
|
-
###
|
|
707
|
+
### `NavBarBlock`
|
|
655
708
|
|
|
656
|
-
A
|
|
709
|
+
A landing page top navigation bar with internal mobile-menu state. Single component handles both desktop bar and mobile drawer.
|
|
657
710
|
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
711
|
+
```tsx
|
|
712
|
+
import { NavBarBlock } from "@trading-game/design-intelligence-layer"
|
|
713
|
+
|
|
714
|
+
<NavBarBlock
|
|
715
|
+
brand={{ fullLogoSrc: "...", iconLogoSrc: "...", alt: "Brand" }}
|
|
716
|
+
links={[{ label: "Products" }, { label: "Docs" }, ...]}
|
|
717
|
+
signIn={{ onClick: ... }}
|
|
718
|
+
signUp={{ onClick: ... }}
|
|
719
|
+
/>
|
|
720
|
+
```
|
|
662
721
|
|
|
663
|
-
|
|
722
|
+
| Breakpoint | Description |
|
|
723
|
+
|------------|-------------|
|
|
724
|
+
| Desktop (≥600 px) | Full-width bar: full logo + tertiary nav links left; Sign in (tertiary) + Sign up (primary) right |
|
|
725
|
+
| Mobile — closed | Icon logo left, hamburger icon-button right |
|
|
726
|
+
| Mobile — open | Stacked tertiary nav links + full-width Sign in (secondary) / Sign up (primary) below a divider |
|
|
664
727
|
|
|
665
|
-
**
|
|
728
|
+
**Components used:** `Button` (variants: `tertiary`, `secondary`, default; sizes: `sm`, `icon-sm`); `Menu`, `X` icons (lucide)
|
|
729
|
+
|
|
730
|
+
**Tokens used:** `bg-prominent`, `border-border-subtle`, `rounded-md`, `px-layout-margin-inline`
|
|
666
731
|
|
|
667
732
|
---
|
|
668
733
|
|
|
669
|
-
###
|
|
734
|
+
### `HeaderNavigationBlock`
|
|
670
735
|
|
|
671
|
-
A product app top header bar.
|
|
736
|
+
A product app top header bar. Includes optional history button with overlaid numeric count badge.
|
|
737
|
+
|
|
738
|
+
```tsx
|
|
739
|
+
import { HeaderNavigationBlock } from "@trading-game/design-intelligence-layer"
|
|
740
|
+
|
|
741
|
+
<HeaderNavigationBlock
|
|
742
|
+
onBack={() => router.back()}
|
|
743
|
+
badge={{ label: "Demo", variant: "fill-warning" }}
|
|
744
|
+
balance={{ amount: "1000.00", currency: "USDT" }}
|
|
745
|
+
history={{ count: 5, onClick: openHistorySheet }} // count 0 hides badge; >99 shows "99+"
|
|
746
|
+
actions={<SoundToggleButton />}
|
|
747
|
+
/>
|
|
748
|
+
```
|
|
672
749
|
|
|
673
750
|
| Region | Content |
|
|
674
751
|
|--------|---------|
|
|
675
|
-
| Left | `NavigationButton` (back arrow) |
|
|
676
|
-
| Centre | `Badge` (fill-warning "Demo" label) +
|
|
677
|
-
| Right | `NavigationButton`
|
|
752
|
+
| Left | `NavigationButton` (back arrow, rendered only if `onBack` provided) |
|
|
753
|
+
| Centre | `Badge` (fill-warning "Demo" label) + balance amount + currency |
|
|
754
|
+
| Right | History `NavigationButton` with optional numeric badge (`bg-primary`, `ring-2 ring-prominent`) + `actions` slot for additional icon buttons |
|
|
755
|
+
|
|
756
|
+
**Components used:** `NavigationButton`, `Badge`; `ArrowLeft`, `History` icons (lucide)
|
|
757
|
+
|
|
758
|
+
**Tokens used:** `bg-prominent`, `border-border-subtle`, `text-on-prominent`, `text-on-subtle`, `bg-primary`, `text-on-primary`, `max-w-layout-diagram-small`, `px-layout-margin-inline`
|
|
759
|
+
|
|
760
|
+
---
|
|
761
|
+
|
|
762
|
+
### `OpenPositionsBlock`
|
|
763
|
+
|
|
764
|
+
A slide-in panel listing open trading positions. Responsive — `Sheet` on desktop, `Drawer` on mobile (via `useIsMobile()`).
|
|
765
|
+
|
|
766
|
+
```tsx
|
|
767
|
+
import { OpenPositionsBlock, type Position } from "@trading-game/design-intelligence-layer"
|
|
768
|
+
|
|
769
|
+
const positions: Position[] = [
|
|
770
|
+
{ kind: "rise-fall", direction: "Rise", market: "Vol 100", duration: "30 minutes",
|
|
771
|
+
stake: "1.00 USDT", pnl: "+0.96 USDT", win: true },
|
|
772
|
+
...
|
|
773
|
+
]
|
|
774
|
+
|
|
775
|
+
<OpenPositionsBlock
|
|
776
|
+
trigger={<Button variant="secondary">Active trades</Button>}
|
|
777
|
+
positions={positions}
|
|
778
|
+
sheetTitle="Positions"
|
|
779
|
+
onViewHistory={openHistoryPage}
|
|
780
|
+
/>
|
|
781
|
+
```
|
|
782
|
+
|
|
783
|
+
Positions are a discriminated union by `kind`:
|
|
784
|
+
|
|
785
|
+
| `kind` | Title rendered as | Extra fields |
|
|
786
|
+
|--------|--------------------|--------------|
|
|
787
|
+
| `"rise-fall"` | `direction` (e.g. "Rise" / "Fall") | — |
|
|
788
|
+
| `"swipe"` | `Swipe-<direction>` (e.g. "Swipe-up") | — |
|
|
789
|
+
| `"box-o"` | `"Box-O"` | `multiplier` |
|
|
790
|
+
| `"digits"` | Type label (e.g. "Matches", "Under") | `type`, `digit?` |
|
|
791
|
+
|
|
792
|
+
**Components used:** `Sheet`, `Drawer`, `Item`, `ItemGroup`, `ItemContent`, `ItemTitle`, `ItemActions`, `Empty`, `EmptyHeader`, `EmptyMedia`, `EmptyTitle`, `Button`, `NavigationButton`, `Separator`
|
|
793
|
+
|
|
794
|
+
**Tokens used:** `bg-prominent`, `border-border-subtle`, `text-semantic-win`, `text-semantic-loss`, `text-on-prominent`, `text-on-subtle`
|
|
795
|
+
|
|
796
|
+
---
|
|
797
|
+
|
|
798
|
+
### `ResultBlock`
|
|
799
|
+
|
|
800
|
+
Universal end-of-round result card. Fixed-width (320 px) with animated halo + thumb illustration (bundled inline as base64) + contract/duration badges + CTA.
|
|
801
|
+
|
|
802
|
+
```tsx
|
|
803
|
+
import { ResultBlock } from "@trading-game/design-intelligence-layer"
|
|
804
|
+
|
|
805
|
+
<ResultBlock
|
|
806
|
+
status="win" // "win" | "loss"
|
|
807
|
+
amount="10,000.00"
|
|
808
|
+
currency="USDT"
|
|
809
|
+
contractLabel="Rise"
|
|
810
|
+
duration="2 hours"
|
|
811
|
+
pickedDigit={7} // optional, for Digits contracts
|
|
812
|
+
ctaMode="next-round" // "next-round" | "go-again" | "conversion"
|
|
813
|
+
/>
|
|
814
|
+
```
|
|
815
|
+
|
|
816
|
+
| `ctaMode` | Renders |
|
|
817
|
+
|-----------|---------|
|
|
818
|
+
| `"next-round"` | Single "Next round" button |
|
|
819
|
+
| `"go-again"` | Single "Go again" button |
|
|
820
|
+
| `"conversion"` | "Ready to play for real?" heading + "Deposit now" + "Stay in demo" |
|
|
821
|
+
|
|
822
|
+
The float / shake / halo animations are defined in `src/styles.css` and ship with the package — consumers who `@import "@trading-game/design-intelligence-layer/styles"` get them automatically.
|
|
823
|
+
|
|
824
|
+
**Components used:** `Card`, `Badge` (variant `standard`), `Button`
|
|
825
|
+
|
|
826
|
+
**Tokens used:** `bg-semantic-win`, `bg-semantic-loss`, `text-semantic-win`, `text-semantic-loss`, `text-on-prominent`, `bg-border-prominent/40`, `font-display`, `font-semibold`, `tabular-nums`, `tracking-tight`, `rounded-md`, `shadow-sm`
|
|
827
|
+
|
|
828
|
+
---
|
|
829
|
+
|
|
830
|
+
### `ResultDialog`
|
|
831
|
+
|
|
832
|
+
Fixed-width system dialog (title + body + two CTAs). Used for messages adjacent to `ResultBlock` like "out of balance" or "on a roll" — same width and styling, no thumb or amount.
|
|
833
|
+
|
|
834
|
+
```tsx
|
|
835
|
+
import { ResultDialog } from "@trading-game/design-intelligence-layer"
|
|
836
|
+
|
|
837
|
+
<ResultDialog
|
|
838
|
+
title="You're out of balance."
|
|
839
|
+
body="Deposit to keep playing or stay in demo mode."
|
|
840
|
+
primaryLabel="Deposit now"
|
|
841
|
+
secondaryLabel="Stay in demo"
|
|
842
|
+
/>
|
|
843
|
+
```
|
|
678
844
|
|
|
679
|
-
**Components used:** `
|
|
845
|
+
**Components used:** `Card`, `Button`
|
|
680
846
|
|
|
681
|
-
**Tokens used:** `
|
|
847
|
+
**Tokens used:** `text-on-prominent`, `text-on-subtle`, `rounded-md`, `shadow-sm`
|
|
682
848
|
|
|
683
849
|
---
|
|
684
850
|
|
|
@@ -210,22 +210,30 @@ Wait for confirmation before proceeding.
|
|
|
210
210
|
|
|
211
211
|
---
|
|
212
212
|
|
|
213
|
-
## Rule 8 — Blocks are
|
|
213
|
+
## Rule 8 — Blocks are first-class exports (import them by name)
|
|
214
214
|
|
|
215
|
-
**Blocks** are
|
|
215
|
+
**Blocks** are opinionated, composed UI sections — exported from `@trading-game/design-intelligence-layer` the same as primitives. Import by name and pass data via props. Variants live as a `layout` / `mode` / `status` prop on a single block, not as separate components.
|
|
216
216
|
|
|
217
217
|
```
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
✅
|
|
221
|
-
|
|
218
|
+
✅ Import blocks directly from the package — same pattern as primitives
|
|
219
|
+
✅ Pass data via props; variants are configured via a single variant prop
|
|
220
|
+
✅ Block names ARE valid component names (treat them like Rule 1 components)
|
|
221
|
+
❌ Do NOT re-implement a block by hand if a block export already covers it
|
|
222
|
+
❌ Do NOT split variants into separate blocks — use the variant prop
|
|
222
223
|
```
|
|
223
224
|
|
|
224
|
-
| Block |
|
|
225
|
-
|
|
226
|
-
|
|
|
227
|
-
|
|
|
228
|
-
|
|
|
225
|
+
| Block | Variants | Importable? |
|
|
226
|
+
|-------|----------|-------------|
|
|
227
|
+
| `HeroBlock` | `layout: "centered" \| "split"` | Yes — `import { HeroBlock }` |
|
|
228
|
+
| `AuthBlock` | `mode: "sign-in" \| "sign-up"` | Yes — `import { AuthBlock }` |
|
|
229
|
+
| `FAQBlock` | `layout: "desktop" \| "mobile"` | Yes — `import { FAQBlock }` |
|
|
230
|
+
| `NavBarBlock` | — (internal mobile-menu state) | Yes — `import { NavBarBlock }` |
|
|
231
|
+
| `HeaderNavigationBlock` | — (optional `history.count` badge) | Yes — `import { HeaderNavigationBlock }` |
|
|
232
|
+
| `OpenPositionsBlock` | `Position` discriminated union | Yes — `import { OpenPositionsBlock, type Position }` |
|
|
233
|
+
| `ResultBlock` | `status` + `ctaMode` | Yes — `import { ResultBlock }` |
|
|
234
|
+
| `ResultDialog` | — | Yes — `import { ResultDialog }` |
|
|
235
|
+
|
|
236
|
+
See `guides/design-system-guide/trading-game-ds-guide.md` § 8.5 for full per-block API, used components, and used tokens.
|
|
229
237
|
|
|
230
238
|
---
|
|
231
239
|
|
package/package.json
CHANGED
package/src/styles.css
CHANGED
|
@@ -490,4 +490,26 @@
|
|
|
490
490
|
font-weight: 600;
|
|
491
491
|
font-size: 8px;
|
|
492
492
|
line-height: 12px;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/* ── Result block — icon motion ─────────────────────────────── */
|
|
496
|
+
[data-results-motion="halo"] {
|
|
497
|
+
opacity: 0.22;
|
|
498
|
+
}
|
|
499
|
+
[data-results-motion="icon-win"] {
|
|
500
|
+
animation: results-icon-float 2.2s ease-in-out infinite;
|
|
501
|
+
}
|
|
502
|
+
[data-results-motion="icon-loss"] {
|
|
503
|
+
animation: results-icon-shake 2.4s ease-in-out infinite;
|
|
504
|
+
}
|
|
505
|
+
@keyframes results-icon-float {
|
|
506
|
+
0%, 100% { transform: translateY(0) rotate(0); }
|
|
507
|
+
50% { transform: translateY(-10px) rotate(-4deg); }
|
|
508
|
+
}
|
|
509
|
+
@keyframes results-icon-shake {
|
|
510
|
+
0%, 100% { transform: rotate(-8deg); }
|
|
511
|
+
50% { transform: rotate(8deg); }
|
|
512
|
+
}
|
|
513
|
+
@media (prefers-reduced-motion: reduce) {
|
|
514
|
+
[data-results-motion] { animation: none !important; }
|
|
493
515
|
}
|