bestax-mcp 0.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 +90 -0
- package/data/catalog.json +1869 -0
- package/data/components/Autocomplete.json +604 -0
- package/data/components/Avatar.json +220 -0
- package/data/components/Avatars.json +294 -0
- package/data/components/Badge.json +261 -0
- package/data/components/Block.json +105 -0
- package/data/components/Box.json +157 -0
- package/data/components/Breadcrumb.json +155 -0
- package/data/components/Button.json +599 -0
- package/data/components/Buttons.json +533 -0
- package/data/components/Card.json +506 -0
- package/data/components/Carousel.json +512 -0
- package/data/components/Cell.json +154 -0
- package/data/components/Checkbox.json +176 -0
- package/data/components/Checkboxes.json +240 -0
- package/data/components/Code.json +128 -0
- package/data/components/Collapse.json +218 -0
- package/data/components/Column.json +284 -0
- package/data/components/Columns.json +542 -0
- package/data/components/ConfigProvider.json +16 -0
- package/data/components/Container.json +149 -0
- package/data/components/Content.json +228 -0
- package/data/components/Control.json +484 -0
- package/data/components/DateInput.json +872 -0
- package/data/components/DateTimeInput.json +952 -0
- package/data/components/Delete.json +153 -0
- package/data/components/Dialog.json +285 -0
- package/data/components/Divider.json +68 -0
- package/data/components/Dropdown.json +353 -0
- package/data/components/Emphasis.json +99 -0
- package/data/components/Field.json +539 -0
- package/data/components/Figure.json +143 -0
- package/data/components/File.json +403 -0
- package/data/components/Footer.json +109 -0
- package/data/components/Grid.json +357 -0
- package/data/components/Hero.json +340 -0
- package/data/components/Icon.json +232 -0
- package/data/components/IconText.json +307 -0
- package/data/components/Image.json +166 -0
- package/data/components/Input.json +583 -0
- package/data/components/Level.json +332 -0
- package/data/components/Link.json +154 -0
- package/data/components/LinkButton.json +247 -0
- package/data/components/ListItem.json +101 -0
- package/data/components/Loading.json +323 -0
- package/data/components/Media.json +345 -0
- package/data/components/Menu.json +317 -0
- package/data/components/Message.json +303 -0
- package/data/components/Modal.json +444 -0
- package/data/components/Navbar.json +996 -0
- package/data/components/Notification.json +165 -0
- package/data/components/Numberinput.json +364 -0
- package/data/components/OrderedList.json +189 -0
- package/data/components/Pagination.json +619 -0
- package/data/components/Panel.json +582 -0
- package/data/components/Paragraph.json +107 -0
- package/data/components/Pre.json +114 -0
- package/data/components/Progress.json +137 -0
- package/data/components/Radio.json +164 -0
- package/data/components/Radios.json +240 -0
- package/data/components/Rate.json +466 -0
- package/data/components/Reveal.json +177 -0
- package/data/components/Section.json +123 -0
- package/data/components/Select.json +526 -0
- package/data/components/Sidebar.json +488 -0
- package/data/components/Skeleton.json +162 -0
- package/data/components/Slider.json +534 -0
- package/data/components/Span.json +100 -0
- package/data/components/Steps.json +452 -0
- package/data/components/Strong.json +105 -0
- package/data/components/SubTitle.json +233 -0
- package/data/components/Switch.json +291 -0
- package/data/components/Table.json +490 -0
- package/data/components/Tabs.json +592 -0
- package/data/components/Tag.json +197 -0
- package/data/components/Taginput.json +587 -0
- package/data/components/Tags.json +181 -0
- package/data/components/TextArea.json +483 -0
- package/data/components/Theme.json +65 -0
- package/data/components/TimeInput.json +906 -0
- package/data/components/Title.json +240 -0
- package/data/components/Toast.json +308 -0
- package/data/components/Tooltip.json +212 -0
- package/data/components/UnorderedList.json +149 -0
- package/data/components/Valid value constants.json +16 -0
- package/data/components/classNames.json +65 -0
- package/data/components/useBulmaClasses.json +169 -0
- package/data/components/usePrefixedClassNames.json +25 -0
- package/data/skills/bestax-custom-component/SKILL.md +196 -0
- package/data/skills/bestax-custom-component/examples/stat-card.tsx +105 -0
- package/data/skills/bestax-custom-component/references/api.md +90 -0
- package/data/skills/bestax-custom-component/references/component-catalog.md +149 -0
- package/data/skills/bestax-custom-component/references/library-contributor.md +395 -0
- package/data/skills/bestax-custom-component/references/patterns.md +136 -0
- package/data/skills/bestax-form/SKILL.md +254 -0
- package/data/skills/bestax-form/references/api.md +103 -0
- package/data/skills/bestax-form/references/patterns.md +210 -0
- package/data/skills/bestax-icons/SKILL.md +80 -0
- package/data/skills/bestax-icons/examples/icon-usage.tsx +80 -0
- package/data/skills/bestax-icons/references/icon-libraries.md +131 -0
- package/data/skills/bestax-layout-scaffold/SKILL.md +196 -0
- package/data/skills/bestax-layout-scaffold/examples/app-shell.tsx +86 -0
- package/data/skills/bestax-layout-scaffold/examples/card-grid.tsx +106 -0
- package/data/skills/bestax-layout-scaffold/examples/centered.tsx +56 -0
- package/data/skills/bestax-layout-scaffold/examples/content-page.tsx +90 -0
- package/data/skills/bestax-layout-scaffold/examples/landing.tsx +122 -0
- package/data/skills/bestax-layout-scaffold/references/archetypes.md +246 -0
- package/data/skills/bestax-layout-scaffold/references/layout-components.md +269 -0
- package/data/skills/bestax-migrate/SKILL.md +78 -0
- package/data/skills/bestax-migrate/references/component-map.md +91 -0
- package/data/skills/bestax-migrate/references/css-migration.md +100 -0
- package/data/skills/bestax-migrate/references/prop-map.md +48 -0
- package/data/skills/bestax-migrate/references/unmappables.md +124 -0
- package/data/skills/bestax-optimize/SKILL.md +131 -0
- package/data/skills/bestax-optimize/references/modular-build.md +173 -0
- package/data/skills/bestax-theming/SKILL.md +117 -0
- package/data/skills/bestax-theming/examples/dark-mode.tsx +38 -0
- package/data/skills/bestax-theming/examples/theme-config.tsx +60 -0
- package/data/skills/bestax-theming/references/css-variables.md +466 -0
- package/data/skills/bestax-theming/references/themeable-components.md +119 -0
- package/data/skills.json +148 -0
- package/dist/data.d.ts +131 -0
- package/dist/data.d.ts.map +1 -0
- package/dist/data.js +111 -0
- package/dist/format.d.ts +37 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +178 -0
- package/dist/helper-props.d.ts +57 -0
- package/dist/helper-props.d.ts.map +1 -0
- package/dist/helper-props.js +249 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/search.d.ts +32 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +194 -0
- package/dist/server.d.ts +28 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +616 -0
- package/dist/version.d.ts +29 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +147 -0
- package/package.json +70 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Icons with @allxsmith/bestax-bulma — the canonical patterns.
|
|
2
|
+
//
|
|
3
|
+
// The app must load the icon library itself (bestax ships no icon fonts):
|
|
4
|
+
// here Font Awesome, via `npm install @fortawesome/fontawesome-free` and
|
|
5
|
+
// `import '@fortawesome/fontawesome-free/css/all.min.css';` in main.tsx.
|
|
6
|
+
// Set the library ONCE on ConfigProvider ('fa' | 'mdi' | 'ion' |
|
|
7
|
+
// 'material-icons' | 'material-symbols' — Ionicons is 'ion', NOT 'ionicons');
|
|
8
|
+
// every <Icon> below then omits `library`.
|
|
9
|
+
import React from 'react';
|
|
10
|
+
import {
|
|
11
|
+
ConfigProvider,
|
|
12
|
+
Icon,
|
|
13
|
+
IconText,
|
|
14
|
+
Button,
|
|
15
|
+
Box,
|
|
16
|
+
Title,
|
|
17
|
+
} from '@allxsmith/bestax-bulma';
|
|
18
|
+
|
|
19
|
+
export function IconShowcase() {
|
|
20
|
+
return (
|
|
21
|
+
<ConfigProvider iconLibrary="fa">
|
|
22
|
+
<Box>
|
|
23
|
+
<Title size="5">Meaningful icons carry their own label</Title>
|
|
24
|
+
{/* Standalone icons convey information — give them a descriptive
|
|
25
|
+
ariaLabel (the default is just "icon"). */}
|
|
26
|
+
<Icon
|
|
27
|
+
name="triangle-exclamation"
|
|
28
|
+
textColor="warning"
|
|
29
|
+
ariaLabel="Warning"
|
|
30
|
+
/>
|
|
31
|
+
<Icon name="circle-check" textColor="success" ariaLabel="Success" />
|
|
32
|
+
|
|
33
|
+
<Title size="5" mt="4">
|
|
34
|
+
Decorative icons hide from screen readers
|
|
35
|
+
</Title>
|
|
36
|
+
{/* Next to visible text the icon repeats the message — aria-hidden
|
|
37
|
+
stops "icon" (or a duplicate) being announced. */}
|
|
38
|
+
<IconText iconProps={{ name: 'star', 'aria-hidden': 'true' }}>
|
|
39
|
+
Starred
|
|
40
|
+
</IconText>
|
|
41
|
+
<Button color="primary">
|
|
42
|
+
<Icon name="floppy-disk" aria-hidden="true" />
|
|
43
|
+
<span>Save</span>
|
|
44
|
+
</Button>
|
|
45
|
+
|
|
46
|
+
<Title size="5" mt="4">
|
|
47
|
+
Sizes, variants, features, color
|
|
48
|
+
</Title>
|
|
49
|
+
{/* `size` sizes the Bulma container; `features` scales the glyph. */}
|
|
50
|
+
<Icon name="rocket" size="large" features="fa-2x" ariaLabel="Launch" />
|
|
51
|
+
{/* Font Awesome styles come from `variant`; brands require it. */}
|
|
52
|
+
<Icon name="bell" variant="regular" ariaLabel="Notifications" />
|
|
53
|
+
<Icon name="github" variant="brands" ariaLabel="GitHub" />
|
|
54
|
+
{/* Spin + color via features and the textColor helper. */}
|
|
55
|
+
<Icon
|
|
56
|
+
name="spinner"
|
|
57
|
+
features="fa-spin"
|
|
58
|
+
textColor="info"
|
|
59
|
+
ariaLabel="Loading"
|
|
60
|
+
/>
|
|
61
|
+
|
|
62
|
+
<Title size="5" mt="4">
|
|
63
|
+
Multi-segment icon text
|
|
64
|
+
</Title>
|
|
65
|
+
<IconText
|
|
66
|
+
items={[
|
|
67
|
+
{
|
|
68
|
+
iconProps: { name: 'train', 'aria-hidden': 'true' },
|
|
69
|
+
text: 'Metro',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
iconProps: { name: 'arrow-right', 'aria-hidden': 'true' },
|
|
73
|
+
text: 'Airport',
|
|
74
|
+
},
|
|
75
|
+
]}
|
|
76
|
+
/>
|
|
77
|
+
</Box>
|
|
78
|
+
</ConfigProvider>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Icon libraries — setup, names, variants, troubleshooting
|
|
2
|
+
|
|
3
|
+
Facts an agent can act on for each of the five libraries `Icon` supports. The library ships no
|
|
4
|
+
icon fonts: the app must install the chosen library (the `npm create bestax` scaffold's
|
|
5
|
+
`--icon` flag does this; in an existing app, follow Setup below).
|
|
6
|
+
|
|
7
|
+
## How `Icon` renders
|
|
8
|
+
|
|
9
|
+
- `fa` / `mdi` — an `<i>` with CSS classes (`fas fa-rocket`, `mdi mdi-rocket-launch`).
|
|
10
|
+
- `material-icons` / `material-symbols` — an `<i>` whose **text content** is the name
|
|
11
|
+
(a font ligature): `<i class="material-icons">rocket_launch</i>`. That's why these names are
|
|
12
|
+
snake_case — they are literal text, not class names.
|
|
13
|
+
- `ion` — the `<ion-icon>` web component: `<ion-icon name="rocket-outline" />`.
|
|
14
|
+
|
|
15
|
+
The resolution order for the library is `library` prop → `ConfigProvider iconLibrary` → `'fa'`.
|
|
16
|
+
Set it once on `ConfigProvider` and omit `library` everywhere else.
|
|
17
|
+
|
|
18
|
+
## Font Awesome — `'fa'` (the default)
|
|
19
|
+
|
|
20
|
+
- **Setup:** `npm install @fortawesome/fontawesome-free` and
|
|
21
|
+
`import '@fortawesome/fontawesome-free/css/all.min.css';` once (e.g. `main.tsx`).
|
|
22
|
+
- **Scaffold flag:** `--icon fontawesome`.
|
|
23
|
+
- **Names:** kebab-case without the `fa-` prefix: `rocket`, `circle-check`, `magnifying-glass`.
|
|
24
|
+
A leading `fa-` in `name` is stripped automatically (so `fa-rocket` also works), but write
|
|
25
|
+
the bare name.
|
|
26
|
+
- **Variants** (`variant` → class): `solid` → `fas` (default), `regular` → `far`, `brands` →
|
|
27
|
+
`fab`, `light` → `fal`, `duotone` → `fad`, `thin` → `fat`. The free package includes only
|
|
28
|
+
solid, regular (partial), and brands — light/duotone/thin need a Font Awesome Pro kit.
|
|
29
|
+
- **Features:** Font Awesome utility classes — `'fa-lg'`, `'fa-2x'`…`'fa-10x'`, `'fa-spin'`,
|
|
30
|
+
`'fa-pulse'`, `'fa-border'`, `'fa-fw'`, `'fa-flip-horizontal'`, `'fa-rotate-90'`.
|
|
31
|
+
- Brand icons **require** `variant="brands"`: `<Icon name="github" variant="brands" />`.
|
|
32
|
+
|
|
33
|
+
## Material Design Icons — `'mdi'`
|
|
34
|
+
|
|
35
|
+
- **Setup:** `npm install @mdi/font` and
|
|
36
|
+
`import '@mdi/font/css/materialdesignicons.min.css';`.
|
|
37
|
+
- **Scaffold flag:** `--icon mdi`.
|
|
38
|
+
- **Names:** kebab-case without the `mdi-` prefix: `account`, `rocket-launch`,
|
|
39
|
+
`home-outline`. A leading `mdi-` is stripped automatically. Outline/off styles are part of
|
|
40
|
+
the **name** (`home-outline`, `bell-off`), not a variant.
|
|
41
|
+
- **Variants:** none — `variant` is ignored for MDI.
|
|
42
|
+
- **Features:** MDI helpers (`'mdi-24px'`, `'mdi-48px'`, `'mdi-spin'`, `'mdi-rotate-90'`) or
|
|
43
|
+
Bulma text-size classes (`'is-size-3'`).
|
|
44
|
+
|
|
45
|
+
## Ionicons — `'ion'` ⚠️ value is `ion`, not `ionicons`
|
|
46
|
+
|
|
47
|
+
- **Setup:** a CDN script pair in `index.html` (no npm package — it registers the
|
|
48
|
+
`<ion-icon>` web component):
|
|
49
|
+
|
|
50
|
+
```html
|
|
51
|
+
<script
|
|
52
|
+
type="module"
|
|
53
|
+
src="https://unpkg.com/ionicons@8.0.13/dist/ionicons/ionicons.esm.js"
|
|
54
|
+
></script>
|
|
55
|
+
<script
|
|
56
|
+
nomodule
|
|
57
|
+
src="https://unpkg.com/ionicons@8.0.13/dist/ionicons/ionicons.js"
|
|
58
|
+
></script>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
- **Scaffold flag:** `--icon ionicons` — which maps to `iconLibrary="ion"`. Passing
|
|
62
|
+
`'ionicons'` as the `library`/`iconLibrary` value renders nothing.
|
|
63
|
+
- **Names:** kebab-case: `rocket`, `heart`, `settings`.
|
|
64
|
+
- **Variants:** `outline` and `sharp` — appended to the name (`variant="outline"` +
|
|
65
|
+
`name="heart"` renders `<ion-icon name="heart-outline">`). Omit for the filled default.
|
|
66
|
+
- **Features:** not applicable (web component, not classes); size the container with `size`
|
|
67
|
+
or style via CSS.
|
|
68
|
+
|
|
69
|
+
## Google Material Icons — `'material-icons'`
|
|
70
|
+
|
|
71
|
+
- **Setup:** `npm install material-icons` and `import 'material-icons';`.
|
|
72
|
+
- **Scaffold flag:** `--icon material-icons`.
|
|
73
|
+
- **Names:** snake_case ligature text: `home`, `rocket_launch`, `shopping_cart`. A kebab-case
|
|
74
|
+
name will not match a ligature and renders as raw text.
|
|
75
|
+
- **Variants:** `filled` (default) / `outlined` / `round` / `sharp` — note **`round`**, not
|
|
76
|
+
`rounded`.
|
|
77
|
+
- **Features:** Bulma classes like `'is-size-1'` (the font scales with text size).
|
|
78
|
+
|
|
79
|
+
## Material Symbols — `'material-symbols'`
|
|
80
|
+
|
|
81
|
+
- **Setup:** `npm install material-symbols` and `import 'material-symbols';`.
|
|
82
|
+
- **Scaffold flag:** `--icon material-symbols`.
|
|
83
|
+
- **Names:** snake_case ligature text, same as Material Icons: `rocket_launch`.
|
|
84
|
+
- **Variants:** `outlined` (default) / `rounded` / `sharp` — note **`rounded`** here vs
|
|
85
|
+
Material Icons' `round`.
|
|
86
|
+
- **Features:** Bulma classes like `'is-size-1'`.
|
|
87
|
+
|
|
88
|
+
## One glyph, five names
|
|
89
|
+
|
|
90
|
+
| Glyph | fa | mdi | ion | material-icons / material-symbols |
|
|
91
|
+
| -------- | ------------------ | --------------- | ---------- | --------------------------------- |
|
|
92
|
+
| Rocket | `rocket` | `rocket-launch` | `rocket` | `rocket_launch` |
|
|
93
|
+
| Home | `house` / `home` | `home` | `home` | `home` |
|
|
94
|
+
| Settings | `gear` | `cog` | `settings` | `settings` |
|
|
95
|
+
| Search | `magnifying-glass` | `magnify` | `search` | `search` |
|
|
96
|
+
|
|
97
|
+
## Blank icon? Check in this order
|
|
98
|
+
|
|
99
|
+
1. **Library value** — `'ion'` not `'ionicons'`; the five valid values are `fa`, `mdi`,
|
|
100
|
+
`ion`, `material-icons`, `material-symbols`.
|
|
101
|
+
2. **Name format for that library** — kebab vs snake_case (see the table above); for
|
|
102
|
+
material-* a wrong name renders as literal text instead of a glyph.
|
|
103
|
+
3. **The library's CSS/script is actually loaded** — the import in `main.tsx` (or the
|
|
104
|
+
Ionicons scripts in `index.html`) must exist; bestax ships none of them.
|
|
105
|
+
4. **Variant availability** — Font Awesome free has no `light`/`duotone`/`thin`; brand
|
|
106
|
+
glyphs need `variant="brands"`.
|
|
107
|
+
|
|
108
|
+
## IconText
|
|
109
|
+
|
|
110
|
+
Pairs icon(s) with text inside a Bulma `icon-text` container. Single icon:
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
<IconText iconProps={{ name: 'check', 'aria-hidden': 'true' }}>Saved</IconText>
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Multiple segments via `items`:
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
<IconText
|
|
120
|
+
items={[
|
|
121
|
+
{ iconProps: { name: 'train', 'aria-hidden': 'true' }, text: 'Metro' },
|
|
122
|
+
{
|
|
123
|
+
iconProps: { name: 'arrow-right', 'aria-hidden': 'true' },
|
|
124
|
+
text: 'Airport',
|
|
125
|
+
},
|
|
126
|
+
]}
|
|
127
|
+
/>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Icons inside `IconText` sit next to their visible text — mark them decorative with
|
|
131
|
+
`aria-hidden` (see SKILL.md's accessibility rules).
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bestax-layout-scaffold
|
|
3
|
+
description: Scaffold a complete, responsive page layout with @allxsmith/bestax-bulma — app shells/dashboards, marketing/landing pages, centered auth/settings pages, and card-grid catalogs. Use when building a full page or overall app layout (not a single component).
|
|
4
|
+
license: MIT
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Scaffolding a page layout with @allxsmith/bestax-bulma
|
|
8
|
+
|
|
9
|
+
Turn a high-level request ("admin dashboard", "landing page", "login screen", "product catalog")
|
|
10
|
+
into a complete responsive page built from bestax-bulma layout components.
|
|
11
|
+
|
|
12
|
+
## Behavioral rule
|
|
13
|
+
|
|
14
|
+
Select an archetype from the request and build it in one shot. Do **not** ask layout questions
|
|
15
|
+
("how many columns?", "where should the nav go?", "what width?") — infer the structure from the
|
|
16
|
+
request and proceed. The archetype determines the structure; fill it with the requested content.
|
|
17
|
+
|
|
18
|
+
Ask **at most one** clarifying question, and only for a high-level fork the request genuinely does
|
|
19
|
+
not imply: whether the page is **public-facing** (marketing) or an **internal tool** (authenticated
|
|
20
|
+
app). When the request already signals this ("dashboard", "admin", "landing", "login", "pricing"),
|
|
21
|
+
skip the question and default.
|
|
22
|
+
|
|
23
|
+
## Select an archetype
|
|
24
|
+
|
|
25
|
+
| Request signals | Archetype |
|
|
26
|
+
| ---------------------------------------------------------------------- | ------------- |
|
|
27
|
+
| dashboard, admin, console, internal tool, authenticated app, "sidebar" | **App shell** |
|
|
28
|
+
| landing, marketing, homepage, product/pricing page, public site | **Landing** |
|
|
29
|
+
| login, sign up, auth, settings, checkout, a single focused form | **Centered** |
|
|
30
|
+
| catalog, gallery, products, listing, "grid of cards", search results | **Card grid** |
|
|
31
|
+
|
|
32
|
+
Default when ambiguous: internal tool → App shell; public-facing → Landing; one focused task →
|
|
33
|
+
Centered; a collection of items → Card grid. For mixed requests, pick the dominant intent (e.g.
|
|
34
|
+
"admin dashboard with a product list" → App shell whose main column holds a Card grid).
|
|
35
|
+
|
|
36
|
+
## Approach
|
|
37
|
+
|
|
38
|
+
- Compose pages from the shipped layout components — `Container`, `Section`, `Hero`, `Footer`,
|
|
39
|
+
`Level`, `Columns`/`Column`, `Grid`/`Cell`, `Navbar`, `Menu`, `Card`. There is **no `Tile`
|
|
40
|
+
component**. For **uniform grids** (card grids, galleries — same-shaped items) prefer
|
|
41
|
+
`Grid`/`Cell`: CSS Grid gives equal-height cells for free (per row — each row's cells match
|
|
42
|
+
its tallest, same row-level behavior as the flex recipe). Use `Columns`/`Column` for
|
|
43
|
+
proportional or per-breakpoint column layouts — and when cards there must be equal height,
|
|
44
|
+
apply the flex recipe (`Column display="flex" flexDirection="column"` + `Card flexGrow="1"`;
|
|
45
|
+
`height: 100%` on the card doesn't help — the column's height is auto).
|
|
46
|
+
- Rely on Bulma's responsive defaults: `Columns` sit side by side on tablet and up and stack on
|
|
47
|
+
mobile. Add responsive `size*` props only to tune the breakpoints.
|
|
48
|
+
- Interactive extras don't share a state API — never transfer one by analogy:
|
|
49
|
+
`Collapse trigger={node} open/defaultOpen onOpen/onClose`, `Tabs value={i}/onChange`
|
|
50
|
+
(each `Tabs.Tab`/`Tabs.Content.Item` requires `index={i}`, and `Tabs.Content` must be a
|
|
51
|
+
**child of `<Tabs>`** — the active-tab context lives on it; a sibling panel never
|
|
52
|
+
switches), `Dropdown active/onActiveChange`,
|
|
53
|
+
`Steps value={i}/onStepClick items={[{label, icon?}]}` (child form is `Steps.Step`, not
|
|
54
|
+
`Steps.Item`). `Reveal cascade` staggers only its **direct children** — to stagger a grid,
|
|
55
|
+
put `<Reveal delay={i * 80}>` inside each `Cell`, not around the container.
|
|
56
|
+
- Link lists (footer nav, sidebars): a bare `UnorderedList` of `ListItem`s is already
|
|
57
|
+
marker-less and flush — Bulma's reset unstyles `ul` — so no prop or CSS is needed;
|
|
58
|
+
bullets appear only inside `Content`.
|
|
59
|
+
- `Navbar.Burger`/`Navbar.Menu` are **controlled** — wire the same `active` state to both:
|
|
60
|
+
`active` on `Navbar.Menu` shows/hides the mobile menu, while `active` + `onClick` on
|
|
61
|
+
`Navbar.Burger` make the burger toggle it and animate. Left unwired, clicking the burger
|
|
62
|
+
does nothing (no error, silent failure). For a `fixed="top"` `Navbar`, add the
|
|
63
|
+
`has-navbar-fixed-top` class to `<html>` so content is not hidden behind it — the library
|
|
64
|
+
does not do this automatically, and an inline padding offset is not a substitute.
|
|
65
|
+
- **Style with helper props — no inline `style`, no raw Bulma `className`s.** Before writing
|
|
66
|
+
`style={{ … }}` anywhere, translate each declaration with the mapping table below — the helper
|
|
67
|
+
props cover the common cases. Bare markup has wrapper elements that take all
|
|
68
|
+
helper props: `<Span textSize="7" textColor="grey">`, `Paragraph`, `Strong` — never a raw
|
|
69
|
+
`<span className="is-size-7 has-text-grey">`. Table cells: `Th`/`Td` take `textAlign="right"`,
|
|
70
|
+
`textWeight`, `textSize` directly (their `color` prop colors the cell; for muted cell text
|
|
71
|
+
wrap content in `Span textColor="grey"`). Set the app-wide icon library once with
|
|
72
|
+
`<ConfigProvider iconLibrary="…">` at the root rather than `library` on every `<Icon>`.
|
|
73
|
+
- **Decorative CSS is budgeted: three compact rules, ≤13 lines per app — comments count:
|
|
74
|
+
at most one short inline note, never a file-header comment block — every value derived
|
|
75
|
+
from `--bulma-*`.** A marketing page gets at most one hero wash, one alternating section
|
|
76
|
+
band, and one featured-card ring, applied via `className` — no resets (Bulma ships one;
|
|
77
|
+
body/list margins are already zero) and no grid textures, masks, or multi-layer backdrops;
|
|
78
|
+
the components carry the design:
|
|
79
|
+
|
|
80
|
+
```css
|
|
81
|
+
.hero-wash {
|
|
82
|
+
background-image: radial-gradient(
|
|
83
|
+
60rem 30rem at 20% -10%,
|
|
84
|
+
hsl(var(--bulma-primary-h) var(--bulma-primary-s) 50% / 0.2),
|
|
85
|
+
transparent 60%
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
.section-alt {
|
|
89
|
+
background: var(--bulma-scheme-main-bis); /* next band: -ter */
|
|
90
|
+
}
|
|
91
|
+
.featured-ring {
|
|
92
|
+
--bulma-shadow: 0 0 0 2px var(--bulma-primary);
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The ring works by overriding the **upstream token**, not the component's own var: `.card`
|
|
97
|
+
and `.box` re-declare `--bulma-card-shadow`/`--bulma-box-shadow` from `--bulma-shadow` on
|
|
98
|
+
their own selector, so setting _those_ from an ancestor never wins (same for
|
|
99
|
+
`--bulma-box-radius`; `--bulma-card-radius` is a literal with no ancestor route at all).
|
|
100
|
+
It has to be a CSS rule rather than `<Theme bulmaVars={{ '--bulma-shadow': … }}>`, because
|
|
101
|
+
`bulmaVars` is a closed typed record and `--bulma-shadow` is not one of its keys — that
|
|
102
|
+
exact call **does not compile**, and it was the single most repeated invention across this
|
|
103
|
+
library's cold-start evals. Either way the subtree stays theme- and dark-mode-aware.
|
|
104
|
+
|
|
105
|
+
- **CTAs on a colored hero must stay legible in both schemes.** On a fixed-color surface
|
|
106
|
+
(`Hero color="primary"`, a dark banner), use **filled** buttons — `color="light"` or
|
|
107
|
+
`color="primary" isInverted` — never a thin `isOutlined` secondary: a light outline + light
|
|
108
|
+
label on a dark surface is low-contrast and gets worse under OS dark mode. And when the page's
|
|
109
|
+
design is single-mode (a fixed light or dark look), pin it at the root —
|
|
110
|
+
`<Theme isRoot colorMode="light">` — so a visitor's OS dark mode can't flip Bulma's text
|
|
111
|
+
colors out from under the fixed palette (details: the `bestax-theming` skill's contrast rules).
|
|
112
|
+
|
|
113
|
+
## Three components core Bulma will talk you out of
|
|
114
|
+
|
|
115
|
+
Most of this library's additions get found on their own, because nothing in Bulma does the
|
|
116
|
+
job. These three do not: each has a Bulma near-miss close enough to stop the search. Across
|
|
117
|
+
44 cold-start builds, `Dialog` was used **zero** times and `LinkButton` in two thirds — and
|
|
118
|
+
every miss shipped the "not this" column instead.
|
|
119
|
+
|
|
120
|
+
| You need | Use | Not this |
|
|
121
|
+
| ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
122
|
+
| A brief confirmation after an action, self-dismissing | `Toast` — mount `<ToastContainer position="top-right" />` once at the app root, then `toast.success('Saved')` (also `.danger`/`.warning`/`.info`) from anywhere | `Notification`/`Message` — static page elements you have to place, position and dismiss yourself |
|
|
123
|
+
| A confirm or alert the user must answer before anything | `Dialog` — mount `<DialogContainer />` at the root, then `if (await dialog.confirm({ title, message })) …` | `Modal` — an empty shell; the title, message, button row and confirm/cancel wiring are all yours to rebuild |
|
|
124
|
+
| A control that reads as text or a link but _does_ something | `LinkButton` (`variant="text" \| "ghost" \| "underline"`, optional `color`) | `<a href="#">`/`<div onClick>` (no keyboard or screen-reader support) or `Button color="text"` (still button-shaped) |
|
|
125
|
+
|
|
126
|
+
Mounting a container without ever calling `toast.*`/`dialog.*` is not usage — the container is
|
|
127
|
+
the mount point, the imperative call is the thing that shows something. Both also work as
|
|
128
|
+
ordinary controlled components when you would rather hold the state yourself —
|
|
129
|
+
`<Toast message … duration onClose>`, `<Dialog isOpen title message type onConfirm onCancel>` —
|
|
130
|
+
but in an app with more than one call site the root container plus the imperative helper is
|
|
131
|
+
less wiring, not more.
|
|
132
|
+
|
|
133
|
+
## Inline style → helper prop mapping
|
|
134
|
+
|
|
135
|
+
Look up the declaration you were about to inline. The spacing, typography, and flex helpers
|
|
136
|
+
below are on every component; `textColor`/`bgColor` are on the content components you'll
|
|
137
|
+
target (`Box`, `Block`, `Title`, `Content`, `Hero`, `Card`, …) — the ones with a semantic
|
|
138
|
+
`color` variant (`Tag`, `Tabs`, `Panel`) take `color` instead; wrap content in a `Block` if
|
|
139
|
+
you need a text color there. `Notification` is the mixed case: it takes `textColor`, but its
|
|
140
|
+
background comes from the semantic `color` prop, not `bgColor`.
|
|
141
|
+
|
|
142
|
+
| Inline style you're about to write | Helper props instead |
|
|
143
|
+
| ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
144
|
+
| `marginTop: '1rem'` (any margin/padding) | `mt="4"` — `m`/`mt`/`mx`/`p`/`py`/… scale: `1`=0.25rem, `2`=0.5rem, `3`=0.75rem, `4`=1rem, `5`=1.5rem, `6`=3rem (nearest step) |
|
|
145
|
+
| `textAlign: 'center'` | `textAlign="centered"` (also `left`, `right`, `justified`) |
|
|
146
|
+
| `color: '#…'` | `textColor` with the nearest Bulma color: `primary`, `link`, `info`, `success`, `warning`, `danger`, `white`, `black`, `grey` (+ `grey-light`, `grey-dark`, …) |
|
|
147
|
+
| `backgroundColor: '#…'` | `bgColor` (same palette) |
|
|
148
|
+
| `fontSize: …` | `textSize="1"`…`"7"` (`1` largest) — for headings use `Title`/`SubTitle` `size` |
|
|
149
|
+
| `fontWeight: …` | `textWeight`: `light`, `normal`, `medium`, `semibold`, `bold` |
|
|
150
|
+
| `textTransform`, italics | `textTransform`: `uppercase`, `lowercase`, `capitalized`, `italic` |
|
|
151
|
+
| `display: 'flex'` + flex properties | same-named props: `display="flex"`, `flexDirection`, `justifyContent`, `alignItems`, `flexWrap` |
|
|
152
|
+
| `height: '100%'` on a flex child | `flexGrow="1"` |
|
|
153
|
+
| `display: 'none'` | `visibility="hidden"`, or responsive `display*` props (`displayMobile`, `displayTablet`, …) |
|
|
154
|
+
| `gap: …` in a flex layout | no `gap` helper exists — space children with `m*` margins; `Grid` and `Columns` take a `gap` prop, so prefer those there |
|
|
155
|
+
|
|
156
|
+
No helper matches (e.g. `maxWidth`, a one-off gradient)? Add a named class to the project
|
|
157
|
+
stylesheet (`src/App.css` in a scaffolded app) and pass it via `className` — still never
|
|
158
|
+
inline `style`.
|
|
159
|
+
|
|
160
|
+
## References
|
|
161
|
+
|
|
162
|
+
- `references/layout-components.md` — the layout component inventory: real prop names, types, and
|
|
163
|
+
accepted values, plus subcomponent nesting.
|
|
164
|
+
- `references/archetypes.md` — the four archetypes: selection criteria, JSX skeleton, and responsive
|
|
165
|
+
behavior.
|
|
166
|
+
|
|
167
|
+
## Examples
|
|
168
|
+
|
|
169
|
+
- `examples/app-shell.tsx` — fixed `Navbar` + sidebar `Menu` + content (dashboard).
|
|
170
|
+
- `examples/landing.tsx` — fixed `Navbar` (controlled burger) + `Hero` + `Section`s + `Footer`.
|
|
171
|
+
- `examples/centered.tsx` — centered single column (auth/settings).
|
|
172
|
+
- `examples/card-grid.tsx` — multiline `Columns` of `Card`s (catalog).
|
|
173
|
+
- `examples/content-page.tsx` — hero + feature cards + CTA styled with helper props (no inline
|
|
174
|
+
`style`), wrapped in `ConfigProvider`.
|
|
175
|
+
|
|
176
|
+
## Checklist
|
|
177
|
+
|
|
178
|
+
- [ ] Map the request to one archetype; do not ask layout questions.
|
|
179
|
+
- [ ] Wrap page content in `Container` (+ `Section` for vertical rhythm).
|
|
180
|
+
- [ ] Use `Grid`/`Cell` for uniform grids (equal heights per row, free); `Columns`/`Column`
|
|
181
|
+
for proportional or per-breakpoint side-by-side layout — with the flex recipe when its
|
|
182
|
+
cards must match height.
|
|
183
|
+
- [ ] Wire `active` state to **both** `Navbar.Burger` and `Navbar.Menu` (they are controlled).
|
|
184
|
+
- [ ] For a fixed navbar, add `has-navbar-fixed-top` to `<html>`.
|
|
185
|
+
- [ ] Do not use `Tile` — it is not shipped.
|
|
186
|
+
- [ ] Action feedback goes through `Toast`, a confirmation through `Dialog`, a text-styled
|
|
187
|
+
action through `LinkButton` — not `Notification`, `Modal` or a bare `<a>`.
|
|
188
|
+
- [ ] Style with helper props, not inline `style` — translate via the mapping table; values
|
|
189
|
+
with no helper get a named class in the stylesheet, never `style={{}}`. No raw Bulma
|
|
190
|
+
`className`s either (`Span`/`Paragraph` wrap bare text; `Th`/`Td` take `textAlign`/`textWeight`).
|
|
191
|
+
- [ ] Decorative CSS ≤13 lines total incl. comments — no file-header comment (hero wash +
|
|
192
|
+
section band + featured-card ring), `--bulma-*`-derived; no resets — Bulma ships one.
|
|
193
|
+
The ring sets `--bulma-shadow` in a CSS rule; `Theme bulmaVars` has no such key.
|
|
194
|
+
- [ ] Set the icon library once via `<ConfigProvider iconLibrary="…">` at the root.
|
|
195
|
+
- [ ] Site built? ~800 KB raw / ~82 KB gzip CSS is the expected default-flavor size — to shrink
|
|
196
|
+
it, run the `bestax-optimize` skill (measure first).
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// App shell with sidebar — fixed top Navbar + a narrow Menu column beside the
|
|
2
|
+
// main content. The admin/dashboard default.
|
|
3
|
+
//
|
|
4
|
+
// A fixed-top navbar needs the `has-navbar-fixed-top` class on <html> so the page
|
|
5
|
+
// is padded below it — Bulma requires this and the library does NOT add it for
|
|
6
|
+
// you. In a real app set it statically in index.html; the useEffect below is the
|
|
7
|
+
// fallback for a conditionally-mounted navbar (and keeps this file self-contained).
|
|
8
|
+
// The columns sit side by side on tablet and up, and stack (menu above
|
|
9
|
+
// content) on mobile.
|
|
10
|
+
//
|
|
11
|
+
// `ConfigProvider` wraps the shell once at the root to set the app-wide icon
|
|
12
|
+
// library (so <Icon> needs no `library` prop) and, optionally, a class prefix.
|
|
13
|
+
import React, { useEffect, useState } from 'react';
|
|
14
|
+
import {
|
|
15
|
+
ConfigProvider,
|
|
16
|
+
Navbar,
|
|
17
|
+
Menu,
|
|
18
|
+
Container,
|
|
19
|
+
Columns,
|
|
20
|
+
Column,
|
|
21
|
+
Section,
|
|
22
|
+
Title,
|
|
23
|
+
Box,
|
|
24
|
+
} from '@allxsmith/bestax-bulma';
|
|
25
|
+
|
|
26
|
+
export default function AdminShell() {
|
|
27
|
+
const [menuOpen, setMenuOpen] = useState(false);
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
document.documentElement.classList.add('has-navbar-fixed-top');
|
|
31
|
+
return () => {
|
|
32
|
+
document.documentElement.classList.remove('has-navbar-fixed-top');
|
|
33
|
+
};
|
|
34
|
+
}, []);
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<ConfigProvider iconLibrary="fa">
|
|
38
|
+
<Navbar fixed="top" color="dark">
|
|
39
|
+
<Navbar.Brand>
|
|
40
|
+
<Navbar.Item href="#">Acme Admin</Navbar.Item>
|
|
41
|
+
<Navbar.Burger
|
|
42
|
+
active={menuOpen}
|
|
43
|
+
onClick={() => setMenuOpen(open => !open)}
|
|
44
|
+
aria-label="menu"
|
|
45
|
+
aria-expanded={menuOpen}
|
|
46
|
+
/>
|
|
47
|
+
</Navbar.Brand>
|
|
48
|
+
<Navbar.Menu active={menuOpen}>
|
|
49
|
+
<Navbar.End>
|
|
50
|
+
<Navbar.Item href="#">Docs</Navbar.Item>
|
|
51
|
+
<Navbar.Item href="#">Account</Navbar.Item>
|
|
52
|
+
</Navbar.End>
|
|
53
|
+
</Navbar.Menu>
|
|
54
|
+
</Navbar>
|
|
55
|
+
|
|
56
|
+
<Container fluid>
|
|
57
|
+
<Columns>
|
|
58
|
+
<Column size={3} sizeWidescreen={2}>
|
|
59
|
+
<Menu>
|
|
60
|
+
<Menu.Label>General</Menu.Label>
|
|
61
|
+
<Menu.List>
|
|
62
|
+
<Menu.Item active href="#">
|
|
63
|
+
Dashboard
|
|
64
|
+
</Menu.Item>
|
|
65
|
+
<Menu.Item href="#">Customers</Menu.Item>
|
|
66
|
+
<Menu.Item href="#">Orders</Menu.Item>
|
|
67
|
+
</Menu.List>
|
|
68
|
+
<Menu.Label>Admin</Menu.Label>
|
|
69
|
+
<Menu.List>
|
|
70
|
+
<Menu.Item href="#">Team</Menu.Item>
|
|
71
|
+
<Menu.Item href="#">Settings</Menu.Item>
|
|
72
|
+
</Menu.List>
|
|
73
|
+
</Menu>
|
|
74
|
+
</Column>
|
|
75
|
+
|
|
76
|
+
<Column>
|
|
77
|
+
<Section>
|
|
78
|
+
<Title size="3">Dashboard</Title>
|
|
79
|
+
<Box>Main content area — drop dashboard widgets here.</Box>
|
|
80
|
+
</Section>
|
|
81
|
+
</Column>
|
|
82
|
+
</Columns>
|
|
83
|
+
</Container>
|
|
84
|
+
</ConfigProvider>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// Card grid / catalog page — a collection of similar items.
|
|
2
|
+
// `<Columns isMultiline>` wraps cards onto new rows; the responsive column sizes
|
|
3
|
+
// give 1 card per row on mobile, 2 on tablet, 3 on desktop.
|
|
4
|
+
// Equal heights: each Column is a flex container and its Card grows to fill
|
|
5
|
+
// it (flexGrow="1"), so short blurbs don't leave ragged card bottoms.
|
|
6
|
+
// (`height: 100%` on the card would NOT work — it resolves against auto
|
|
7
|
+
// height. For uniform grids, Grid/Cell gives equal heights for free.)
|
|
8
|
+
import React from 'react';
|
|
9
|
+
import {
|
|
10
|
+
Section,
|
|
11
|
+
Container,
|
|
12
|
+
Title,
|
|
13
|
+
Columns,
|
|
14
|
+
Column,
|
|
15
|
+
Card,
|
|
16
|
+
} from '@allxsmith/bestax-bulma';
|
|
17
|
+
|
|
18
|
+
interface Product {
|
|
19
|
+
id: number;
|
|
20
|
+
name: string;
|
|
21
|
+
price: string;
|
|
22
|
+
image: string;
|
|
23
|
+
blurb: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const PRODUCTS: Product[] = [
|
|
27
|
+
{
|
|
28
|
+
id: 1,
|
|
29
|
+
name: 'Aurora Lamp',
|
|
30
|
+
price: '$48',
|
|
31
|
+
image: 'https://picsum.photos/seed/1/600/400',
|
|
32
|
+
blurb: 'Warm ambient light.',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: 2,
|
|
36
|
+
name: 'Drift Chair',
|
|
37
|
+
price: '$220',
|
|
38
|
+
image: 'https://picsum.photos/seed/2/600/400',
|
|
39
|
+
blurb: 'Ergonomic and airy.',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
id: 3,
|
|
43
|
+
name: 'Stone Mug',
|
|
44
|
+
price: '$18',
|
|
45
|
+
image: 'https://picsum.photos/seed/3/600/400',
|
|
46
|
+
blurb: 'Hand-thrown ceramic.',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: 4,
|
|
50
|
+
name: 'Field Notebook',
|
|
51
|
+
price: '$12',
|
|
52
|
+
image: 'https://picsum.photos/seed/4/600/400',
|
|
53
|
+
blurb: 'Pocket-sized, lined.',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: 5,
|
|
57
|
+
name: 'Trail Bottle',
|
|
58
|
+
price: '$26',
|
|
59
|
+
image: 'https://picsum.photos/seed/5/600/400',
|
|
60
|
+
blurb: 'Insulated steel.',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
id: 6,
|
|
64
|
+
name: 'Linen Throw',
|
|
65
|
+
price: '$64',
|
|
66
|
+
image: 'https://picsum.photos/seed/6/600/400',
|
|
67
|
+
blurb: 'Soft, breathable.',
|
|
68
|
+
},
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
export default function CatalogPage() {
|
|
72
|
+
return (
|
|
73
|
+
<Section>
|
|
74
|
+
<Container>
|
|
75
|
+
<Title size="3" mb="5">
|
|
76
|
+
Catalog
|
|
77
|
+
</Title>
|
|
78
|
+
<Columns isMultiline>
|
|
79
|
+
{PRODUCTS.map(product => (
|
|
80
|
+
<Column
|
|
81
|
+
key={product.id}
|
|
82
|
+
sizeMobile="full"
|
|
83
|
+
sizeTablet="half"
|
|
84
|
+
sizeDesktop="one-third"
|
|
85
|
+
display="flex"
|
|
86
|
+
flexDirection="column"
|
|
87
|
+
>
|
|
88
|
+
<Card
|
|
89
|
+
flexGrow="1"
|
|
90
|
+
image={product.image}
|
|
91
|
+
imageAlt={product.name}
|
|
92
|
+
header={product.name}
|
|
93
|
+
// Card wraps each footer item in .card-footer-item itself —
|
|
94
|
+
// no raw span/className needed (and a literal class would
|
|
95
|
+
// break under ConfigProvider classPrefix).
|
|
96
|
+
footer={product.price}
|
|
97
|
+
>
|
|
98
|
+
<p>{product.blurb}</p>
|
|
99
|
+
</Card>
|
|
100
|
+
</Column>
|
|
101
|
+
))}
|
|
102
|
+
</Columns>
|
|
103
|
+
</Container>
|
|
104
|
+
</Section>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Centered single-column page — auth, settings, focused forms.
|
|
2
|
+
// A narrow column is centered with `<Columns isCentered>`; on mobile the column
|
|
3
|
+
// becomes full width automatically.
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import {
|
|
6
|
+
Section,
|
|
7
|
+
Container,
|
|
8
|
+
Columns,
|
|
9
|
+
Column,
|
|
10
|
+
Box,
|
|
11
|
+
Title,
|
|
12
|
+
SubTitle,
|
|
13
|
+
Input,
|
|
14
|
+
Button,
|
|
15
|
+
} from '@allxsmith/bestax-bulma';
|
|
16
|
+
|
|
17
|
+
export default function LoginPage() {
|
|
18
|
+
return (
|
|
19
|
+
<Section>
|
|
20
|
+
<Container>
|
|
21
|
+
<Columns isCentered>
|
|
22
|
+
<Column
|
|
23
|
+
size="half"
|
|
24
|
+
sizeTablet="two-thirds"
|
|
25
|
+
sizeDesktop="half"
|
|
26
|
+
sizeWidescreen="one-third"
|
|
27
|
+
>
|
|
28
|
+
<Box>
|
|
29
|
+
<Title size="4" textAlign="centered">
|
|
30
|
+
Sign in
|
|
31
|
+
</Title>
|
|
32
|
+
<SubTitle size="6" textAlign="centered" textColor="grey">
|
|
33
|
+
Welcome back
|
|
34
|
+
</SubTitle>
|
|
35
|
+
<Input
|
|
36
|
+
label="Email"
|
|
37
|
+
type="email"
|
|
38
|
+
iconLeftName="envelope"
|
|
39
|
+
placeholder="you@example.com"
|
|
40
|
+
/>
|
|
41
|
+
<Input
|
|
42
|
+
label="Password"
|
|
43
|
+
type="password"
|
|
44
|
+
iconLeftName="lock"
|
|
45
|
+
placeholder="••••••••"
|
|
46
|
+
/>
|
|
47
|
+
<Button color="primary" isFullWidth mt="4">
|
|
48
|
+
Sign in
|
|
49
|
+
</Button>
|
|
50
|
+
</Box>
|
|
51
|
+
</Column>
|
|
52
|
+
</Columns>
|
|
53
|
+
</Container>
|
|
54
|
+
</Section>
|
|
55
|
+
);
|
|
56
|
+
}
|