@invisibleloop/pulse 0.20.5 โ 0.20.7
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/.claude/pulse-checklist.md +1 -2
- package/CLAUDE.md +1 -2
- package/docs/.claude/pulse-checklist.md +1 -2
- package/docs/public/coutumes.css +21 -44
- package/docs/public/docs.css +73 -6
- package/docs/public/home-brut.css +175 -191
- package/docs/public/pulse-ui.css +8 -1037
- package/docs/public/retrowheels.css +23 -0
- package/docs/public/shop.css +35 -1
- package/docs/public/sparkys.css +56 -23
- package/docs/public/theme.css +51 -7
- package/docs/server.js +0 -11
- package/docs/src/lib/component-page.js +2 -1
- package/docs/src/lib/nav.js +0 -11
- package/docs/src/pages/accessibility.js +2 -1
- package/docs/src/pages/actions.js +2 -1
- package/docs/src/pages/auth.js +2 -1
- package/docs/src/pages/caching.js +2 -1
- package/docs/src/pages/components/accordion.js +2 -1
- package/docs/src/pages/components/alert.js +2 -1
- package/docs/src/pages/components/app-badge.js +2 -1
- package/docs/src/pages/components/avatar.js +2 -1
- package/docs/src/pages/components/badge.js +2 -1
- package/docs/src/pages/components/breadcrumbs.js +2 -1
- package/docs/src/pages/components/button.js +2 -1
- package/docs/src/pages/components/card.js +2 -1
- package/docs/src/pages/components/charts.js +4 -2
- package/docs/src/pages/components/checkbox.js +2 -1
- package/docs/src/pages/components/cluster.js +2 -1
- package/docs/src/pages/components/container.js +2 -1
- package/docs/src/pages/components/cta.js +2 -1
- package/docs/src/pages/components/divider.js +2 -1
- package/docs/src/pages/components/empty.js +2 -1
- package/docs/src/pages/components/feature.js +2 -1
- package/docs/src/pages/components/fieldset.js +2 -1
- package/docs/src/pages/components/fileupload.js +2 -1
- package/docs/src/pages/components/footer.js +2 -1
- package/docs/src/pages/components/grid.js +11 -6
- package/docs/src/pages/components/heading.js +2 -1
- package/docs/src/pages/components/hero.js +2 -1
- package/docs/src/pages/components/icons.js +2 -1
- package/docs/src/pages/components/image.js +2 -1
- package/docs/src/pages/components/input.js +2 -1
- package/docs/src/pages/components/media.js +2 -1
- package/docs/src/pages/components/modal.js +2 -1
- package/docs/src/pages/components/nav.js +2 -1
- package/docs/src/pages/components/phone-frame.js +2 -1
- package/docs/src/pages/components/progress.js +2 -1
- package/docs/src/pages/components/prose.js +2 -1
- package/docs/src/pages/components/pullquote.js +2 -1
- package/docs/src/pages/components/radio.js +2 -1
- package/docs/src/pages/components/rating.js +2 -1
- package/docs/src/pages/components/search.js +2 -1
- package/docs/src/pages/components/section.js +2 -1
- package/docs/src/pages/components/segmented.js +2 -1
- package/docs/src/pages/components/select.js +2 -1
- package/docs/src/pages/components/slider.js +2 -1
- package/docs/src/pages/components/spinner.js +2 -1
- package/docs/src/pages/components/stack.js +2 -1
- package/docs/src/pages/components/stat.js +2 -1
- package/docs/src/pages/components/stepper.js +2 -1
- package/docs/src/pages/components/table.js +2 -1
- package/docs/src/pages/components/textarea.js +2 -1
- package/docs/src/pages/components/toggle.js +2 -1
- package/docs/src/pages/components/tooltip.js +2 -1
- package/docs/src/pages/components.js +2 -5
- package/docs/src/pages/config.js +2 -1
- package/docs/src/pages/constraints.js +2 -1
- package/docs/src/pages/deploy.js +2 -1
- package/docs/src/pages/error-pages.js +2 -1
- package/docs/src/pages/extending.js +2 -1
- package/docs/src/pages/faq.js +2 -1
- package/docs/src/pages/forms.js +2 -1
- package/docs/src/pages/getting-started.js +2 -1
- package/docs/src/pages/guard.js +2 -1
- package/docs/src/pages/home.js +24 -15
- package/docs/src/pages/how-it-works.js +22 -15
- package/docs/src/pages/hydration.js +2 -1
- package/docs/src/pages/images.js +2 -1
- package/docs/src/pages/markdown.js +2 -1
- package/docs/src/pages/meta.js +2 -1
- package/docs/src/pages/mutations.js +2 -1
- package/docs/src/pages/navigation.js +2 -1
- package/docs/src/pages/performance.js +2 -1
- package/docs/src/pages/persist.js +2 -1
- package/docs/src/pages/project-structure.js +2 -1
- package/docs/src/pages/prompt-examples.js +2 -1
- package/docs/src/pages/raw-responses.js +2 -1
- package/docs/src/pages/routing.js +2 -1
- package/docs/src/pages/server-api.js +2 -1
- package/docs/src/pages/server-data.js +2 -1
- package/docs/src/pages/slash-commands.js +2 -1
- package/docs/src/pages/spec.js +2 -1
- package/docs/src/pages/state.js +2 -1
- package/docs/src/pages/store.js +2 -1
- package/docs/src/pages/streaming.js +2 -1
- package/docs/src/pages/stripe.js +2 -1
- package/docs/src/pages/supabase.js +2 -1
- package/docs/src/pages/templates/coutumes.js +83 -72
- package/docs/src/pages/templates/mobile-app.js +36 -9
- package/docs/src/pages/templates/retrowheels.js +17 -4
- package/docs/src/pages/templates/shop.js +21 -10
- package/docs/src/pages/templates/sparkys.js +35 -20
- package/docs/src/pages/templates.js +2 -2
- package/docs/src/pages/testing.js +2 -1
- package/docs/src/pages/validation.js +2 -1
- package/examples/.claude/pulse-checklist.md +1 -2
- package/examples/examples.test.js +4 -4
- package/examples/pricing.js +21 -3
- package/examples/public/pulse-ui.css +8 -1037
- package/examples/retrowheels.css +23 -0
- package/examples/retrowheels.js +17 -4
- package/package.json +5 -1
- package/public/.pulse-ui-version +1 -1
- package/public/pulse-ui.css +8 -1037
- package/src/agent/checklist.md +1 -2
- package/src/agent/guide-components.md +43 -67
- package/src/agent/guide-design-gallery.md +14 -14
- package/src/agent/guide-design-references.md +21 -21
- package/src/agent/guide-styles.md +2 -2
- package/src/agent/guide-templates.md +6 -6
- package/src/agent/identity.md +1 -1
- package/src/agent/workflow.md +1 -2
- package/src/mcp/server.js +31 -24
- package/src/ui/index.js +0 -27
- package/src/ui/ui.test.js +0 -137
- package/types/charts.d.ts +61 -0
- package/types/ui.d.ts +1 -129
- package/docs/src/pages/components/banner.js +0 -44
- package/docs/src/pages/components/carousel.js +0 -71
- package/docs/src/pages/components/code-window.js +0 -56
- package/docs/src/pages/components/decorate.js +0 -74
- package/docs/src/pages/components/gallery.js +0 -102
- package/docs/src/pages/components/list.js +0 -111
- package/docs/src/pages/components/marquee.js +0 -76
- package/docs/src/pages/components/photo-card.js +0 -74
- package/docs/src/pages/components/pricing.js +0 -67
- package/docs/src/pages/components/testimonial.js +0 -48
- package/docs/src/pages/components/timeline.js +0 -226
- package/src/ui/banner.js +0 -41
- package/src/ui/brand-statement.js +0 -58
- package/src/ui/carousel.js +0 -59
- package/src/ui/code-window.js +0 -39
- package/src/ui/colophon.js +0 -29
- package/src/ui/contact-row.js +0 -41
- package/src/ui/decorate.js +0 -55
- package/src/ui/display-heading.js +0 -44
- package/src/ui/drop-cap.js +0 -29
- package/src/ui/editorial-hero.js +0 -63
- package/src/ui/entry-list.js +0 -36
- package/src/ui/gallery.js +0 -60
- package/src/ui/image-pair.js +0 -72
- package/src/ui/list.js +0 -36
- package/src/ui/marquee.js +0 -48
- package/src/ui/photo-card.js +0 -44
- package/src/ui/pricing.js +0 -56
- package/src/ui/product-card.js +0 -65
- package/src/ui/section-label.js +0 -38
- package/src/ui/service-card.js +0 -47
- package/src/ui/stat-grid.js +0 -40
- package/src/ui/testimonial.js +0 -59
- package/src/ui/timeline.js +0 -72
- package/src/ui/top-strip.js +0 -47
- package/src/ui/trust-list.js +0 -46
package/src/mcp/server.js
CHANGED
|
@@ -455,15 +455,12 @@ Import from \`@invisibleloop/pulse/ui\`. Always include \`/pulse-ui.css\` in \`m
|
|
|
455
455
|
| \`card\` | \`title\`, \`content\`, \`footer\`, \`variant\` (default/elevated/bordered/flat/glass/tinted) |
|
|
456
456
|
| \`feature\` | \`icon\`, \`title\`, \`description\`, \`level\`, \`center\` |
|
|
457
457
|
| \`stat\` | \`label\`, \`value\`, \`change\`, \`trend\`, \`center\` |
|
|
458
|
-
| \`testimonial\` | \`quote\`, \`name\`, \`role\`, \`rating\` |
|
|
459
458
|
| \`cta\` | \`title\`, \`subtitle\`, \`actions\` (HTML slot), \`eyebrow\` |
|
|
460
459
|
| \`footer\` | \`logo\`, \`logoHref\`, \`links\`, \`legal\`, \`columns\` |
|
|
461
460
|
| \`input\` | \`name\`, \`label\`, \`type\`, \`required\`, \`error\` |
|
|
462
461
|
| \`modal\` | \`id\`, \`title\`, \`content\`, \`footer\` โ always in DOM, never conditional |
|
|
463
|
-
| \`
|
|
464
|
-
| \`
|
|
465
|
-
| \`pullquote\` | \`quote\`, \`cite\`, \`size\` |
|
|
466
|
-
| \`entryList\` | \`items\` ([{meta, title, description}]), \`metaLabel\` โ tabular editorial list |
|
|
462
|
+
| \`heading\` | \`text\`, \`level\`, \`size\` |
|
|
463
|
+
| \`pullquote\` | \`quote\`, \`cite\`, \`size\`, \`variant\` (default/editorial) |
|
|
467
464
|
|
|
468
465
|
---
|
|
469
466
|
|
|
@@ -1593,9 +1590,7 @@ Work through every item. Fix anything that fails. Refer to the spec source at ${
|
|
|
1593
1590
|
- \`.hero\`, \`.-hero\`, \`__hero\` โ should use \`hero()\` component
|
|
1594
1591
|
- \`.card\`, \`.product-card\`, \`.service-card\` โ should use \`card()\` component
|
|
1595
1592
|
- Any two-column image + text layout โ should use \`media()\` component
|
|
1596
|
-
- \`.banner\`, \`.strip\`, \`.bar\` โ should use \`banner()\` component
|
|
1597
1593
|
- \`.feature\`, \`.feature-card\` โ should use \`feature()\` component
|
|
1598
|
-
- \`.testimonial\` โ should use \`testimonial()\` component
|
|
1599
1594
|
|
|
1600
1595
|
**Before flagging a pattern match**, ask: *can the \`hero()\` (or relevant) component actually reproduce this layout?* If the design uses full-viewport height, custom gradient glows, clamp-scaled display type, asymmetric layout, or other features the component doesn't support โ that is a **creative override**, not a violation. Check the auto-checked items above: if "creative override declared" is shown, these checks are advisory only and Lighthouse is the pass bar.
|
|
1601
1596
|
|
|
@@ -1804,7 +1799,8 @@ const ARCHETYPES = {
|
|
|
1804
1799
|
description: 'Data-rich admin or analytics page with metrics, charts, and tabular data',
|
|
1805
1800
|
stateHint: "{ period: 'week', loading: false }",
|
|
1806
1801
|
serverHint: "{ stats: async (ctx) => fetchStats(), rows: async (ctx) => fetchRows() }",
|
|
1807
|
-
scaffold: `import { nav, stat, card, grid,
|
|
1802
|
+
scaffold: `import { nav, stat, card, grid, table, section, container, badge, empty, spinner } from '@invisibleloop/pulse/ui'
|
|
1803
|
+
import { barChart } from '@invisibleloop/pulse/charts'
|
|
1808
1804
|
|
|
1809
1805
|
export default {
|
|
1810
1806
|
route: '/dashboard',
|
|
@@ -1841,7 +1837,7 @@ export default {
|
|
|
1841
1837
|
|
|
1842
1838
|
landing: {
|
|
1843
1839
|
keywords: ['landing', 'marketing', 'homepage', 'product', 'saas', 'startup', 'website', 'launch', 'hero', 'promotional'],
|
|
1844
|
-
components: ['nav', 'hero', 'feature', 'stat', '
|
|
1840
|
+
components: ['nav', 'hero', 'feature', 'stat', 'cta', 'footer', 'grid', 'section', 'container', 'button', 'appBadge'],
|
|
1845
1841
|
description: 'Marketing or product landing page with hero, features, and calls to action',
|
|
1846
1842
|
stateHint: 'null โ purely server-rendered, no client state needed',
|
|
1847
1843
|
serverHint: 'none โ all content is static in the view',
|
|
@@ -2120,7 +2116,7 @@ export default {
|
|
|
2120
2116
|
|
|
2121
2117
|
profile: {
|
|
2122
2118
|
keywords: ['profile', 'user page', 'bio', 'portfolio', 'about', 'member', 'author', 'personal page', 'public profile'],
|
|
2123
|
-
components: ['nav', 'avatar', 'card', 'stat', 'badge', 'grid', 'section', 'container', 'button', '
|
|
2119
|
+
components: ['nav', 'avatar', 'card', 'stat', 'badge', 'grid', 'section', 'container', 'button', 'prose'],
|
|
2124
2120
|
description: 'User or entity profile page with metadata and activity',
|
|
2125
2121
|
stateHint: 'null โ purely server-rendered',
|
|
2126
2122
|
serverHint: "{ user: async (ctx) => getUser(ctx.params.id), activity: async (ctx) => getActivity(ctx.params.id) }",
|
|
@@ -2164,11 +2160,24 @@ export default {
|
|
|
2164
2160
|
|
|
2165
2161
|
pricing: {
|
|
2166
2162
|
keywords: ['pricing', 'plans', 'subscription', 'tiers', 'billing', 'upgrade', 'compare', 'packages'],
|
|
2167
|
-
components: ['nav', '
|
|
2163
|
+
components: ['nav', 'card', 'grid', 'feature', 'cta', 'accordion', 'footer', 'section', 'button', 'badge'],
|
|
2168
2164
|
description: 'Pricing page with plan comparison, feature lists, and upgrade CTA',
|
|
2169
2165
|
stateHint: "{ billing: 'monthly' } โ for toggle between monthly/annual",
|
|
2170
2166
|
serverHint: 'none โ content is typically static',
|
|
2171
|
-
scaffold: `import { nav,
|
|
2167
|
+
scaffold: `import { nav, card, grid, cta, accordion, footer, section, container, button, badge, iconCheck } from '@invisibleloop/pulse/ui'
|
|
2168
|
+
|
|
2169
|
+
const plan = (p) => card({
|
|
2170
|
+
variant: p.featured ? 'elevated' : 'bordered',
|
|
2171
|
+
content: \`
|
|
2172
|
+
\${p.featured ? badge({ label: 'Most popular' }) : ''}
|
|
2173
|
+
<h3 class="u-text-xl u-font-bold u-mt-2">\${p.name}</h3>
|
|
2174
|
+
<p class="u-text-3xl u-font-bold u-mt-2">\${p.price}<span class="u-text-sm u-text-muted">\${p.period}</span></p>
|
|
2175
|
+
<ul class="u-mt-4 u-flex u-flex-col u-gap-2">
|
|
2176
|
+
\${p.features.map(f => \`<li class="u-flex u-gap-2 u-items-center">\${iconCheck({ size: 16 })} \${f}</li>\`).join('')}
|
|
2177
|
+
</ul>
|
|
2178
|
+
\`,
|
|
2179
|
+
footer: p.cta,
|
|
2180
|
+
})
|
|
2172
2181
|
|
|
2173
2182
|
export default {
|
|
2174
2183
|
route: '/pricing',
|
|
@@ -2186,13 +2195,11 @@ export default {
|
|
|
2186
2195
|
\${section({ content: container({ content: \`
|
|
2187
2196
|
<h1 class="u-text-4xl u-font-bold u-text-center u-mb-2">Simple pricing</h1>
|
|
2188
2197
|
<p class="u-text-center u-text-muted u-mb-8">No hidden fees. Cancel any time.</p>
|
|
2189
|
-
\${
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
]
|
|
2195
|
-
})}
|
|
2198
|
+
\${grid({ cols: 3, content: [
|
|
2199
|
+
{ name: 'Free', price: '\$0', period: '/forever', features: ['Feature A', 'Feature B'], cta: button({ label: 'Get started', variant: 'secondary' }) },
|
|
2200
|
+
{ name: 'Pro', price: '\$12', period: '/month', features: ['Everything in Free', 'Feature C', 'Feature D'], featured: true, cta: button({ label: 'Start free trial' }) },
|
|
2201
|
+
{ name: 'Team', price: '\$49', period: '/month', features: ['Everything in Pro', 'Feature E', 'Unlimited seats'], cta: button({ label: 'Contact sales', variant: 'secondary' }) },
|
|
2202
|
+
].map(plan).join('') })}
|
|
2196
2203
|
\${accordion({ items: [
|
|
2197
2204
|
{ title: 'Can I cancel any time?', content: 'Yes โ no lock-in, cancel from your account settings.' },
|
|
2198
2205
|
{ title: 'What payment methods do you accept?', content: 'Visa, Mastercard, Amex, and PayPal.' },
|
|
@@ -3038,15 +3045,15 @@ Accepts antiStyle ("what should this NOT look like?") and inspiration (a site or
|
|
|
3038
3045
|
if (vibe) {
|
|
3039
3046
|
lines.push(`- [ ] Vibe: \`meta.vibe: '${vibe}'\` โ sets data-vibe on body, activating geometry/type presets`)
|
|
3040
3047
|
const vibeGuide = {
|
|
3041
|
-
warm: 'Pair with rounded imagery (
|
|
3048
|
+
warm: 'Pair with rounded imagery (uiImage with rounded corners), warmer accent tones, section variant: paper or alt',
|
|
3042
3049
|
editorial: 'Use layout: overlap on hero for dramatic imagery. Serif headings via --font-display. section variant: diagonal for transitions.',
|
|
3043
|
-
playful: '
|
|
3050
|
+
playful: 'grid of uiImage with rounded corners, bright accent, raw HTML marquee-style strip if needed (creative override)',
|
|
3044
3051
|
minimal: 'hero align: left (no center), section variant: spotlight, clean whitespace, monochrome palette',
|
|
3045
3052
|
bold: 'hero gradient with strong color, large stat components, section variant: dark for contrast sections',
|
|
3046
3053
|
brutalist: 'raw section wrappers, oversized heading with zero padding, no shadows, high contrast accent (red/lime)',
|
|
3047
|
-
retro: '
|
|
3048
|
-
corporate: 'feature grid with checkmarks,
|
|
3049
|
-
neon: 'section(variant: "spotlight") for glow sections,
|
|
3054
|
+
retro: 'badge eyebrows, thick dividers, earthy amber/cream palette, raw HTML dot-pattern background (creative override)',
|
|
3055
|
+
corporate: 'feature grid with checkmarks, card() with logo+quote for testimonials, stat bar',
|
|
3056
|
+
neon: 'section(variant: "spotlight") for glow sections, raw HTML terminal/API code block (creative override) for dev examples, stat with glowing accent',
|
|
3050
3057
|
paper: 'pullquote prominently, prose with generous line-height, avatar for author, container(size: "sm")',
|
|
3051
3058
|
}
|
|
3052
3059
|
if (vibeGuide[vibe]) lines.push(` **${vibe} component suggestions:** ${vibeGuide[vibe]}`)
|
package/src/ui/index.js
CHANGED
|
@@ -33,9 +33,7 @@ export { empty } from './empty.js'
|
|
|
33
33
|
export { table } from './table.js'
|
|
34
34
|
export { hero } from './hero.js'
|
|
35
35
|
export { phoneFrame } from './phone-frame.js'
|
|
36
|
-
export { testimonial } from './testimonial.js'
|
|
37
36
|
export { feature } from './feature.js'
|
|
38
|
-
export { pricing } from './pricing.js'
|
|
39
37
|
export { accordion } from './accordion.js'
|
|
40
38
|
export { nav } from './nav.js'
|
|
41
39
|
export { appBadge } from './app-badge.js'
|
|
@@ -45,52 +43,27 @@ export { grid } from './grid.js'
|
|
|
45
43
|
export { stack } from './stack.js'
|
|
46
44
|
export { cluster } from './cluster.js'
|
|
47
45
|
export { divider } from './divider.js'
|
|
48
|
-
export { banner } from './banner.js'
|
|
49
46
|
export { media } from './media.js'
|
|
50
47
|
export { tooltip } from './tooltip.js'
|
|
51
48
|
export { modal, modalTrigger } from './modal.js'
|
|
52
|
-
export { carousel } from './carousel.js'
|
|
53
49
|
export { cta } from './cta.js'
|
|
54
|
-
export { codeWindow } from './code-window.js'
|
|
55
50
|
export { footer } from './footer.js'
|
|
56
|
-
export { timeline, timelineItem } from './timeline.js'
|
|
57
51
|
export { toggle } from './switch.js'
|
|
58
52
|
export { checkbox } from './checkbox.js'
|
|
59
53
|
export { radio, radioGroup } from './radio.js'
|
|
60
54
|
export { rating } from './rating.js'
|
|
61
55
|
export { spinner } from './spinner.js'
|
|
62
56
|
export { progress } from './progress.js'
|
|
63
|
-
export { barChart, lineChart, donutChart, sparkline } from './charts.js'
|
|
64
57
|
export { slider } from './slider.js'
|
|
65
58
|
export { segmented } from './segmented.js'
|
|
66
59
|
export { fileUpload } from './fileupload.js'
|
|
67
60
|
export { breadcrumbs } from './breadcrumbs.js'
|
|
68
61
|
export { stepper } from './stepper.js'
|
|
69
62
|
export { uiImage } from './uiimage.js'
|
|
70
|
-
export { gallery } from './gallery.js'
|
|
71
|
-
export { photoCard } from './photo-card.js'
|
|
72
|
-
export { productCard } from './product-card.js'
|
|
73
|
-
export { editorialHero } from './editorial-hero.js'
|
|
74
|
-
export { imagePair } from './image-pair.js'
|
|
75
|
-
export { brandStatement } from './brand-statement.js'
|
|
76
|
-
export { marquee } from './marquee.js'
|
|
77
|
-
export { serviceCard } from './service-card.js'
|
|
78
|
-
export { contactRow } from './contact-row.js'
|
|
79
|
-
export { trustList } from './trust-list.js'
|
|
80
|
-
export { topStrip } from './top-strip.js'
|
|
81
|
-
export { statGrid } from './stat-grid.js'
|
|
82
|
-
export { decorate } from './decorate.js'
|
|
83
63
|
export { pullquote } from './pullquote.js'
|
|
84
64
|
export { prose } from './prose.js'
|
|
85
65
|
export { heading } from './heading.js'
|
|
86
66
|
|
|
87
|
-
// Editorial components
|
|
88
|
-
export { entryList } from './entry-list.js'
|
|
89
|
-
export { displayHeading } from './display-heading.js'
|
|
90
|
-
export { sectionLabel } from './section-label.js'
|
|
91
|
-
export { dropCap } from './drop-cap.js'
|
|
92
|
-
export { colophon } from './colophon.js'
|
|
93
|
-
export { list } from './list.js'
|
|
94
67
|
export {
|
|
95
68
|
iconArrowLeft, iconArrowRight, iconArrowUp, iconArrowDown,
|
|
96
69
|
iconChevronLeft, iconChevronRight, iconChevronUp, iconChevronDown,
|
package/src/ui/ui.test.js
CHANGED
|
@@ -20,21 +20,16 @@ import { avatar } from './avatar.js'
|
|
|
20
20
|
import { empty } from './empty.js'
|
|
21
21
|
import { table } from './table.js'
|
|
22
22
|
import { hero } from './hero.js'
|
|
23
|
-
import { testimonial } from './testimonial.js'
|
|
24
23
|
import { feature } from './feature.js'
|
|
25
|
-
import { pricing } from './pricing.js'
|
|
26
24
|
import { accordion } from './accordion.js'
|
|
27
25
|
import { nav } from './nav.js'
|
|
28
26
|
import { appBadge } from './app-badge.js'
|
|
29
|
-
import { dropCap } from './drop-cap.js'
|
|
30
|
-
import { gallery } from './gallery.js'
|
|
31
27
|
import { container } from './container.js'
|
|
32
28
|
import { section } from './section.js'
|
|
33
29
|
import { grid } from './grid.js'
|
|
34
30
|
import { stack } from './stack.js'
|
|
35
31
|
import { cluster } from './cluster.js'
|
|
36
32
|
import { divider } from './divider.js'
|
|
37
|
-
import { banner } from './banner.js'
|
|
38
33
|
import { media } from './media.js'
|
|
39
34
|
import { fieldset } from './fieldset.js'
|
|
40
35
|
import { slider } from './slider.js'
|
|
@@ -521,43 +516,6 @@ test('hero: escapes title and eyebrow', () => {
|
|
|
521
516
|
assert.doesNotMatch(html, /<b>bad<\/b>/)
|
|
522
517
|
})
|
|
523
518
|
|
|
524
|
-
// โโโ testimonial โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
525
|
-
|
|
526
|
-
test('testimonial: renders quote, name, role', () => {
|
|
527
|
-
const html = testimonial({ quote: 'Great app', name: 'Alice Smith', role: 'CEO' })
|
|
528
|
-
assert.match(html, /Great app/)
|
|
529
|
-
assert.match(html, /Alice Smith/)
|
|
530
|
-
assert.match(html, /CEO/)
|
|
531
|
-
})
|
|
532
|
-
|
|
533
|
-
test('testimonial: renders stars when rating provided', () => {
|
|
534
|
-
const html = testimonial({ quote: 'x', name: 'A', rating: 5 })
|
|
535
|
-
assert.match(html, /ui-testimonial-rating/)
|
|
536
|
-
assert.match(html, /โ
โ
โ
โ
โ
/)
|
|
537
|
-
})
|
|
538
|
-
|
|
539
|
-
test('testimonial: no stars when rating omitted', () => {
|
|
540
|
-
assert.doesNotMatch(testimonial({ quote: 'x', name: 'A' }), /ui-testimonial-rating/)
|
|
541
|
-
})
|
|
542
|
-
|
|
543
|
-
test('testimonial: renders initials when src omitted', () => {
|
|
544
|
-
const html = testimonial({ quote: 'x', name: 'Alice Smith' })
|
|
545
|
-
assert.match(html, /ui-testimonial-avatar--initials/)
|
|
546
|
-
assert.match(html, /AS/)
|
|
547
|
-
})
|
|
548
|
-
|
|
549
|
-
test('testimonial: renders img when src provided', () => {
|
|
550
|
-
const html = testimonial({ quote: 'x', name: 'Alice', src: '/photo.jpg' })
|
|
551
|
-
assert.match(html, /<img/)
|
|
552
|
-
assert.match(html, /photo\.jpg/)
|
|
553
|
-
})
|
|
554
|
-
|
|
555
|
-
test('testimonial: escapes quote and name', () => {
|
|
556
|
-
const html = testimonial({ quote: '<script>', name: '<b>X</b>' })
|
|
557
|
-
assert.doesNotMatch(html, /<script>/)
|
|
558
|
-
assert.doesNotMatch(html, /<b>X<\/b>/)
|
|
559
|
-
})
|
|
560
|
-
|
|
561
519
|
// โโโ feature โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
562
520
|
|
|
563
521
|
test('feature: renders title and description', () => {
|
|
@@ -578,43 +536,6 @@ test('feature: escapes title and description', () => {
|
|
|
578
536
|
assert.doesNotMatch(html, /<b>bad<\/b>/)
|
|
579
537
|
})
|
|
580
538
|
|
|
581
|
-
// โโโ pricing โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
582
|
-
|
|
583
|
-
test('pricing: renders name, price, period', () => {
|
|
584
|
-
const html = pricing({ name: 'Pro', price: '$9', period: '/month' })
|
|
585
|
-
assert.match(html, /ui-pricing-name/)
|
|
586
|
-
assert.match(html, /\$9/)
|
|
587
|
-
assert.match(html, /\/month/)
|
|
588
|
-
})
|
|
589
|
-
|
|
590
|
-
test('pricing: renders feature list', () => {
|
|
591
|
-
const html = pricing({ name: 'x', price: 'Free', features: ['Unlimited pages', 'Support'] })
|
|
592
|
-
assert.match(html, /Unlimited pages/)
|
|
593
|
-
assert.match(html, /Support/)
|
|
594
|
-
assert.match(html, /ui-pricing-check/)
|
|
595
|
-
})
|
|
596
|
-
|
|
597
|
-
test('pricing: highlighted adds modifier class', () => {
|
|
598
|
-
assert.match(pricing({ name: 'x', price: 'x', highlighted: true }), /ui-pricing--highlighted/)
|
|
599
|
-
})
|
|
600
|
-
|
|
601
|
-
test('pricing: badge renders when provided', () => {
|
|
602
|
-
const html = pricing({ name: 'x', price: 'x', badge: 'Most popular' })
|
|
603
|
-
assert.match(html, /ui-pricing-badge/)
|
|
604
|
-
assert.match(html, /Most popular/)
|
|
605
|
-
})
|
|
606
|
-
|
|
607
|
-
test('pricing: action slot passes through raw HTML', () => {
|
|
608
|
-
const html = pricing({ name: 'x', price: 'x', action: '<button>Buy</button>' })
|
|
609
|
-
assert.match(html, /<button>Buy<\/button>/)
|
|
610
|
-
})
|
|
611
|
-
|
|
612
|
-
test('pricing: escapes name and description', () => {
|
|
613
|
-
const html = pricing({ name: '<script>', description: '<b>x</b>' })
|
|
614
|
-
assert.doesNotMatch(html, /<script>/)
|
|
615
|
-
assert.doesNotMatch(html, /<b>x<\/b>/)
|
|
616
|
-
})
|
|
617
|
-
|
|
618
539
|
// โโโ accordion โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
619
540
|
|
|
620
541
|
test('accordion: renders details/summary', () => {
|
|
@@ -859,32 +780,6 @@ test('divider: escapes label', () => {
|
|
|
859
780
|
assert.doesNotMatch(divider({ label: '<script>' }), /<script>/)
|
|
860
781
|
})
|
|
861
782
|
|
|
862
|
-
// โโโ banner โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
863
|
-
|
|
864
|
-
test('banner: renders content', () => {
|
|
865
|
-
assert.match(banner({ content: 'Now available' }), /Now available/)
|
|
866
|
-
})
|
|
867
|
-
|
|
868
|
-
test('banner: info variant by default', () => {
|
|
869
|
-
assert.match(banner({ content: '' }), /ui-banner--info/)
|
|
870
|
-
})
|
|
871
|
-
|
|
872
|
-
test('banner: promo variant adds class', () => {
|
|
873
|
-
assert.match(banner({ content: '', variant: 'promo' }), /ui-banner--promo/)
|
|
874
|
-
})
|
|
875
|
-
|
|
876
|
-
test('banner: warning variant adds class', () => {
|
|
877
|
-
assert.match(banner({ content: '', variant: 'warning' }), /ui-banner--warning/)
|
|
878
|
-
})
|
|
879
|
-
|
|
880
|
-
test('banner: unknown variant falls back to info', () => {
|
|
881
|
-
assert.match(banner({ content: '', variant: 'fancy' }), /ui-banner--info/)
|
|
882
|
-
})
|
|
883
|
-
|
|
884
|
-
test('banner: has role=banner', () => {
|
|
885
|
-
assert.match(banner({ content: '' }), /role="banner"/)
|
|
886
|
-
})
|
|
887
|
-
|
|
888
783
|
// โโโ media โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
889
784
|
|
|
890
785
|
test('media: renders image and content slots', () => {
|
|
@@ -1322,38 +1217,6 @@ test('uiImage: escapes src to prevent XSS', () => {
|
|
|
1322
1217
|
assert.doesNotMatch(html, /<script>/)
|
|
1323
1218
|
})
|
|
1324
1219
|
|
|
1325
|
-
test('dropCap: inline style carries only the dynamic font-size โ alignment lives in CSS', () => {
|
|
1326
|
-
// Regression: a relative inline line-height (lines * 0.8 โ 2.4 for 3 lines)
|
|
1327
|
-
// made the float box ~3x the glyph height, so serif caps floated below the
|
|
1328
|
-
// opening line instead of top-aligning. line-height/float/margin now live in
|
|
1329
|
-
// .ui-drop-cap-letter (pulse-ui.css) with a fixed ~cap-height value.
|
|
1330
|
-
const html = dropCap({ letter: 'O', content: 'nce upon a time.' })
|
|
1331
|
-
assert.match(html, /class="ui-drop-cap-letter"/)
|
|
1332
|
-
assert.match(html, /style="font-size:3\.6em"/)
|
|
1333
|
-
assert.doesNotMatch(html, /line-height/)
|
|
1334
|
-
assert.doesNotMatch(html, /float:left/)
|
|
1335
|
-
})
|
|
1336
|
-
|
|
1337
|
-
test('dropCap: lines option scales the font-size', () => {
|
|
1338
|
-
const html = dropCap({ letter: 'O', content: 'nce.', lines: 5 })
|
|
1339
|
-
assert.match(html, /style="font-size:6em"/)
|
|
1340
|
-
})
|
|
1341
|
-
|
|
1342
|
-
test('gallery: images are lazy by default', () => {
|
|
1343
|
-
const html = gallery({ images: [{ src: '/a.jpg', alt: 'A' }] })
|
|
1344
|
-
assert.match(html, /loading="lazy"/)
|
|
1345
|
-
})
|
|
1346
|
-
|
|
1347
|
-
test('gallery: lazy:false renders eager images', () => {
|
|
1348
|
-
const html = gallery({ images: [{ src: '/a.jpg', alt: 'A' }], lazy: false })
|
|
1349
|
-
assert.doesNotMatch(html, /loading="lazy"/)
|
|
1350
|
-
})
|
|
1351
|
-
|
|
1352
|
-
test('dropCap: escapes letter and content', () => {
|
|
1353
|
-
const html = dropCap({ letter: '<', content: '<script>alert(1)</script>' })
|
|
1354
|
-
assert.doesNotMatch(html, /<script>/)
|
|
1355
|
-
})
|
|
1356
|
-
|
|
1357
1220
|
test('pulse-ui.css: form controls are at least 16px on touch devices (iOS focus-zoom)', () => {
|
|
1358
1221
|
// iOS Safari zooms the page when a focused input's font-size is under 16px,
|
|
1359
1222
|
// forcing the user to pinch back out. A (pointer: coarse) block must keep
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pulse Charts โ SVG chart components
|
|
3
|
+
* @invisibleloop/pulse/charts
|
|
4
|
+
*
|
|
5
|
+
* All components are pure functions: (props?) => HTML string.
|
|
6
|
+
* Import only what you need โ no side effects on import.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
type ChartColor = 'accent' | 'success' | 'warning' | 'error' | 'blue' | 'muted'
|
|
10
|
+
|
|
11
|
+
export interface ChartDataPoint {
|
|
12
|
+
label: string
|
|
13
|
+
value: number
|
|
14
|
+
}
|
|
15
|
+
export interface DonutDataPoint {
|
|
16
|
+
label: string
|
|
17
|
+
value: number
|
|
18
|
+
color?: string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface BarChartProps {
|
|
22
|
+
data?: ChartDataPoint[]
|
|
23
|
+
height?: number
|
|
24
|
+
color?: ChartColor
|
|
25
|
+
showValues?: boolean
|
|
26
|
+
showGrid?: boolean
|
|
27
|
+
gap?: number
|
|
28
|
+
class?: string
|
|
29
|
+
}
|
|
30
|
+
export function barChart(props?: BarChartProps): string
|
|
31
|
+
|
|
32
|
+
export interface LineChartProps {
|
|
33
|
+
data?: ChartDataPoint[]
|
|
34
|
+
height?: number
|
|
35
|
+
color?: ChartColor
|
|
36
|
+
area?: boolean
|
|
37
|
+
showDots?: boolean
|
|
38
|
+
showGrid?: boolean
|
|
39
|
+
class?: string
|
|
40
|
+
}
|
|
41
|
+
export function lineChart(props?: LineChartProps): string
|
|
42
|
+
|
|
43
|
+
export interface DonutChartProps {
|
|
44
|
+
data?: DonutDataPoint[]
|
|
45
|
+
size?: number
|
|
46
|
+
thickness?: number
|
|
47
|
+
label?: string
|
|
48
|
+
sublabel?: string
|
|
49
|
+
class?: string
|
|
50
|
+
}
|
|
51
|
+
export function donutChart(props?: DonutChartProps): string
|
|
52
|
+
|
|
53
|
+
export interface SparklineProps {
|
|
54
|
+
data?: number[]
|
|
55
|
+
width?: number
|
|
56
|
+
height?: number
|
|
57
|
+
color?: ChartColor
|
|
58
|
+
area?: boolean
|
|
59
|
+
class?: string
|
|
60
|
+
}
|
|
61
|
+
export function sparkline(props?: SparklineProps): string
|
package/types/ui.d.ts
CHANGED
|
@@ -14,7 +14,6 @@ type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger'
|
|
|
14
14
|
type Size = 'sm' | 'md' | 'lg'
|
|
15
15
|
type AlertVariant = 'info' | 'success' | 'warning' | 'error'
|
|
16
16
|
type BadgeVariant = 'default' | 'success' | 'warning' | 'error' | 'info'
|
|
17
|
-
type ChartColor = 'accent' | 'success' | 'warning' | 'error' | 'blue' | 'muted'
|
|
18
17
|
|
|
19
18
|
// ---------------------------------------------------------------------------
|
|
20
19
|
// Form controls
|
|
@@ -223,17 +222,6 @@ export interface PullquoteProps {
|
|
|
223
222
|
}
|
|
224
223
|
export function pullquote(props?: PullquoteProps): string
|
|
225
224
|
|
|
226
|
-
export interface ListItem {
|
|
227
|
-
text: string
|
|
228
|
-
href?: string
|
|
229
|
-
}
|
|
230
|
-
export interface ListProps {
|
|
231
|
-
items?: Array<string | ListItem>
|
|
232
|
-
ordered?: boolean
|
|
233
|
-
class?: string
|
|
234
|
-
}
|
|
235
|
-
export function list(props?: ListProps): string
|
|
236
|
-
|
|
237
225
|
// ---------------------------------------------------------------------------
|
|
238
226
|
// Navigation
|
|
239
227
|
// ---------------------------------------------------------------------------
|
|
@@ -360,29 +348,6 @@ export interface FeatureProps {
|
|
|
360
348
|
}
|
|
361
349
|
export function feature(props?: FeatureProps): string
|
|
362
350
|
|
|
363
|
-
export interface TestimonialProps {
|
|
364
|
-
quote?: string
|
|
365
|
-
name?: string
|
|
366
|
-
role?: string
|
|
367
|
-
avatar?: string
|
|
368
|
-
class?: string
|
|
369
|
-
}
|
|
370
|
-
export function testimonial(props?: TestimonialProps): string
|
|
371
|
-
|
|
372
|
-
export interface PricingTier {
|
|
373
|
-
name?: string
|
|
374
|
-
price?: string
|
|
375
|
-
period?: string
|
|
376
|
-
features?: string[]
|
|
377
|
-
action?: string
|
|
378
|
-
featured?: boolean
|
|
379
|
-
}
|
|
380
|
-
export interface PricingProps {
|
|
381
|
-
tiers?: PricingTier[]
|
|
382
|
-
class?: string
|
|
383
|
-
}
|
|
384
|
-
export function pricing(props?: PricingProps): string
|
|
385
|
-
|
|
386
351
|
export interface CtaProps {
|
|
387
352
|
heading?: string
|
|
388
353
|
content?: string
|
|
@@ -391,13 +356,6 @@ export interface CtaProps {
|
|
|
391
356
|
}
|
|
392
357
|
export function cta(props?: CtaProps): string
|
|
393
358
|
|
|
394
|
-
export interface BannerProps {
|
|
395
|
-
content?: string
|
|
396
|
-
variant?: AlertVariant
|
|
397
|
-
class?: string
|
|
398
|
-
}
|
|
399
|
-
export function banner(props?: BannerProps): string
|
|
400
|
-
|
|
401
359
|
// ---------------------------------------------------------------------------
|
|
402
360
|
// Media
|
|
403
361
|
// ---------------------------------------------------------------------------
|
|
@@ -421,12 +379,6 @@ export interface UiImageProps {
|
|
|
421
379
|
}
|
|
422
380
|
export function uiImage(props?: UiImageProps): string
|
|
423
381
|
|
|
424
|
-
export interface CarouselProps {
|
|
425
|
-
items?: string[]
|
|
426
|
-
class?: string
|
|
427
|
-
}
|
|
428
|
-
export function carousel(props?: CarouselProps): string
|
|
429
|
-
|
|
430
382
|
// ---------------------------------------------------------------------------
|
|
431
383
|
// Interactive UI
|
|
432
384
|
// ---------------------------------------------------------------------------
|
|
@@ -514,25 +466,9 @@ export interface FileUploadProps {
|
|
|
514
466
|
export function fileUpload(props?: FileUploadProps): string
|
|
515
467
|
|
|
516
468
|
// ---------------------------------------------------------------------------
|
|
517
|
-
//
|
|
469
|
+
// Stepper
|
|
518
470
|
// ---------------------------------------------------------------------------
|
|
519
471
|
|
|
520
|
-
export interface TimelineItemProps {
|
|
521
|
-
title?: string
|
|
522
|
-
content?: string
|
|
523
|
-
date?: string
|
|
524
|
-
icon?: string
|
|
525
|
-
active?: boolean
|
|
526
|
-
class?: string
|
|
527
|
-
}
|
|
528
|
-
export function timelineItem(props?: TimelineItemProps): string
|
|
529
|
-
|
|
530
|
-
export interface TimelineProps {
|
|
531
|
-
items?: string[]
|
|
532
|
-
class?: string
|
|
533
|
-
}
|
|
534
|
-
export function timeline(props?: TimelineProps): string
|
|
535
|
-
|
|
536
472
|
export interface StepperStep {
|
|
537
473
|
label: string
|
|
538
474
|
complete?: boolean
|
|
@@ -562,70 +498,6 @@ export interface FooterProps {
|
|
|
562
498
|
}
|
|
563
499
|
export function footer(props?: FooterProps): string
|
|
564
500
|
|
|
565
|
-
export interface CodeWindowProps {
|
|
566
|
-
code?: string
|
|
567
|
-
language?: string
|
|
568
|
-
filename?: string
|
|
569
|
-
class?: string
|
|
570
|
-
}
|
|
571
|
-
export function codeWindow(props?: CodeWindowProps): string
|
|
572
|
-
|
|
573
|
-
// ---------------------------------------------------------------------------
|
|
574
|
-
// Charts
|
|
575
|
-
// ---------------------------------------------------------------------------
|
|
576
|
-
|
|
577
|
-
export interface ChartDataPoint {
|
|
578
|
-
label: string
|
|
579
|
-
value: number
|
|
580
|
-
}
|
|
581
|
-
export interface DonutDataPoint {
|
|
582
|
-
label: string
|
|
583
|
-
value: number
|
|
584
|
-
color?: string
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
export interface BarChartProps {
|
|
588
|
-
data?: ChartDataPoint[]
|
|
589
|
-
height?: number
|
|
590
|
-
color?: ChartColor
|
|
591
|
-
showValues?: boolean
|
|
592
|
-
showGrid?: boolean
|
|
593
|
-
gap?: number
|
|
594
|
-
class?: string
|
|
595
|
-
}
|
|
596
|
-
export function barChart(props?: BarChartProps): string
|
|
597
|
-
|
|
598
|
-
export interface LineChartProps {
|
|
599
|
-
data?: ChartDataPoint[]
|
|
600
|
-
height?: number
|
|
601
|
-
color?: ChartColor
|
|
602
|
-
area?: boolean
|
|
603
|
-
showDots?: boolean
|
|
604
|
-
showGrid?: boolean
|
|
605
|
-
class?: string
|
|
606
|
-
}
|
|
607
|
-
export function lineChart(props?: LineChartProps): string
|
|
608
|
-
|
|
609
|
-
export interface DonutChartProps {
|
|
610
|
-
data?: DonutDataPoint[]
|
|
611
|
-
size?: number
|
|
612
|
-
thickness?: number
|
|
613
|
-
label?: string
|
|
614
|
-
sublabel?: string
|
|
615
|
-
class?: string
|
|
616
|
-
}
|
|
617
|
-
export function donutChart(props?: DonutChartProps): string
|
|
618
|
-
|
|
619
|
-
export interface SparklineProps {
|
|
620
|
-
data?: number[]
|
|
621
|
-
width?: number
|
|
622
|
-
height?: number
|
|
623
|
-
color?: ChartColor
|
|
624
|
-
area?: boolean
|
|
625
|
-
class?: string
|
|
626
|
-
}
|
|
627
|
-
export function sparkline(props?: SparklineProps): string
|
|
628
|
-
|
|
629
501
|
// ---------------------------------------------------------------------------
|
|
630
502
|
// Icons
|
|
631
503
|
// ---------------------------------------------------------------------------
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { renderComponentPage, demo } from '../../lib/component-page.js'
|
|
2
|
-
import { prevNext } from '../../lib/nav.js'
|
|
3
|
-
import { table } from '../../lib/layout.js'
|
|
4
|
-
import { banner, stack } from '../../../../src/ui/index.js'
|
|
5
|
-
|
|
6
|
-
const { prev, next } = prevNext('/components/banner')
|
|
7
|
-
|
|
8
|
-
export default {
|
|
9
|
-
route: '/components/banner',
|
|
10
|
-
meta: {
|
|
11
|
-
title: 'Banner โ Pulse Docs',
|
|
12
|
-
description: 'Banner component for Pulse UI.',
|
|
13
|
-
styles: ['/pulse-ui.css', '/docs.css'],
|
|
14
|
-
},
|
|
15
|
-
view: () => renderComponentPage({
|
|
16
|
-
currentHref: '/components/banner',
|
|
17
|
-
prev,
|
|
18
|
-
next,
|
|
19
|
-
name: 'banner',
|
|
20
|
-
description: 'Full-width announcement bar. Sits above the nav for promotions and launch announcements. The content slot accepts links and formatted text.',
|
|
21
|
-
content: `
|
|
22
|
-
${demo(
|
|
23
|
-
stack({
|
|
24
|
-
gap: 'sm',
|
|
25
|
-
content:
|
|
26
|
-
banner({ variant: 'promo', content: '๐ Chippy Bird v2.0 is out โ <a href="#" style="color:inherit;text-decoration:underline">see what\'s new</a>' }) +
|
|
27
|
-
banner({ variant: 'info', content: 'Android support is coming soon. <a href="#" style="color:inherit;text-decoration:underline">Join the waitlist</a>' }) +
|
|
28
|
-
banner({ variant: 'warning', content: 'Scheduled maintenance Sunday 2โ4am UTC.' }),
|
|
29
|
-
}),
|
|
30
|
-
`banner({ variant: 'promo', content:
|
|
31
|
-
'๐ v2.0 is out โ ' + button({ label: "See what's new", variant: 'ghost', size: 'sm', href: '/changelog' })
|
|
32
|
-
})`
|
|
33
|
-
)}
|
|
34
|
-
|
|
35
|
-
${table(
|
|
36
|
-
['Prop', 'Type', 'Default', 'Description'],
|
|
37
|
-
[
|
|
38
|
-
['<code>content</code>', 'string (HTML)', 'โ', 'Raw HTML slot'],
|
|
39
|
-
['<code>variant</code>', 'string', "'info'", "'info' ยท 'promo' ยท 'warning'"],
|
|
40
|
-
]
|
|
41
|
-
)}
|
|
42
|
-
`,
|
|
43
|
-
}),
|
|
44
|
-
}
|