@troychaplin/parlour-ui 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +141 -145
- package/dist/_shared/client-Ban3HFV8.mjs +174 -0
- package/dist/_shared/client-D7AH6qxi.cjs +1 -0
- package/dist/_shared/shared-CihwD_kP.mjs +546 -0
- package/dist/_shared/shared-HWeZXz9t.cjs +1 -0
- package/dist/components/BrandIcon/BrandIcon.d.ts +9 -0
- package/dist/components/BrandIcon/BrandIcon.d.ts.map +1 -0
- package/dist/components/BrandIcon/brandIcons.d.ts +88 -0
- package/dist/components/BrandIcon/brandIcons.d.ts.map +1 -0
- package/dist/components/BrandIcon/index.cjs +1 -0
- package/dist/components/BrandIcon/index.d.ts +99 -0
- package/dist/components/BrandIcon/index.d.ts.map +1 -0
- package/dist/components/BrandIcon/index.mjs +2 -0
- package/dist/components/Card/Card.d.ts +5 -2
- package/dist/components/Card/Card.d.ts.map +1 -1
- package/dist/components/Card/index.cjs +1 -1
- package/dist/components/Card/index.d.ts +6 -2
- package/dist/components/Card/index.mjs +2 -21
- package/dist/components/Card/styles.css +123 -26
- package/dist/components/Card/styles.scss +123 -26
- package/dist/components/CodeBlock/index.cjs +1 -1
- package/dist/components/CodeBlock/index.d.ts +1 -0
- package/dist/components/CodeBlock/index.mjs +1 -1
- package/dist/components/Column/index.cjs +1 -1
- package/dist/components/Column/index.mjs +1 -1
- package/dist/components/Container/index.d.ts +1 -0
- package/dist/components/Container/styles.css +6 -0
- package/dist/components/Container/styles.scss +6 -0
- package/dist/components/FlexGroup/index.cjs +1 -1
- package/dist/components/FlexGroup/index.mjs +1 -1
- package/dist/components/GridGroup/index.cjs +1 -1
- package/dist/components/GridGroup/index.mjs +1 -1
- package/dist/components/Hero/index.cjs +1 -1
- package/dist/components/Hero/index.mjs +1 -1
- package/dist/components/HeroHeader/styles.css +2 -1
- package/dist/components/HeroHeader/styles.scss +2 -1
- package/dist/components/InfoBar/index.cjs +1 -1
- package/dist/components/InfoBar/index.mjs +1 -1
- package/dist/components/Main/Main.d.ts +1 -1
- package/dist/components/Main/Main.d.ts.map +1 -1
- package/dist/components/Main/index.cjs +1 -1
- package/dist/components/Main/index.d.ts +1 -1
- package/dist/components/Main/index.mjs +6 -4
- package/dist/components/Main/styles.css +4 -0
- package/dist/components/Main/styles.scss +4 -0
- package/dist/components/ProjectCard/ProjectCard.d.ts +14 -0
- package/dist/components/ProjectCard/ProjectCard.d.ts.map +1 -0
- package/dist/components/ProjectCard/index.cjs +1 -0
- package/dist/components/ProjectCard/index.d.ts +151 -0
- package/dist/components/ProjectCard/index.d.ts.map +1 -0
- package/dist/components/ProjectCard/index.mjs +51 -0
- package/dist/components/ProjectCard/styles.css +95 -0
- package/dist/components/ProjectCard/styles.scss +95 -0
- package/dist/components/SiteFooter/SiteFooter.d.ts +13 -0
- package/dist/components/SiteFooter/SiteFooter.d.ts.map +1 -0
- package/dist/components/SiteFooter/index.cjs +1 -0
- package/dist/components/SiteFooter/index.d.ts +15 -0
- package/dist/components/SiteFooter/index.d.ts.map +1 -0
- package/dist/components/SiteFooter/index.mjs +64 -0
- package/dist/components/SiteFooter/styles.css +86 -0
- package/dist/components/SiteFooter/styles.scss +86 -0
- package/dist/components/SiteHeader/index.cjs +1 -1
- package/dist/components/SiteHeader/index.mjs +1 -1
- package/dist/components/SkipLink/SkipLink.d.ts +8 -0
- package/dist/components/SkipLink/SkipLink.d.ts.map +1 -0
- package/dist/components/SkipLink/index.cjs +1 -0
- package/dist/components/SkipLink/index.d.ts +11 -0
- package/dist/components/SkipLink/index.d.ts.map +1 -0
- package/dist/components/SkipLink/index.mjs +14 -0
- package/dist/components/SkipLink/styles.css +29 -0
- package/dist/components/SkipLink/styles.scss +29 -0
- package/dist/components/_shared/BrandIcon-CRT5CX33.cjs +1 -0
- package/dist/components/_shared/BrandIcon-CcelVr9Y.mjs +111 -0
- package/dist/components/_shared/Card-CHHpCLeB.cjs +1 -0
- package/dist/components/_shared/Card-HwBpJDVj.mjs +34 -0
- package/dist/components/_shared/{FlexGroup-CgPbyEha.cjs → FlexGroup-D9sTJeh4.cjs} +1 -1
- package/dist/components/_shared/{FlexGroup-CnOrx2MF.mjs → FlexGroup-DorFgrVL.mjs} +1 -1
- package/dist/components/_shared/parlour-tokens-B-n0blwG.cjs +1 -0
- package/dist/components/_shared/{parlour-tokens-CHt4gBUd.mjs → parlour-tokens-DpDDQf0L.mjs} +2 -0
- package/dist/components/_shared/propClasses-BWhHB1BQ.cjs +1 -0
- package/dist/components/_shared/{propClasses-R9s_eOfA.mjs → propClasses-DXjiKI33.mjs} +2 -1
- package/dist/components/tokens/index.cjs +1 -1
- package/dist/components/tokens/index.mjs +1 -1
- package/dist/data/ProjectData.d.ts +3 -0
- package/dist/data/ProjectData.d.ts.map +1 -0
- package/dist/graphics/parlour-icon.svg +27 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +3 -3
- package/dist/style.css +1 -1
- package/dist/styles/c2b/parlour-tokens.d.ts +1 -1
- package/dist/styles/parlour-tokens.css +1 -0
- package/dist/styles/parlour-tokens.d.ts +1 -1
- package/dist/styles/parlour-tokens.js +2 -1
- package/dist/styles/parlour-tokens.scss +1 -0
- package/dist/utils/propClasses.d.ts +2 -0
- package/dist/utils/propClasses.d.ts.map +1 -1
- package/dist/wordpress/block-theme.css +1 -0
- package/dist/wordpress/hybrid-theme.css +1 -0
- package/package.json +1 -1
- package/dist/_shared/client-CLAcY4nN.cjs +0 -1
- package/dist/_shared/client-CsCPbj42.mjs +0 -93
- package/dist/_shared/shared-B07rlYN8.cjs +0 -1
- package/dist/_shared/shared-DZTw1JIu.mjs +0 -400
- package/dist/components/_shared/parlour-tokens-BT0frVnY.cjs +0 -1
- package/dist/components/_shared/propClasses-CLbmpfVJ.cjs +0 -1
package/README.md
CHANGED
|
@@ -1,41 +1,75 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="./public/graphics/parlour-icon.svg" alt="Parlour logo: two scoops of ice cream melting over a bowl" width="140" />
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
<h1 align="center">Parlour</h1>
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>Scoop. Serve. Repeat.</strong>
|
|
9
|
+
</p>
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
<p align="center">
|
|
12
|
+
A token-first UI kit for React and WordPress.<br />
|
|
13
|
+
One set of tokens, every flavour.
|
|
14
|
+
</p>
|
|
8
15
|
|
|
9
|
-
|
|
16
|
+
<p align="center">
|
|
17
|
+
<a href="https://www.npmjs.com/package/@troychaplin/parlour-ui"><img src="https://img.shields.io/npm/v/@troychaplin/parlour-ui?color=c2185b&label=npm" alt="npm version" /></a>
|
|
18
|
+
<a href="https://troychaplin.github.io/parlour-ui/"><img src="https://img.shields.io/badge/Storybook-live-8fb56a" alt="Live Storybook" /></a>
|
|
19
|
+
</p>
|
|
10
20
|
|
|
11
|
-
|
|
21
|
+
<p align="center">
|
|
22
|
+
<a href="https://troychaplin.github.io/parlour-ui/"><strong>Browse the Storybook</strong></a> ·
|
|
23
|
+
<a href="#get-a-scoop">Get started</a> ·
|
|
24
|
+
<a href="#serve-it-in-wordpress">WordPress</a> ·
|
|
25
|
+
<a href="CHANGELOG.mdx">Changelog</a>
|
|
26
|
+
</p>
|
|
12
27
|
|
|
13
|
-
|
|
14
|
-
[`@troychaplin/component2block`](https://www.npmjs.com/package/@troychaplin/component2block)
|
|
15
|
-
compiles `c2b.config.json` into CSS custom properties (`--parlour--*`), SCSS
|
|
16
|
-
variables, base element styles, and a WordPress `theme.json` with matching editor
|
|
17
|
-
styles. A React app and the WordPress Site Editor render the same design language
|
|
18
|
-
because they read the same tokens — no parallel stylesheet to keep in sync by hand.
|
|
19
|
-
- **Fluid by default.** All 16 type steps are `clamp()` values that scale with the
|
|
20
|
-
viewport, and the spacing scale goes fluid from `small` upward. Responsive
|
|
21
|
-
typography without a stack of breakpoints.
|
|
22
|
-
- **No runtime, no lock-in.** Plain SCSS and CSS custom properties — no Tailwind, no
|
|
23
|
-
CSS-in-JS, no provider to wrap your tree in. Per-component CSS is exported
|
|
24
|
-
individually, so a WordPress block can ship only the styles it actually uses.
|
|
25
|
-
- **Accessibility is a build failure.** Every Storybook story runs through
|
|
26
|
-
[axe](https://github.com/dequelabs/axe-core) at the `error` threshold, on every pull
|
|
27
|
-
request and on pre-push. A violation blocks the merge — it isn't a warning someone
|
|
28
|
-
triages later.
|
|
29
|
-
- **Deliberately small.** Budgeted at 25 kB for the JS bundle and 7 kB for the
|
|
30
|
-
stylesheet, brotli-compressed. `pnpm size` checks both.
|
|
28
|
+
---
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
> build, and accessibility tooling are solid; the component catalogue is small and
|
|
34
|
-
> growing. See the [changelog](CHANGELOG.mdx) for what has landed.
|
|
30
|
+
## A palette cleanser for React and WordPress
|
|
35
31
|
|
|
36
|
-
|
|
32
|
+
You've built the same design twice before. Once in React, once in WordPress, and then spent months keeping two stylesheets from drifting apart.
|
|
37
33
|
|
|
38
|
-
|
|
34
|
+
Parlour ends that. You define your design once, as tokens, and Parlour serves it everywhere: a React component library, a Next.js app, a WordPress block theme, a hybrid theme, and the styles inside your custom blocks. Same colours, same type, same spacing. Not "close enough." The same.
|
|
35
|
+
|
|
36
|
+
## Scoop. Serve. Repeat.
|
|
37
|
+
|
|
38
|
+
**Scoop.** Take exactly what you need. Use the whole stylesheet, or scoop out a single component's CSS for a WordPress block that only ships the styles it actually uses.
|
|
39
|
+
|
|
40
|
+
**Serve.** One token file becomes CSS custom properties, SCSS variables, base element styles, and a WordPress `theme.json`, all generated together. React apps and the WordPress Site Editor read from the same source, so they always match.
|
|
41
|
+
|
|
42
|
+
**Repeat.** Change a token and every output updates on the next build. No parallel stylesheets, no copy-pasting hex codes, no "why is the button a different blue in WordPress?"
|
|
43
|
+
|
|
44
|
+
## What's on the menu
|
|
45
|
+
|
|
46
|
+
**One recipe, two kitchens.** Your design tokens live in a single file, `c2b.config.json`. [`@troychaplin/component2block`](https://www.npmjs.com/package/@troychaplin/component2block) compiles it into everything React and WordPress need, so both ecosystems render the same design language without anyone keeping them in sync by hand.
|
|
47
|
+
|
|
48
|
+
**Fluid from the first spoonful.** All 16 type steps are `clamp()` values that scale smoothly with the viewport, and the spacing scale goes fluid from `small` upward. Responsive typography without a stack of breakpoints.
|
|
49
|
+
|
|
50
|
+
**No runtime. No lock-in.** Plain SCSS and CSS custom properties. No Tailwind, no CSS-in-JS, no provider wrapping your whole app. Every component's CSS is published on its own, so you only serve what's on the plate.
|
|
51
|
+
|
|
52
|
+
**Accessibility isn't a topping, it's the base.** Every Storybook story is tested with [axe](https://github.com/dequelabs/axe-core) at the `error` threshold, on every pull request and before every push. An accessibility violation blocks the merge. It's never a warning someone gets to later.
|
|
53
|
+
|
|
54
|
+
**A light dessert.** Budgeted at 25 kB for the JavaScript and 7 kB for the stylesheet, brotli-compressed, and checked on every build with `pnpm size`.
|
|
55
|
+
|
|
56
|
+
**Server Components welcome.** Most components render on the server in the Next.js App Router. Only the few that need React context are client components.
|
|
57
|
+
|
|
58
|
+
**Fresh ingredients.** Built with React 18 and 19, TypeScript 6, Vite 8, Storybook 10, and SCSS.
|
|
59
|
+
|
|
60
|
+
> **Fresh out of the churn.** Parlour is early-stage and moving quickly. The token pipeline, build, and accessibility tooling are solid; the component catalogue is small and growing every release. See the [changelog](CHANGELOG.mdx) for what's landed.
|
|
61
|
+
|
|
62
|
+
## Coming soon to the counter
|
|
63
|
+
|
|
64
|
+
**Flavours.** Full colour patterns you can switch between, not just light and dark. Pick a flavour and the whole site, in React and WordPress, follows.
|
|
65
|
+
|
|
66
|
+
**Your own recipe.** Enter your own brand variables and let Parlour generate everything else: tokens, base styles, and WordPress theme files.
|
|
67
|
+
|
|
68
|
+
**Saved templates.** Keep your recipes and reuse them across projects, from React apps to WordPress themes and beyond.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Get a scoop
|
|
39
73
|
|
|
40
74
|
```bash
|
|
41
75
|
npm install @troychaplin/parlour-ui
|
|
@@ -43,7 +77,7 @@ npm install @troychaplin/parlour-ui
|
|
|
43
77
|
|
|
44
78
|
React and React DOM 18 or 19 are peer dependencies.
|
|
45
79
|
|
|
46
|
-
### React
|
|
80
|
+
### Serve it in React
|
|
47
81
|
|
|
48
82
|
Import the stylesheet once, where your app starts:
|
|
49
83
|
|
|
@@ -51,7 +85,7 @@ Import the stylesheet once, where your app starts:
|
|
|
51
85
|
import '@troychaplin/parlour-ui/styles.css';
|
|
52
86
|
```
|
|
53
87
|
|
|
54
|
-
Then
|
|
88
|
+
Then build with the components:
|
|
55
89
|
|
|
56
90
|
```tsx
|
|
57
91
|
import { Button, Container, Main } from '@troychaplin/parlour-ui';
|
|
@@ -68,16 +102,11 @@ export function Page() {
|
|
|
68
102
|
}
|
|
69
103
|
```
|
|
70
104
|
|
|
71
|
-
`styles.css`
|
|
72
|
-
component's CSS, and the `@font-face` rules for Inter Tight, Source Serif 4 and JetBrains Mono.
|
|
73
|
-
The font files ship with the package, and your bundler picks them up from the stylesheet. The
|
|
74
|
-
components don't import any CSS themselves, so this import is required.
|
|
105
|
+
`styles.css` is the full sundae: design tokens, base element styles, layout classes, every component's CSS, and the `@font-face` rules for Inter Tight, Source Serif 4, and JetBrains Mono. The font files ship with the package and your bundler picks them up automatically. Components don't import their own CSS, so this one import is required.
|
|
75
106
|
|
|
76
107
|
#### Router links
|
|
77
108
|
|
|
78
|
-
`Button` with an `href`, and `SiteHeader`, render plain `<a>` links unless you wrap
|
|
79
|
-
`LinkProvider` with your router's link component. That component receives standard anchor props,
|
|
80
|
-
including `href`:
|
|
109
|
+
`Button` with an `href`, and `SiteHeader`, render plain `<a>` links unless you wrap your app in `LinkProvider` with your router's link component. That component receives standard anchor props, including `href`:
|
|
81
110
|
|
|
82
111
|
```tsx
|
|
83
112
|
import { LinkProvider } from '@troychaplin/parlour-ui';
|
|
@@ -87,15 +116,11 @@ import { LinkProvider } from '@troychaplin/parlour-ui';
|
|
|
87
116
|
</LinkProvider>;
|
|
88
117
|
```
|
|
89
118
|
|
|
90
|
-
Next.js's `Link` takes `href` as
|
|
91
|
-
instead: `({ href = '', ...props }) => <Link to={href} {...props} />`.
|
|
119
|
+
Next.js's `Link` takes `href` as-is. React Router's `Link` expects `to`, so pass a small wrapper instead: `({ href = '', ...props }) => <Link to={href} {...props} />`.
|
|
92
120
|
|
|
93
|
-
|
|
121
|
+
### Serve it in Next.js
|
|
94
122
|
|
|
95
|
-
Parlour
|
|
96
|
-
React context, so they're marked `'use client'` and render as Client Components; every other
|
|
97
|
-
component renders on the server. A Server Component can't pass a function such as Next.js's `Link`
|
|
98
|
-
to a Client Component, so set up `LinkProvider` in a client providers file:
|
|
123
|
+
Parlour works in Server Components. `Button`, `SiteHeader`, and `LinkProvider` use React context, so they're marked `'use client'`; everything else renders on the server. Since a Server Component can't pass a function like Next.js's `Link` to a Client Component, set up `LinkProvider` in a client providers file:
|
|
99
124
|
|
|
100
125
|
```tsx
|
|
101
126
|
// app/providers.tsx
|
|
@@ -125,49 +150,21 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
|
|
125
150
|
}
|
|
126
151
|
```
|
|
127
152
|
|
|
128
|
-
|
|
153
|
+
Using the Pages Router? Import the stylesheet and add `LinkProvider` in `pages/_app.tsx`.
|
|
129
154
|
|
|
130
|
-
###
|
|
155
|
+
### Serve it in WordPress
|
|
131
156
|
|
|
132
|
-
|
|
157
|
+
`dist/wordpress/` has everything a theme needs:
|
|
133
158
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
| `/tokens.css` | The design tokens as `--parlour--*` custom properties |
|
|
139
|
-
| `/base-styles.css` | Element defaults for the body, headings, links and buttons |
|
|
140
|
-
| `/layout.css` | Layout classes that match WordPress's, such as `is-layout-constrained` |
|
|
141
|
-
| `/typography.css` | Spacing after headings |
|
|
142
|
-
| `/fonts.css` | `@font-face` rules for the bundled fonts |
|
|
143
|
-
| `/tokens` | The token names as a JavaScript object, `parlourTokens` |
|
|
144
|
-
| `/<Component>` | One component's JavaScript, such as `/Button` |
|
|
145
|
-
| `/<Component>.css` | One component's CSS, such as `/Button.css` |
|
|
146
|
-
| `/block-theme.css`, `/hybrid-theme.css` | Stylesheets for WordPress themes |
|
|
147
|
-
|
|
148
|
-
The WordPress theme files, `integrate.php` and `theme-parlour.json`, are in `dist/wordpress/`, and
|
|
149
|
-
the font files are in `dist/fonts/`. Copy those by path.
|
|
150
|
-
|
|
151
|
-
### WordPress themes
|
|
152
|
-
|
|
153
|
-
`dist/wordpress/` has what a theme needs:
|
|
154
|
-
|
|
155
|
-
- `theme-parlour.json` — the tokens as `theme.json` presets: the color palette and gradient, 16
|
|
156
|
-
fluid font sizes, the three font families with their font files, the spacing scale, shadows,
|
|
157
|
-
and the content and wide widths. It also sets default styles for text, headings, links, buttons
|
|
158
|
-
and captions.
|
|
159
|
-
- `integrate.php` — loads `theme-parlour.json` as WordPress's default `theme.json` layer, so your
|
|
160
|
-
theme's own `theme.json` only needs to hold overrides.
|
|
161
|
-
- `block-theme.css` — for block themes: the tokens, the `.sr-only` utility and heading spacing.
|
|
162
|
-
- `hybrid-theme.css` — for hybrid themes with PHP templates: adds Parlour's element defaults,
|
|
163
|
-
layout classes and global styles.
|
|
159
|
+
- **`theme-parlour.json`** turns the tokens into `theme.json` presets: the colour palette and gradient, 16 fluid font sizes, the three font families with their font files, the spacing scale, shadows, and content and wide widths. It also sets default styles for text, headings, links, buttons, and captions.
|
|
160
|
+
- **`integrate.php`** loads `theme-parlour.json` as WordPress's default `theme.json` layer, so your theme's own `theme.json` only needs to hold overrides.
|
|
161
|
+
- **`block-theme.css`** is for block themes: the tokens, the `.sr-only` utility, and heading spacing.
|
|
162
|
+
- **`hybrid-theme.css`** is for hybrid themes with PHP templates, adding Parlour's element defaults, layout classes, and global styles.
|
|
164
163
|
|
|
165
164
|
To set up a theme:
|
|
166
165
|
|
|
167
|
-
1. Copy `integrate.php`, `theme-parlour.json
|
|
168
|
-
|
|
169
|
-
2. Copy `dist/fonts/` to `assets/fonts/` in your theme, the path `theme-parlour.json` gives for the
|
|
170
|
-
font files.
|
|
166
|
+
1. Copy `integrate.php`, `theme-parlour.json`, and the stylesheet you need into one folder in your theme, such as `assets/parlour/`. `integrate.php` looks for `theme-parlour.json` next to itself.
|
|
167
|
+
2. Copy `dist/fonts/` to `assets/fonts/` in your theme, which is the path `theme-parlour.json` uses for the font files.
|
|
171
168
|
3. Load everything from `functions.php`:
|
|
172
169
|
|
|
173
170
|
```php
|
|
@@ -184,18 +181,13 @@ add_action( 'after_setup_theme', function () {
|
|
|
184
181
|
|
|
185
182
|
For a hybrid theme, use `hybrid-theme.css` in both places.
|
|
186
183
|
|
|
187
|
-
Parlour is built locked, so `integrate.php` also stops the theme from changing the
|
|
188
|
-
and breakpoints, and turns off custom colors, gradients and duotone in the Site Editor.
|
|
184
|
+
Parlour is built locked, so `integrate.php` also stops the theme from changing layout widths and breakpoints, and turns off custom colours, gradients, and duotone in the Site Editor. Your design stays on-brand, no matter who's editing.
|
|
189
185
|
|
|
190
|
-
###
|
|
186
|
+
### Serve it in custom blocks
|
|
191
187
|
|
|
192
|
-
|
|
193
|
-
markup it renders. Component CSS reads the `--parlour--*` custom properties, so the page needs the
|
|
194
|
-
tokens too: a theme set up as above already loads them, and otherwise the block should bundle
|
|
195
|
-
`tokens.css`.
|
|
188
|
+
Every component's CSS is published on its own, so a block can bundle just the styles for the markup it renders. Component CSS reads the `--parlour--*` custom properties, so the page needs the tokens too: a theme set up as above already loads them; otherwise, bundle `tokens.css` with the block.
|
|
196
189
|
|
|
197
|
-
With `@wordpress/scripts`, import them at the top of the block's `style.scss`, which loads in the
|
|
198
|
-
editor and on the front end:
|
|
190
|
+
With `@wordpress/scripts`, import them at the top of the block's `style.scss`, which loads in both the editor and on the front end:
|
|
199
191
|
|
|
200
192
|
```scss
|
|
201
193
|
// src/my-block/style.scss
|
|
@@ -203,36 +195,49 @@ editor and on the front end:
|
|
|
203
195
|
@import '@troychaplin/parlour-ui/Button.css';
|
|
204
196
|
```
|
|
205
197
|
|
|
206
|
-
##
|
|
198
|
+
## What comes in the box
|
|
207
199
|
|
|
208
|
-
Every
|
|
200
|
+
Every path below starts with `@troychaplin/parlour-ui`.
|
|
201
|
+
|
|
202
|
+
| Path | Contents |
|
|
203
|
+
| --------------------------------------- | ---------------------------------------------------------------------------------------- |
|
|
204
|
+
| _(package root)_ | Every React component, as ES modules and CommonJS, with TypeScript types |
|
|
205
|
+
| `/styles.css` | The full stylesheet: tokens, base styles, layout classes, every component, and the fonts |
|
|
206
|
+
| `/tokens.css` | The design tokens as `--parlour--*` custom properties |
|
|
207
|
+
| `/base-styles.css` | Element defaults for the body, headings, links, and buttons |
|
|
208
|
+
| `/layout.css` | Layout classes that match WordPress's, such as `is-layout-constrained` |
|
|
209
|
+
| `/typography.css` | Spacing after headings |
|
|
210
|
+
| `/fonts.css` | `@font-face` rules for the bundled fonts |
|
|
211
|
+
| `/tokens` | The token names as a JavaScript object, `parlourTokens` |
|
|
212
|
+
| `/<Component>` | One component's JavaScript, such as `/Button` |
|
|
213
|
+
| `/<Component>.css` | One component's CSS, such as `/Button.css` |
|
|
214
|
+
| `/block-theme.css`, `/hybrid-theme.css` | Stylesheets for WordPress themes |
|
|
215
|
+
|
|
216
|
+
The WordPress theme files (`integrate.php` and `theme-parlour.json`) are in `dist/wordpress/`, and the font files are in `dist/fonts/`. Copy those by path.
|
|
209
217
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
| **Typography** | Three families (Inter Tight, Source Serif 4, JetBrains Mono), 16 fluid size steps, nine weights, three line heights |
|
|
214
|
-
| **Spacing** | A 12-step scale from `3-x-small` to `5-x-large`, fluid from `small` upward |
|
|
215
|
-
| **Effects** | Five shadow presets (natural, deep, sharp, outlined, crisp), five border radii, and a gradient |
|
|
216
|
-
| **Layout** | Content width (768px), wide width (1152px), small (600px), and full-bleed |
|
|
218
|
+
## The ingredients
|
|
219
|
+
|
|
220
|
+
Every CSS variable uses the `--parlour--` prefix (double dash).
|
|
217
221
|
|
|
218
|
-
|
|
222
|
+
| Category | What's in it |
|
|
223
|
+
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
224
|
+
| **Colours** | `accent-primary` and `accent-secondary`, an 11-step neutral ramp (`neutral-50` → `neutral-950`), semantic states (`info`, `success`, `warning`, `error`), and brand colours for seven social platforms |
|
|
225
|
+
| **Typography** | Three families (Inter Tight, Source Serif 4, JetBrains Mono), 16 fluid size steps, nine weights, three line heights |
|
|
226
|
+
| **Spacing** | A 12-step scale from `3-x-small` to `5-x-large`, fluid from `small` upward |
|
|
227
|
+
| **Effects** | Five shadow presets (natural, deep, sharp, outlined, crisp), five border radii, and a gradient |
|
|
228
|
+
| **Layout** | Content width (768px), wide width (1152px), small (600px), and full-bleed |
|
|
219
229
|
|
|
220
|
-
|
|
230
|
+
Taste them all live in the Storybook under **Stylebook**.
|
|
221
231
|
|
|
222
|
-
|
|
223
|
-
that fail accessibility checks will not pass CI.
|
|
232
|
+
## The menu (documentation)
|
|
224
233
|
|
|
225
|
-
|
|
234
|
+
The [live Storybook](https://troychaplin.github.io/parlour-ui/) is the full menu. **Getting Started** covers installation and framework setup, **Stylebook** has live token demos, and every component has its own docs page with props, CSS classes, tokens, and accessibility notes.
|
|
226
235
|
|
|
227
|
-
|
|
228
|
-
**Getting Started** covers installation and framework integration, **Stylebook** has live token
|
|
229
|
-
demos, and every component ships its own docs page with props, CSS classes, tokens, and
|
|
230
|
-
accessibility notes.
|
|
236
|
+
---
|
|
231
237
|
|
|
232
|
-
|
|
233
|
-
[`AGENTS.md`](AGENTS.md) and the [`build-component` skill](.claude/skills/build-component/SKILL.md).
|
|
238
|
+
## Behind the counter
|
|
234
239
|
|
|
235
|
-
|
|
240
|
+
Want to help make Parlour? Contributor conventions (how to build a component's TSX, styles, stories, and docs) are in [`AGENTS.md`](AGENTS.md) and the [`build-component` skill](.claude/skills/build-component/SKILL.md).
|
|
236
241
|
|
|
237
242
|
```bash
|
|
238
243
|
# Requires Node 24+ (see .nvmrc)
|
|
@@ -250,10 +255,10 @@ pnpm run dev # Storybook at http://localhost:6006
|
|
|
250
255
|
|
|
251
256
|
| Command | Description |
|
|
252
257
|
| ---------------------------- | --------------------------------------------------------------------------------------------------- |
|
|
253
|
-
| `pnpm run dev` | Run `c2b generate` then start Storybook dev server
|
|
258
|
+
| `pnpm run dev` | Run `c2b generate` then start the Storybook dev server |
|
|
254
259
|
| `pnpm run build` | Library build: ESM and CommonJS bundles, per-component files, types, tokens and the WordPress files |
|
|
255
260
|
| `pnpm run build-storybook` | Build static Storybook for deployment |
|
|
256
|
-
| `pnpm run c2b` | Regenerate tokens, base styles, and
|
|
261
|
+
| `pnpm run c2b` | Regenerate tokens, base styles, and WordPress theme files |
|
|
257
262
|
| `pnpm run typecheck` | TypeScript type checking (no emit) |
|
|
258
263
|
| `pnpm run lint` | ESLint across `src/` |
|
|
259
264
|
| `pnpm run lint:fix` | ESLint with auto-fix |
|
|
@@ -266,33 +271,18 @@ pnpm run dev # Storybook at http://localhost:6006
|
|
|
266
271
|
| `pnpm run size` | Check the JS bundle and stylesheet against their size budgets |
|
|
267
272
|
| `pnpm run release <version>` | Changelog, version bump, commit and tag on main. Push the tag to publish to npm |
|
|
268
273
|
|
|
269
|
-
###
|
|
270
|
-
|
|
271
|
-
Formatting is enforced automatically so
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
- **
|
|
275
|
-
|
|
276
|
-
- **
|
|
277
|
-
files when they're committed. `.prettierignore` excludes build output and generated files
|
|
278
|
-
(`dist/`, `storybook-static/`, `src/styles/c2b/`, etc.).
|
|
279
|
-
- **ESLint** (`eslint.config.mjs`) lints `src/` for code quality (React, hooks,
|
|
280
|
-
jsx-a11y, Storybook rules), with `eslint-config-prettier` disabling any
|
|
281
|
-
formatting rules that could conflict with Prettier.
|
|
282
|
-
- **VSCode workspace settings** (`.vscode/settings.json`, committed to the repo)
|
|
283
|
-
set Prettier as the default formatter with format-on-save and ESLint
|
|
284
|
-
auto-fix-on-save enabled. `.vscode/extensions.json` recommends the Prettier,
|
|
285
|
-
ESLint, and EditorConfig extensions so VSCode prompts new contributors to
|
|
286
|
-
install them.
|
|
274
|
+
### Keeping the kitchen clean
|
|
275
|
+
|
|
276
|
+
Formatting is enforced automatically, so nobody's diffs are about personal editor preferences:
|
|
277
|
+
|
|
278
|
+
- **EditorConfig** (`.editorconfig`) sets base whitespace rules: 4-space indent, LF line endings, and trimmed trailing whitespace.
|
|
279
|
+
- **Prettier** (`.prettierrc`) formats TS, TSX, and SCSS in `src/`, plus JSON, Markdown, and MDX files when they're committed. `.prettierignore` excludes build output and generated files (`dist/`, `storybook-static/`, `src/styles/c2b/`, and so on).
|
|
280
|
+
- **ESLint** (`eslint.config.mjs`) lints `src/` for code quality (React, hooks, jsx-a11y, and Storybook rules), with `eslint-config-prettier` turning off any formatting rules that could conflict with Prettier.
|
|
281
|
+
- **VS Code workspace settings** (`.vscode/settings.json`) set Prettier as the default formatter with format-on-save and ESLint auto-fix-on-save. `.vscode/extensions.json` recommends the Prettier, ESLint, and EditorConfig extensions to new contributors.
|
|
287
282
|
- **`.gitattributes`** normalizes line endings to LF across operating systems.
|
|
288
|
-
- **Husky
|
|
289
|
-
`lint-staged` first, which formats and auto-fixes only the files staged in
|
|
290
|
-
that commit (Prettier for TS/TSX/SCSS/JSON/MD/MDX, ESLint `--fix` for TS/TSX).
|
|
291
|
-
It then runs the full `pnpm lint` and `pnpm typecheck` as a final check
|
|
292
|
-
across the whole project. `.husky/pre-push` runs `pnpm test:storybook`.
|
|
283
|
+
- **Husky and lint-staged** run on every commit: `lint-staged` formats and auto-fixes only the staged files, then the full `pnpm lint` and `pnpm typecheck` run as a final check. `.husky/pre-push` runs `pnpm test:storybook`.
|
|
293
284
|
|
|
294
|
-
Run `pnpm format` to format everything in `src/`, or `pnpm format:check` to
|
|
295
|
-
without writing changes.
|
|
285
|
+
Run `pnpm format` to format everything in `src/`, or `pnpm format:check` to check formatting without writing changes.
|
|
296
286
|
|
|
297
287
|
### Project structure
|
|
298
288
|
|
|
@@ -304,7 +294,7 @@ src/
|
|
|
304
294
|
tokens/ # Runtime token export (parlourTokens)
|
|
305
295
|
docs/ # Storybook documentation pages
|
|
306
296
|
getting-started/ # Install and framework integration guides
|
|
307
|
-
stylebook/ # Live token demos (
|
|
297
|
+
stylebook/ # Live token demos (colours, typography, spacing, effects)
|
|
308
298
|
styles/
|
|
309
299
|
main.scss # Consumer-facing stylesheet entry
|
|
310
300
|
base/ # Hand-authored globals (focus, selection, utilities)
|
|
@@ -320,9 +310,15 @@ dist/
|
|
|
320
310
|
fonts/ # Font files used by styles.css and theme-parlour.json
|
|
321
311
|
```
|
|
322
312
|
|
|
323
|
-
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
<p align="center">
|
|
316
|
+
<a href="https://troychaplin.github.io/parlour-ui/">Storybook</a> ·
|
|
317
|
+
<a href="https://www.npmjs.com/package/@troychaplin/parlour-ui">npm</a> ·
|
|
318
|
+
<a href="https://github.com/troychaplin/parlour-ui">Source</a> ·
|
|
319
|
+
<a href="CHANGELOG.mdx">Changelog</a>
|
|
320
|
+
</p>
|
|
324
321
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
- [Changelog](CHANGELOG.mdx)
|
|
322
|
+
<p align="center">
|
|
323
|
+
<strong>Scoop. Serve. Repeat.</strong> 🍨
|
|
324
|
+
</p>
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { _ as e, f as t, g as n, h as r, m as i, p as a, v as o } from "./shared-CihwD_kP.mjs";
|
|
3
|
+
import { createContext as s, useContext as c } from "react";
|
|
4
|
+
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
5
|
+
var d = s((e) => /* @__PURE__ */ l("a", { ...e })), f = () => c(d), p = ({ text: e = "Button", color: t = "medium", rounded: n = "sm", type: r = "button", isSmall: i = !1, isFull: a = !1, isOutline: o = !1, disabled: s = !1, className: c, ...u }) => {
|
|
6
|
+
let d = f(), p = [
|
|
7
|
+
"parlour-button",
|
|
8
|
+
s ? "parlour-button--disabled" : `parlour-button--${t}`,
|
|
9
|
+
n && `parlour-button--radius-${n}`,
|
|
10
|
+
o && !s && "parlour-button--outline",
|
|
11
|
+
i && "parlour-button--small",
|
|
12
|
+
a && "parlour-button--full",
|
|
13
|
+
c
|
|
14
|
+
].filter(Boolean).join(" ");
|
|
15
|
+
return u.href === void 0 ? /* @__PURE__ */ l("button", {
|
|
16
|
+
type: r,
|
|
17
|
+
className: p,
|
|
18
|
+
disabled: s,
|
|
19
|
+
...u,
|
|
20
|
+
children: e
|
|
21
|
+
}) : /* @__PURE__ */ l(d, {
|
|
22
|
+
className: p,
|
|
23
|
+
...u,
|
|
24
|
+
children: e
|
|
25
|
+
});
|
|
26
|
+
}, m = ({ component: e, children: t }) => /* @__PURE__ */ l(d.Provider, {
|
|
27
|
+
value: e,
|
|
28
|
+
children: t
|
|
29
|
+
}), h = [
|
|
30
|
+
{
|
|
31
|
+
href: "/about",
|
|
32
|
+
label: "About"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
href: "/blog",
|
|
36
|
+
label: "Blog"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
href: "/resume",
|
|
40
|
+
label: "Resume"
|
|
41
|
+
}
|
|
42
|
+
], g = (e, t) => {
|
|
43
|
+
let n = t ? e.indexOf(t) : -1;
|
|
44
|
+
return !t || n === -1 ? [e] : [
|
|
45
|
+
e.slice(0, n),
|
|
46
|
+
t,
|
|
47
|
+
e.slice(n + t.length)
|
|
48
|
+
];
|
|
49
|
+
}, _ = ({ className: e = "", children: t, siteTitle: n = "Parlour", siteTitleAccent: a }) => {
|
|
50
|
+
let o = ["parlour-site-header", e].filter(Boolean).join(" "), s = f(), [c, d, m] = g(n, a);
|
|
51
|
+
return /* @__PURE__ */ l("header", {
|
|
52
|
+
className: o,
|
|
53
|
+
children: /* @__PURE__ */ u(r, {
|
|
54
|
+
gap: "normal",
|
|
55
|
+
maxWidth: "alignwide",
|
|
56
|
+
justify: "space-between",
|
|
57
|
+
align: "center",
|
|
58
|
+
children: [
|
|
59
|
+
/* @__PURE__ */ l("div", {
|
|
60
|
+
className: "parlour-site-header__branding",
|
|
61
|
+
children: /* @__PURE__ */ l("p", { children: /* @__PURE__ */ u(s, {
|
|
62
|
+
href: "/",
|
|
63
|
+
rel: "home",
|
|
64
|
+
children: [
|
|
65
|
+
c,
|
|
66
|
+
d && /* @__PURE__ */ l("span", {
|
|
67
|
+
className: "parlour-site-header__title-accent",
|
|
68
|
+
children: d
|
|
69
|
+
}),
|
|
70
|
+
m
|
|
71
|
+
]
|
|
72
|
+
}) })
|
|
73
|
+
}),
|
|
74
|
+
/* @__PURE__ */ l("nav", {
|
|
75
|
+
className: "parlour-site-header__nav",
|
|
76
|
+
"aria-label": "Primary",
|
|
77
|
+
children: /* @__PURE__ */ l("ul", { children: h.map(({ href: e, label: t }) => /* @__PURE__ */ l("li", { children: /* @__PURE__ */ l(s, {
|
|
78
|
+
href: e,
|
|
79
|
+
children: t
|
|
80
|
+
}) }, e)) })
|
|
81
|
+
}),
|
|
82
|
+
/* @__PURE__ */ l("div", { children: /* @__PURE__ */ l(i, { children: /* @__PURE__ */ l(p, {
|
|
83
|
+
text: "Hire Me",
|
|
84
|
+
isSmall: !0,
|
|
85
|
+
isOutline: !0
|
|
86
|
+
}) }) }),
|
|
87
|
+
t
|
|
88
|
+
]
|
|
89
|
+
})
|
|
90
|
+
});
|
|
91
|
+
}, v = [
|
|
92
|
+
"github",
|
|
93
|
+
"x",
|
|
94
|
+
"bluesky",
|
|
95
|
+
"linkedin",
|
|
96
|
+
"facebook",
|
|
97
|
+
"instagram",
|
|
98
|
+
"youtube",
|
|
99
|
+
"tiktok"
|
|
100
|
+
], y = ({ name: e, nameHref: n, year: r = (/* @__PURE__ */ new Date()).getFullYear(), text: i, className: o, github: s, x: c, bluesky: d, linkedin: p, facebook: m, instagram: h, youtube: g, tiktok: _, ...y }) => {
|
|
101
|
+
let b = f(), x = ["parlour-site-footer", o].filter(Boolean).join(" "), S = {
|
|
102
|
+
github: s,
|
|
103
|
+
x: c,
|
|
104
|
+
bluesky: d,
|
|
105
|
+
linkedin: p,
|
|
106
|
+
facebook: m,
|
|
107
|
+
instagram: h,
|
|
108
|
+
youtube: g,
|
|
109
|
+
tiktok: _
|
|
110
|
+
}, C = v.filter((e) => S[e]);
|
|
111
|
+
return /* @__PURE__ */ l("footer", {
|
|
112
|
+
className: x,
|
|
113
|
+
...y,
|
|
114
|
+
children: /* @__PURE__ */ u("div", {
|
|
115
|
+
className: "parlour-site-footer__inner",
|
|
116
|
+
children: [
|
|
117
|
+
/* @__PURE__ */ u("p", {
|
|
118
|
+
className: "parlour-site-footer__copyright",
|
|
119
|
+
children: [
|
|
120
|
+
"© ",
|
|
121
|
+
r,
|
|
122
|
+
" ",
|
|
123
|
+
n ? /* @__PURE__ */ l(b, {
|
|
124
|
+
href: n,
|
|
125
|
+
children: e
|
|
126
|
+
}) : e
|
|
127
|
+
]
|
|
128
|
+
}),
|
|
129
|
+
i && /* @__PURE__ */ l("p", {
|
|
130
|
+
className: "parlour-site-footer__text",
|
|
131
|
+
children: i
|
|
132
|
+
}),
|
|
133
|
+
C.length > 0 && /* @__PURE__ */ l("ul", {
|
|
134
|
+
className: "parlour-site-footer__social",
|
|
135
|
+
children: C.map((e) => /* @__PURE__ */ l("li", { children: /* @__PURE__ */ l(b, {
|
|
136
|
+
className: "parlour-site-footer__social-link",
|
|
137
|
+
href: S[e],
|
|
138
|
+
rel: "me",
|
|
139
|
+
"aria-label": a[e].title,
|
|
140
|
+
children: /* @__PURE__ */ l(t, { name: e })
|
|
141
|
+
}) }, e))
|
|
142
|
+
})
|
|
143
|
+
]
|
|
144
|
+
})
|
|
145
|
+
});
|
|
146
|
+
}, b = ({ children: t, as: r = "div", backgroundColor: i = "light", border: a = !0, borderColor: s = "light", borderRadius: c = "none", paddingInline: u = "x-large", paddingBlock: d = "large", href: p, linkProps: m, className: h, ...g }) => {
|
|
147
|
+
let _ = r, v = f(), y = [
|
|
148
|
+
"parlour-card",
|
|
149
|
+
`parlour-card--bg-${n[i]}`,
|
|
150
|
+
a && "parlour-card--border",
|
|
151
|
+
a && `parlour-card--border-${n[s]}`,
|
|
152
|
+
`parlour-card--radius-${e[c]}`,
|
|
153
|
+
`parlour-card--padding-inline-${o[u]}`,
|
|
154
|
+
`parlour-card--padding-block-${o[d]}`,
|
|
155
|
+
p && "parlour-card--linked",
|
|
156
|
+
h
|
|
157
|
+
].filter(Boolean).join(" ");
|
|
158
|
+
return p ? /* @__PURE__ */ l(_, {
|
|
159
|
+
className: y,
|
|
160
|
+
...g,
|
|
161
|
+
children: /* @__PURE__ */ l(v, {
|
|
162
|
+
className: "parlour-card__link",
|
|
163
|
+
href: p,
|
|
164
|
+
...m,
|
|
165
|
+
children: t
|
|
166
|
+
})
|
|
167
|
+
}) : /* @__PURE__ */ l(_, {
|
|
168
|
+
className: y,
|
|
169
|
+
...g,
|
|
170
|
+
children: t
|
|
171
|
+
});
|
|
172
|
+
};
|
|
173
|
+
//#endregion
|
|
174
|
+
export { p as a, m as i, y as n, _ as r, b as t };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";const e=require("./rolldown-runtime-BocRIvOZ.cjs"),t=require("./shared-HWeZXz9t.cjs");let n=require("react");n=e.t(n,1);let r=require("react/jsx-runtime");var i=(0,n.createContext)(e=>(0,r.jsx)(`a`,{...e})),a=()=>(0,n.useContext)(i),o=({text:e=`Button`,color:t=`medium`,rounded:n=`sm`,type:i=`button`,isSmall:o=!1,isFull:s=!1,isOutline:c=!1,disabled:l=!1,className:u,...d})=>{let f=a(),p=[`parlour-button`,l?`parlour-button--disabled`:`parlour-button--${t}`,n&&`parlour-button--radius-${n}`,c&&!l&&`parlour-button--outline`,o&&`parlour-button--small`,s&&`parlour-button--full`,u].filter(Boolean).join(` `);return d.href===void 0?(0,r.jsx)(`button`,{type:i,className:p,disabled:l,...d,children:e}):(0,r.jsx)(f,{className:p,...d,children:e})},s=({component:e,children:t})=>(0,r.jsx)(i.Provider,{value:e,children:t}),c=[{href:`/about`,label:`About`},{href:`/blog`,label:`Blog`},{href:`/resume`,label:`Resume`}],l=(e,t)=>{let n=t?e.indexOf(t):-1;return!t||n===-1?[e]:[e.slice(0,n),t,e.slice(n+t.length)]},u=({className:e=``,children:n,siteTitle:i=`Parlour`,siteTitleAccent:s})=>{let u=[`parlour-site-header`,e].filter(Boolean).join(` `),d=a(),[f,p,m]=l(i,s);return(0,r.jsx)(`header`,{className:u,children:(0,r.jsxs)(t.h,{gap:`normal`,maxWidth:`alignwide`,justify:`space-between`,align:`center`,children:[(0,r.jsx)(`div`,{className:`parlour-site-header__branding`,children:(0,r.jsx)(`p`,{children:(0,r.jsxs)(d,{href:`/`,rel:`home`,children:[f,p&&(0,r.jsx)(`span`,{className:`parlour-site-header__title-accent`,children:p}),m]})})}),(0,r.jsx)(`nav`,{className:`parlour-site-header__nav`,"aria-label":`Primary`,children:(0,r.jsx)(`ul`,{children:c.map(({href:e,label:t})=>(0,r.jsx)(`li`,{children:(0,r.jsx)(d,{href:e,children:t})},e))})}),(0,r.jsx)(`div`,{children:(0,r.jsx)(t.m,{children:(0,r.jsx)(o,{text:`Hire Me`,isSmall:!0,isOutline:!0})})}),n]})})},d=[`github`,`x`,`bluesky`,`linkedin`,`facebook`,`instagram`,`youtube`,`tiktok`],f=({name:e,nameHref:n,year:i=new Date().getFullYear(),text:o,className:s,github:c,x:l,bluesky:u,linkedin:f,facebook:p,instagram:m,youtube:h,tiktok:g,..._})=>{let v=a(),y=[`parlour-site-footer`,s].filter(Boolean).join(` `),b={github:c,x:l,bluesky:u,linkedin:f,facebook:p,instagram:m,youtube:h,tiktok:g},x=d.filter(e=>b[e]);return(0,r.jsx)(`footer`,{className:y,..._,children:(0,r.jsxs)(`div`,{className:`parlour-site-footer__inner`,children:[(0,r.jsxs)(`p`,{className:`parlour-site-footer__copyright`,children:[`© `,i,` `,n?(0,r.jsx)(v,{href:n,children:e}):e]}),o&&(0,r.jsx)(`p`,{className:`parlour-site-footer__text`,children:o}),x.length>0&&(0,r.jsx)(`ul`,{className:`parlour-site-footer__social`,children:x.map(e=>(0,r.jsx)(`li`,{children:(0,r.jsx)(v,{className:`parlour-site-footer__social-link`,href:b[e],rel:`me`,"aria-label":t.p[e].title,children:(0,r.jsx)(t.f,{name:e})})},e))})]})})},p=({children:e,as:n=`div`,backgroundColor:i=`light`,border:o=!0,borderColor:s=`light`,borderRadius:c=`none`,paddingInline:l=`x-large`,paddingBlock:u=`large`,href:d,linkProps:f,className:p,...m})=>{let h=n,g=a(),_=[`parlour-card`,`parlour-card--bg-${t.g[i]}`,o&&`parlour-card--border`,o&&`parlour-card--border-${t.g[s]}`,`parlour-card--radius-${t._[c]}`,`parlour-card--padding-inline-${t.v[l]}`,`parlour-card--padding-block-${t.v[u]}`,d&&`parlour-card--linked`,p].filter(Boolean).join(` `);return d?(0,r.jsx)(h,{className:_,...m,children:(0,r.jsx)(g,{className:`parlour-card__link`,href:d,...f,children:e})}):(0,r.jsx)(h,{className:_,...m,children:e})};Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return p}});
|