@nexub/mcp 3.0.0 → 3.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.
- package/dist/skill/SKILL.md +21 -7
- package/dist/skill/references/components/bar-chart.md +81 -0
- package/dist/skill/references/components/button.md +19 -1
- package/dist/skill/references/components/card.md +28 -1
- package/dist/skill/references/components/cta-band.md +34 -0
- package/dist/skill/references/components/donut-chart.md +53 -0
- package/dist/skill/references/components/eyebrow-chip.md +21 -1
- package/dist/skill/references/components/faq.md +35 -0
- package/dist/skill/references/components/feature-split.md +40 -0
- package/dist/skill/references/components/hero.md +44 -0
- package/dist/skill/references/components/how-it-works.md +35 -0
- package/dist/skill/references/components/line-chart.md +83 -0
- package/dist/skill/references/components/logo-strip.md +35 -0
- package/dist/skill/references/components/marketing-footer.md +43 -0
- package/dist/skill/references/components/marketing-nav.md +63 -0
- package/dist/skill/references/components/motion-float.md +33 -0
- package/dist/skill/references/components/motion-marquee.md +35 -0
- package/dist/skill/references/components/motion-reveal.md +33 -0
- package/dist/skill/references/components/number-ticker.md +18 -0
- package/dist/skill/references/components/pricing-table.md +42 -0
- package/dist/skill/references/components/product-grid.md +39 -0
- package/dist/skill/references/components/section-header.md +35 -0
- package/dist/skill/references/components/sparkline.md +41 -0
- package/dist/skill/references/components/stat-band.md +37 -0
- package/dist/skill/references/components/testimonial-grid.md +37 -0
- package/dist/skill/references/components.md +25 -2
- package/dist/skill/references/tokens.md +3 -2
- package/package.json +1 -1
package/dist/skill/SKILL.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: nexub-ds
|
|
3
|
-
description: Build SaaS UI with the Nexub Design System (@nexub/react, @nexub/patterns, @nexub/tokens, @nexub/themes, @nexub/icons). Use when building or restyling any React screen, page, dashboard, form, settings page, auth flow, pricing page or component in a project that uses Nexub DS, or when the user asks for Nexub, Calm Depth or Liquid Glass UI.
|
|
3
|
+
description: Build SaaS UI with the Nexub Design System (@nexub/react, @nexub/patterns, @nexub/marketing, @nexub/tokens, @nexub/themes, @nexub/icons). Use when building or restyling any React screen, page, dashboard, form, settings page, auth flow, pricing page, marketing or landing page, or component in a project that uses Nexub DS, or when the user asks for Nexub, Calm Depth, marketing mode or Liquid Glass UI.
|
|
4
4
|
license: MIT
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Nexub Design System
|
|
8
8
|
|
|
9
|
-
Nexub DS is a token-driven React design system for SaaS products. The visual language is **Calm Depth**: tonal surfaces, one accent per view, spring motion, honest numbers. **Liquid Glass** is an optional material for the floating control layer.
|
|
9
|
+
Nexub DS is a token-driven React design system for SaaS products. The visual language is **Calm Depth**: tonal surfaces, one accent per view, spring motion, honest numbers. **Liquid Glass** is an optional material for the floating control layer. **Marketing mode** (`data-mode="marketing"`) is the livelier look for marketing sites, on the same tokens.
|
|
10
10
|
|
|
11
11
|
Reference files (read only what the task needs):
|
|
12
12
|
|
|
@@ -54,6 +54,8 @@ export default {
|
|
|
54
54
|
@source "../node_modules/@nexub/patterns/dist";
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
+
**Next.js App Router:** presentational components (Heading, Text, Container, Section, Stack, Badge, EyebrowChip, Logo, Float, Marquee and every `@nexub/marketing` section except `MarketingNav`, `PricingTable` and `FAQ`) are server components. Import per component (`@nexub/react/Button`, `@nexub/marketing/Hero`, `cn` from `@nexub/react/cn`) or set `experimental.optimizePackageImports: ['@nexub/react', '@nexub/marketing', '@nexub/icons']`, or the page ships every client component. Compound components (`Accordion.Root`, `TopNav.Root`) only work inside a `'use client'` file. To use `next/font`, import `@nexub/themes/core` (no fonts, no page backdrop) instead of `base` and name the font variables `--font-family-sans` and `--font-family-display`. With Tailwind, never also import `@nexub/react/styles.css`.
|
|
58
|
+
|
|
57
59
|
Wrap the app in `<ThemeProvider defaultTheme="system" storageKey="app-theme">` from `@nexub/react`. In server-rendered apps (Next.js), put `<ThemeScript storageKey="app-theme" />` in `<head>` and add `suppressHydrationWarning` to `<html>`. Product brands: set `data-product="leap" | "bookub" | "payub" | "founderub"` on the root. This remaps the `tertiary` role.
|
|
58
60
|
|
|
59
61
|
## 2. How to build a screen
|
|
@@ -68,7 +70,8 @@ Starting points for typical SaaS screens:
|
|
|
68
70
|
| Screen | Build with |
|
|
69
71
|
| --- | --- |
|
|
70
72
|
| App frame | `AppShell` (`AppShell.Root/Header/Body/Sidebar/Main`) + `Sidebar` or `NavigationRail` + `AppHeader` or `TopNav` |
|
|
71
|
-
| Dashboard | `PageHeader` + a `Grid` of `StatCard` + `DataTable` or `Table` + `ActivityFeed` |
|
|
73
|
+
| Dashboard | `PageHeader` + a `Grid` of `StatCard` + `BarChart` / `LineChart` + `DataTable` or `Table` + `ActivityFeed` |
|
|
74
|
+
| Charts | `BarChart` (compare categories), `LineChart` (trend over time), `DonutChart` (parts of a whole, six slices at most), `Sparkline` (trend inside a stat or table cell). Pass `title`, `data`, `index` and `series`; colours come from the chart palette, never hex |
|
|
72
75
|
| List / detail | `ListDetail` + `FilterBar` + `EmptyState` |
|
|
73
76
|
| Settings | `SettingsLayout` / `SettingsRow` + `SettingsSection` + `FormField` |
|
|
74
77
|
| Sign in / sign up | `AuthCard` + `FormField` + `PasswordInput` |
|
|
@@ -76,13 +79,14 @@ Starting points for typical SaaS screens:
|
|
|
76
79
|
| Onboarding | `StepIndicator` + `CheckList` |
|
|
77
80
|
| Search / commands | `CommandPalette` + `KeyboardShortcut` |
|
|
78
81
|
| Empty, loading, error | `EmptyState`, `Skeleton`, `ErrorState`, `Toast` |
|
|
82
|
+
| Marketing / landing page | `@nexub/marketing` under `data-mode="marketing"`: `MarketingNav`, `Hero`, `LogoStrip`, `StatBand`, `FeatureSplit`, `HowItWorks`, `ProductGrid`, `TestimonialGrid`, `PricingTable`, `FAQ`, `CTABand`, `MarketingFooter` |
|
|
79
83
|
|
|
80
84
|
Money: use `Amount` and `MoneyInput`. They use tabular figures, the currency's own minor unit and a true minus sign. Icons: import from `@nexub/icons`, not `lucide-react` directly.
|
|
81
85
|
|
|
82
86
|
## 3. Calm Depth principles
|
|
83
87
|
|
|
84
88
|
1. **Content leads, chrome recedes.** Navigation is quieter than content. Remove a divider before you add one; let spacing and tone separate regions. Do: a tonal sidebar with no border, where the active item is a soft pill. Don't: a saturated brand-blue sidebar item, or a hard line around every region.
|
|
85
|
-
2. **Hierarchy through tone and layout, not decoration.** Surfaces step `surface` → `surface-container-*` → `surface-elevated`. Shadows are only for things that float. Product UI has no gradients, no colored icon tiles and no gradient eyebrow chips.
|
|
89
|
+
2. **Hierarchy through tone and layout, not decoration.** Surfaces step `surface` → `surface-container-*` → `surface-elevated`. Shadows are only for things that float. Product UI has no gradients, no colored icon tiles and no gradient eyebrow chips (those belong to marketing mode only).
|
|
86
90
|
3. **One accent, spent deliberately.** Each view gets one filled (primary) button. Everything else is `tonal`, `outlined` or `text`. Never put two filled buttons side by side.
|
|
87
91
|
4. **Physical, interruptible motion.** Use the spring tokens (`ease-spatial-default duration-spatial-default`), not raw durations. Exits are faster than entrances. Honor `prefers-reduced-motion`.
|
|
88
92
|
5. **Honest numbers and states.** Use tabular figures in data. Hover, pressed, selected and disabled are explicit component states. Never fake a state with opacity.
|
|
@@ -95,15 +99,25 @@ Money: use `Amount` and `MoneyInput`. They use tabular figures, the currency's o
|
|
|
95
99
|
- Never put glass on glass. Show at most three glass layers at a time. Tint only the one primary action (`data-glass-tint="primary"`).
|
|
96
100
|
- Never put white text on glass over an unknown background.
|
|
97
101
|
|
|
98
|
-
## 5.
|
|
102
|
+
## 5. Marketing mode rules
|
|
103
|
+
|
|
104
|
+
- Turn it on with `data-mode="marketing"` and `@nexub/themes/marketing`. Nothing outside the attribute changes; never use it in product UI.
|
|
105
|
+
- Gradients in three places only: the `Hero`, the main button (`Button variant="hero"`) and the `CTABand`.
|
|
106
|
+
- At most one `variant="hero"` button per screen; pair it with an outlined button.
|
|
107
|
+
- Product accents (`Card variant="showcase" accent="payub"`, `TestimonialCard accent`) only on product-specific content.
|
|
108
|
+
- Motion budget: one entrance per section (`Reveal` or the hero's rise), at most two `Float`s in view, one `Marquee` plus the footer's. All of it stops under reduced motion.
|
|
109
|
+
- Page width `Container size="marketing"` (1280px); headlines `text-display-xl` on the hero only; one h1 per page (the `Hero` title).
|
|
110
|
+
|
|
111
|
+
## 6. UI copy
|
|
99
112
|
|
|
100
113
|
Copy is clear, direct, human and confident. Use sentence case, active voice, contractions and specific verbs ("Save changes", not "Submit"). Errors say what happened and what to do: "Your session expired. Sign in again." No "Oops", no emoji in errors, no "Please be advised".
|
|
101
114
|
|
|
102
|
-
##
|
|
115
|
+
## 7. Before you finish
|
|
103
116
|
|
|
104
117
|
- [ ] Every control comes from `@nexub/react` or `@nexub/patterns`. No deprecated component (see the index).
|
|
105
118
|
- [ ] There are no hex or rgb colors, Tailwind palette colors, arbitrary px values or custom shadows. Everything is a token utility or `var(--…)`.
|
|
106
119
|
- [ ] Every background role is paired with its `on-` role. Secondary text uses `on-surface-variant` or `on-surface-muted`.
|
|
107
|
-
- [ ] Each view has at most one filled button.
|
|
120
|
+
- [ ] Each view has at most one filled button (marketing: at most one hero button).
|
|
121
|
+
- [ ] In Next.js, server pages import per component and use no compound component outside a `'use client'` file.
|
|
108
122
|
- [ ] The screen works in light and dark (`data-theme`) and at `data-contrast="high"`.
|
|
109
123
|
- [ ] Every input has a label. Icon-only buttons have an `aria-label`. Keyboard paths work.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Bar Chart
|
|
2
|
+
|
|
3
|
+
Compare values across categories, grouped or stacked. Server-rendered SVG on the chart palette.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/react` · Category: Data Display · Status: beta
|
|
6
|
+
- Import: `import { BarChart } from '@nexub/react';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/components/bar-chart
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `title` (required) | `string` | | Accessible name of the chart and caption of its data table. |
|
|
14
|
+
| `data` (required) | `T[]` | | One row per category, in order. |
|
|
15
|
+
| `index` (required) | `keyof T` | | Key of the category label in each row (the x axis). |
|
|
16
|
+
| `series` (required) | `ChartSeries[]` | | `{ key, label?, color? }` per series. `color` is 1–8 from the categorical chart palette; defaults to the series position. |
|
|
17
|
+
| `valueFormat` | `(value: number) => string` | | Formats axis labels, hover text and the data table. |
|
|
18
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Plot height: 8, 12 or 16rem. |
|
|
19
|
+
| `legend` | `boolean` | | Show the legend. Defaults to on for more than one series. |
|
|
20
|
+
| `stacked` | `boolean` | `false` | One bar per category with the series stacked. |
|
|
21
|
+
|
|
22
|
+
## Example: Grouped
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
import { BarChart } from '@nexub/react';
|
|
26
|
+
|
|
27
|
+
const data = [
|
|
28
|
+
{ month: 'May', thisYear: 42, lastYear: 35 },
|
|
29
|
+
{ month: 'Jun', thisYear: 48, lastYear: 37 },
|
|
30
|
+
{ month: 'Jul', thisYear: 45, lastYear: 40 },
|
|
31
|
+
{ month: 'Aug', thisYear: 56, lastYear: 41 },
|
|
32
|
+
{ month: 'Sep', thisYear: 61, lastYear: 47 },
|
|
33
|
+
{ month: 'Oct', thisYear: 68, lastYear: 50 },
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
export default function Example() {
|
|
37
|
+
return (
|
|
38
|
+
<BarChart
|
|
39
|
+
className="w-full"
|
|
40
|
+
title="Revenue by month"
|
|
41
|
+
data={data}
|
|
42
|
+
index="month"
|
|
43
|
+
series={[{ key: 'thisYear', label: '2026' }, { key: 'lastYear', label: '2025' }]}
|
|
44
|
+
valueFormat={(v) => `$${v}k`}
|
|
45
|
+
/>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Example: Stacked
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
import { BarChart } from '@nexub/react';
|
|
54
|
+
|
|
55
|
+
const data = [
|
|
56
|
+
{ quarter: 'Q1', web: 120, ios: 80, android: 60 },
|
|
57
|
+
{ quarter: 'Q2', web: 140, ios: 95, android: 72 },
|
|
58
|
+
{ quarter: 'Q3', web: 150, ios: 110, android: 90 },
|
|
59
|
+
{ quarter: 'Q4', web: 170, ios: 128, android: 101 },
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
export default function Example() {
|
|
63
|
+
return (
|
|
64
|
+
<BarChart
|
|
65
|
+
stacked
|
|
66
|
+
className="w-full"
|
|
67
|
+
title="Signups by platform"
|
|
68
|
+
data={data}
|
|
69
|
+
index="quarter"
|
|
70
|
+
series={[{ key: 'web', label: 'Web' }, { key: 'ios', label: 'iOS' }, { key: 'android', label: 'Android' }]}
|
|
71
|
+
/>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Accessibility
|
|
77
|
+
|
|
78
|
+
- The chart is a `figure` named by `title`. The drawing is hidden from assistive tech; a visually hidden table carries every value.
|
|
79
|
+
- Colour is never the only cue: the legend and table name each series. Past six series, label directly or group the rest as "Other".
|
|
80
|
+
|
|
81
|
+
Related: [line-chart](line-chart.md), [donut-chart](donut-chart.md), [sparkline](sparkline.md)
|
|
@@ -24,7 +24,7 @@ Triggers an action or event. Supports multiple variants, sizes, and semantic ton
|
|
|
24
24
|
|
|
25
25
|
| Prop | Type | Default | Description |
|
|
26
26
|
| --- | --- | --- | --- |
|
|
27
|
-
| `variant` | `'filled' \| 'tonal' \| 'outlined' \| 'text' \| 'glass' \| 'subtle' \| 'link' \| 'destructive' \| 'accent'` | `'primary'` | Visual style of the button. Legacy aliases still work: primary = filled, secondary = tonal, outline = outlined, ghost = text. |
|
|
27
|
+
| `variant` | `'filled' \| 'tonal' \| 'outlined' \| 'text' \| 'glass' \| 'hero' \| 'subtle' \| 'link' \| 'destructive' \| 'accent'` | `'primary'` | Visual style of the button. `hero` is the marketing-mode main button (gradient, glow, spring lift): a filled button outside `data-mode="marketing"`; one per screen. Legacy aliases still work: primary = filled, secondary = tonal, outline = outlined, ghost = text. |
|
|
28
28
|
| `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | Control height and padding. |
|
|
29
29
|
| `status` | `'idle' \| 'loading' \| 'success' \| 'error'` | `'idle'` | Async feedback (beta, 1.7.0). `loading` shows a spinner and blocks clicks but keeps focus; `success` draws a check; `error` shakes once. The label stays in flow, so the width holds. |
|
|
30
30
|
| `loading` | `boolean` | `false` | Alias for `status="loading"`. |
|
|
@@ -127,6 +127,24 @@ export default function Example() {
|
|
|
127
127
|
}
|
|
128
128
|
```
|
|
129
129
|
|
|
130
|
+
## Example: Hero (marketing mode)
|
|
131
|
+
|
|
132
|
+
Inside `data-mode="marketing"` with `@nexub/themes/marketing` loaded. The focus ring sits outside the gradient.
|
|
133
|
+
|
|
134
|
+
```tsx
|
|
135
|
+
import { Button } from '@nexub/react';
|
|
136
|
+
import { ArrowRight } from '@nexub/icons';
|
|
137
|
+
|
|
138
|
+
export default function Example() {
|
|
139
|
+
return (
|
|
140
|
+
<div data-mode="marketing" className="flex flex-wrap items-center gap-3">
|
|
141
|
+
<Button variant="hero" size="lg" trailingIcon={<ArrowRight size={16} />}>Start free</Button>
|
|
142
|
+
<Button variant="outlined" size="lg">Book a demo</Button>
|
|
143
|
+
</div>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
130
148
|
## Accessibility
|
|
131
149
|
|
|
132
150
|
- Roles: button
|
|
@@ -10,7 +10,8 @@ Surface container for grouping related content. Supports flat, surface, and inte
|
|
|
10
10
|
|
|
11
11
|
| Prop | Type | Default | Description |
|
|
12
12
|
| --- | --- | --- | --- |
|
|
13
|
-
| `variant` | `'flat' \| 'surface' \| 'interactive'` | `'flat'` | `interactive` lifts 2px on hover (spatial spring, elevation 1 → 2), sinks to 0.99 on press and adds a state layer. Use it for cards that are links or buttons. |
|
|
13
|
+
| `variant` | `'flat' \| 'surface' \| 'interactive' \| 'showcase'` | `'flat'` | `interactive` lifts 2px on hover (spatial spring, elevation 1 → 2), sinks to 0.99 on press and adds a state layer. Use it for cards that are links or buttons. `showcase` is the marketing-mode card (24px corners, soft shadow, hover lift); a flat card outside `data-mode="marketing"`. |
|
|
14
|
+
| `accent` | `'leap' \| 'bookub' \| 'payub' \| 'founderub'` | | With `variant="showcase"`: a product-coloured top edge and tint in marketing mode. Sets `data-product` on the card. Only for product-specific content. |
|
|
14
15
|
| `effect` | `'none' \| 'sheen'` | `'none'` | Opt-in. `sheen` is a soft light that follows the pointer, with a brighter rim near the edge. Off for touch, reduced motion and reduced transparency. |
|
|
15
16
|
| `tone` | `ToneValue` | `undefined` | Applies a semantic left-border accent. |
|
|
16
17
|
| `asChild` | `boolean` | `false` | Merges props onto the immediate child element. |
|
|
@@ -95,6 +96,32 @@ export default function Example() {
|
|
|
95
96
|
}
|
|
96
97
|
```
|
|
97
98
|
|
|
99
|
+
## Example: Showcase (marketing mode)
|
|
100
|
+
|
|
101
|
+
Product accents on showcase cards, inside `data-mode="marketing"`.
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
import { Card } from '@nexub/react';
|
|
105
|
+
|
|
106
|
+
const products = [
|
|
107
|
+
{ accent: 'payub', name: 'Payub', line: 'Payroll and HR' },
|
|
108
|
+
{ accent: 'bookub', name: 'Bookub', line: 'Bookkeeping' },
|
|
109
|
+
] as const;
|
|
110
|
+
|
|
111
|
+
export default function Example() {
|
|
112
|
+
return (
|
|
113
|
+
<div data-mode="marketing" className="grid w-full gap-6 sm:grid-cols-2">
|
|
114
|
+
{products.map((p) => (
|
|
115
|
+
<Card key={p.name} variant="showcase" accent={p.accent} className="flex flex-col gap-2 p-6">
|
|
116
|
+
<h3 className="m-0 text-title-lg">{p.name}</h3>
|
|
117
|
+
<p className="m-0 text-body-md text-[var(--color-on-surface-variant)]">{p.line}</p>
|
|
118
|
+
</Card>
|
|
119
|
+
))}
|
|
120
|
+
</div>
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
98
125
|
## Accessibility
|
|
99
126
|
|
|
100
127
|
- Roles: region (when used as a landmark)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# CTABand
|
|
2
|
+
|
|
3
|
+
The closing call to action on a primary band: the hero gradient in marketing mode. Server component.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/marketing` · Category: Marketing · Status: beta
|
|
6
|
+
- Import: `import { CtaBand } from '@nexub/marketing';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/patterns/cta-band
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `title` (required) | `React.ReactNode` | | The heading (h2). |
|
|
14
|
+
| `description` | `React.ReactNode` | | One supporting line. |
|
|
15
|
+
| `actions` | `React.ReactNode` | | Buttons. On the band use `variant="filled" tone="neutral"` or an outlined button. |
|
|
16
|
+
|
|
17
|
+
## Example: Default
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import { Button } from '@nexub/react';
|
|
21
|
+
import { CTABand } from '@nexub/marketing';
|
|
22
|
+
|
|
23
|
+
export default function Example() {
|
|
24
|
+
return (
|
|
25
|
+
<div data-mode="marketing" className="w-full">
|
|
26
|
+
<CTABand
|
|
27
|
+
title="Start running your company on Nexub"
|
|
28
|
+
description="Free for 30 days. No card needed."
|
|
29
|
+
actions={<Button variant="filled" tone="neutral" size="lg">Create an account</Button>}
|
|
30
|
+
/>
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
```
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Donut Chart
|
|
2
|
+
|
|
3
|
+
Parts of a whole, with an optional total in the hole. Keep it to six slices or fewer.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/react` · Category: Data Display · Status: beta
|
|
6
|
+
- Import: `import { DonutChart } from '@nexub/react';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/components/donut-chart
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `title` (required) | `string` | | Accessible name of the chart. |
|
|
14
|
+
| `data` (required) | `{ label: string; value: number; color?: ChartColor }[]` | | One entry per slice. |
|
|
15
|
+
| `center` | `ReactNode` | | Content in the hole, such as the total. |
|
|
16
|
+
| `valueFormat` | `(value: number) => string` | | Formats the hover text and the data table. |
|
|
17
|
+
| `legend` | `boolean` | `true` | Show the legend beside the donut. |
|
|
18
|
+
|
|
19
|
+
## Example: With total
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
import { DonutChart } from '@nexub/react';
|
|
23
|
+
|
|
24
|
+
const plans = [
|
|
25
|
+
{ label: 'Pro', value: 540 },
|
|
26
|
+
{ label: 'Team', value: 310 },
|
|
27
|
+
{ label: 'Starter', value: 220 },
|
|
28
|
+
{ label: 'Free', value: 130 },
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
export default function Example() {
|
|
32
|
+
return (
|
|
33
|
+
<DonutChart
|
|
34
|
+
title="Customers by plan"
|
|
35
|
+
data={plans}
|
|
36
|
+
center={
|
|
37
|
+
<span>
|
|
38
|
+
1,200
|
|
39
|
+
<br />
|
|
40
|
+
<span className="text-label-sm text-[var(--color-on-surface-muted)]">customers</span>
|
|
41
|
+
</span>
|
|
42
|
+
}
|
|
43
|
+
/>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Accessibility
|
|
49
|
+
|
|
50
|
+
- The chart is a `figure` named by `title`. The drawing is hidden from assistive tech; a visually hidden table carries every value.
|
|
51
|
+
- Colour is never the only cue: the legend and table name each series. Past six series, label directly or group the rest as "Other".
|
|
52
|
+
|
|
53
|
+
Related: [bar-chart](bar-chart.md)
|
|
@@ -10,7 +10,10 @@ A compact eyebrow label, typically used above headings.
|
|
|
10
10
|
|
|
11
11
|
| Prop | Type | Default | Description |
|
|
12
12
|
| --- | --- | --- | --- |
|
|
13
|
-
| `
|
|
13
|
+
| `tone` | `ToneValue` | `'neutral'` | Text colour. |
|
|
14
|
+
| `variant` | `'soft' \| 'gradient'` | `'soft'` | `gradient`: the marketing-mode chip; looks like `soft` outside `data-mode="marketing"`. |
|
|
15
|
+
| `live` | `boolean` | `false` | A decorative "live" dot before the label; it pings in marketing mode and stays still under reduced motion. |
|
|
16
|
+
| `leadingIcon` | `React.ReactNode` | | Icon before the label. |
|
|
14
17
|
|
|
15
18
|
## Example: Default
|
|
16
19
|
|
|
@@ -36,3 +39,20 @@ export default function Example() {
|
|
|
36
39
|
);
|
|
37
40
|
}
|
|
38
41
|
```
|
|
42
|
+
|
|
43
|
+
## Example: Gradient and live (marketing mode)
|
|
44
|
+
|
|
45
|
+
Inside `data-mode="marketing"`.
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
import { EyebrowChip } from '@nexub/react';
|
|
49
|
+
|
|
50
|
+
export default function Example() {
|
|
51
|
+
return (
|
|
52
|
+
<div data-mode="marketing" className="flex flex-wrap items-center gap-3">
|
|
53
|
+
<EyebrowChip variant="gradient" tone="info">Now in Vietnam</EyebrowChip>
|
|
54
|
+
<EyebrowChip variant="gradient" tone="success" live>Live</EyebrowChip>
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
```
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# FAQ
|
|
2
|
+
|
|
3
|
+
Questions and answers in an Accordion, one open at a time. Client component.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/marketing` · Category: Marketing · Status: beta
|
|
6
|
+
- Import: `import { Faq } from '@nexub/marketing';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/patterns/faq
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `items` (required) | `{ question, answer }[]` | | The questions; answers can hold links. |
|
|
14
|
+
| `header` | `React.ReactNode` | | A SectionHeader, usually. |
|
|
15
|
+
|
|
16
|
+
## Example: Default
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
import { FAQ, SectionHeader } from '@nexub/marketing';
|
|
20
|
+
|
|
21
|
+
export default function Example() {
|
|
22
|
+
return (
|
|
23
|
+
<div data-mode="marketing" className="w-full">
|
|
24
|
+
<FAQ
|
|
25
|
+
header={<SectionHeader title="Questions" />}
|
|
26
|
+
items={[
|
|
27
|
+
{ question: 'Which countries do you support?', answer: 'Singapore, India, Indonesia, Malaysia and Vietnam.' },
|
|
28
|
+
{ question: 'Can I switch plans later?', answer: 'Yes, at any time. We prorate the difference.' },
|
|
29
|
+
{ question: 'Is my data secure?', answer: 'Data is encrypted at rest and in transit, and stored in the region you choose.' },
|
|
30
|
+
]}
|
|
31
|
+
/>
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
```
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# FeatureSplit
|
|
2
|
+
|
|
3
|
+
Text and a check list beside a visual; `reverse` swaps the sides on wide screens. Server component.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/marketing` · Category: Marketing · Status: beta
|
|
6
|
+
- Import: `import { FeatureSplit } from '@nexub/marketing';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/patterns/feature-split
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `title` (required) | `React.ReactNode` | | The heading (h2). |
|
|
14
|
+
| `visual` (required) | `React.ReactNode` | | Screenshot or illustration. |
|
|
15
|
+
| `eyebrow` | `React.ReactNode` | | A string becomes a gradient EyebrowChip. |
|
|
16
|
+
| `description` | `React.ReactNode` | | Body copy. |
|
|
17
|
+
| `points` | `string[]` | | Benefit lines, shown as a check list. |
|
|
18
|
+
| `actions` | `React.ReactNode` | | Buttons. |
|
|
19
|
+
| `reverse` | `boolean` | `false` | Visual on the left on wide screens. |
|
|
20
|
+
|
|
21
|
+
## Example: Default
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import { Card } from '@nexub/react';
|
|
25
|
+
import { FeatureSplit } from '@nexub/marketing';
|
|
26
|
+
|
|
27
|
+
export default function Example() {
|
|
28
|
+
return (
|
|
29
|
+
<div data-mode="marketing" className="w-full">
|
|
30
|
+
<FeatureSplit
|
|
31
|
+
eyebrow="Payroll"
|
|
32
|
+
title="Pay your team on time, every time"
|
|
33
|
+
description="Run payroll in minutes with tax and statutory filings handled for you."
|
|
34
|
+
points={['CPF, EPF and BPJS filed for you', 'Payslips in every employee’s language', 'Approvals on your phone']}
|
|
35
|
+
visual={<Card variant="showcase" accent="payub" className="aspect-[4/3] w-full" aria-label="Payroll screenshot" />}
|
|
36
|
+
/>
|
|
37
|
+
</div>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
```
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Hero
|
|
2
|
+
|
|
3
|
+
The page hero: ambient backdrop, eyebrow, display headline (the page's one h1), lead, actions and a visual. Server component.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/marketing` · Category: Marketing · Status: beta
|
|
6
|
+
- Import: `import { Hero } from '@nexub/marketing';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/patterns/hero
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `title` (required) | `React.ReactNode` | | The headline, rendered as the h1. |
|
|
14
|
+
| `eyebrow` | `React.ReactNode` | | A string becomes a gradient EyebrowChip. |
|
|
15
|
+
| `description` | `React.ReactNode` | | The lead paragraph. |
|
|
16
|
+
| `actions` | `React.ReactNode` | | One `Button variant="hero"` and one outlined button, usually. |
|
|
17
|
+
| `visual` | `React.ReactNode` | | Product shot or illustration. Beside the text on wide screens with `align="start"`. |
|
|
18
|
+
| `align` | `'center' \| 'start'` | `'center'` | Text alignment and layout. |
|
|
19
|
+
|
|
20
|
+
## Example: Default
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
import { Button } from '@nexub/react';
|
|
24
|
+
import { Hero } from '@nexub/marketing';
|
|
25
|
+
import { ArrowRight } from '@nexub/icons';
|
|
26
|
+
|
|
27
|
+
export default function Example() {
|
|
28
|
+
return (
|
|
29
|
+
<div data-mode="marketing" className="w-full">
|
|
30
|
+
<Hero
|
|
31
|
+
eyebrow="Now in Vietnam"
|
|
32
|
+
title="Run your whole company in one place"
|
|
33
|
+
description="Payroll, bookkeeping and compliance for growing teams across Southeast Asia and India."
|
|
34
|
+
actions={
|
|
35
|
+
<>
|
|
36
|
+
<Button variant="hero" size="lg" trailingIcon={<ArrowRight size={16} />}>Start free</Button>
|
|
37
|
+
<Button variant="outlined" size="lg">Book a demo</Button>
|
|
38
|
+
</>
|
|
39
|
+
}
|
|
40
|
+
/>
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
```
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# HowItWorks
|
|
2
|
+
|
|
3
|
+
Numbered steps in an ordered list. Server component.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/marketing` · Category: Marketing · Status: beta
|
|
6
|
+
- Import: `import { HowItWorks } from '@nexub/marketing';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/patterns/how-it-works
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `steps` (required) | `{ title, description, icon? }[]` | | The steps; the number shows unless an icon is given. |
|
|
14
|
+
| `header` | `React.ReactNode` | | A SectionHeader, usually. |
|
|
15
|
+
|
|
16
|
+
## Example: Default
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
import { HowItWorks, SectionHeader } from '@nexub/marketing';
|
|
20
|
+
|
|
21
|
+
export default function Example() {
|
|
22
|
+
return (
|
|
23
|
+
<div data-mode="marketing" className="w-full">
|
|
24
|
+
<HowItWorks
|
|
25
|
+
header={<SectionHeader title="Up and running in a day" />}
|
|
26
|
+
steps={[
|
|
27
|
+
{ title: 'Create your account', description: 'Sign up with your company details.' },
|
|
28
|
+
{ title: 'Invite your team', description: 'Add people and their bank details.' },
|
|
29
|
+
{ title: 'Run your first payroll', description: 'Review, approve and pay.' },
|
|
30
|
+
]}
|
|
31
|
+
/>
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
```
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Line Chart
|
|
2
|
+
|
|
3
|
+
Show a trend over ordered categories such as time. Server-rendered SVG on the chart palette.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/react` · Category: Data Display · Status: beta
|
|
6
|
+
- Import: `import { LineChart } from '@nexub/react';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/components/line-chart
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `title` (required) | `string` | | Accessible name of the chart and caption of its data table. |
|
|
14
|
+
| `data` (required) | `T[]` | | One row per category, in order. |
|
|
15
|
+
| `index` (required) | `keyof T` | | Key of the category label in each row (the x axis). |
|
|
16
|
+
| `series` (required) | `ChartSeries[]` | | `{ key, label?, color? }` per series. `color` is 1–8 from the categorical chart palette; defaults to the series position. |
|
|
17
|
+
| `valueFormat` | `(value: number) => string` | | Formats axis labels, hover text and the data table. |
|
|
18
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Plot height: 8, 12 or 16rem. |
|
|
19
|
+
| `legend` | `boolean` | | Show the legend. Defaults to on for more than one series. |
|
|
20
|
+
| `area` | `boolean` | `false` | Fill the area under each line. |
|
|
21
|
+
|
|
22
|
+
## Example: Two series
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
import { LineChart } from '@nexub/react';
|
|
26
|
+
|
|
27
|
+
const data = [
|
|
28
|
+
{ week: 'W1', active: 820, trial: 310 },
|
|
29
|
+
{ week: 'W2', active: 870, trial: 290 },
|
|
30
|
+
{ week: 'W3', active: 905, trial: 340 },
|
|
31
|
+
{ week: 'W4', active: 960, trial: 330 },
|
|
32
|
+
{ week: 'W5', active: 1010, trial: 360 },
|
|
33
|
+
{ week: 'W6', active: 1080, trial: 355 },
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
export default function Example() {
|
|
37
|
+
return (
|
|
38
|
+
<LineChart
|
|
39
|
+
className="w-full"
|
|
40
|
+
title="Weekly users"
|
|
41
|
+
data={data}
|
|
42
|
+
index="week"
|
|
43
|
+
series={[{ key: 'active', label: 'Active' }, { key: 'trial', label: 'Trial' }]}
|
|
44
|
+
/>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Example: Area
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
import { LineChart } from '@nexub/react';
|
|
53
|
+
|
|
54
|
+
const data = [
|
|
55
|
+
{ day: 'Mon', p95: 210 },
|
|
56
|
+
{ day: 'Tue', p95: 190 },
|
|
57
|
+
{ day: 'Wed', p95: 240 },
|
|
58
|
+
{ day: 'Thu', p95: 205 },
|
|
59
|
+
{ day: 'Fri', p95: 180 },
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
export default function Example() {
|
|
63
|
+
return (
|
|
64
|
+
<LineChart
|
|
65
|
+
area
|
|
66
|
+
size="sm"
|
|
67
|
+
className="w-full"
|
|
68
|
+
title="API latency, p95"
|
|
69
|
+
data={data}
|
|
70
|
+
index="day"
|
|
71
|
+
series={[{ key: 'p95', label: 'p95 latency', color: 6 }]}
|
|
72
|
+
valueFormat={(v) => `${v} ms`}
|
|
73
|
+
/>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Accessibility
|
|
79
|
+
|
|
80
|
+
- The chart is a `figure` named by `title`. The drawing is hidden from assistive tech; a visually hidden table carries every value.
|
|
81
|
+
- Colour is never the only cue: the legend and table name each series. Past six series, label directly or group the rest as "Other".
|
|
82
|
+
|
|
83
|
+
Related: [bar-chart](bar-chart.md), [sparkline](sparkline.md)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# LogoStrip
|
|
2
|
+
|
|
3
|
+
A row of customer logos under the hero, scrolling sideways (paused on hover and focus) or wrapped. Server component.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/marketing` · Category: Marketing · Status: beta
|
|
6
|
+
- Import: `import { LogoStrip } from '@nexub/marketing';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/patterns/logo-strip
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `label` | `React.ReactNode` | | e.g. "Trusted by 2,000+ teams". |
|
|
14
|
+
| `scroll` | `boolean` | `true` | Scroll the logos (marketing mode only); off gives a wrapped row. |
|
|
15
|
+
| `children` (required) | `React.ReactNode` | | The logos. Give each its alt text. |
|
|
16
|
+
|
|
17
|
+
## Example: Default
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import { LogoStrip } from '@nexub/marketing';
|
|
21
|
+
|
|
22
|
+
const customers = ['Acme', 'Globex', 'Initech', 'Umbrella', 'Hooli', 'Vandelay'];
|
|
23
|
+
|
|
24
|
+
export default function Example() {
|
|
25
|
+
return (
|
|
26
|
+
<div data-mode="marketing" className="w-full">
|
|
27
|
+
<LogoStrip label="Trusted by 2,000+ teams">
|
|
28
|
+
{customers.map((name) => (
|
|
29
|
+
<span key={name} className="text-title-lg text-[var(--color-on-surface-muted)]">{name}</span>
|
|
30
|
+
))}
|
|
31
|
+
</LogoStrip>
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
```
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# MarketingFooter
|
|
2
|
+
|
|
3
|
+
The site footer: a tools strip, the logo, link columns and the legal line. Server component.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/marketing` · Category: Marketing · Status: beta
|
|
6
|
+
- Import: `import { MarketingFooter } from '@nexub/marketing';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/patterns/marketing-footer
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `columns` (required) | `{ title, links: { label, href }[] }[]` | | Link columns, each a labelled nav. |
|
|
14
|
+
| `logo` | `React.ReactNode` | | Logo. |
|
|
15
|
+
| `tagline` | `React.ReactNode` | | A line under the logo. |
|
|
16
|
+
| `tools` | `React.ReactNode[]` | | Tools or integrations, scrolling in a strip. |
|
|
17
|
+
| `toolsLabel` | `string` | `'Works with'` | Label of the tools strip. |
|
|
18
|
+
| `bottom` | `React.ReactNode` | | Copyright and legal links. |
|
|
19
|
+
|
|
20
|
+
## Example: Default
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
import { Logo } from '@nexub/react';
|
|
24
|
+
import { MarketingFooter } from '@nexub/marketing';
|
|
25
|
+
|
|
26
|
+
export default function Example() {
|
|
27
|
+
return (
|
|
28
|
+
<div data-mode="marketing" className="w-full">
|
|
29
|
+
<MarketingFooter
|
|
30
|
+
logo={<Logo size="sm" />}
|
|
31
|
+
tagline="The operating system for growing companies."
|
|
32
|
+
tools={['Slack', 'Xero', 'Google Workspace', 'Stripe', 'QuickBooks', 'WhatsApp']}
|
|
33
|
+
columns={[
|
|
34
|
+
{ title: 'Products', links: [{ label: 'Payub', href: '#payub' }, { label: 'Bookub', href: '#bookub' }, { label: 'Leap', href: '#leap' }] },
|
|
35
|
+
{ title: 'Company', links: [{ label: 'About', href: '#about' }, { label: 'Careers', href: '#careers' }] },
|
|
36
|
+
{ title: 'Resources', links: [{ label: 'Help centre', href: '#help' }, { label: 'Status', href: '#status' }] },
|
|
37
|
+
]}
|
|
38
|
+
bottom="© 2026 Nexub Pte. Ltd., Singapore"
|
|
39
|
+
/>
|
|
40
|
+
</div>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
```
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# MarketingNav
|
|
2
|
+
|
|
3
|
+
The site header: logo, links with mega-menus, a country switcher and actions. Below `lg` the links move into a side sheet.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/marketing` · Category: Marketing · Status: beta
|
|
6
|
+
- Import: `import { MarketingNav } from '@nexub/marketing';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/patterns/marketing-nav
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `logo` (required) | `React.ReactNode` | | Logo, wrapped in a link to `logoHref`. |
|
|
14
|
+
| `items` (required) | `MarketingNavItem[]` | | Links; an item with `items` opens a mega-menu of links with descriptions. |
|
|
15
|
+
| `countries` | `MarketingCountry[]` | | Country sites: `{ code, label, href }`. The switcher shows when there are two or more. |
|
|
16
|
+
| `country` | `string` | | Current country code. |
|
|
17
|
+
| `actions` | `React.ReactNode` | | Sign in / Get started buttons. |
|
|
18
|
+
| `logoHref` | `string` | `'/'` | Where the logo links. |
|
|
19
|
+
| `menuLabel` | `string` | `'Open menu'` | Accessible name of the mobile menu button. |
|
|
20
|
+
|
|
21
|
+
## Example: Default
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import { Button, Logo } from '@nexub/react';
|
|
25
|
+
import { MarketingNav } from '@nexub/marketing';
|
|
26
|
+
|
|
27
|
+
export default function Example() {
|
|
28
|
+
return (
|
|
29
|
+
<div data-mode="marketing" className="w-full">
|
|
30
|
+
<MarketingNav
|
|
31
|
+
logo={<Logo size="sm" />}
|
|
32
|
+
items={[
|
|
33
|
+
{
|
|
34
|
+
label: 'Products',
|
|
35
|
+
items: [
|
|
36
|
+
{ label: 'Payub', href: '#payub', description: 'Payroll and HR' },
|
|
37
|
+
{ label: 'Bookub', href: '#bookub', description: 'Bookkeeping' },
|
|
38
|
+
{ label: 'Leap', href: '#leap', description: 'Company formation' },
|
|
39
|
+
{ label: 'Founderub', href: '#founderub', description: 'Founder tools' },
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
{ label: 'Pricing', href: '#pricing' },
|
|
43
|
+
{ label: 'Customers', href: '#customers' },
|
|
44
|
+
]}
|
|
45
|
+
countries={[
|
|
46
|
+
{ code: 'SG', label: 'Singapore', href: '#sg' },
|
|
47
|
+
{ code: 'IN', label: 'India', href: '#in' },
|
|
48
|
+
{ code: 'ID', label: 'Indonesia', href: '#id' },
|
|
49
|
+
{ code: 'MY', label: 'Malaysia', href: '#my' },
|
|
50
|
+
{ code: 'VN', label: 'Vietnam', href: '#vn' },
|
|
51
|
+
]}
|
|
52
|
+
country="SG"
|
|
53
|
+
actions={
|
|
54
|
+
<>
|
|
55
|
+
<Button variant="text" size="sm" asChild><a href="#signin">Sign in</a></Button>
|
|
56
|
+
<Button variant="filled" size="sm" asChild><a href="#start">Get started</a></Button>
|
|
57
|
+
</>
|
|
58
|
+
}
|
|
59
|
+
/>
|
|
60
|
+
</div>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
```
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Float
|
|
2
|
+
|
|
3
|
+
Gently bobs its content (floating cards over a hero visual), in marketing mode. Server component; still under reduced motion.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/react` · Category: Motion · Status: beta
|
|
6
|
+
- Import: `import { MotionFloat } from '@nexub/react';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/components/motion-float
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `speed` | `'normal' \| 'slow'` | `'normal'` | `slow` drifts on a longer, reversed loop, so two floating cards don’t move in step. |
|
|
14
|
+
| `asChild` | `boolean` | `false` | Merge onto the child element instead of a div. |
|
|
15
|
+
|
|
16
|
+
## Example: Default
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
import { Card, Float } from '@nexub/react';
|
|
20
|
+
|
|
21
|
+
export default function Example() {
|
|
22
|
+
return (
|
|
23
|
+
<div data-mode="marketing" className="flex gap-8 p-6">
|
|
24
|
+
<Float>
|
|
25
|
+
<Card variant="showcase" className="nx-mkt-float-card p-5">Payroll approved</Card>
|
|
26
|
+
</Float>
|
|
27
|
+
<Float speed="slow">
|
|
28
|
+
<Card variant="showcase" className="nx-mkt-float-card p-5">Books closed</Card>
|
|
29
|
+
</Float>
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
```
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Marquee
|
|
2
|
+
|
|
3
|
+
A row that scrolls sideways forever (logo strips, tool lists), in marketing mode. Pauses on hover and while focus is inside, stands still under reduced motion; the repeated copy is hidden from assistive tech and can’t be focused. Server component.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/react` · Category: Motion · Status: beta
|
|
6
|
+
- Import: `import { MotionMarquee } from '@nexub/react';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/components/motion-marquee
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `speed` | `'slow' \| 'normal' \| 'fast'` | `'normal'` | Loop length: 44s, 28s or 18s. |
|
|
14
|
+
| `rowClassName` | `string` | `'gap-12 pe-12 items-center'` | Classes for each copy of the row. |
|
|
15
|
+
| `children` (required) | `React.ReactNode` | | The items. |
|
|
16
|
+
|
|
17
|
+
## Example: Default
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import { Marquee } from '@nexub/react';
|
|
21
|
+
|
|
22
|
+
const tools = ['Slack', 'Xero', 'Google Workspace', 'Stripe', 'QuickBooks', 'WhatsApp'];
|
|
23
|
+
|
|
24
|
+
export default function Example() {
|
|
25
|
+
return (
|
|
26
|
+
<div data-mode="marketing" className="w-full">
|
|
27
|
+
<Marquee>
|
|
28
|
+
{tools.map((t) => (
|
|
29
|
+
<span key={t} className="text-title-md text-[var(--color-on-surface-variant)]">{t}</span>
|
|
30
|
+
))}
|
|
31
|
+
</Marquee>
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
```
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Reveal
|
|
2
|
+
|
|
3
|
+
Fades its content up as it scrolls into view, in marketing mode. CSS scroll-driven where supported, an IntersectionObserver elsewhere; content on screen at load, and every visitor without JS or with reduced motion, just sees it.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/react` · Category: Motion · Status: beta
|
|
6
|
+
- Import: `import { MotionReveal } from '@nexub/react';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/components/motion-reveal
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `asChild` | `boolean` | `false` | Merge onto the child element instead of a div. |
|
|
14
|
+
| `children` (required) | `React.ReactNode` | | Content to reveal. |
|
|
15
|
+
|
|
16
|
+
## Example: Default
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
import { Card, Reveal } from '@nexub/react';
|
|
20
|
+
|
|
21
|
+
export default function Example() {
|
|
22
|
+
return (
|
|
23
|
+
<div data-mode="marketing" className="flex h-64 w-full flex-col gap-6 overflow-y-auto p-2">
|
|
24
|
+
<p className="m-0 shrink-0 pb-40 text-body-md text-[var(--color-on-surface-variant)]">Scroll down</p>
|
|
25
|
+
{[1, 2, 3].map((n) => (
|
|
26
|
+
<Reveal key={n} className="shrink-0">
|
|
27
|
+
<Card variant="showcase" className="p-6">Section {n}</Card>
|
|
28
|
+
</Reveal>
|
|
29
|
+
))}
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
```
|
|
@@ -14,6 +14,7 @@ A number whose digits roll to new values on the spatial spring. The first render
|
|
|
14
14
|
| `format` | `Intl.NumberFormatOptions` | | Formatting for a number `value`. |
|
|
15
15
|
| `locale` | `string` | | BCP 47 locale. Defaults to the user's. |
|
|
16
16
|
| `aria-live` | `'off' \| 'polite'` | `'off'` | Announce changes to screen readers. Use `polite` only for values the user is waiting on. |
|
|
17
|
+
| `countOnView` | `boolean` | `false` | Count up from zeros when the ticker first scrolls into view (3.1). Only for a ticker that starts below the fold; the server HTML and screen readers always get the real value. Off under reduced motion. |
|
|
17
18
|
|
|
18
19
|
## Example: Formatted number
|
|
19
20
|
|
|
@@ -57,6 +58,23 @@ export default function Example() {
|
|
|
57
58
|
}
|
|
58
59
|
```
|
|
59
60
|
|
|
61
|
+
## Example: Count on view
|
|
62
|
+
|
|
63
|
+
Scroll the preview so the number enters the view; it counts up once.
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
import { NumberTicker } from '@nexub/react';
|
|
67
|
+
|
|
68
|
+
export default function Example() {
|
|
69
|
+
return (
|
|
70
|
+
<div className="flex h-48 w-full flex-col overflow-y-auto">
|
|
71
|
+
<p className="m-0 shrink-0 pb-64 text-body-md text-[var(--color-on-surface-variant)]">Scroll down</p>
|
|
72
|
+
<NumberTicker value={2000} countOnView className="shrink-0 text-display-sm" />
|
|
73
|
+
</div>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
60
78
|
## Accessibility
|
|
61
79
|
|
|
62
80
|
- The full value is read as one string; the rolling digits are hidden from assistive tech.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# PricingTable
|
|
2
|
+
|
|
3
|
+
Plans side by side with a monthly / yearly switch, built on PlanCard and SegmentedControl. Client component.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/marketing` · Category: Marketing · Status: beta
|
|
6
|
+
- Import: `import { PricingTable } from '@nexub/marketing';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/patterns/pricing-table
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `plans` (required) | `PricingPlan[]` | | Each plan: `name`, `price: { monthly, yearly }` per month, `features`, `cta`, and `href` or `onSelect`; `highlighted` and `badge` optional. |
|
|
14
|
+
| `currency` (required) | `string` | | ISO 4217 code. |
|
|
15
|
+
| `locale` | `string` | | BCP 47 locale for the prices. |
|
|
16
|
+
| `defaultPeriod` | `'monthly' \| 'yearly'` | `'monthly'` | Billing period shown first. |
|
|
17
|
+
| `periodLabels` | `Record<BillingPeriod, string>` | | Labels of the switch. |
|
|
18
|
+
| `perMonthLabel` | `string` | `'/month'` | Shown after each price. |
|
|
19
|
+
| `header` | `React.ReactNode` | | A SectionHeader, usually. |
|
|
20
|
+
|
|
21
|
+
## Example: Default
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import { PricingTable, SectionHeader } from '@nexub/marketing';
|
|
25
|
+
|
|
26
|
+
export default function Example() {
|
|
27
|
+
return (
|
|
28
|
+
<div data-mode="marketing" className="w-full">
|
|
29
|
+
<PricingTable
|
|
30
|
+
header={<SectionHeader title="Simple pricing" description="Save two months with yearly billing." />}
|
|
31
|
+
currency="SGD"
|
|
32
|
+
locale="en-SG"
|
|
33
|
+
plans={[
|
|
34
|
+
{ name: 'Starter', price: { monthly: 29, yearly: 24 }, features: ['Up to 10 people', 'Payroll', 'Email support'], cta: 'Start free', href: '#starter' },
|
|
35
|
+
{ name: 'Growth', price: { monthly: 79, yearly: 66 }, features: ['Up to 100 people', 'Payroll and HR', 'Bookkeeping'], cta: 'Start free', href: '#growth', highlighted: true, badge: 'Most popular' },
|
|
36
|
+
{ name: 'Scale', price: { monthly: 199, yearly: 166 }, features: ['Unlimited people', 'All products', 'Dedicated manager'], cta: 'Talk to sales', href: '#scale' },
|
|
37
|
+
]}
|
|
38
|
+
/>
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
```
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# ProductGrid
|
|
2
|
+
|
|
3
|
+
Product cards in a grid; each card is one link with the product's accent. Server component.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/marketing` · Category: Marketing · Status: beta
|
|
6
|
+
- Import: `import { ProductGrid } from '@nexub/marketing';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/patterns/product-grid
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `header` | `React.ReactNode` | | ProductGrid: a SectionHeader, usually. |
|
|
14
|
+
| `name` (required) | `string` | | ProductCard: product name, the card's link text. |
|
|
15
|
+
| `description` (required) | `React.ReactNode` | | ProductCard: one line on what it does. |
|
|
16
|
+
| `href` (required) | `string` | | ProductCard: the product page. |
|
|
17
|
+
| `icon` | `React.ReactNode` | | ProductCard: the product mark. |
|
|
18
|
+
| `accent` | `'leap' \| 'bookub' \| 'payub' \| 'founderub'` | | ProductCard: coloured top edge and tint in marketing mode. |
|
|
19
|
+
| `linkLabel` | `string` | `'Learn more'` | ProductCard: the visual link cue. |
|
|
20
|
+
|
|
21
|
+
## Example: Default
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import { BookubMark, FounderubMark, LeapMark, PayubMark } from '@nexub/icons';
|
|
25
|
+
import { ProductCard, ProductGrid, SectionHeader } from '@nexub/marketing';
|
|
26
|
+
|
|
27
|
+
export default function Example() {
|
|
28
|
+
return (
|
|
29
|
+
<div data-mode="marketing" className="w-full">
|
|
30
|
+
<ProductGrid header={<SectionHeader eyebrow="Platform" title="One account, four products" />}>
|
|
31
|
+
<ProductCard name="Leap" description="Incorporate and stay compliant." href="#leap" accent="leap" icon={<LeapMark size={24} />} />
|
|
32
|
+
<ProductCard name="Bookub" description="Bookkeeping that closes itself." href="#bookub" accent="bookub" icon={<BookubMark size={24} />} />
|
|
33
|
+
<ProductCard name="Payub" description="Payroll and HR in one place." href="#payub" accent="payub" icon={<PayubMark size={24} />} />
|
|
34
|
+
<ProductCard name="Founderub" description="Cap table and fundraising." href="#founderub" accent="founderub" icon={<FounderubMark size={24} />} />
|
|
35
|
+
</ProductGrid>
|
|
36
|
+
</div>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
```
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# SectionHeader
|
|
2
|
+
|
|
3
|
+
Eyebrow, headline and lead that open a section. Server component.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/marketing` · Category: Marketing · Status: beta
|
|
6
|
+
- Import: `import { SectionHeader } from '@nexub/marketing';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/patterns/section-header
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `title` (required) | `React.ReactNode` | | The section heading (h2 by default). |
|
|
14
|
+
| `eyebrow` | `React.ReactNode` | | A string becomes a gradient EyebrowChip. |
|
|
15
|
+
| `description` | `React.ReactNode` | | The lead paragraph. |
|
|
16
|
+
| `align` | `'center' \| 'start'` | `'center'` | Alignment. |
|
|
17
|
+
| `level` | `2 \| 3` | `2` | Heading level. |
|
|
18
|
+
|
|
19
|
+
## Example: Default
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
import { SectionHeader } from '@nexub/marketing';
|
|
23
|
+
|
|
24
|
+
export default function Example() {
|
|
25
|
+
return (
|
|
26
|
+
<div data-mode="marketing" className="w-full py-10">
|
|
27
|
+
<SectionHeader
|
|
28
|
+
eyebrow="Platform"
|
|
29
|
+
title="Everything your company needs"
|
|
30
|
+
description="Four products on one account, one login and one bill."
|
|
31
|
+
/>
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
```
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Sparkline
|
|
2
|
+
|
|
3
|
+
A tiny trend line with no axes, for stat cards and table cells.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/react` · Category: Data Display · Status: beta
|
|
6
|
+
- Import: `import { Sparkline } from '@nexub/react';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/components/sparkline
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `values` (required) | `number[]` | | The points, oldest first. |
|
|
14
|
+
| `label` | `string` | | Accessible summary, such as "Revenue, last 12 weeks, up 8%". Without it the sparkline is decorative. |
|
|
15
|
+
| `color` | `ChartColor` | `1` | Palette colour, 1–8. |
|
|
16
|
+
| `area` | `boolean` | `false` | Fill the area under the line. |
|
|
17
|
+
|
|
18
|
+
## Example: In a stat
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
import { Sparkline } from '@nexub/react';
|
|
22
|
+
|
|
23
|
+
export default function Example() {
|
|
24
|
+
return (
|
|
25
|
+
<div className="flex items-end gap-4 rounded-2xl border border-[var(--color-outline-variant)] p-4">
|
|
26
|
+
<div>
|
|
27
|
+
<p className="text-label-md text-[var(--color-on-surface-variant)]">Monthly revenue</p>
|
|
28
|
+
<p className="text-title-lg text-[var(--color-on-surface)]">$68,420</p>
|
|
29
|
+
</div>
|
|
30
|
+
<Sparkline area values={[42, 48, 45, 56, 61, 68]} label="Up 62% over six months" color={2} />
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Accessibility
|
|
37
|
+
|
|
38
|
+
- The chart is a `figure` named by `title`. The drawing is hidden from assistive tech; a visually hidden table carries every value.
|
|
39
|
+
- Colour is never the only cue: the legend and table name each series. Past six series, label directly or group the rest as "Other".
|
|
40
|
+
|
|
41
|
+
Related: [line-chart](line-chart.md), [stat-card](stat-card.md)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# StatBand
|
|
2
|
+
|
|
3
|
+
A band of headline numbers that count up as they scroll into view. StatBandItem is named apart from the StatCard pattern. Server component.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/marketing` · Category: Marketing · Status: beta
|
|
6
|
+
- Import: `import { StatBand } from '@nexub/marketing';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/patterns/stat-band
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `title` | `React.ReactNode` | | StatBand: a heading above the stats. |
|
|
14
|
+
| `value` (required) | `number \| string` | | StatBandItem: a number counts up from zeros when it scrolls into view; the server HTML keeps the real value. |
|
|
15
|
+
| `label` (required) | `React.ReactNode` | | StatBandItem: what the number counts. |
|
|
16
|
+
| `prefix / suffix` | `string` | | StatBandItem: e.g. "$" or "+". |
|
|
17
|
+
| `tone` | `ToneValue` | `'info'` | StatBandItem: the number's colour (accent roles, AA as large text). |
|
|
18
|
+
| `format` | `Intl.NumberFormatOptions` | | StatBandItem: number formatting. |
|
|
19
|
+
|
|
20
|
+
## Example: Default
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
import { StatBand, StatBandItem } from '@nexub/marketing';
|
|
24
|
+
|
|
25
|
+
export default function Example() {
|
|
26
|
+
return (
|
|
27
|
+
<div data-mode="marketing" className="w-full">
|
|
28
|
+
<StatBand title="Teams run on Nexub">
|
|
29
|
+
<StatBandItem value={2000} suffix="+" label="Companies" />
|
|
30
|
+
<StatBandItem value={5} label="Countries" tone="success" />
|
|
31
|
+
<StatBandItem value={98} suffix="%" label="On-time payroll" tone="payub" />
|
|
32
|
+
<StatBandItem value={4.9} label="Average rating" tone="founderub" format={{ minimumFractionDigits: 1 }} />
|
|
33
|
+
</StatBand>
|
|
34
|
+
</div>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
```
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# TestimonialGrid
|
|
2
|
+
|
|
3
|
+
Customer quotes in product-coloured cards, with an optional star rating. Server component.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/marketing` · Category: Marketing · Status: beta
|
|
6
|
+
- Import: `import { TestimonialGrid } from '@nexub/marketing';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/patterns/testimonial-grid
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `header` | `React.ReactNode` | | TestimonialGrid: a SectionHeader, usually. |
|
|
14
|
+
| `quote` (required) | `React.ReactNode` | | TestimonialCard: the quote. |
|
|
15
|
+
| `name` (required) | `string` | | TestimonialCard: who said it. |
|
|
16
|
+
| `role` | `React.ReactNode` | | TestimonialCard: job title and company. |
|
|
17
|
+
| `avatarSrc` | `string` | | TestimonialCard: photo; initials otherwise. |
|
|
18
|
+
| `rating` | `number` | | TestimonialCard: stars out of 5, announced as "Rated n out of 5". |
|
|
19
|
+
| `accent` | `'leap' \| 'bookub' \| 'payub' \| 'founderub'` | | TestimonialCard: the product the customer uses. |
|
|
20
|
+
|
|
21
|
+
## Example: Default
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import { SectionHeader, TestimonialCard, TestimonialGrid } from '@nexub/marketing';
|
|
25
|
+
|
|
26
|
+
export default function Example() {
|
|
27
|
+
return (
|
|
28
|
+
<div data-mode="marketing" className="w-full">
|
|
29
|
+
<TestimonialGrid header={<SectionHeader eyebrow="Customers" title="Loved by finance teams" />}>
|
|
30
|
+
<TestimonialCard accent="payub" rating={5} name="Priya Nair" role="Head of People, Kopi Labs" quote="Payroll used to take two days. Now it takes twenty minutes." />
|
|
31
|
+
<TestimonialCard accent="bookub" rating={5} name="Daniel Tan" role="CFO, Harbourline" quote="Our books close on the third working day, every month." />
|
|
32
|
+
<TestimonialCard accent="leap" rating={5} name="Linh Pham" role="Founder, Sonvo" quote="We incorporated in Singapore without leaving Hanoi." />
|
|
33
|
+
</TestimonialGrid>
|
|
34
|
+
</div>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Component index
|
|
2
2
|
|
|
3
|
-
Nexub DS v3.
|
|
3
|
+
Nexub DS v3.2.0. Open `components/<slug>.md` for props, examples and accessibility notes.
|
|
4
4
|
Never use a component marked deprecated.
|
|
5
5
|
|
|
6
6
|
## Components — Actions
|
|
@@ -26,10 +26,14 @@ Never use a component marked deprecated.
|
|
|
26
26
|
## Components — Data Display
|
|
27
27
|
|
|
28
28
|
- [Amount](components/amount.md) `@nexub/react`: Honest money: Intl formatting, tabular numerals, the currency’s minor unit and a true minus sign.
|
|
29
|
+
- [Bar Chart](components/bar-chart.md) `@nexub/react`: Compare values across categories, grouped or stacked. Server-rendered SVG on the chart palette.
|
|
29
30
|
- [Data Table](components/data-table.md) `@nexub/react`: Feature-rich data table with sorting and row selection powered by TanStack Table.
|
|
31
|
+
- [Donut Chart](components/donut-chart.md) `@nexub/react`: Parts of a whole, with an optional total in the hole. Keep it to six slices or fewer.
|
|
30
32
|
- [Empty State](components/empty-state.md) `@nexub/react`: Placeholder UI shown when a list or page has no content.
|
|
31
33
|
- [Error State](components/error-state.md) `@nexub/react`: Full-page or section error view with retry action.
|
|
34
|
+
- [Line Chart](components/line-chart.md) `@nexub/react`: Show a trend over ordered categories such as time. Server-rendered SVG on the chart palette.
|
|
32
35
|
- [Number Ticker](components/number-ticker.md) `@nexub/react`: A number whose digits roll to new values on the spatial spring. The first render never animates.
|
|
36
|
+
- [Sparkline](components/sparkline.md) `@nexub/react`: A tiny trend line with no axes, for stat cards and table cells.
|
|
33
37
|
- [Table](components/table.md) `@nexub/react`: Semantic HTML table with styled variants.
|
|
34
38
|
|
|
35
39
|
## Components — Disclosure
|
|
@@ -114,6 +118,9 @@ Never use a component marked deprecated.
|
|
|
114
118
|
|
|
115
119
|
- [Collapse](components/motion-collapse.md) `@nexub/react`: Expands and collapses content along the block axis.
|
|
116
120
|
- [Fade](components/motion-fade.md) `@nexub/react`: Animates opacity between 0 and 1 based on the `in` prop.
|
|
121
|
+
- [Float](components/motion-float.md) `@nexub/react`: Gently bobs its content (floating cards over a hero visual), in marketing mode. Server component; still under reduced motion.
|
|
122
|
+
- [Marquee](components/motion-marquee.md) `@nexub/react`: A row that scrolls sideways forever (logo strips, tool lists), in marketing mode. Pauses on hover and while focus is inside, stands still under reduced motion; the repeated copy is hidden from assistive tech and can’t be focused. Server component.
|
|
123
|
+
- [Reveal](components/motion-reveal.md) `@nexub/react`: Fades its content up as it scrolls into view, in marketing mode. CSS scroll-driven where supported, an IntersectionObserver elsewhere; content on screen at load, and every visitor without JS or with reduced motion, just sees it.
|
|
117
124
|
- [Scale](components/motion-scale.md) `@nexub/react`: Scales content in/out from its center.
|
|
118
125
|
- [Slide](components/motion-slide.md) `@nexub/react`: Slides content in from a direction based on the `in` prop.
|
|
119
126
|
|
|
@@ -139,6 +146,22 @@ Never use a component marked deprecated.
|
|
|
139
146
|
- [Heading](components/heading.md) `@nexub/react`: Semantic heading component with size, weight, and tone control.
|
|
140
147
|
- [Text](components/text.md) `@nexub/react`: Paragraph text component with size, tone, and weight variants.
|
|
141
148
|
|
|
149
|
+
## Marketing — Marketing
|
|
150
|
+
|
|
151
|
+
- [CTABand](components/cta-band.md) `@nexub/marketing`: The closing call to action on a primary band: the hero gradient in marketing mode. Server component.
|
|
152
|
+
- [FAQ](components/faq.md) `@nexub/marketing`: Questions and answers in an Accordion, one open at a time. Client component.
|
|
153
|
+
- [FeatureSplit](components/feature-split.md) `@nexub/marketing`: Text and a check list beside a visual; `reverse` swaps the sides on wide screens. Server component.
|
|
154
|
+
- [Hero](components/hero.md) `@nexub/marketing`: The page hero: ambient backdrop, eyebrow, display headline (the page's one h1), lead, actions and a visual. Server component.
|
|
155
|
+
- [HowItWorks](components/how-it-works.md) `@nexub/marketing`: Numbered steps in an ordered list. Server component.
|
|
156
|
+
- [LogoStrip](components/logo-strip.md) `@nexub/marketing`: A row of customer logos under the hero, scrolling sideways (paused on hover and focus) or wrapped. Server component.
|
|
157
|
+
- [MarketingFooter](components/marketing-footer.md) `@nexub/marketing`: The site footer: a tools strip, the logo, link columns and the legal line. Server component.
|
|
158
|
+
- [MarketingNav](components/marketing-nav.md) `@nexub/marketing`: The site header: logo, links with mega-menus, a country switcher and actions. Below `lg` the links move into a side sheet.
|
|
159
|
+
- [PricingTable](components/pricing-table.md) `@nexub/marketing`: Plans side by side with a monthly / yearly switch, built on PlanCard and SegmentedControl. Client component.
|
|
160
|
+
- [ProductGrid](components/product-grid.md) `@nexub/marketing`: Product cards in a grid; each card is one link with the product's accent. Server component.
|
|
161
|
+
- [SectionHeader](components/section-header.md) `@nexub/marketing`: Eyebrow, headline and lead that open a section. Server component.
|
|
162
|
+
- [StatBand](components/stat-band.md) `@nexub/marketing`: A band of headline numbers that count up as they scroll into view. StatBandItem is named apart from the StatCard pattern. Server component.
|
|
163
|
+
- [TestimonialGrid](components/testimonial-grid.md) `@nexub/marketing`: Customer quotes in product-coloured cards, with an optional star rating. Server component.
|
|
164
|
+
|
|
142
165
|
## Patterns — AI
|
|
143
166
|
|
|
144
167
|
- [Conversation](components/conversation.md) `@nexub/patterns`: Chat layout: a scrolling message list that follows new content, with a sticky composer underneath.
|
|
@@ -184,5 +207,5 @@ Never use a component marked deprecated.
|
|
|
184
207
|
|
|
185
208
|
These exist; read their TypeScript props in `node_modules/<package>/dist/index.d.ts`.
|
|
186
209
|
|
|
187
|
-
- `@nexub/react`: AppShell, AspectRatio, CheckList, Code, CommandPalette, Container, ContextMenu, CountryBadge, DropdownMenu, FileUpload, Flag, FormError, KeyboardShortcut, Logo, Menubar, Motion, NavigationMenu, NexubProvider, PageHeader, Section, Sidebar, ThemeProvider, Toolbar, TopNav, VisuallyHidden
|
|
210
|
+
- `@nexub/react`: AppShell, AspectRatio, Chart, CheckList, Code, CommandPalette, Container, ContextMenu, CountryBadge, DropdownMenu, FileUpload, Flag, FormError, KeyboardShortcut, Logo, Menubar, Motion, NavigationMenu, NexubProvider, PageHeader, Section, Sidebar, ThemeProvider, Toolbar, TopNav, VisuallyHidden
|
|
188
211
|
- `@nexub/patterns`: ActivityPage, AppHeader, AppLauncher, ChatPage, CheckoutPage, DashboardPage, PageFrame, PaywallPage, SettingsLayout, SettingsPage, SignInPage, TransactionDetailPage
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Tokens
|
|
2
2
|
|
|
3
|
-
Nexub DS v3.
|
|
3
|
+
Nexub DS v3.2.0. Every token is a CSS custom property from `@nexub/tokens/css` (loaded by `@nexub/themes/base`).
|
|
4
4
|
The Tailwind preset (`@nexub/tokens/tailwind`) maps them to utilities. Never hardcode a hex, px spacing or shadow that a token covers.
|
|
5
5
|
|
|
6
6
|
## Color roles
|
|
@@ -93,6 +93,7 @@ Fonts: `font-sans` (Inter, UI), `font-display` (Plus Jakarta Sans, headlines), `
|
|
|
93
93
|
|
|
94
94
|
| Tailwind | Size / line height | Weight |
|
|
95
95
|
| --- | --- | --- |
|
|
96
|
+
| `text-display-xl` | 64px / 68px | 800 |
|
|
96
97
|
| `text-display-lg` | 56px / 60px | 700 |
|
|
97
98
|
| `text-display-md` | 44px / 48px | 700 |
|
|
98
99
|
| `text-display-sm` | 36px / 40px | 700 |
|
|
@@ -142,7 +143,7 @@ Fonts: `font-sans` (Inter, UI), `font-display` (Plus Jakarta Sans, headlines), `
|
|
|
142
143
|
| `--spacing-2-5` | `2-5` | 10px |
|
|
143
144
|
| `--spacing-3-5` | `3-5` | 14px |
|
|
144
145
|
|
|
145
|
-
Containers: `max-w-container-sm` (640px), `max-w-container-md` (768px), `max-w-container-lg` (1024px), `max-w-container-xl` (1280px), `max-w-container-2xl` (1536px), `max-w-container-nexub` (1440px), `max-w-container-prose` (65ch).
|
|
146
|
+
Containers: `max-w-container-sm` (640px), `max-w-container-md` (768px), `max-w-container-lg` (1024px), `max-w-container-xl` (1280px), `max-w-container-2xl` (1536px), `max-w-container-nexub` (1440px), `max-w-container-marketing` (1280px), `max-w-container-prose` (65ch).
|
|
146
147
|
|
|
147
148
|
## Control and component sizes
|
|
148
149
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nexub/mcp",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "MCP server for Nexub Design System: gives Claude, Cursor and any MCP client the components, patterns, tokens and design rules of the installed release.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|