@breadcoop/ui 1.0.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 +255 -0
- package/dist/fonts/PogacaBodyBold.woff2 +0 -0
- package/dist/fonts/PogacaBodyLight.woff2 +0 -0
- package/dist/fonts/PogacaBodyRegular.woff2 +0 -0
- package/dist/fonts/PogacaDisplayBlack.woff2 +0 -0
- package/dist/fonts/PogacaDisplayBold.woff2 +0 -0
- package/dist/fonts/PogacaDisplayRegular.woff2 +0 -0
- package/dist/fonts/fonts.css +42 -0
- package/dist/fonts/readme.md +20 -0
- package/dist/index.d.mts +113 -0
- package/dist/index.d.ts +113 -0
- package/dist/index.js +1 -0
- package/dist/index.mjs +1 -0
- package/dist/tailwind-preset.js +51 -0
- package/dist/theme.css +169 -0
- package/package.json +85 -0
- package/tailwind-preset.js +51 -0
- package/theme.css +169 -0
package/README.md
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
# Bread UI Kit
|
|
2
|
+
|
|
3
|
+
A React TypeScript component library for implementing Bread Coop branding in JS/TS projects. Choose your integration approach based on your needs.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install bread-ui-kit
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage Options
|
|
12
|
+
|
|
13
|
+
### Option 1: Drop-in CSS Theme (Simplest)
|
|
14
|
+
|
|
15
|
+
Perfect for projects that want to use pre-built components without configuration. **Fonts are included automatically!**
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { LiftedButton, Heading1, Body } from "bread-ui-kit";
|
|
20
|
+
// Import the complete theme CSS
|
|
21
|
+
import "bread-ui-kit/theme";
|
|
22
|
+
|
|
23
|
+
function App() {
|
|
24
|
+
return (
|
|
25
|
+
<div>
|
|
26
|
+
<Heading1>Welcome to Bread Coop</Heading1>
|
|
27
|
+
<Body>This text uses our brand typography.</Body>
|
|
28
|
+
<LiftedButton preset="primary" onClick={() => console.log("Clicked!")}>
|
|
29
|
+
Click me
|
|
30
|
+
</LiftedButton>
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Option 2: Tailwind Preset (Maximum Flexibility)
|
|
37
|
+
|
|
38
|
+
For projects that want full Tailwind integration with custom utilities and your design tokens.
|
|
39
|
+
|
|
40
|
+
#### Tailwind v3/v4 (Config-driven)
|
|
41
|
+
|
|
42
|
+
```js
|
|
43
|
+
// tailwind.config.js
|
|
44
|
+
module.exports = {
|
|
45
|
+
presets: [require("bread-ui-kit/tailwind-preset")],
|
|
46
|
+
content: [
|
|
47
|
+
"./src/**/*.{js,ts,jsx,tsx}",
|
|
48
|
+
"./node_modules/bread-ui-kit/dist/**/*.{js,ts,jsx,tsx}",
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
import React from "react";
|
|
55
|
+
import { LiftedButton, Heading1, Typography } from "bread-ui-kit";
|
|
56
|
+
|
|
57
|
+
function App() {
|
|
58
|
+
return (
|
|
59
|
+
<div>
|
|
60
|
+
{/* Use pre-built typography components */}
|
|
61
|
+
<Heading1>Brand Consistent Heading</Heading1>
|
|
62
|
+
<Typography variant="body">Consistent body text</Typography>
|
|
63
|
+
|
|
64
|
+
{/* Use pre-built button components */}
|
|
65
|
+
<LiftedButton preset="primary">Click me</LiftedButton>
|
|
66
|
+
|
|
67
|
+
{/* Or use Tailwind utilities with your design tokens */}
|
|
68
|
+
<div className="bg-primary-orange text-white p-4 rounded-md">
|
|
69
|
+
Custom styled element
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
#### Tailwind v4 (Configless)
|
|
77
|
+
|
|
78
|
+
```css
|
|
79
|
+
/* globals.css */
|
|
80
|
+
@import "tailwindcss";
|
|
81
|
+
@import "bread-ui-kit/tailwind-preset";
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
import React from "react";
|
|
86
|
+
import { LiftedButton, Heading1, Body } from "bread-ui-kit";
|
|
87
|
+
import "./globals.css";
|
|
88
|
+
|
|
89
|
+
function App() {
|
|
90
|
+
return (
|
|
91
|
+
<div>
|
|
92
|
+
<Heading1>Brand Consistent Heading</Heading1>
|
|
93
|
+
<Body>Consistent body text</Body>
|
|
94
|
+
<LiftedButton preset="primary">Click me</LiftedButton>
|
|
95
|
+
<div className="bg-primary-orange text-white p-4 rounded-md">
|
|
96
|
+
Custom styled element
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Design Tokens
|
|
104
|
+
|
|
105
|
+
The Bread Coop design system includes comprehensive design tokens:
|
|
106
|
+
|
|
107
|
+
### Colors
|
|
108
|
+
|
|
109
|
+
- **Primary Orange**: `#ea6023` (primary-orange)
|
|
110
|
+
- **Primary Jade**: `#286b63` (primary-jade)
|
|
111
|
+
- **Primary Blue**: `#1c5bb9` (primary-blue)
|
|
112
|
+
- **Paper Colors**: Light, warm paper tones (paper-main, paper-0, paper-1, paper-2)
|
|
113
|
+
- **Surface Colors**: Dark, rich surface tones (surface-ink, surface-brown, etc.)
|
|
114
|
+
- **System Colors**: Success (system-green), error (system-red), warning (system-warning)
|
|
115
|
+
|
|
116
|
+
### Typography
|
|
117
|
+
|
|
118
|
+
- **Bread Display**: Bold, impactful display font
|
|
119
|
+
- **Bread Body**: Clean, readable body font
|
|
120
|
+
- **Roboto**: Monospace font for code
|
|
121
|
+
|
|
122
|
+
### Available Classes
|
|
123
|
+
|
|
124
|
+
- **Text Styles**: `.text-h1`, `.text-h2`, `.text-h3`, `.text-h4`, `.text-h5`, `.text-body`
|
|
125
|
+
- **Button Styles**: `.bread-button-primary`, `.bread-button-secondary`, `.bread-button-outline`
|
|
126
|
+
- **Utility Classes**: All Tailwind utilities with your custom colors
|
|
127
|
+
|
|
128
|
+
## Components
|
|
129
|
+
|
|
130
|
+
### Typography
|
|
131
|
+
|
|
132
|
+
Brand-consistent typography components that ensure proper font usage across your application. **Bread Coop fonts are automatically loaded when you import the theme!**
|
|
133
|
+
|
|
134
|
+
#### Typography Component
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
import { Typography } from "bread-ui-kit";
|
|
138
|
+
|
|
139
|
+
<Typography variant="h1">Main Heading</Typography>
|
|
140
|
+
<Typography variant="h2">Section Heading</Typography>
|
|
141
|
+
<Typography variant="body">Body text content</Typography>
|
|
142
|
+
<Typography variant="caption">Small caption text</Typography>
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
#### Individual Typography Components
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
import { Heading1, Heading2, Heading3, Body, Caption } from "bread-ui-kit";
|
|
149
|
+
|
|
150
|
+
<Heading1>Main Heading</Heading1>
|
|
151
|
+
<Heading2>Section Heading</Heading2>
|
|
152
|
+
<Heading3>Subsection Heading</Heading3>
|
|
153
|
+
<Body>Body text content</Body>
|
|
154
|
+
<Caption>Small caption text</Caption>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
#### Props
|
|
158
|
+
|
|
159
|
+
| Component | Props | Description |
|
|
160
|
+
| ------------------------- | ---------------------------------------------------------------------- | ---------------------- |
|
|
161
|
+
| Typography | `variant: "h1" \| "h2" \| "h3" \| "h4" \| "h5" \| "body" \| "caption"` | Typography variant |
|
|
162
|
+
| Typography | `children: React.ReactNode` | Content to display |
|
|
163
|
+
| Typography | `className?: string` | Additional CSS classes |
|
|
164
|
+
| Heading1-3, Body, Caption | `children: React.ReactNode` | Content to display |
|
|
165
|
+
| Heading1-3, Body, Caption | `className?: string` | Additional CSS classes |
|
|
166
|
+
|
|
167
|
+
### LiftedButton
|
|
168
|
+
|
|
169
|
+
A unique button component with a "lifted" design that creates a 3D effect with a shadow layer. The button floats above a dark base and depresses when clicked.
|
|
170
|
+
|
|
171
|
+
#### Props
|
|
172
|
+
|
|
173
|
+
| Prop | Type | Default | Description |
|
|
174
|
+
| -------------- | ------------------------------------------------------------------- | --------- | ----------------------------------- |
|
|
175
|
+
| children | React.ReactNode | - | The content of the button |
|
|
176
|
+
| preset | 'primary' \| 'secondary' \| 'destructive' \| 'positive' \| 'stroke' | 'primary' | The preset style of the button |
|
|
177
|
+
| leftIcon | React.ReactNode | - | Icon to display on the left side |
|
|
178
|
+
| rightIcon | React.ReactNode | - | Icon to display on the right side |
|
|
179
|
+
| disabled | boolean | false | Whether the button is disabled |
|
|
180
|
+
| colorOverrides | Partial<LiftedButtonColors> | {} | Override specific colors |
|
|
181
|
+
| offsetPx | number | 4 | Pixel offset for the lifted effect |
|
|
182
|
+
| durationMs | number | 300 | Transition duration in milliseconds |
|
|
183
|
+
| width | 'full' \| 'auto' \| 'mobile-full' | 'auto' | Button width behavior |
|
|
184
|
+
| scrollTo | string | - | Element ID to scroll to on click |
|
|
185
|
+
| className | string | '' | Additional CSS classes |
|
|
186
|
+
| type | 'button' \| 'submit' \| 'reset' | 'button' | Button type |
|
|
187
|
+
| onClick | () => void | - | Click handler |
|
|
188
|
+
|
|
189
|
+
#### Presets
|
|
190
|
+
|
|
191
|
+
- **primary**: Orange background with white text
|
|
192
|
+
- **secondary**: Light orange background with orange text
|
|
193
|
+
- **destructive**: Red background with white text
|
|
194
|
+
- **positive**: Green background with white text
|
|
195
|
+
- **stroke**: White background with dark text and border
|
|
196
|
+
|
|
197
|
+
#### Examples
|
|
198
|
+
|
|
199
|
+
```tsx
|
|
200
|
+
import { LiftedButton } from "bread-ui-kit";
|
|
201
|
+
import { ArrowUpRight, SignOut } from "@phosphor-icons/react";
|
|
202
|
+
|
|
203
|
+
// Basic usage
|
|
204
|
+
<LiftedButton>Click me</LiftedButton>
|
|
205
|
+
|
|
206
|
+
// With presets
|
|
207
|
+
<LiftedButton preset="primary">Primary Button</LiftedButton>
|
|
208
|
+
<LiftedButton preset="secondary">Secondary Button</LiftedButton>
|
|
209
|
+
<LiftedButton preset="destructive">Delete</LiftedButton>
|
|
210
|
+
<LiftedButton preset="positive">Save</LiftedButton>
|
|
211
|
+
<LiftedButton preset="stroke">Cancel</LiftedButton>
|
|
212
|
+
|
|
213
|
+
// With icons
|
|
214
|
+
<LiftedButton leftIcon={<ArrowUpRight />}>External Link</LiftedButton>
|
|
215
|
+
<LiftedButton rightIcon={<SignOut />}>Sign Out</LiftedButton>
|
|
216
|
+
|
|
217
|
+
// Full width
|
|
218
|
+
<LiftedButton width="full">Full Width Button</LiftedButton>
|
|
219
|
+
|
|
220
|
+
// Mobile full width (full on mobile, auto on desktop)
|
|
221
|
+
<LiftedButton width="mobile-full">Responsive Button</LiftedButton>
|
|
222
|
+
|
|
223
|
+
// Custom offset and duration
|
|
224
|
+
<LiftedButton offsetPx={8} durationMs={500}>
|
|
225
|
+
Custom Animation
|
|
226
|
+
</LiftedButton>
|
|
227
|
+
|
|
228
|
+
// Scroll to element
|
|
229
|
+
<LiftedButton scrollTo="contact-section">
|
|
230
|
+
Contact Us
|
|
231
|
+
</LiftedButton>
|
|
232
|
+
|
|
233
|
+
// Disabled state
|
|
234
|
+
<LiftedButton disabled>Disabled Button</LiftedButton>
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Development
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
# Install dependencies
|
|
241
|
+
npm install
|
|
242
|
+
|
|
243
|
+
# Build the library
|
|
244
|
+
npm run build
|
|
245
|
+
|
|
246
|
+
# Run linting
|
|
247
|
+
npm run lint
|
|
248
|
+
|
|
249
|
+
# Run type checking
|
|
250
|
+
npm run type-check
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## License
|
|
254
|
+
|
|
255
|
+
MIT
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/* Bread Coop Fonts - Hosted by bread-ui-kit package */
|
|
2
|
+
|
|
3
|
+
@font-face {
|
|
4
|
+
font-family: "Bread Display";
|
|
5
|
+
src: url("./PogacaDisplayBlack.woff2") format("woff2");
|
|
6
|
+
font-weight: 900;
|
|
7
|
+
font-display: swap;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
@font-face {
|
|
11
|
+
font-family: "Bread Display";
|
|
12
|
+
src: url("./PogacaDisplayBold.woff2") format("woff2");
|
|
13
|
+
font-weight: 700;
|
|
14
|
+
font-display: swap;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@font-face {
|
|
18
|
+
font-family: "Bread Display";
|
|
19
|
+
src: url("./PogacaDisplayRegular.woff2") format("woff2");
|
|
20
|
+
font-weight: 400;
|
|
21
|
+
font-display: swap;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@font-face {
|
|
25
|
+
font-family: "Bread Body";
|
|
26
|
+
src: url("./PogacaBodyRegular.woff2") format("woff2");
|
|
27
|
+
font-weight: 400;
|
|
28
|
+
font-display: swap;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@font-face {
|
|
32
|
+
font-family: "Bread Body";
|
|
33
|
+
src: url("./PogacaBodyBold.woff2") format("woff2");
|
|
34
|
+
font-weight: 700;
|
|
35
|
+
font-display: swap;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* Set CSS variables for the fonts */
|
|
39
|
+
:root {
|
|
40
|
+
--font-breadDisplay: "Bread Display", ui-sans-serif, system-ui, sans-serif;
|
|
41
|
+
--font-breadBody: "Bread Body", ui-sans-serif, system-ui, sans-serif;
|
|
42
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
## Adding more fonts
|
|
2
|
+
|
|
3
|
+
The fonts themselves are defined in src/app/fonts.tsx. Once you've added a font there, you then need to add them to globals.css under the `@theme` defintion, and if you want nice combined classes, add those to `@layer components`.
|
|
4
|
+
|
|
5
|
+
## Compressing fonts
|
|
6
|
+
|
|
7
|
+
The raw fonts supplied by our designers are not in wott2 format (which is a compressed and web optimized format). I've manually compressed and converted the relevant font files. If you need to add any, or adjust the compression, here are the steps.
|
|
8
|
+
|
|
9
|
+
1. Install python's font tools with `pip install fonttools brotli zopfli`
|
|
10
|
+
2. Convert the font using the snippet below:
|
|
11
|
+
``` bash
|
|
12
|
+
pyftsubset src/fonts/raw/FAMILY/FONT.file \
|
|
13
|
+
--output-file=src/fonts/compressed/FONT-latinExt-puct-curr.woff2 \
|
|
14
|
+
--flavor=woff2 \
|
|
15
|
+
--unicodes="U+0020-007E, U+00A0-00FF, U+2000-206F, U+20A0-20CF" \
|
|
16
|
+
--layout-features='*' \
|
|
17
|
+
--no-hinting \
|
|
18
|
+
```
|
|
19
|
+
If you find you're missing charachters, you probably need to tweak the unicodes range. I am inluding Latin standard, the extension for normal accents, for extended punctuation, and for a full range of currencies. You can add individual carachters if you know the unicode.
|
|
20
|
+
3. Update the `src/app/fonts.tsx` font file definitions
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
type LiftedButtonColors = {
|
|
5
|
+
bg: string;
|
|
6
|
+
text: string;
|
|
7
|
+
hoverBg: string;
|
|
8
|
+
hoverText: string;
|
|
9
|
+
shadowBg: string;
|
|
10
|
+
};
|
|
11
|
+
type LiftedButtonPreset = keyof typeof LIFTED_BUTTON_PRESETS;
|
|
12
|
+
declare const LIFTED_BUTTON_PRESETS: {
|
|
13
|
+
primary: {
|
|
14
|
+
bg: string;
|
|
15
|
+
text: string;
|
|
16
|
+
hoverBg: string;
|
|
17
|
+
hoverText: string;
|
|
18
|
+
shadowBg: string;
|
|
19
|
+
};
|
|
20
|
+
secondary: {
|
|
21
|
+
bg: string;
|
|
22
|
+
text: string;
|
|
23
|
+
hoverBg: string;
|
|
24
|
+
hoverText: string;
|
|
25
|
+
shadowBg: string;
|
|
26
|
+
};
|
|
27
|
+
destructive: {
|
|
28
|
+
bg: string;
|
|
29
|
+
text: string;
|
|
30
|
+
hoverBg: string;
|
|
31
|
+
hoverText: string;
|
|
32
|
+
shadowBg: string;
|
|
33
|
+
};
|
|
34
|
+
positive: {
|
|
35
|
+
bg: string;
|
|
36
|
+
text: string;
|
|
37
|
+
hoverBg: string;
|
|
38
|
+
hoverText: string;
|
|
39
|
+
shadowBg: string;
|
|
40
|
+
};
|
|
41
|
+
stroke: {
|
|
42
|
+
bg: string;
|
|
43
|
+
text: string;
|
|
44
|
+
hoverBg: string;
|
|
45
|
+
hoverText: string;
|
|
46
|
+
shadowBg: string;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
type LiftedButtonProps = {
|
|
51
|
+
children: React.ReactNode;
|
|
52
|
+
leftIcon?: React.ReactNode;
|
|
53
|
+
rightIcon?: React.ReactNode;
|
|
54
|
+
disabled?: boolean;
|
|
55
|
+
preset?: LiftedButtonPreset;
|
|
56
|
+
colorOverrides?: Partial<LiftedButtonColors>;
|
|
57
|
+
offsetPx?: number;
|
|
58
|
+
durationMs?: number;
|
|
59
|
+
className?: string;
|
|
60
|
+
width?: "full" | "auto" | "mobile-full";
|
|
61
|
+
scrollTo?: string;
|
|
62
|
+
} & React.ComponentPropsWithoutRef<"button">;
|
|
63
|
+
/**
|
|
64
|
+
* LiftedButton — a square-edged button that floats up-left of a dark base layer.
|
|
65
|
+
* - Preset: Choose "primary" (default), "secondary", "destructive", or "positive"
|
|
66
|
+
* - ColorOverrides: Pass in a dict specifying manual colours
|
|
67
|
+
* - Hover: fades to alternate colors.
|
|
68
|
+
* - Active: depresses button and colors return to normal.
|
|
69
|
+
* - Transition duration defaults to 500ms.
|
|
70
|
+
* - Icons can be rendered on the right or left.
|
|
71
|
+
*/
|
|
72
|
+
declare function LiftedButton({ children, leftIcon, rightIcon, disabled, preset, colorOverrides, offsetPx, durationMs, className, type, width, scrollTo, ...rest }: LiftedButtonProps): react_jsx_runtime.JSX.Element;
|
|
73
|
+
|
|
74
|
+
declare const fontVariables: {
|
|
75
|
+
readonly breadDisplay: "--font-breadDisplay";
|
|
76
|
+
readonly breadBody: "--font-breadBody";
|
|
77
|
+
};
|
|
78
|
+
declare const Typography: React.FC<{
|
|
79
|
+
variant: "h1" | "h2" | "h3" | "h4" | "h5" | "body" | "caption";
|
|
80
|
+
children: React.ReactNode;
|
|
81
|
+
className?: string;
|
|
82
|
+
}>;
|
|
83
|
+
declare const Heading1: React.FC<{
|
|
84
|
+
children: React.ReactNode;
|
|
85
|
+
className?: string;
|
|
86
|
+
}>;
|
|
87
|
+
declare const Heading2: React.FC<{
|
|
88
|
+
children: React.ReactNode;
|
|
89
|
+
className?: string;
|
|
90
|
+
}>;
|
|
91
|
+
declare const Heading3: React.FC<{
|
|
92
|
+
children: React.ReactNode;
|
|
93
|
+
className?: string;
|
|
94
|
+
}>;
|
|
95
|
+
declare const Heading4: React.FC<{
|
|
96
|
+
children: React.ReactNode;
|
|
97
|
+
className?: string;
|
|
98
|
+
}>;
|
|
99
|
+
declare const Heading5: React.FC<{
|
|
100
|
+
children: React.ReactNode;
|
|
101
|
+
className?: string;
|
|
102
|
+
}>;
|
|
103
|
+
declare const Body: React.FC<{
|
|
104
|
+
children: React.ReactNode;
|
|
105
|
+
className?: string;
|
|
106
|
+
bold?: boolean;
|
|
107
|
+
}>;
|
|
108
|
+
declare const Caption: React.FC<{
|
|
109
|
+
children: React.ReactNode;
|
|
110
|
+
className?: string;
|
|
111
|
+
}>;
|
|
112
|
+
|
|
113
|
+
export { Body, Caption, Heading1, Heading2, Heading3, Heading4, Heading5, LiftedButton, type LiftedButtonProps, Typography, fontVariables };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
type LiftedButtonColors = {
|
|
5
|
+
bg: string;
|
|
6
|
+
text: string;
|
|
7
|
+
hoverBg: string;
|
|
8
|
+
hoverText: string;
|
|
9
|
+
shadowBg: string;
|
|
10
|
+
};
|
|
11
|
+
type LiftedButtonPreset = keyof typeof LIFTED_BUTTON_PRESETS;
|
|
12
|
+
declare const LIFTED_BUTTON_PRESETS: {
|
|
13
|
+
primary: {
|
|
14
|
+
bg: string;
|
|
15
|
+
text: string;
|
|
16
|
+
hoverBg: string;
|
|
17
|
+
hoverText: string;
|
|
18
|
+
shadowBg: string;
|
|
19
|
+
};
|
|
20
|
+
secondary: {
|
|
21
|
+
bg: string;
|
|
22
|
+
text: string;
|
|
23
|
+
hoverBg: string;
|
|
24
|
+
hoverText: string;
|
|
25
|
+
shadowBg: string;
|
|
26
|
+
};
|
|
27
|
+
destructive: {
|
|
28
|
+
bg: string;
|
|
29
|
+
text: string;
|
|
30
|
+
hoverBg: string;
|
|
31
|
+
hoverText: string;
|
|
32
|
+
shadowBg: string;
|
|
33
|
+
};
|
|
34
|
+
positive: {
|
|
35
|
+
bg: string;
|
|
36
|
+
text: string;
|
|
37
|
+
hoverBg: string;
|
|
38
|
+
hoverText: string;
|
|
39
|
+
shadowBg: string;
|
|
40
|
+
};
|
|
41
|
+
stroke: {
|
|
42
|
+
bg: string;
|
|
43
|
+
text: string;
|
|
44
|
+
hoverBg: string;
|
|
45
|
+
hoverText: string;
|
|
46
|
+
shadowBg: string;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
type LiftedButtonProps = {
|
|
51
|
+
children: React.ReactNode;
|
|
52
|
+
leftIcon?: React.ReactNode;
|
|
53
|
+
rightIcon?: React.ReactNode;
|
|
54
|
+
disabled?: boolean;
|
|
55
|
+
preset?: LiftedButtonPreset;
|
|
56
|
+
colorOverrides?: Partial<LiftedButtonColors>;
|
|
57
|
+
offsetPx?: number;
|
|
58
|
+
durationMs?: number;
|
|
59
|
+
className?: string;
|
|
60
|
+
width?: "full" | "auto" | "mobile-full";
|
|
61
|
+
scrollTo?: string;
|
|
62
|
+
} & React.ComponentPropsWithoutRef<"button">;
|
|
63
|
+
/**
|
|
64
|
+
* LiftedButton — a square-edged button that floats up-left of a dark base layer.
|
|
65
|
+
* - Preset: Choose "primary" (default), "secondary", "destructive", or "positive"
|
|
66
|
+
* - ColorOverrides: Pass in a dict specifying manual colours
|
|
67
|
+
* - Hover: fades to alternate colors.
|
|
68
|
+
* - Active: depresses button and colors return to normal.
|
|
69
|
+
* - Transition duration defaults to 500ms.
|
|
70
|
+
* - Icons can be rendered on the right or left.
|
|
71
|
+
*/
|
|
72
|
+
declare function LiftedButton({ children, leftIcon, rightIcon, disabled, preset, colorOverrides, offsetPx, durationMs, className, type, width, scrollTo, ...rest }: LiftedButtonProps): react_jsx_runtime.JSX.Element;
|
|
73
|
+
|
|
74
|
+
declare const fontVariables: {
|
|
75
|
+
readonly breadDisplay: "--font-breadDisplay";
|
|
76
|
+
readonly breadBody: "--font-breadBody";
|
|
77
|
+
};
|
|
78
|
+
declare const Typography: React.FC<{
|
|
79
|
+
variant: "h1" | "h2" | "h3" | "h4" | "h5" | "body" | "caption";
|
|
80
|
+
children: React.ReactNode;
|
|
81
|
+
className?: string;
|
|
82
|
+
}>;
|
|
83
|
+
declare const Heading1: React.FC<{
|
|
84
|
+
children: React.ReactNode;
|
|
85
|
+
className?: string;
|
|
86
|
+
}>;
|
|
87
|
+
declare const Heading2: React.FC<{
|
|
88
|
+
children: React.ReactNode;
|
|
89
|
+
className?: string;
|
|
90
|
+
}>;
|
|
91
|
+
declare const Heading3: React.FC<{
|
|
92
|
+
children: React.ReactNode;
|
|
93
|
+
className?: string;
|
|
94
|
+
}>;
|
|
95
|
+
declare const Heading4: React.FC<{
|
|
96
|
+
children: React.ReactNode;
|
|
97
|
+
className?: string;
|
|
98
|
+
}>;
|
|
99
|
+
declare const Heading5: React.FC<{
|
|
100
|
+
children: React.ReactNode;
|
|
101
|
+
className?: string;
|
|
102
|
+
}>;
|
|
103
|
+
declare const Body: React.FC<{
|
|
104
|
+
children: React.ReactNode;
|
|
105
|
+
className?: string;
|
|
106
|
+
bold?: boolean;
|
|
107
|
+
}>;
|
|
108
|
+
declare const Caption: React.FC<{
|
|
109
|
+
children: React.ReactNode;
|
|
110
|
+
className?: string;
|
|
111
|
+
}>;
|
|
112
|
+
|
|
113
|
+
export { Body, Caption, Heading1, Heading2, Heading3, Heading4, Heading5, LiftedButton, type LiftedButtonProps, Typography, fontVariables };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";function e(e,t,r){if(t in e){Object.defineProperty(e,t,{value:r,enumerable:true,configurable:true,writable:true})}else{e[t]=r}return e}function t(t){for(var r=1;r<arguments.length;r++){var n=arguments[r]!=null?arguments[r]:{};var o=Object.keys(n);if(typeof Object.getOwnPropertySymbols==="function"){o=o.concat(Object.getOwnPropertySymbols(n).filter(function(e){return Object.getOwnPropertyDescriptor(n,e).enumerable}))}o.forEach(function(r){e(t,r,n[r])})}return t}function r(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);if(t){n=n.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})}r.push.apply(r,n)}return r}function n(e,t){t=t!=null?t:{};if(Object.getOwnPropertyDescriptors){Object.defineProperties(e,Object.getOwnPropertyDescriptors(t))}else{r(Object(t)).forEach(function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))})}return e}function o(e,t){if(e==null)return{};var r=a(e,t);var n,o;if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o<i.length;o++){n=i[o];if(t.indexOf(n)>=0)continue;if(!Object.prototype.propertyIsEnumerable.call(e,n))continue;r[n]=e[n]}}return r}function a(e,t){if(e==null)return{};var r={};var n=Object.keys(e);var o,a;for(a=0;a<n.length;a++){o=n[a];if(t.indexOf(o)>=0)continue;r[o]=e[o]}return r}var i=require("react"),c=require("react/jsx-runtime");function l(e){return e&&e.__esModule?e:{default:e}}var s=l(i);var u={primary:{bg:"--color-primary-orange",text:"--color-paper-main",hoverBg:"--color-orange-1",hoverText:"#ffffff",shadowBg:"#595959"},secondary:{bg:"#FBDED1",text:"--color-primary-orange",hoverBg:"#FFF1EA",hoverText:"--color-primary-orange",shadowBg:"#595959"},destructive:{bg:"--color-system-red",text:"--color-paper-main",hoverBg:"#BF0A00",hoverText:"#ffffff",shadowBg:"#595959"},positive:{bg:"--color-system-green",text:"--color-paper-main",hoverBg:"#2B8F00",hoverText:"#ffffff",shadowBg:"#595959"},stroke:{bg:"--color-paper-main",text:"--color-surface-ink",hoverBg:"--color-paper-2",hoverText:"--color-surface-ink",shadowBg:"#595959"}};function d(e){return{"--btn-bg":f(e.bg),"--btn-text":f(e.text),"--btn-hover-bg":f(e.hoverBg),"--btn-hover-text":f(e.hoverText),"--btn-shadow":f(e.shadowBg)}}function f(e){return e?e.startsWith("--")?"var(".concat(e,")"):e:""}var v=function(e,t){if(s.default.isValidElement(e)){var r="".concat(e.props.className||""," ").concat(t).trim();return s.default.cloneElement(e,{className:r})}return e};function p(e){var r=e.children,a=e.leftIcon,i=e.rightIcon,l=e.disabled,s=l===void 0?false:l,f=e.preset,p=f===void 0?"primary":f,h=e.colorOverrides,b=h===void 0?{}:h,x=e.offsetPx,g=x===void 0?4:x,m=e.durationMs,y=m===void 0?300:m,j=e.className,O=j===void 0?"":j,w=e.type,N=w===void 0?"button":w,B=e.width,P=B===void 0?"auto":B,k=e.scrollTo,D=o(e,["children","leftIcon","rightIcon","disabled","preset","colorOverrides","offsetPx","durationMs","className","type","width","scrollTo"]);var E=t({},u[p],b),T=n(t({},d(E)),{"--btn-offset":"".concat(g,"px"),"--btn-duration":"".concat(y,"ms")}),I=["relative z-10 inline-flex items-center justify-center gap-[8px]","text-body text-[16px]","px-[32px] h-14",s?"cursor-not-allowed":"cursor-pointer",P==="full"?"w-full":"",P==="mobile-full"?"w-full xl:w-auto":""],F=["bg-[var(--btn-bg)] text-[var(--btn-text)]","group-hover:bg-[var(--btn-hover-bg)] group-hover:text-[var(--btn-hover-text)]","group-active:bg-[var(--btn-bg)] group-active:text-[var(--btn-text)]","transition-all duration-[var(--btn-duration)] ease-out","-translate-x-[var(--btn-offset)] -translate-y-[var(--btn-offset)]","group-active:translate-x-0 group-active:translate-y-0"],S=["bg-[var(--color-surface-grey)] opacity-50"],H=I.concat(s?S:F);H.push(O);var C=function(e){var t;k&&(e.preventDefault(),(t=document.getElementById(k))===null||t===void 0?void 0:t.scrollIntoView({behavior:"smooth"})),D.onClick&&D.onClick(e)};return c.jsxs("span",{className:[P==="full"?"relative block select-none align-middle":P==="mobile-full"?"relative block md:inline-block select-none align-middle":"relative inline-block select-none align-middle","group"].join(" "),style:T,children:[s?null:c.jsx("span",{"aria-hidden":true,className:"absolute inset-0 bg-[var(--btn-shadow)]"}),c.jsxs("button",n(t({type:N,className:H.join(" "),onClick:C},D),{children:[a?c.jsx("span",{className:"shrink-0 py-[5px] flex items-center justify-center","aria-hidden":true,children:v(a,"w-6 h-6")}):null,c.jsx("span",{className:"whitespace-nowrap mt-1 leading-none p-[5px]",children:r}),i?c.jsx("span",{className:"shrink-0 py-[5px] flex items-center justify-center","aria-hidden":true,children:v(i,"w-6 h-6")}):null]}))]})}var h={breadDisplay:"--font-breadDisplay",breadBody:"--font-breadBody"},b=function(e){var t=e.variant,r=e.children,n=e.className,o=n===void 0?"":n;var a=["h1","h2","h3"].includes(t)?"font-breadDisplay":"font-breadBody",i={h1:"text-h1",h2:"text-h2",h3:"text-h3",h4:"text-h4",h5:"text-h5",body:"text-body",caption:"text-caption"},c=t.startsWith("h")?t:"p";return s.default.createElement(c,{className:"".concat(a," ").concat(i[t]," ").concat(o).trim()},r)},x=function(e){var t=e.children,r=e.className,n=r===void 0?"":r;return c.jsx(b,{variant:"h1",className:n,children:t})},g=function(e){var t=e.children,r=e.className,n=r===void 0?"":r;return c.jsx(b,{variant:"h2",className:n,children:t})},m=function(e){var t=e.children,r=e.className,n=r===void 0?"":r;return c.jsx(b,{variant:"h3",className:n,children:t})},y=function(e){var t=e.children,r=e.className,n=r===void 0?"":r;return c.jsx(b,{variant:"h4",className:n,children:t})},j=function(e){var t=e.children,r=e.className,n=r===void 0?"":r;return c.jsx(b,{variant:"h5",className:n,children:t})},O=function(e){var t=e.children,r=e.className,n=r===void 0?"":r,o=e.bold,a=o===void 0?false:o;return c.jsx(b,{variant:"body",className:"".concat(a?"text-body-bold":""," ").concat(n).trim(),children:t})},w=function(e){var t=e.children,r=e.className,n=r===void 0?"":r;return c.jsx(b,{variant:"caption",className:n,children:t})};exports.Body=O;exports.Caption=w;exports.Heading1=x;exports.Heading2=g;exports.Heading3=m;exports.Heading4=y;exports.Heading5=j;exports.LiftedButton=p;exports.Typography=b;exports.fontVariables=h;
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(e,t,r){if(t in e){Object.defineProperty(e,t,{value:r,enumerable:true,configurable:true,writable:true})}else{e[t]=r}return e}function t(t){for(var r=1;r<arguments.length;r++){var n=arguments[r]!=null?arguments[r]:{};var a=Object.keys(n);if(typeof Object.getOwnPropertySymbols==="function"){a=a.concat(Object.getOwnPropertySymbols(n).filter(function(e){return Object.getOwnPropertyDescriptor(n,e).enumerable}))}a.forEach(function(r){e(t,r,n[r])})}return t}function r(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);if(t){n=n.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})}r.push.apply(r,n)}return r}function n(e,t){t=t!=null?t:{};if(Object.getOwnPropertyDescriptors){Object.defineProperties(e,Object.getOwnPropertyDescriptors(t))}else{r(Object(t)).forEach(function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))})}return e}function a(e,t){if(e==null)return{};var r=o(e,t);var n,a;if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++){n=i[a];if(t.indexOf(n)>=0)continue;if(!Object.prototype.propertyIsEnumerable.call(e,n))continue;r[n]=e[n]}}return r}function o(e,t){if(e==null)return{};var r={};var n=Object.keys(e);var a,o;for(o=0;o<n.length;o++){a=n[o];if(t.indexOf(a)>=0)continue;r[a]=e[a]}return r}import i from"react";import{jsx as c,jsxs as l}from"react/jsx-runtime";var s={primary:{bg:"--color-primary-orange",text:"--color-paper-main",hoverBg:"--color-orange-1",hoverText:"#ffffff",shadowBg:"#595959"},secondary:{bg:"#FBDED1",text:"--color-primary-orange",hoverBg:"#FFF1EA",hoverText:"--color-primary-orange",shadowBg:"#595959"},destructive:{bg:"--color-system-red",text:"--color-paper-main",hoverBg:"#BF0A00",hoverText:"#ffffff",shadowBg:"#595959"},positive:{bg:"--color-system-green",text:"--color-paper-main",hoverBg:"#2B8F00",hoverText:"#ffffff",shadowBg:"#595959"},stroke:{bg:"--color-paper-main",text:"--color-surface-ink",hoverBg:"--color-paper-2",hoverText:"--color-surface-ink",shadowBg:"#595959"}};function d(e){return{"--btn-bg":u(e.bg),"--btn-text":u(e.text),"--btn-hover-bg":u(e.hoverBg),"--btn-hover-text":u(e.hoverText),"--btn-shadow":u(e.shadowBg)}}function u(e){return e?e.startsWith("--")?"var(".concat(e,")"):e:""}var f=function(e,t){if(i.isValidElement(e)){var r="".concat(e.props.className||""," ").concat(t).trim();return i.cloneElement(e,{className:r})}return e};function v(e){var r=e.children,o=e.leftIcon,i=e.rightIcon,u=e.disabled,v=u===void 0?false:u,p=e.preset,h=p===void 0?"primary":p,b=e.colorOverrides,m=b===void 0?{}:b,g=e.offsetPx,y=g===void 0?4:g,x=e.durationMs,O=x===void 0?300:x,w=e.className,N=w===void 0?"":w,j=e.type,B=j===void 0?"button":j,P=e.width,k=P===void 0?"auto":P,D=e.scrollTo,E=a(e,["children","leftIcon","rightIcon","disabled","preset","colorOverrides","offsetPx","durationMs","className","type","width","scrollTo"]);var T=t({},s[h],m),I=n(t({},d(T)),{"--btn-offset":"".concat(y,"px"),"--btn-duration":"".concat(O,"ms")}),S=["relative z-10 inline-flex items-center justify-center gap-[8px]","text-body text-[16px]","px-[32px] h-14",v?"cursor-not-allowed":"cursor-pointer",k==="full"?"w-full":"",k==="mobile-full"?"w-full xl:w-auto":""],F=["bg-[var(--btn-bg)] text-[var(--btn-text)]","group-hover:bg-[var(--btn-hover-bg)] group-hover:text-[var(--btn-hover-text)]","group-active:bg-[var(--btn-bg)] group-active:text-[var(--btn-text)]","transition-all duration-[var(--btn-duration)] ease-out","-translate-x-[var(--btn-offset)] -translate-y-[var(--btn-offset)]","group-active:translate-x-0 group-active:translate-y-0"],H=["bg-[var(--color-surface-grey)] opacity-50"],C=S.concat(v?H:F);C.push(N);var V=function(e){var t;D&&(e.preventDefault(),(t=document.getElementById(D))===null||t===void 0?void 0:t.scrollIntoView({behavior:"smooth"})),E.onClick&&E.onClick(e)};return l("span",{className:[k==="full"?"relative block select-none align-middle":k==="mobile-full"?"relative block md:inline-block select-none align-middle":"relative inline-block select-none align-middle","group"].join(" "),style:I,children:[v?null:c("span",{"aria-hidden":true,className:"absolute inset-0 bg-[var(--btn-shadow)]"}),l("button",n(t({type:B,className:C.join(" "),onClick:V},E),{children:[o?c("span",{className:"shrink-0 py-[5px] flex items-center justify-center","aria-hidden":true,children:f(o,"w-6 h-6")}):null,c("span",{className:"whitespace-nowrap mt-1 leading-none p-[5px]",children:r}),i?c("span",{className:"shrink-0 py-[5px] flex items-center justify-center","aria-hidden":true,children:f(i,"w-6 h-6")}):null]}))]})}var p={breadDisplay:"--font-breadDisplay",breadBody:"--font-breadBody"},h=function(e){var t=e.variant,r=e.children,n=e.className,a=n===void 0?"":n;var o=["h1","h2","h3"].includes(t)?"font-breadDisplay":"font-breadBody",c={h1:"text-h1",h2:"text-h2",h3:"text-h3",h4:"text-h4",h5:"text-h5",body:"text-body",caption:"text-caption"},l=t.startsWith("h")?t:"p";return i.createElement(l,{className:"".concat(o," ").concat(c[t]," ").concat(a).trim()},r)},b=function(e){var t=e.children,r=e.className,n=r===void 0?"":r;return c(h,{variant:"h1",className:n,children:t})},m=function(e){var t=e.children,r=e.className,n=r===void 0?"":r;return c(h,{variant:"h2",className:n,children:t})},g=function(e){var t=e.children,r=e.className,n=r===void 0?"":r;return c(h,{variant:"h3",className:n,children:t})},y=function(e){var t=e.children,r=e.className,n=r===void 0?"":r;return c(h,{variant:"h4",className:n,children:t})},x=function(e){var t=e.children,r=e.className,n=r===void 0?"":r;return c(h,{variant:"h5",className:n,children:t})},O=function(e){var t=e.children,r=e.className,n=r===void 0?"":r,a=e.bold,o=a===void 0?false:a;return c(h,{variant:"body",className:"".concat(o?"text-body-bold":""," ").concat(n).trim(),children:t})},w=function(e){var t=e.children,r=e.className,n=r===void 0?"":r;return c(h,{variant:"caption",className:n,children:t})};export{O as Body,w as Caption,b as Heading1,m as Heading2,g as Heading3,y as Heading4,x as Heading5,v as LiftedButton,h as Typography,p as fontVariables};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/** @type {import('tailwindcss').Config} */
|
|
2
|
+
module.exports = {
|
|
3
|
+
theme: {
|
|
4
|
+
extend: {
|
|
5
|
+
colors: {
|
|
6
|
+
// Bread Coop brand colors
|
|
7
|
+
"primary-orange": "#ea6023",
|
|
8
|
+
"orange-0": "#ffc080",
|
|
9
|
+
"orange-1": "#d14a0f",
|
|
10
|
+
"orange-2": "#b83c08",
|
|
11
|
+
"primary-jade": "#286b63",
|
|
12
|
+
"jade-0": "#9cacc6",
|
|
13
|
+
"jade-1": "#72849d",
|
|
14
|
+
"jade-2": "#134a44",
|
|
15
|
+
"primary-blue": "#1c5bb9",
|
|
16
|
+
"blue-0": "#a8c3ea",
|
|
17
|
+
"blue-1": "#588ddb",
|
|
18
|
+
"blue-2": "#1b4a90",
|
|
19
|
+
"paper-main": "#f6f3eb",
|
|
20
|
+
"paper-0": "#fdfcf9",
|
|
21
|
+
"paper-1": "#f0ebe0",
|
|
22
|
+
"paper-2": "#eae2d6",
|
|
23
|
+
"surface-ink": "#1b201a",
|
|
24
|
+
"surface-grey": "#808080",
|
|
25
|
+
"surface-grey-2": "#595959",
|
|
26
|
+
"surface-brown": "#513c35",
|
|
27
|
+
"surface-brown-1": "#301f18",
|
|
28
|
+
"system-green": "#32a800",
|
|
29
|
+
"system-red": "#df0b00",
|
|
30
|
+
"system-warning": "#ce7f00",
|
|
31
|
+
"text-standard": "#171414",
|
|
32
|
+
},
|
|
33
|
+
fontFamily: {
|
|
34
|
+
breadDisplay: [
|
|
35
|
+
"var(--font-breadDisplay)",
|
|
36
|
+
"ui-sans-serif",
|
|
37
|
+
"system-ui",
|
|
38
|
+
"sans-serif",
|
|
39
|
+
],
|
|
40
|
+
breadBody: [
|
|
41
|
+
"var(--font-breadBody)",
|
|
42
|
+
"ui-sans-serif",
|
|
43
|
+
"system-ui",
|
|
44
|
+
"sans-serif",
|
|
45
|
+
],
|
|
46
|
+
roboto: ["var(--font-roboto)", "ui-monospace", "monospace"],
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
plugins: [],
|
|
51
|
+
};
|
package/dist/theme.css
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
|
|
3
|
+
/* Bread Coop Fonts - Hosted by bread-ui-kit package */
|
|
4
|
+
@font-face {
|
|
5
|
+
font-family: "Bread Display";
|
|
6
|
+
src: url("./fonts/PogacaDisplayBlack.woff2") format("woff2");
|
|
7
|
+
font-weight: 900;
|
|
8
|
+
font-display: swap;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
@font-face {
|
|
12
|
+
font-family: "Bread Display";
|
|
13
|
+
src: url("./fonts/PogacaDisplayBold.woff2") format("woff2");
|
|
14
|
+
font-weight: 700;
|
|
15
|
+
font-display: swap;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@font-face {
|
|
19
|
+
font-family: "Bread Display";
|
|
20
|
+
src: url("./fonts/PogacaDisplayRegular.woff2") format("woff2");
|
|
21
|
+
font-weight: 400;
|
|
22
|
+
font-display: swap;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@font-face {
|
|
26
|
+
font-family: "Bread Body";
|
|
27
|
+
src: url("./fonts/PogacaBodyRegular.woff2") format("woff2");
|
|
28
|
+
font-weight: 400;
|
|
29
|
+
font-display: swap;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@font-face {
|
|
33
|
+
font-family: "Bread Body";
|
|
34
|
+
src: url("./fonts/PogacaBodyBold.woff2") format("woff2");
|
|
35
|
+
font-weight: 700;
|
|
36
|
+
font-display: swap;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
:root {
|
|
40
|
+
--background: #ffffff;
|
|
41
|
+
--foreground: #171717;
|
|
42
|
+
--font-breadDisplay: "Bread Display", ui-sans-serif, system-ui, sans-serif;
|
|
43
|
+
--font-breadBody: "Bread Body", ui-sans-serif, system-ui, sans-serif;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@theme {
|
|
47
|
+
--color-background: var(--background);
|
|
48
|
+
--color-foreground: var(--foreground);
|
|
49
|
+
--font-breadDisplay: var(--font-breadDisplay), ui-sans-serif, system-ui,
|
|
50
|
+
sans-serif;
|
|
51
|
+
--font-breadBody: var(--font-breadBody), ui-sans-serif, system-ui, sans-serif;
|
|
52
|
+
--font-mono: var(--font-roboto);
|
|
53
|
+
|
|
54
|
+
/* Custom Colors */
|
|
55
|
+
--color-primary-orange: #ea6023;
|
|
56
|
+
--color-orange-0: #ffc080;
|
|
57
|
+
--color-orange-1: #d14a0f;
|
|
58
|
+
--color-orange-2: #b83c08;
|
|
59
|
+
--color-primary-jade: #286b63;
|
|
60
|
+
--color-jade-0: #9cacc6;
|
|
61
|
+
--color-jade-1: #72849d;
|
|
62
|
+
--color-jade-2: #134a44;
|
|
63
|
+
--color-primary-blue: #1c5bb9;
|
|
64
|
+
--color-blue-0: #a8c3ea;
|
|
65
|
+
--color-blue-1: #588ddb;
|
|
66
|
+
--color-blue-2: #1b4a90;
|
|
67
|
+
--color-paper-main: #f6f3eb;
|
|
68
|
+
--color-paper-0: #fdfcf9;
|
|
69
|
+
--color-paper-1: #f0ebe0;
|
|
70
|
+
--color-paper-2: #eae2d6;
|
|
71
|
+
--color-surface-ink: #1b201a;
|
|
72
|
+
--color-surface-grey: #808080;
|
|
73
|
+
--color-surface-grey-2: #595959;
|
|
74
|
+
--color-surface-brown: #513c35;
|
|
75
|
+
--color-surface-brown-1: #301f18;
|
|
76
|
+
--color-system-green: #32a800;
|
|
77
|
+
--color-system-red: #df0b00;
|
|
78
|
+
--color-system-warning: #ce7f00;
|
|
79
|
+
--color-text-standard: #171414;
|
|
80
|
+
|
|
81
|
+
/* Custom Fonts */
|
|
82
|
+
--font-roboto: var(--font-roboto);
|
|
83
|
+
--font-breadDisplay: var(--font-breadDisplay);
|
|
84
|
+
--font-breadBody: var(--font-breadBody);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@media (prefers-color-scheme: dark) {
|
|
88
|
+
:root {
|
|
89
|
+
--background: #0a0a0a;
|
|
90
|
+
--foreground: #ededed;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@layer components {
|
|
95
|
+
.text-h1 {
|
|
96
|
+
@apply font-breadDisplay font-[900] text-[3rem] leading-[36px] md:text-[96px] md:leading-[76px] xl:text-[7rem] xl:leading-[83px] tracking-tight uppercase;
|
|
97
|
+
}
|
|
98
|
+
.text-h2 {
|
|
99
|
+
@apply font-breadDisplay font-[900] text-[1.5rem] leading-[20px] md:text-[2.5rem] md:leading-[36px] xl:text-[3rem] xl:leading-[48px] tracking-tight;
|
|
100
|
+
}
|
|
101
|
+
.text-h3 {
|
|
102
|
+
@apply font-breadDisplay font-[900] text-[3rem] xl:text-[80px] leading-[36px] xl:leading-[63px] tracking-tighter;
|
|
103
|
+
}
|
|
104
|
+
.text-h4 {
|
|
105
|
+
@apply font-breadBody font-[700] text-[24px] xl:text-[2rem] leading-[24px] xl:leading-[2rem];
|
|
106
|
+
}
|
|
107
|
+
.text-h5 {
|
|
108
|
+
@apply font-breadBody font-[400] text-[1rem] xl:text-[1.5rem] xl:leading-[24px];
|
|
109
|
+
}
|
|
110
|
+
.text-body {
|
|
111
|
+
@apply font-breadBody text-base;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.text-breadDisplay-bold {
|
|
115
|
+
@apply font-breadDisplay font-[700] text-base;
|
|
116
|
+
}
|
|
117
|
+
.text-breadDisplay {
|
|
118
|
+
@apply font-breadDisplay font-[500] text-base;
|
|
119
|
+
}
|
|
120
|
+
.text-body-bold {
|
|
121
|
+
@apply font-breadBody text-base font-[700];
|
|
122
|
+
}
|
|
123
|
+
.text-caption {
|
|
124
|
+
@apply font-breadBody text-[0.7rem];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* Button Components */
|
|
128
|
+
.bread-button {
|
|
129
|
+
@apply font-medium rounded-md transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.bread-button-primary {
|
|
133
|
+
@apply bg-primary-orange text-white hover:bg-orange-1 focus:ring-primary-orange;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.bread-button-secondary {
|
|
137
|
+
@apply bg-primary-jade text-white hover:bg-jade-2 focus:ring-primary-jade;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.bread-button-outline {
|
|
141
|
+
@apply border-2 border-primary-orange text-primary-orange hover:bg-orange-0 focus:ring-primary-orange;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.bread-button-small {
|
|
145
|
+
@apply px-3 py-1.5 text-sm;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.bread-button-medium {
|
|
149
|
+
@apply px-4 py-2 text-base;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.bread-button-large {
|
|
153
|
+
@apply px-6 py-3 text-lg;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.bread-button-disabled {
|
|
157
|
+
@apply opacity-50 cursor-not-allowed;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.bread-button-enabled {
|
|
161
|
+
@apply cursor-pointer;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
body {
|
|
166
|
+
background: var(--background);
|
|
167
|
+
color: var(--foreground);
|
|
168
|
+
font-family: var(--font-inter), Arial, Helvetica, sans-serif;
|
|
169
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@breadcoop/ui",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A component library for implementing Bread Coop branding in JS/TS projects",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"style": "dist/index.css",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.mjs",
|
|
13
|
+
"require": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./style": "./dist/index.css",
|
|
16
|
+
"./tailwind-preset": "./tailwind-preset.js",
|
|
17
|
+
"./theme": "./theme.css",
|
|
18
|
+
"./package.json": "./package.json"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"tailwind-preset.js",
|
|
23
|
+
"theme.css",
|
|
24
|
+
"fonts"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsup && npm run copy-files",
|
|
28
|
+
"build:all": "npm run build && npm run build-storybook",
|
|
29
|
+
"copy-files": "cp tailwind-preset.js dist/ && cp theme.css dist/ && cp -r src/fonts dist/",
|
|
30
|
+
"dev": "tsup --watch",
|
|
31
|
+
"storybook": "storybook dev -p 6006",
|
|
32
|
+
"build-storybook": "storybook build",
|
|
33
|
+
"test": "jest",
|
|
34
|
+
"lint": "eslint src --ext .ts,.tsx",
|
|
35
|
+
"lint:fix": "eslint src --ext .ts,.tsx --fix",
|
|
36
|
+
"type-check": "tsc --noEmit",
|
|
37
|
+
"prepublishOnly": "npm run build"
|
|
38
|
+
},
|
|
39
|
+
"keywords": [
|
|
40
|
+
"react",
|
|
41
|
+
"typescript",
|
|
42
|
+
"ui",
|
|
43
|
+
"components",
|
|
44
|
+
"bread",
|
|
45
|
+
"coop"
|
|
46
|
+
],
|
|
47
|
+
"author": "Bread Coop",
|
|
48
|
+
"license": "P2P",
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"react": ">=16.8.0",
|
|
51
|
+
"react-dom": ">=16.8.0"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@phosphor-icons/react": "^2.1.1",
|
|
55
|
+
"@storybook/addon-docs": "^9.1.8",
|
|
56
|
+
"@storybook/addon-webpack5-compiler-swc": "^4.0.1",
|
|
57
|
+
"@storybook/react-vite": "^9.1.8",
|
|
58
|
+
"@storybook/react-webpack5": "^9.1.8",
|
|
59
|
+
"@swc/core": "^1.3.100",
|
|
60
|
+
"@tailwindcss/postcss": "^4.1.13",
|
|
61
|
+
"@types/react": "^18.2.45",
|
|
62
|
+
"@types/react-dom": "^18.2.18",
|
|
63
|
+
"@typescript-eslint/eslint-plugin": "^6.15.0",
|
|
64
|
+
"@typescript-eslint/parser": "^6.15.0",
|
|
65
|
+
"autoprefixer": "^10.4.21",
|
|
66
|
+
"eslint": "^8.56.0",
|
|
67
|
+
"eslint-plugin-react": "^7.33.2",
|
|
68
|
+
"eslint-plugin-react-hooks": "^4.6.0",
|
|
69
|
+
"eslint-plugin-storybook": "^9.1.8",
|
|
70
|
+
"postcss": "^8.5.6",
|
|
71
|
+
"postcss-loader": "^8.2.0",
|
|
72
|
+
"storybook": "^9.1.8",
|
|
73
|
+
"tailwindcss": "^4.1.13",
|
|
74
|
+
"tsup": "^8.0.1",
|
|
75
|
+
"typescript": "^5.3.3"
|
|
76
|
+
},
|
|
77
|
+
"repository": {
|
|
78
|
+
"type": "git",
|
|
79
|
+
"url": "https://github.com/bread-coop/bread-ui-kit.git"
|
|
80
|
+
},
|
|
81
|
+
"bugs": {
|
|
82
|
+
"url": "https://github.com/bread-coop/bread-ui-kit/issues"
|
|
83
|
+
},
|
|
84
|
+
"homepage": "https://github.com/bread-coop/bread-ui-kit#readme"
|
|
85
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/** @type {import('tailwindcss').Config} */
|
|
2
|
+
module.exports = {
|
|
3
|
+
theme: {
|
|
4
|
+
extend: {
|
|
5
|
+
colors: {
|
|
6
|
+
// Bread Coop brand colors
|
|
7
|
+
"primary-orange": "#ea6023",
|
|
8
|
+
"orange-0": "#ffc080",
|
|
9
|
+
"orange-1": "#d14a0f",
|
|
10
|
+
"orange-2": "#b83c08",
|
|
11
|
+
"primary-jade": "#286b63",
|
|
12
|
+
"jade-0": "#9cacc6",
|
|
13
|
+
"jade-1": "#72849d",
|
|
14
|
+
"jade-2": "#134a44",
|
|
15
|
+
"primary-blue": "#1c5bb9",
|
|
16
|
+
"blue-0": "#a8c3ea",
|
|
17
|
+
"blue-1": "#588ddb",
|
|
18
|
+
"blue-2": "#1b4a90",
|
|
19
|
+
"paper-main": "#f6f3eb",
|
|
20
|
+
"paper-0": "#fdfcf9",
|
|
21
|
+
"paper-1": "#f0ebe0",
|
|
22
|
+
"paper-2": "#eae2d6",
|
|
23
|
+
"surface-ink": "#1b201a",
|
|
24
|
+
"surface-grey": "#808080",
|
|
25
|
+
"surface-grey-2": "#595959",
|
|
26
|
+
"surface-brown": "#513c35",
|
|
27
|
+
"surface-brown-1": "#301f18",
|
|
28
|
+
"system-green": "#32a800",
|
|
29
|
+
"system-red": "#df0b00",
|
|
30
|
+
"system-warning": "#ce7f00",
|
|
31
|
+
"text-standard": "#171414",
|
|
32
|
+
},
|
|
33
|
+
fontFamily: {
|
|
34
|
+
breadDisplay: [
|
|
35
|
+
"var(--font-breadDisplay)",
|
|
36
|
+
"ui-sans-serif",
|
|
37
|
+
"system-ui",
|
|
38
|
+
"sans-serif",
|
|
39
|
+
],
|
|
40
|
+
breadBody: [
|
|
41
|
+
"var(--font-breadBody)",
|
|
42
|
+
"ui-sans-serif",
|
|
43
|
+
"system-ui",
|
|
44
|
+
"sans-serif",
|
|
45
|
+
],
|
|
46
|
+
roboto: ["var(--font-roboto)", "ui-monospace", "monospace"],
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
plugins: [],
|
|
51
|
+
};
|
package/theme.css
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
|
|
3
|
+
/* Bread Coop Fonts - Hosted by bread-ui-kit package */
|
|
4
|
+
@font-face {
|
|
5
|
+
font-family: "Bread Display";
|
|
6
|
+
src: url("./fonts/PogacaDisplayBlack.woff2") format("woff2");
|
|
7
|
+
font-weight: 900;
|
|
8
|
+
font-display: swap;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
@font-face {
|
|
12
|
+
font-family: "Bread Display";
|
|
13
|
+
src: url("./fonts/PogacaDisplayBold.woff2") format("woff2");
|
|
14
|
+
font-weight: 700;
|
|
15
|
+
font-display: swap;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@font-face {
|
|
19
|
+
font-family: "Bread Display";
|
|
20
|
+
src: url("./fonts/PogacaDisplayRegular.woff2") format("woff2");
|
|
21
|
+
font-weight: 400;
|
|
22
|
+
font-display: swap;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@font-face {
|
|
26
|
+
font-family: "Bread Body";
|
|
27
|
+
src: url("./fonts/PogacaBodyRegular.woff2") format("woff2");
|
|
28
|
+
font-weight: 400;
|
|
29
|
+
font-display: swap;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@font-face {
|
|
33
|
+
font-family: "Bread Body";
|
|
34
|
+
src: url("./fonts/PogacaBodyBold.woff2") format("woff2");
|
|
35
|
+
font-weight: 700;
|
|
36
|
+
font-display: swap;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
:root {
|
|
40
|
+
--background: #ffffff;
|
|
41
|
+
--foreground: #171717;
|
|
42
|
+
--font-breadDisplay: "Bread Display", ui-sans-serif, system-ui, sans-serif;
|
|
43
|
+
--font-breadBody: "Bread Body", ui-sans-serif, system-ui, sans-serif;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@theme {
|
|
47
|
+
--color-background: var(--background);
|
|
48
|
+
--color-foreground: var(--foreground);
|
|
49
|
+
--font-breadDisplay: var(--font-breadDisplay), ui-sans-serif, system-ui,
|
|
50
|
+
sans-serif;
|
|
51
|
+
--font-breadBody: var(--font-breadBody), ui-sans-serif, system-ui, sans-serif;
|
|
52
|
+
--font-mono: var(--font-roboto);
|
|
53
|
+
|
|
54
|
+
/* Custom Colors */
|
|
55
|
+
--color-primary-orange: #ea6023;
|
|
56
|
+
--color-orange-0: #ffc080;
|
|
57
|
+
--color-orange-1: #d14a0f;
|
|
58
|
+
--color-orange-2: #b83c08;
|
|
59
|
+
--color-primary-jade: #286b63;
|
|
60
|
+
--color-jade-0: #9cacc6;
|
|
61
|
+
--color-jade-1: #72849d;
|
|
62
|
+
--color-jade-2: #134a44;
|
|
63
|
+
--color-primary-blue: #1c5bb9;
|
|
64
|
+
--color-blue-0: #a8c3ea;
|
|
65
|
+
--color-blue-1: #588ddb;
|
|
66
|
+
--color-blue-2: #1b4a90;
|
|
67
|
+
--color-paper-main: #f6f3eb;
|
|
68
|
+
--color-paper-0: #fdfcf9;
|
|
69
|
+
--color-paper-1: #f0ebe0;
|
|
70
|
+
--color-paper-2: #eae2d6;
|
|
71
|
+
--color-surface-ink: #1b201a;
|
|
72
|
+
--color-surface-grey: #808080;
|
|
73
|
+
--color-surface-grey-2: #595959;
|
|
74
|
+
--color-surface-brown: #513c35;
|
|
75
|
+
--color-surface-brown-1: #301f18;
|
|
76
|
+
--color-system-green: #32a800;
|
|
77
|
+
--color-system-red: #df0b00;
|
|
78
|
+
--color-system-warning: #ce7f00;
|
|
79
|
+
--color-text-standard: #171414;
|
|
80
|
+
|
|
81
|
+
/* Custom Fonts */
|
|
82
|
+
--font-roboto: var(--font-roboto);
|
|
83
|
+
--font-breadDisplay: var(--font-breadDisplay);
|
|
84
|
+
--font-breadBody: var(--font-breadBody);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@media (prefers-color-scheme: dark) {
|
|
88
|
+
:root {
|
|
89
|
+
--background: #0a0a0a;
|
|
90
|
+
--foreground: #ededed;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@layer components {
|
|
95
|
+
.text-h1 {
|
|
96
|
+
@apply font-breadDisplay font-[900] text-[3rem] leading-[36px] md:text-[96px] md:leading-[76px] xl:text-[7rem] xl:leading-[83px] tracking-tight uppercase;
|
|
97
|
+
}
|
|
98
|
+
.text-h2 {
|
|
99
|
+
@apply font-breadDisplay font-[900] text-[1.5rem] leading-[20px] md:text-[2.5rem] md:leading-[36px] xl:text-[3rem] xl:leading-[48px] tracking-tight;
|
|
100
|
+
}
|
|
101
|
+
.text-h3 {
|
|
102
|
+
@apply font-breadDisplay font-[900] text-[3rem] xl:text-[80px] leading-[36px] xl:leading-[63px] tracking-tighter;
|
|
103
|
+
}
|
|
104
|
+
.text-h4 {
|
|
105
|
+
@apply font-breadBody font-[700] text-[24px] xl:text-[2rem] leading-[24px] xl:leading-[2rem];
|
|
106
|
+
}
|
|
107
|
+
.text-h5 {
|
|
108
|
+
@apply font-breadBody font-[400] text-[1rem] xl:text-[1.5rem] xl:leading-[24px];
|
|
109
|
+
}
|
|
110
|
+
.text-body {
|
|
111
|
+
@apply font-breadBody text-base;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.text-breadDisplay-bold {
|
|
115
|
+
@apply font-breadDisplay font-[700] text-base;
|
|
116
|
+
}
|
|
117
|
+
.text-breadDisplay {
|
|
118
|
+
@apply font-breadDisplay font-[500] text-base;
|
|
119
|
+
}
|
|
120
|
+
.text-body-bold {
|
|
121
|
+
@apply font-breadBody text-base font-[700];
|
|
122
|
+
}
|
|
123
|
+
.text-caption {
|
|
124
|
+
@apply font-breadBody text-[0.7rem];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* Button Components */
|
|
128
|
+
.bread-button {
|
|
129
|
+
@apply font-medium rounded-md transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.bread-button-primary {
|
|
133
|
+
@apply bg-primary-orange text-white hover:bg-orange-1 focus:ring-primary-orange;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.bread-button-secondary {
|
|
137
|
+
@apply bg-primary-jade text-white hover:bg-jade-2 focus:ring-primary-jade;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.bread-button-outline {
|
|
141
|
+
@apply border-2 border-primary-orange text-primary-orange hover:bg-orange-0 focus:ring-primary-orange;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.bread-button-small {
|
|
145
|
+
@apply px-3 py-1.5 text-sm;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.bread-button-medium {
|
|
149
|
+
@apply px-4 py-2 text-base;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.bread-button-large {
|
|
153
|
+
@apply px-6 py-3 text-lg;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.bread-button-disabled {
|
|
157
|
+
@apply opacity-50 cursor-not-allowed;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.bread-button-enabled {
|
|
161
|
+
@apply cursor-pointer;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
body {
|
|
166
|
+
background: var(--background);
|
|
167
|
+
color: var(--foreground);
|
|
168
|
+
font-family: var(--font-inter), Arial, Helvetica, sans-serif;
|
|
169
|
+
}
|