@flopay/ui 0.1.0 → 0.3.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/README.md +3 -2
- package/assets/logo.png +0 -0
- package/dist/chunk-XF3CK37X.mjs +11 -0
- package/dist/chunk-XF3CK37X.mjs.map +1 -0
- package/dist/index.mjs +3 -6
- package/dist/index.mjs.map +1 -1
- package/dist/marketing/index.cjs +122 -0
- package/dist/marketing/index.cjs.map +1 -0
- package/dist/marketing/index.d.cts +77 -0
- package/dist/marketing/index.d.ts +77 -0
- package/dist/marketing/index.mjs +80 -0
- package/dist/marketing/index.mjs.map +1 -0
- package/package.json +16 -2
- package/styles/tokens.css +5 -0
package/README.md
CHANGED
|
@@ -103,7 +103,8 @@ After that, releases are automatic:
|
|
|
103
103
|
1. Bump `version` in `package.json` on `main`.
|
|
104
104
|
2. `CI` runs (`.github/workflows/ci.yml`).
|
|
105
105
|
3. On CI success, `Publish Package` (`.github/workflows/publish.yml`) sees the
|
|
106
|
-
new version has no `v<version>` tag, `npm publish`es via OIDC
|
|
107
|
-
provenance
|
|
106
|
+
new version has no `v<version>` tag, `npm publish`es via OIDC, then pushes
|
|
107
|
+
the tag. (No npm provenance: this repo is private, and provenance attestation
|
|
108
|
+
requires a public source repo.)
|
|
108
109
|
|
|
109
110
|
CSS files ship raw (no build step); only the JS/types are bundled by tsup.
|
package/assets/logo.png
ADDED
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cn.ts"],"sourcesContent":["import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\n/**\n * Merge class names, resolving conflicting Tailwind utilities (last wins).\n * Mirrors the helper used across the FloPay frontends so consumers can extend\n * any primitive's classes safely.\n */\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n"],"mappings":";AAAA,SAA0B,YAAY;AACtC,SAAS,eAAe;AAOjB,SAAS,MAAM,QAAsB;AAC1C,SAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B;","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
function cn(...inputs) {
|
|
5
|
-
return twMerge(clsx(inputs));
|
|
6
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
cn
|
|
3
|
+
} from "./chunk-XF3CK37X.mjs";
|
|
7
4
|
|
|
8
5
|
// src/components/badge.tsx
|
|
9
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/
|
|
1
|
+
{"version":3,"sources":["../src/components/badge.tsx","../src/components/button.tsx","../src/components/card.tsx","../src/components/container.tsx","../src/components/section.tsx"],"sourcesContent":["import type { HTMLAttributes } from 'react';\nimport { cn } from '../cn';\n\nexport interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {\n /** Render a leading status dot. */\n dot?: boolean;\n}\n\n/** Pill badge, optionally with a leading status dot. */\nexport function Badge({ dot = false, className, children, ...props }: BadgeProps) {\n return (\n <span className={cn('badge', className)} {...props}>\n {dot ? <span className=\"badge-dot\" /> : null}\n {children}\n </span>\n );\n}\n","import type { ButtonHTMLAttributes } from 'react';\nimport { cn } from '../cn';\n\nexport type ButtonVariant = 'primary' | 'secondary' | 'outline';\n\nexport interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: ButtonVariant;\n}\n\nconst variantClass: Record<ButtonVariant, string> = {\n primary: 'btn-primary',\n secondary: 'btn-secondary',\n outline: 'btn-outline',\n};\n\nexport function Button({ variant = 'primary', className, type = 'button', ...props }: ButtonProps) {\n return <button type={type} className={cn(variantClass[variant], className)} {...props} />;\n}\n","import type { HTMLAttributes } from 'react';\nimport { cn } from '../cn';\n\nexport type CardProps = HTMLAttributes<HTMLDivElement>;\n\n/** Bordered surface card with hover elevation. */\nexport function Card({ className, ...props }: CardProps) {\n return <div className={cn('card', className)} {...props} />;\n}\n","import type { HTMLAttributes } from 'react';\nimport { cn } from '../cn';\n\nexport type ContainerProps = HTMLAttributes<HTMLDivElement>;\n\n/** Centered, max-width content wrapper (var(--max-w)) with horizontal padding. */\nexport function Container({ className, ...props }: ContainerProps) {\n return <div className={cn('container', className)} {...props} />;\n}\n","import type { HTMLAttributes, ReactNode } from 'react';\nimport { cn } from '../cn';\n\nexport type SectionProps = HTMLAttributes<HTMLElement>;\n\n/** Vertical page section with max-width and standard padding. */\nexport function Section({ className, ...props }: SectionProps) {\n return <section className={cn('section', className)} {...props} />;\n}\n\nexport interface SectionHeaderProps {\n /** Small eyebrow label above the title (brand colored). */\n label?: ReactNode;\n title: ReactNode;\n description?: ReactNode;\n className?: string;\n}\n\n/** Centered section heading: optional label, title, optional description. */\nexport function SectionHeader({ label, title, description, className }: SectionHeaderProps) {\n return (\n <div className={cn('section-center', className)}>\n {label ? <div className=\"section-label\">{label}</div> : null}\n <h2 className=\"section-title\">{title}</h2>\n {description ? <p className=\"section-desc\">{description}</p> : null}\n </div>\n );\n}\n"],"mappings":";;;;;AAWI,SACS,KADT;AAFG,SAAS,MAAM,EAAE,MAAM,OAAO,WAAW,UAAU,GAAG,MAAM,GAAe;AAChF,SACE,qBAAC,UAAK,WAAW,GAAG,SAAS,SAAS,GAAI,GAAG,OAC1C;AAAA,UAAM,oBAAC,UAAK,WAAU,aAAY,IAAK;AAAA,IACvC;AAAA,KACH;AAEJ;;;ACAS,gBAAAA,YAAA;AAPT,IAAM,eAA8C;AAAA,EAClD,SAAS;AAAA,EACT,WAAW;AAAA,EACX,SAAS;AACX;AAEO,SAAS,OAAO,EAAE,UAAU,WAAW,WAAW,OAAO,UAAU,GAAG,MAAM,GAAgB;AACjG,SAAO,gBAAAA,KAAC,YAAO,MAAY,WAAW,GAAG,aAAa,OAAO,GAAG,SAAS,GAAI,GAAG,OAAO;AACzF;;;ACVS,gBAAAC,YAAA;AADF,SAAS,KAAK,EAAE,WAAW,GAAG,MAAM,GAAc;AACvD,SAAO,gBAAAA,KAAC,SAAI,WAAW,GAAG,QAAQ,SAAS,GAAI,GAAG,OAAO;AAC3D;;;ACDS,gBAAAC,YAAA;AADF,SAAS,UAAU,EAAE,WAAW,GAAG,MAAM,GAAmB;AACjE,SAAO,gBAAAA,KAAC,SAAI,WAAW,GAAG,aAAa,SAAS,GAAI,GAAG,OAAO;AAChE;;;ACDS,gBAAAC,MAcL,QAAAC,aAdK;AADF,SAAS,QAAQ,EAAE,WAAW,GAAG,MAAM,GAAiB;AAC7D,SAAO,gBAAAD,KAAC,aAAQ,WAAW,GAAG,WAAW,SAAS,GAAI,GAAG,OAAO;AAClE;AAWO,SAAS,cAAc,EAAE,OAAO,OAAO,aAAa,UAAU,GAAuB;AAC1F,SACE,gBAAAC,MAAC,SAAI,WAAW,GAAG,kBAAkB,SAAS,GAC3C;AAAA,YAAQ,gBAAAD,KAAC,SAAI,WAAU,iBAAiB,iBAAM,IAAS;AAAA,IACxD,gBAAAA,KAAC,QAAG,WAAU,iBAAiB,iBAAM;AAAA,IACpC,cAAc,gBAAAA,KAAC,OAAE,WAAU,gBAAgB,uBAAY,IAAO;AAAA,KACjE;AAEJ;","names":["jsx","jsx","jsx","jsx","jsxs"]}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/marketing/index.ts
|
|
31
|
+
var marketing_exports = {};
|
|
32
|
+
__export(marketing_exports, {
|
|
33
|
+
Footer: () => Footer,
|
|
34
|
+
MarketingLink: () => MarketingLink,
|
|
35
|
+
Nav: () => Nav
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(marketing_exports);
|
|
38
|
+
|
|
39
|
+
// src/marketing/footer.tsx
|
|
40
|
+
var import_image = __toESM(require("next/image"), 1);
|
|
41
|
+
|
|
42
|
+
// src/cn.ts
|
|
43
|
+
var import_clsx = require("clsx");
|
|
44
|
+
var import_tailwind_merge = require("tailwind-merge");
|
|
45
|
+
function cn(...inputs) {
|
|
46
|
+
return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// src/marketing/link.tsx
|
|
50
|
+
var import_link = __toESM(require("next/link"), 1);
|
|
51
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
52
|
+
function MarketingLink({ href, external, className, children }) {
|
|
53
|
+
const isAbsolute = /^https?:\/\//.test(href) || href.startsWith("//");
|
|
54
|
+
const isProtocol = !isAbsolute && /^[a-z][a-z0-9+.-]*:/i.test(href);
|
|
55
|
+
const openExternally = external ?? isAbsolute;
|
|
56
|
+
if (openExternally) {
|
|
57
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href, className, target: "_blank", rel: "noopener noreferrer", children });
|
|
58
|
+
}
|
|
59
|
+
if (isProtocol) {
|
|
60
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href, className, children });
|
|
61
|
+
}
|
|
62
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_link.default, { href, className, children });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// src/marketing/footer.tsx
|
|
66
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
67
|
+
function Footer({ brand, columns = [], legal = [], copyright, className }) {
|
|
68
|
+
const size = brand.size ?? 20;
|
|
69
|
+
const image = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_image.default, { src: brand.src, alt: brand.alt ?? "", width: size, height: size });
|
|
70
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("footer", { className: cn("footer", className), children: [
|
|
71
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "footer-inner", children: [
|
|
72
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "footer-brand", children: [
|
|
73
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(MarketingLink, { href: brand.href ?? "/", className: "nav-logo", children: [
|
|
74
|
+
brand.mark ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "nav-logo-mark", style: { width: size, height: size }, children: image }) : image,
|
|
75
|
+
brand.label
|
|
76
|
+
] }),
|
|
77
|
+
brand.tagline ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { children: brand.tagline }) : null
|
|
78
|
+
] }),
|
|
79
|
+
columns.map((column, index) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "footer-column", children: [
|
|
80
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h4", { children: column.title }),
|
|
81
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ul", { children: column.links.map((link) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(MarketingLink, { href: link.href, external: link.external, children: link.label }) }, link.href)) })
|
|
82
|
+
] }, index))
|
|
83
|
+
] }),
|
|
84
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "footer-bottom", children: [
|
|
85
|
+
copyright ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { children: copyright }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {}),
|
|
86
|
+
legal.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "footer-legal", children: legal.map((link) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(MarketingLink, { href: link.href, external: link.external, children: link.label }, link.href)) }) : null
|
|
87
|
+
] })
|
|
88
|
+
] });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// src/marketing/nav.tsx
|
|
92
|
+
var import_image2 = __toESM(require("next/image"), 1);
|
|
93
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
94
|
+
function Nav({ logo, links = [], children, className }) {
|
|
95
|
+
const size = logo.size ?? 28;
|
|
96
|
+
const image = /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_image2.default, { src: logo.src, alt: logo.alt ?? "", width: size, height: size, priority: true });
|
|
97
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("nav", { className: cn("nav", className), children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "nav-inner", children: [
|
|
98
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(MarketingLink, { href: logo.href ?? "/", className: "nav-logo", children: [
|
|
99
|
+
logo.mark ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "nav-logo-mark", style: { width: size, height: size }, children: image }) : image,
|
|
100
|
+
logo.label
|
|
101
|
+
] }),
|
|
102
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("ul", { className: "nav-links", children: [
|
|
103
|
+
links.map((link) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
104
|
+
MarketingLink,
|
|
105
|
+
{
|
|
106
|
+
href: link.href,
|
|
107
|
+
external: link.external,
|
|
108
|
+
className: link.cta ? "nav-cta" : void 0,
|
|
109
|
+
children: link.label
|
|
110
|
+
}
|
|
111
|
+
) }, link.href)),
|
|
112
|
+
children ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("li", { children }) : null
|
|
113
|
+
] })
|
|
114
|
+
] }) });
|
|
115
|
+
}
|
|
116
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
117
|
+
0 && (module.exports = {
|
|
118
|
+
Footer,
|
|
119
|
+
MarketingLink,
|
|
120
|
+
Nav
|
|
121
|
+
});
|
|
122
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/marketing/index.ts","../../src/marketing/footer.tsx","../../src/cn.ts","../../src/marketing/link.tsx","../../src/marketing/nav.tsx"],"sourcesContent":["export type { FooterBrand, FooterColumn, FooterLink, FooterProps } from './footer';\nexport { Footer } from './footer';\nexport type { MarketingLinkProps } from './link';\nexport { MarketingLink } from './link';\nexport type { NavLink, NavLogo, NavProps } from './nav';\nexport { Nav } from './nav';\n","import Image, { type ImageProps } from 'next/image';\nimport type { ReactNode } from 'react';\nimport { cn } from '../cn';\nimport { MarketingLink } from './link';\n\nexport interface FooterLink {\n href: string;\n label: ReactNode;\n external?: boolean;\n}\n\nexport interface FooterColumn {\n title: ReactNode;\n links: FooterLink[];\n}\n\nexport interface FooterBrand {\n /** A URL string or a statically-imported image (e.g. `@flopay/ui/logo.png`). */\n src: ImageProps['src'];\n alt?: string;\n label?: ReactNode;\n href?: string;\n size?: number;\n mark?: boolean;\n tagline?: ReactNode;\n}\n\nexport interface FooterProps {\n brand: FooterBrand;\n columns?: FooterColumn[];\n legal?: FooterLink[];\n copyright?: ReactNode;\n className?: string;\n}\n\n/** Shared site footer for marketing surfaces (landing, demo). */\nexport function Footer({ brand, columns = [], legal = [], copyright, className }: FooterProps) {\n const size = brand.size ?? 20;\n const image = <Image src={brand.src} alt={brand.alt ?? ''} width={size} height={size} />;\n\n return (\n <footer className={cn('footer', className)}>\n <div className=\"footer-inner\">\n <div className=\"footer-brand\">\n <MarketingLink href={brand.href ?? '/'} className=\"nav-logo\">\n {brand.mark ? (\n <span className=\"nav-logo-mark\" style={{ width: size, height: size }}>\n {image}\n </span>\n ) : (\n image\n )}\n {brand.label}\n </MarketingLink>\n {brand.tagline ? <p>{brand.tagline}</p> : null}\n </div>\n {columns.map((column, index) => (\n <div className=\"footer-column\" key={index}>\n <h4>{column.title}</h4>\n <ul>\n {column.links.map((link) => (\n <li key={link.href}>\n <MarketingLink href={link.href} external={link.external}>\n {link.label}\n </MarketingLink>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n <div className=\"footer-bottom\">\n {copyright ? <p>{copyright}</p> : <span />}\n {legal.length > 0 ? (\n <div className=\"footer-legal\">\n {legal.map((link) => (\n <MarketingLink key={link.href} href={link.href} external={link.external}>\n {link.label}\n </MarketingLink>\n ))}\n </div>\n ) : null}\n </div>\n </footer>\n );\n}\n","import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\n/**\n * Merge class names, resolving conflicting Tailwind utilities (last wins).\n * Mirrors the helper used across the FloPay frontends so consumers can extend\n * any primitive's classes safely.\n */\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import Link from 'next/link';\nimport type { ReactNode } from 'react';\n\nexport interface MarketingLinkProps {\n href: string;\n /** Force new-tab rendering. Defaults to true for absolute http(s) URLs. */\n external?: boolean;\n className?: string;\n children: ReactNode;\n}\n\n/**\n * Picks the right element for a marketing link:\n * - internal route (\"/...\", \"#...\") → next/link\n * - protocol link (mailto:/tel:) → plain anchor\n * - absolute URL (or `external`) → new-tab anchor\n */\nexport function MarketingLink({ href, external, className, children }: MarketingLinkProps) {\n const isAbsolute = /^https?:\\/\\//.test(href) || href.startsWith('//');\n const isProtocol = !isAbsolute && /^[a-z][a-z0-9+.-]*:/i.test(href);\n const openExternally = external ?? isAbsolute;\n\n if (openExternally) {\n return (\n <a href={href} className={className} target=\"_blank\" rel=\"noopener noreferrer\">\n {children}\n </a>\n );\n }\n if (isProtocol) {\n return (\n <a href={href} className={className}>\n {children}\n </a>\n );\n }\n return (\n <Link href={href} className={className}>\n {children}\n </Link>\n );\n}\n","import Image, { type ImageProps } from 'next/image';\nimport type { ReactNode } from 'react';\nimport { cn } from '../cn';\nimport { MarketingLink } from './link';\n\nexport interface NavLink {\n href: string;\n label: ReactNode;\n external?: boolean;\n /** Render as the prominent call-to-action button. */\n cta?: boolean;\n}\n\nexport interface NavLogo {\n /** A URL string or a statically-imported image (e.g. `@flopay/ui/logo.png`). */\n src: ImageProps['src'];\n alt?: string;\n label?: ReactNode;\n href?: string;\n /** Logo image edge size in px (default 28). */\n size?: number;\n /** Wrap the image in the rounded brand mark. */\n mark?: boolean;\n}\n\nexport interface NavProps {\n logo: NavLogo;\n links?: NavLink[];\n /** Extra item appended to the link list (e.g. an interactive control). */\n children?: ReactNode;\n className?: string;\n}\n\n/** Shared fixed top navigation for marketing surfaces (landing, demo). */\nexport function Nav({ logo, links = [], children, className }: NavProps) {\n const size = logo.size ?? 28;\n const image = <Image src={logo.src} alt={logo.alt ?? ''} width={size} height={size} priority />;\n\n return (\n <nav className={cn('nav', className)}>\n <div className=\"nav-inner\">\n <MarketingLink href={logo.href ?? '/'} className=\"nav-logo\">\n {logo.mark ? (\n <span className=\"nav-logo-mark\" style={{ width: size, height: size }}>\n {image}\n </span>\n ) : (\n image\n )}\n {logo.label}\n </MarketingLink>\n <ul className=\"nav-links\">\n {links.map((link) => (\n <li key={link.href}>\n <MarketingLink\n href={link.href}\n external={link.external}\n className={link.cta ? 'nav-cta' : undefined}\n >\n {link.label}\n </MarketingLink>\n </li>\n ))}\n {children ? <li>{children}</li> : null}\n </ul>\n </div>\n </nav>\n );\n}\n"],"mappings":"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","names":["Link","import_jsx_runtime","Image","import_image","import_jsx_runtime","Image"]}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { ImageProps } from 'next/image';
|
|
4
|
+
|
|
5
|
+
interface FooterLink {
|
|
6
|
+
href: string;
|
|
7
|
+
label: ReactNode;
|
|
8
|
+
external?: boolean;
|
|
9
|
+
}
|
|
10
|
+
interface FooterColumn {
|
|
11
|
+
title: ReactNode;
|
|
12
|
+
links: FooterLink[];
|
|
13
|
+
}
|
|
14
|
+
interface FooterBrand {
|
|
15
|
+
/** A URL string or a statically-imported image (e.g. `@flopay/ui/logo.png`). */
|
|
16
|
+
src: ImageProps['src'];
|
|
17
|
+
alt?: string;
|
|
18
|
+
label?: ReactNode;
|
|
19
|
+
href?: string;
|
|
20
|
+
size?: number;
|
|
21
|
+
mark?: boolean;
|
|
22
|
+
tagline?: ReactNode;
|
|
23
|
+
}
|
|
24
|
+
interface FooterProps {
|
|
25
|
+
brand: FooterBrand;
|
|
26
|
+
columns?: FooterColumn[];
|
|
27
|
+
legal?: FooterLink[];
|
|
28
|
+
copyright?: ReactNode;
|
|
29
|
+
className?: string;
|
|
30
|
+
}
|
|
31
|
+
/** Shared site footer for marketing surfaces (landing, demo). */
|
|
32
|
+
declare function Footer({ brand, columns, legal, copyright, className }: FooterProps): react.JSX.Element;
|
|
33
|
+
|
|
34
|
+
interface MarketingLinkProps {
|
|
35
|
+
href: string;
|
|
36
|
+
/** Force new-tab rendering. Defaults to true for absolute http(s) URLs. */
|
|
37
|
+
external?: boolean;
|
|
38
|
+
className?: string;
|
|
39
|
+
children: ReactNode;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Picks the right element for a marketing link:
|
|
43
|
+
* - internal route ("/...", "#...") → next/link
|
|
44
|
+
* - protocol link (mailto:/tel:) → plain anchor
|
|
45
|
+
* - absolute URL (or `external`) → new-tab anchor
|
|
46
|
+
*/
|
|
47
|
+
declare function MarketingLink({ href, external, className, children }: MarketingLinkProps): react.JSX.Element;
|
|
48
|
+
|
|
49
|
+
interface NavLink {
|
|
50
|
+
href: string;
|
|
51
|
+
label: ReactNode;
|
|
52
|
+
external?: boolean;
|
|
53
|
+
/** Render as the prominent call-to-action button. */
|
|
54
|
+
cta?: boolean;
|
|
55
|
+
}
|
|
56
|
+
interface NavLogo {
|
|
57
|
+
/** A URL string or a statically-imported image (e.g. `@flopay/ui/logo.png`). */
|
|
58
|
+
src: ImageProps['src'];
|
|
59
|
+
alt?: string;
|
|
60
|
+
label?: ReactNode;
|
|
61
|
+
href?: string;
|
|
62
|
+
/** Logo image edge size in px (default 28). */
|
|
63
|
+
size?: number;
|
|
64
|
+
/** Wrap the image in the rounded brand mark. */
|
|
65
|
+
mark?: boolean;
|
|
66
|
+
}
|
|
67
|
+
interface NavProps {
|
|
68
|
+
logo: NavLogo;
|
|
69
|
+
links?: NavLink[];
|
|
70
|
+
/** Extra item appended to the link list (e.g. an interactive control). */
|
|
71
|
+
children?: ReactNode;
|
|
72
|
+
className?: string;
|
|
73
|
+
}
|
|
74
|
+
/** Shared fixed top navigation for marketing surfaces (landing, demo). */
|
|
75
|
+
declare function Nav({ logo, links, children, className }: NavProps): react.JSX.Element;
|
|
76
|
+
|
|
77
|
+
export { Footer, type FooterBrand, type FooterColumn, type FooterLink, type FooterProps, MarketingLink, type MarketingLinkProps, Nav, type NavLink, type NavLogo, type NavProps };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { ImageProps } from 'next/image';
|
|
4
|
+
|
|
5
|
+
interface FooterLink {
|
|
6
|
+
href: string;
|
|
7
|
+
label: ReactNode;
|
|
8
|
+
external?: boolean;
|
|
9
|
+
}
|
|
10
|
+
interface FooterColumn {
|
|
11
|
+
title: ReactNode;
|
|
12
|
+
links: FooterLink[];
|
|
13
|
+
}
|
|
14
|
+
interface FooterBrand {
|
|
15
|
+
/** A URL string or a statically-imported image (e.g. `@flopay/ui/logo.png`). */
|
|
16
|
+
src: ImageProps['src'];
|
|
17
|
+
alt?: string;
|
|
18
|
+
label?: ReactNode;
|
|
19
|
+
href?: string;
|
|
20
|
+
size?: number;
|
|
21
|
+
mark?: boolean;
|
|
22
|
+
tagline?: ReactNode;
|
|
23
|
+
}
|
|
24
|
+
interface FooterProps {
|
|
25
|
+
brand: FooterBrand;
|
|
26
|
+
columns?: FooterColumn[];
|
|
27
|
+
legal?: FooterLink[];
|
|
28
|
+
copyright?: ReactNode;
|
|
29
|
+
className?: string;
|
|
30
|
+
}
|
|
31
|
+
/** Shared site footer for marketing surfaces (landing, demo). */
|
|
32
|
+
declare function Footer({ brand, columns, legal, copyright, className }: FooterProps): react.JSX.Element;
|
|
33
|
+
|
|
34
|
+
interface MarketingLinkProps {
|
|
35
|
+
href: string;
|
|
36
|
+
/** Force new-tab rendering. Defaults to true for absolute http(s) URLs. */
|
|
37
|
+
external?: boolean;
|
|
38
|
+
className?: string;
|
|
39
|
+
children: ReactNode;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Picks the right element for a marketing link:
|
|
43
|
+
* - internal route ("/...", "#...") → next/link
|
|
44
|
+
* - protocol link (mailto:/tel:) → plain anchor
|
|
45
|
+
* - absolute URL (or `external`) → new-tab anchor
|
|
46
|
+
*/
|
|
47
|
+
declare function MarketingLink({ href, external, className, children }: MarketingLinkProps): react.JSX.Element;
|
|
48
|
+
|
|
49
|
+
interface NavLink {
|
|
50
|
+
href: string;
|
|
51
|
+
label: ReactNode;
|
|
52
|
+
external?: boolean;
|
|
53
|
+
/** Render as the prominent call-to-action button. */
|
|
54
|
+
cta?: boolean;
|
|
55
|
+
}
|
|
56
|
+
interface NavLogo {
|
|
57
|
+
/** A URL string or a statically-imported image (e.g. `@flopay/ui/logo.png`). */
|
|
58
|
+
src: ImageProps['src'];
|
|
59
|
+
alt?: string;
|
|
60
|
+
label?: ReactNode;
|
|
61
|
+
href?: string;
|
|
62
|
+
/** Logo image edge size in px (default 28). */
|
|
63
|
+
size?: number;
|
|
64
|
+
/** Wrap the image in the rounded brand mark. */
|
|
65
|
+
mark?: boolean;
|
|
66
|
+
}
|
|
67
|
+
interface NavProps {
|
|
68
|
+
logo: NavLogo;
|
|
69
|
+
links?: NavLink[];
|
|
70
|
+
/** Extra item appended to the link list (e.g. an interactive control). */
|
|
71
|
+
children?: ReactNode;
|
|
72
|
+
className?: string;
|
|
73
|
+
}
|
|
74
|
+
/** Shared fixed top navigation for marketing surfaces (landing, demo). */
|
|
75
|
+
declare function Nav({ logo, links, children, className }: NavProps): react.JSX.Element;
|
|
76
|
+
|
|
77
|
+
export { Footer, type FooterBrand, type FooterColumn, type FooterLink, type FooterProps, MarketingLink, type MarketingLinkProps, Nav, type NavLink, type NavLogo, type NavProps };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cn
|
|
3
|
+
} from "../chunk-XF3CK37X.mjs";
|
|
4
|
+
|
|
5
|
+
// src/marketing/footer.tsx
|
|
6
|
+
import Image from "next/image";
|
|
7
|
+
|
|
8
|
+
// src/marketing/link.tsx
|
|
9
|
+
import Link from "next/link";
|
|
10
|
+
import { jsx } from "react/jsx-runtime";
|
|
11
|
+
function MarketingLink({ href, external, className, children }) {
|
|
12
|
+
const isAbsolute = /^https?:\/\//.test(href) || href.startsWith("//");
|
|
13
|
+
const isProtocol = !isAbsolute && /^[a-z][a-z0-9+.-]*:/i.test(href);
|
|
14
|
+
const openExternally = external ?? isAbsolute;
|
|
15
|
+
if (openExternally) {
|
|
16
|
+
return /* @__PURE__ */ jsx("a", { href, className, target: "_blank", rel: "noopener noreferrer", children });
|
|
17
|
+
}
|
|
18
|
+
if (isProtocol) {
|
|
19
|
+
return /* @__PURE__ */ jsx("a", { href, className, children });
|
|
20
|
+
}
|
|
21
|
+
return /* @__PURE__ */ jsx(Link, { href, className, children });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// src/marketing/footer.tsx
|
|
25
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
26
|
+
function Footer({ brand, columns = [], legal = [], copyright, className }) {
|
|
27
|
+
const size = brand.size ?? 20;
|
|
28
|
+
const image = /* @__PURE__ */ jsx2(Image, { src: brand.src, alt: brand.alt ?? "", width: size, height: size });
|
|
29
|
+
return /* @__PURE__ */ jsxs("footer", { className: cn("footer", className), children: [
|
|
30
|
+
/* @__PURE__ */ jsxs("div", { className: "footer-inner", children: [
|
|
31
|
+
/* @__PURE__ */ jsxs("div", { className: "footer-brand", children: [
|
|
32
|
+
/* @__PURE__ */ jsxs(MarketingLink, { href: brand.href ?? "/", className: "nav-logo", children: [
|
|
33
|
+
brand.mark ? /* @__PURE__ */ jsx2("span", { className: "nav-logo-mark", style: { width: size, height: size }, children: image }) : image,
|
|
34
|
+
brand.label
|
|
35
|
+
] }),
|
|
36
|
+
brand.tagline ? /* @__PURE__ */ jsx2("p", { children: brand.tagline }) : null
|
|
37
|
+
] }),
|
|
38
|
+
columns.map((column, index) => /* @__PURE__ */ jsxs("div", { className: "footer-column", children: [
|
|
39
|
+
/* @__PURE__ */ jsx2("h4", { children: column.title }),
|
|
40
|
+
/* @__PURE__ */ jsx2("ul", { children: column.links.map((link) => /* @__PURE__ */ jsx2("li", { children: /* @__PURE__ */ jsx2(MarketingLink, { href: link.href, external: link.external, children: link.label }) }, link.href)) })
|
|
41
|
+
] }, index))
|
|
42
|
+
] }),
|
|
43
|
+
/* @__PURE__ */ jsxs("div", { className: "footer-bottom", children: [
|
|
44
|
+
copyright ? /* @__PURE__ */ jsx2("p", { children: copyright }) : /* @__PURE__ */ jsx2("span", {}),
|
|
45
|
+
legal.length > 0 ? /* @__PURE__ */ jsx2("div", { className: "footer-legal", children: legal.map((link) => /* @__PURE__ */ jsx2(MarketingLink, { href: link.href, external: link.external, children: link.label }, link.href)) }) : null
|
|
46
|
+
] })
|
|
47
|
+
] });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// src/marketing/nav.tsx
|
|
51
|
+
import Image2 from "next/image";
|
|
52
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
53
|
+
function Nav({ logo, links = [], children, className }) {
|
|
54
|
+
const size = logo.size ?? 28;
|
|
55
|
+
const image = /* @__PURE__ */ jsx3(Image2, { src: logo.src, alt: logo.alt ?? "", width: size, height: size, priority: true });
|
|
56
|
+
return /* @__PURE__ */ jsx3("nav", { className: cn("nav", className), children: /* @__PURE__ */ jsxs2("div", { className: "nav-inner", children: [
|
|
57
|
+
/* @__PURE__ */ jsxs2(MarketingLink, { href: logo.href ?? "/", className: "nav-logo", children: [
|
|
58
|
+
logo.mark ? /* @__PURE__ */ jsx3("span", { className: "nav-logo-mark", style: { width: size, height: size }, children: image }) : image,
|
|
59
|
+
logo.label
|
|
60
|
+
] }),
|
|
61
|
+
/* @__PURE__ */ jsxs2("ul", { className: "nav-links", children: [
|
|
62
|
+
links.map((link) => /* @__PURE__ */ jsx3("li", { children: /* @__PURE__ */ jsx3(
|
|
63
|
+
MarketingLink,
|
|
64
|
+
{
|
|
65
|
+
href: link.href,
|
|
66
|
+
external: link.external,
|
|
67
|
+
className: link.cta ? "nav-cta" : void 0,
|
|
68
|
+
children: link.label
|
|
69
|
+
}
|
|
70
|
+
) }, link.href)),
|
|
71
|
+
children ? /* @__PURE__ */ jsx3("li", { children }) : null
|
|
72
|
+
] })
|
|
73
|
+
] }) });
|
|
74
|
+
}
|
|
75
|
+
export {
|
|
76
|
+
Footer,
|
|
77
|
+
MarketingLink,
|
|
78
|
+
Nav
|
|
79
|
+
};
|
|
80
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/marketing/footer.tsx","../../src/marketing/link.tsx","../../src/marketing/nav.tsx"],"sourcesContent":["import Image, { type ImageProps } from 'next/image';\nimport type { ReactNode } from 'react';\nimport { cn } from '../cn';\nimport { MarketingLink } from './link';\n\nexport interface FooterLink {\n href: string;\n label: ReactNode;\n external?: boolean;\n}\n\nexport interface FooterColumn {\n title: ReactNode;\n links: FooterLink[];\n}\n\nexport interface FooterBrand {\n /** A URL string or a statically-imported image (e.g. `@flopay/ui/logo.png`). */\n src: ImageProps['src'];\n alt?: string;\n label?: ReactNode;\n href?: string;\n size?: number;\n mark?: boolean;\n tagline?: ReactNode;\n}\n\nexport interface FooterProps {\n brand: FooterBrand;\n columns?: FooterColumn[];\n legal?: FooterLink[];\n copyright?: ReactNode;\n className?: string;\n}\n\n/** Shared site footer for marketing surfaces (landing, demo). */\nexport function Footer({ brand, columns = [], legal = [], copyright, className }: FooterProps) {\n const size = brand.size ?? 20;\n const image = <Image src={brand.src} alt={brand.alt ?? ''} width={size} height={size} />;\n\n return (\n <footer className={cn('footer', className)}>\n <div className=\"footer-inner\">\n <div className=\"footer-brand\">\n <MarketingLink href={brand.href ?? '/'} className=\"nav-logo\">\n {brand.mark ? (\n <span className=\"nav-logo-mark\" style={{ width: size, height: size }}>\n {image}\n </span>\n ) : (\n image\n )}\n {brand.label}\n </MarketingLink>\n {brand.tagline ? <p>{brand.tagline}</p> : null}\n </div>\n {columns.map((column, index) => (\n <div className=\"footer-column\" key={index}>\n <h4>{column.title}</h4>\n <ul>\n {column.links.map((link) => (\n <li key={link.href}>\n <MarketingLink href={link.href} external={link.external}>\n {link.label}\n </MarketingLink>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n <div className=\"footer-bottom\">\n {copyright ? <p>{copyright}</p> : <span />}\n {legal.length > 0 ? (\n <div className=\"footer-legal\">\n {legal.map((link) => (\n <MarketingLink key={link.href} href={link.href} external={link.external}>\n {link.label}\n </MarketingLink>\n ))}\n </div>\n ) : null}\n </div>\n </footer>\n );\n}\n","import Link from 'next/link';\nimport type { ReactNode } from 'react';\n\nexport interface MarketingLinkProps {\n href: string;\n /** Force new-tab rendering. Defaults to true for absolute http(s) URLs. */\n external?: boolean;\n className?: string;\n children: ReactNode;\n}\n\n/**\n * Picks the right element for a marketing link:\n * - internal route (\"/...\", \"#...\") → next/link\n * - protocol link (mailto:/tel:) → plain anchor\n * - absolute URL (or `external`) → new-tab anchor\n */\nexport function MarketingLink({ href, external, className, children }: MarketingLinkProps) {\n const isAbsolute = /^https?:\\/\\//.test(href) || href.startsWith('//');\n const isProtocol = !isAbsolute && /^[a-z][a-z0-9+.-]*:/i.test(href);\n const openExternally = external ?? isAbsolute;\n\n if (openExternally) {\n return (\n <a href={href} className={className} target=\"_blank\" rel=\"noopener noreferrer\">\n {children}\n </a>\n );\n }\n if (isProtocol) {\n return (\n <a href={href} className={className}>\n {children}\n </a>\n );\n }\n return (\n <Link href={href} className={className}>\n {children}\n </Link>\n );\n}\n","import Image, { type ImageProps } from 'next/image';\nimport type { ReactNode } from 'react';\nimport { cn } from '../cn';\nimport { MarketingLink } from './link';\n\nexport interface NavLink {\n href: string;\n label: ReactNode;\n external?: boolean;\n /** Render as the prominent call-to-action button. */\n cta?: boolean;\n}\n\nexport interface NavLogo {\n /** A URL string or a statically-imported image (e.g. `@flopay/ui/logo.png`). */\n src: ImageProps['src'];\n alt?: string;\n label?: ReactNode;\n href?: string;\n /** Logo image edge size in px (default 28). */\n size?: number;\n /** Wrap the image in the rounded brand mark. */\n mark?: boolean;\n}\n\nexport interface NavProps {\n logo: NavLogo;\n links?: NavLink[];\n /** Extra item appended to the link list (e.g. an interactive control). */\n children?: ReactNode;\n className?: string;\n}\n\n/** Shared fixed top navigation for marketing surfaces (landing, demo). */\nexport function Nav({ logo, links = [], children, className }: NavProps) {\n const size = logo.size ?? 28;\n const image = <Image src={logo.src} alt={logo.alt ?? ''} width={size} height={size} priority />;\n\n return (\n <nav className={cn('nav', className)}>\n <div className=\"nav-inner\">\n <MarketingLink href={logo.href ?? '/'} className=\"nav-logo\">\n {logo.mark ? (\n <span className=\"nav-logo-mark\" style={{ width: size, height: size }}>\n {image}\n </span>\n ) : (\n image\n )}\n {logo.label}\n </MarketingLink>\n <ul className=\"nav-links\">\n {links.map((link) => (\n <li key={link.href}>\n <MarketingLink\n href={link.href}\n external={link.external}\n className={link.cta ? 'nav-cta' : undefined}\n >\n {link.label}\n </MarketingLink>\n </li>\n ))}\n {children ? <li>{children}</li> : null}\n </ul>\n </div>\n </nav>\n );\n}\n"],"mappings":"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","names":["jsx","Image","jsx","jsxs","Image"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flopay/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"packageManager": "pnpm@9.15.0",
|
|
6
6
|
"description": "FloPay shared design system — design tokens, a Tailwind v4 preset, and React primitives shared across landing, demo, docs, and dashboard.",
|
|
@@ -22,12 +22,18 @@
|
|
|
22
22
|
"import": "./dist/index.mjs",
|
|
23
23
|
"require": "./dist/index.cjs"
|
|
24
24
|
},
|
|
25
|
+
"./marketing": {
|
|
26
|
+
"types": "./dist/marketing/index.d.ts",
|
|
27
|
+
"import": "./dist/marketing/index.mjs",
|
|
28
|
+
"require": "./dist/marketing/index.cjs"
|
|
29
|
+
},
|
|
25
30
|
"./styles": "./styles/index.css",
|
|
26
31
|
"./styles/index.css": "./styles/index.css",
|
|
27
32
|
"./styles/tokens.css": "./styles/tokens.css",
|
|
28
33
|
"./styles/reset.css": "./styles/reset.css",
|
|
29
34
|
"./styles/components.css": "./styles/components.css",
|
|
30
35
|
"./styles/preset.css": "./styles/preset.css",
|
|
36
|
+
"./logo.png": "./assets/logo.png",
|
|
31
37
|
"./package.json": "./package.json"
|
|
32
38
|
},
|
|
33
39
|
"main": "./dist/index.cjs",
|
|
@@ -35,7 +41,8 @@
|
|
|
35
41
|
"types": "./dist/index.d.ts",
|
|
36
42
|
"files": [
|
|
37
43
|
"dist",
|
|
38
|
-
"styles"
|
|
44
|
+
"styles",
|
|
45
|
+
"assets"
|
|
39
46
|
],
|
|
40
47
|
"scripts": {
|
|
41
48
|
"build": "tsup",
|
|
@@ -47,9 +54,15 @@
|
|
|
47
54
|
"prepublishOnly": "node scripts/check-publish-registry.cjs"
|
|
48
55
|
},
|
|
49
56
|
"peerDependencies": {
|
|
57
|
+
"next": ">=15",
|
|
50
58
|
"react": "^19",
|
|
51
59
|
"react-dom": "^19"
|
|
52
60
|
},
|
|
61
|
+
"peerDependenciesMeta": {
|
|
62
|
+
"next": {
|
|
63
|
+
"optional": true
|
|
64
|
+
}
|
|
65
|
+
},
|
|
53
66
|
"dependencies": {
|
|
54
67
|
"clsx": "^2.1.1",
|
|
55
68
|
"tailwind-merge": "^3.6.0"
|
|
@@ -58,6 +71,7 @@
|
|
|
58
71
|
"@biomejs/biome": "^2.4.15",
|
|
59
72
|
"@types/react": "^19.2.15",
|
|
60
73
|
"@types/react-dom": "^19.2.3",
|
|
74
|
+
"next": "^16.2.6",
|
|
61
75
|
"react": "^19.2.6",
|
|
62
76
|
"react-dom": "^19.2.6",
|
|
63
77
|
"tsup": "^8.3.0",
|
package/styles/tokens.css
CHANGED
|
@@ -35,6 +35,11 @@
|
|
|
35
35
|
--brand-light: #4ba6ec;
|
|
36
36
|
--brand-secondary: #38d299;
|
|
37
37
|
|
|
38
|
+
/* Brand as raw HSL channels — for consumers that need `H S% L%`
|
|
39
|
+
(e.g. Fumadocs `--fd-primary`). Mirror --brand / --brand-light. */
|
|
40
|
+
--brand-hsl: 207 81% 48%;
|
|
41
|
+
--brand-light-hsl: 206 81% 61%;
|
|
42
|
+
|
|
38
43
|
/* Status */
|
|
39
44
|
--success: #16a34a;
|
|
40
45
|
--danger: #dc2626;
|