@shabboo/kit 0.0.0-stage → 0.1.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/CHANGELOG.md +7 -0
- package/DESIGN.md +128 -0
- package/LICENSE +21 -0
- package/README.md +75 -2
- package/dist/motion.d.ts +14 -0
- package/dist/motion.js +23 -0
- package/dist/ui/icons.d.ts +24 -0
- package/dist/ui/icons.js +23 -0
- package/package.json +83 -3
- package/src/motion.tsx +33 -0
- package/src/styles/fonts.css +8 -0
- package/src/styles/print.css +36 -0
- package/src/styles/styles.css +246 -0
- package/src/styles/tokens.css +303 -0
- package/src/ui/Badge.astro +95 -0
- package/src/ui/Breadcrumbs.astro +28 -0
- package/src/ui/Button.astro +190 -0
- package/src/ui/Callout.astro +112 -0
- package/src/ui/Card.astro +79 -0
- package/src/ui/Dialog.astro +168 -0
- package/src/ui/Disclosure.astro +197 -0
- package/src/ui/EntryItem.astro +43 -0
- package/src/ui/Field.astro +167 -0
- package/src/ui/Figure.astro +47 -0
- package/src/ui/HCard.astro +86 -0
- package/src/ui/Icon.astro +59 -0
- package/src/ui/Kbd.astro +35 -0
- package/src/ui/Label.astro +15 -0
- package/src/ui/Pagination.astro +124 -0
- package/src/ui/PixelFrame.astro +121 -0
- package/src/ui/Quote.astro +49 -0
- package/src/ui/Tag.astro +91 -0
- package/src/ui/TagList.astro +68 -0
- package/src/ui/Timeline.astro +23 -0
- package/src/ui/TimelineItem.astro +105 -0
- package/src/ui/icons.ts +27 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# @shabboo/kit
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#9](https://github.com/mehrad77/matthiola/pull/9) [`b604377`](https://github.com/mehrad77/matthiola/commit/b60437792c8724fd1c323c9e8c8d4aedbb74b0a7) Thanks [@mehrad77](https://github.com/mehrad77)! - First public release of ShabUI: tokens, the day theme, base and print CSS, self-hosted fonts, icon data, `MotionRoot`, and the Astro components shown at ui.shab.boo.
|
package/DESIGN.md
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# ShabUI: design guide for agents
|
|
2
|
+
|
|
3
|
+
ShabUI is the shab.boo design system: the tokens and UI kit in `packages/kit`, published to npm as `@shabboo/kit` and shown at ui.shab.boo. These are the rules for building UI with it, in plain text. Read this before you write or style any UI. Token, theme and status basics live in the Conventions of `AGENTS.md`; they are not repeated here. Each section says which ui.shab.boo page shows it rendered (`apps/ui/src/pages/…`). If you change a rule on one side, change it on the other.
|
|
4
|
+
|
|
5
|
+
Before you use a kit component, read the frontmatter of `apps/ui/src/pages/components/<slug>.mdx`: `use`, `avoid`, `a11y.you` and `props`. Its status is in `apps/ui/src/registry.ts`. A `planned` component doesn't exist yet.
|
|
6
|
+
|
|
7
|
+
## Tokens
|
|
8
|
+
|
|
9
|
+
Pick a token by what you need. Apps may also use the palette; the UI kit (`src/ui/`) uses only these semantic tokens.
|
|
10
|
+
|
|
11
|
+
| Need | Token |
|
|
12
|
+
|---|---|
|
|
13
|
+
| Page, panel, well | `--surface`, `--surface-raised`, `--surface-sunken` (a well is one step off the page toward the text: lighter at night, darker by day) |
|
|
14
|
+
| Input fill (on a page, on a panel) | `--field`, `--field-raised` |
|
|
15
|
+
| Body, secondary, helper, placeholder, disabled text | `--text`, `--text-muted`, `--text-helper` (an alias of muted), `--text-placeholder` (4.5:1 on any layer), `--text-disabled` (about 3:1: readable, plainly off) |
|
|
16
|
+
| Accent text, text on a filled control | `--text-accent`, `--text-on-fill` |
|
|
17
|
+
| A tiny highlight (the required mark, a signal badge or frame) | `--text-signal` |
|
|
18
|
+
| Primary fill and its border | `--fill-accent`, `--fill-accent-strong` |
|
|
19
|
+
| A soft accent glow (a lit timeline dot, a dialog's halo) | `--fill-glow` |
|
|
20
|
+
| A control's edge (3:1 on any layer) | `--stroke-control` |
|
|
21
|
+
| An accent edge (hover, focus, current) | `--stroke-strong` |
|
|
22
|
+
| A decorative hairline (divider, panel) | `--stroke`, `--stroke-subtle` |
|
|
23
|
+
| Hover, press, selected (over any layer) | `--state-hover`, `--state-active`, `--state-selected` |
|
|
24
|
+
| Disabled control | `--fill-disabled`, `--text-disabled` |
|
|
25
|
+
| Error, warning, info, success | `--status-*` (text, icon, border), `--status-*-fill` (tint). Always add an icon or a word. |
|
|
26
|
+
| Modal backdrop | `--overlay` |
|
|
27
|
+
| Focus | the global ring (`--focus-ring`); never remove it |
|
|
28
|
+
| Stacking | `--z-base`, `--z-raised`, `--z-sticky`, `--z-overlay`, `--z-toast` |
|
|
29
|
+
| Durations, easing | `--dur-fast`, `--dur-moderate`, `--dur-slow`, `--ease`, `--ease-enter`, `--ease-exit`; pixel: `--dur-step`, `--ease-step`, `--ease-dither`, `--blink` |
|
|
30
|
+
| Icon size, touch target | `--icon-sm`, `--icon-md`, `--icon-lg`, `--target-min` |
|
|
31
|
+
| Control height and side padding, per size | `--control-h-sm\|md\|lg`, `--control-pad-sm\|md\|lg` |
|
|
32
|
+
| Corners | `--radius` (every box), `--radius-pill` (fully round ends) |
|
|
33
|
+
| Faces | `--font-serif` (prose), `--font-mono` (UI, labels), `--font-arabic` (Persian and Arabic, for any mono text) |
|
|
34
|
+
| Type size, line height, mono tracking | `--step--2` … `--step-5`, `--leading`, `--tracking-mono` (never in Persian or Arabic) |
|
|
35
|
+
| Space, page gutter, widths | `--space-1` … `--space-8`, `--gutter`, `--measure` (prose), `--wide` (page) |
|
|
36
|
+
| Charts, in order | `--chart-1` … `--chart-5` |
|
|
37
|
+
|
|
38
|
+
Shown on: `foundations/colors`, `layers`, `status`, `layout`.
|
|
39
|
+
|
|
40
|
+
## Writing
|
|
41
|
+
|
|
42
|
+
Shown on: `foundations/content`.
|
|
43
|
+
|
|
44
|
+
- Sentence case for headings, labels and buttons.
|
|
45
|
+
- Buttons start with a verb and say what happens: "Send message", not "Submit" or "OK".
|
|
46
|
+
- Labels are nouns, with no colon. Mono labels are uppercased by CSS, so write them in lowercase.
|
|
47
|
+
- Use the fewest words that are still clear. Cut "please", "simply" and "just".
|
|
48
|
+
- Errors say what happened, then how to fix it. Don't blame the reader, and don't shout.
|
|
49
|
+
- Empty states say what goes here and how to add it.
|
|
50
|
+
- Every date goes in `<time datetime>`. Format dates and numbers with `Intl` for the locale, so Persian gets ۰–۹ and Arabic ٠–٩.
|
|
51
|
+
- In Persian and Arabic, never letter-space and never italicize. Use the zero-width non-joiner, not a space.
|
|
52
|
+
- The author's copy (posts, chapters, the resume) stays verbatim. This guide sets no brand voice.
|
|
53
|
+
|
|
54
|
+
## Accessibility
|
|
55
|
+
|
|
56
|
+
Shown on: `foundations/accessibility`, `focus`, `direction`.
|
|
57
|
+
|
|
58
|
+
The target is WCAG 2.1 AA. Check these before you call a component built:
|
|
59
|
+
|
|
60
|
+
- **Contrast.** Text needs 4.5:1, or 3:1 at large sizes. A control's edges and marks need 3:1. Disabled is exempt, but must still look disabled.
|
|
61
|
+
- **Keyboard.**
|
|
62
|
+
- Tab and Enter (or Space) do everything a pointer does.
|
|
63
|
+
- Tab order follows reading order, in both directions.
|
|
64
|
+
- Focus is always visible.
|
|
65
|
+
- Esc closes what opened and returns focus to the opener.
|
|
66
|
+
- Arrow keys are only for composite widgets, and they flip in RTL.
|
|
67
|
+
- **Screen readers.**
|
|
68
|
+
- Use a native element first.
|
|
69
|
+
- Every control has a name: a visible label, or `aria-label` when it's an icon alone.
|
|
70
|
+
- Tie hints and errors in with `aria-describedby`, and mark invalid fields with `aria-invalid`.
|
|
71
|
+
- Put state in the markup (`aria-pressed`, `aria-expanded`, `aria-current`).
|
|
72
|
+
- Decorative icons and art get `aria-hidden`.
|
|
73
|
+
- Content that changes on its own goes in a polite live region.
|
|
74
|
+
- **Touch.** Anything you tap is at least `--target-min` (44px), or has that much room around it. A kit control drawn smaller reaches it one of two ways:
|
|
75
|
+
- **Hit area** (the default): an invisible pseudo-element, `inset: min(0px, (100% - var(--target-min)) / 2)`, so it grows only where it is short. Button, Dialog's close, linked Tag (block axis only, since chips sit side by side).
|
|
76
|
+
- **Grow on touch**: under `@media (pointer: coarse)` the control itself takes `--target-min`, when neighbours sit too close for a hit area or a native control can't carry a pseudo-element. Pagination, small Disclosure, Field.
|
|
77
|
+
- Quiet buttons and inline links are exempt: in running text a taller hit area would cover the lines around it.
|
|
78
|
+
- **Motion.** Every animation sits inside `@media (prefers-reduced-motion: no-preference)`, and the component looks finished without it. Nothing flashes more than three times a second.
|
|
79
|
+
- **RTL.** Use logical properties only. Check every component in Persian too.
|
|
80
|
+
|
|
81
|
+
## Patterns
|
|
82
|
+
|
|
83
|
+
Shown on: `patterns/*`.
|
|
84
|
+
|
|
85
|
+
- **Empty.** Say what goes here in the list's own words ("No posts tagged night yet"), plus one action to fill it. It isn't an error, so use neutral colors. A search with no results repeats the query and suggests a wider one.
|
|
86
|
+
- **Loading.**
|
|
87
|
+
- Reserve the content's space so the page doesn't jump.
|
|
88
|
+
- Show nothing for the first few hundred milliseconds.
|
|
89
|
+
- Set `aria-busy="true"` while the region fills.
|
|
90
|
+
- No shimmer under reduced motion.
|
|
91
|
+
- Render the page and load only the part; never put the whole page behind a spinner.
|
|
92
|
+
- On failure, say what happened and offer a retry.
|
|
93
|
+
- **Notifications.**
|
|
94
|
+
- Put the message as close to what it's about as possible: a badge, then a callout, then a toast, then a dialog.
|
|
95
|
+
- Every message has an icon or a word, never color alone.
|
|
96
|
+
- Errors stay until they're fixed, so never put one in a toast.
|
|
97
|
+
- Use `role="status"` for news and `role="alert"` only for errors that need action now.
|
|
98
|
+
- Don't move focus to a message that doesn't ask a question.
|
|
99
|
+
- **Forms.**
|
|
100
|
+
- One column, a visible label above each field, and the placeholder only as an example.
|
|
101
|
+
- Ask only what you need, and mark required fields.
|
|
102
|
+
- Validate on blur or submit, never on every keystroke.
|
|
103
|
+
- Put each error under its field, saying how to fix it.
|
|
104
|
+
- One primary button at the end, starting with a verb. Never disable it; say what's missing when it's pressed.
|
|
105
|
+
- Use the right `type` and `autocomplete`.
|
|
106
|
+
- **Disabled vs read-only.**
|
|
107
|
+
- Use read-only when the value matters but isn't the reader's to change.
|
|
108
|
+
- Use disabled only when the control will come back, and say nearby what brings it back.
|
|
109
|
+
- Hide what will never be available instead of disabling it.
|
|
110
|
+
- Use `aria-disabled="true"` when the control must stay focusable.
|
|
111
|
+
|
|
112
|
+
## Pixel art
|
|
113
|
+
|
|
114
|
+
Shown on: `foundations/pixel-art`, `texture`.
|
|
115
|
+
|
|
116
|
+
- The whole system shares one whole-cell grid: hard edges, PixelFrame, dither and stepped motion in the kit; the painted scenes and figures on the landing.
|
|
117
|
+
- Light comes from the upper left; right and bottom edges take the shade. Edge cells reach 1.7:1 against `--ink-3`.
|
|
118
|
+
- `--fig-*` tokens are for art only, never UI or text. A new art colour is a new token.
|
|
119
|
+
- New figures are painter recipes (`packages/painter/recipes/shabboo/`), emitted into the landing's `data.ts`; never hand-edit it. The page lists every step.
|
|
120
|
+
|
|
121
|
+
## Motion
|
|
122
|
+
|
|
123
|
+
Shown on: `foundations/motion`, `texture`.
|
|
124
|
+
|
|
125
|
+
- **Smooth** (`--dur-*`, `--ease*`) is for content: things entering, leaving, or growing.
|
|
126
|
+
- **Stepped** (`steps()`, `--dur-step`) is the pixel UI: presses, blinks, scans and dithers. Don't tween a pixel element.
|
|
127
|
+
- Animate only on the reader's action. Never replay on page load or on a client-side page swap (persisted elements are re-inserted; gate the animation behind a flag set on click).
|
|
128
|
+
- Nothing moves under reduced motion.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mehrad Rousta
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,76 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @shabboo/kit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
ShabUI, the design system behind [shab.boo](https://shab.boo): a night-first palette with a day theme, design tokens, base CSS, self-hosted fonts and RTL-ready Astro components. Every part is shown, in both directions and both themes, at **[ui.shab.boo](https://ui.shab.boo)**.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
pnpm add @shabboo/kit # or npm i / yarn add
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Astro
|
|
10
|
+
|
|
11
|
+
Import the styles once, in your layout, then use the components:
|
|
12
|
+
|
|
13
|
+
```astro
|
|
14
|
+
---
|
|
15
|
+
import "@shabboo/kit/fonts.css";
|
|
16
|
+
import "@shabboo/kit/styles.css";
|
|
17
|
+
import Button from "@shabboo/kit/Button.astro";
|
|
18
|
+
---
|
|
19
|
+
<html lang="en" dir="ltr">
|
|
20
|
+
<body>
|
|
21
|
+
<Button href="/start">Start</Button>
|
|
22
|
+
</body>
|
|
23
|
+
</html>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## React, Vue, plain HTML
|
|
27
|
+
|
|
28
|
+
The components are Astro-only for now; the tokens and CSS work anywhere:
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
import "@shabboo/kit/fonts.css";
|
|
32
|
+
import "@shabboo/kit/styles.css"; // tokens + base, prose and utility styles
|
|
33
|
+
// or only the custom properties, no element styles:
|
|
34
|
+
import "@shabboo/kit/tokens.css";
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```css
|
|
38
|
+
.panel {
|
|
39
|
+
background: var(--surface-raised);
|
|
40
|
+
color: var(--text);
|
|
41
|
+
border: 1px solid var(--stroke);
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
React islands animated with [Motion](https://motion.dev) can wrap themselves in `MotionRoot`, which respects `prefers-reduced-motion`:
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
import { MotionRoot, fadeUp } from "@shabboo/kit/motion";
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`@shabboo/kit/icons` exports the icon path data (`PATHS`, `ICON_NAMES`) for drawing the same icons in any framework.
|
|
52
|
+
|
|
53
|
+
## Themes and direction
|
|
54
|
+
|
|
55
|
+
Night is the default. `data-theme="light"` on any element switches its subtree to day; `data-theme="dark"` brings night back. Components use logical properties, so `dir="rtl"` just works.
|
|
56
|
+
|
|
57
|
+
## What's in the box
|
|
58
|
+
|
|
59
|
+
| Import | What |
|
|
60
|
+
|---|---|
|
|
61
|
+
| `@shabboo/kit/tokens.css` | Custom properties only: palette, semantic layer, day theme, scales |
|
|
62
|
+
| `@shabboo/kit/styles.css` | `tokens.css` + print theme + reset, base, prose and utilities |
|
|
63
|
+
| `@shabboo/kit/print.css` | The print theme alone |
|
|
64
|
+
| `@shabboo/kit/fonts.css` | Newsreader, JetBrains Mono and Vazirmatn via Fontsource |
|
|
65
|
+
| `@shabboo/kit/<Name>.astro` | Components: `Button`, `Badge`, `Callout`, `Card`, `Dialog`, `Field`, … |
|
|
66
|
+
| `@shabboo/kit/icons` | Icon path data |
|
|
67
|
+
| `@shabboo/kit/motion` | `MotionRoot` and shared Motion variants |
|
|
68
|
+
| `@shabboo/kit/DESIGN.md` | The rules: which token for what, writing, accessibility, patterns |
|
|
69
|
+
|
|
70
|
+
## Versioning
|
|
71
|
+
|
|
72
|
+
Semver. While the version is 0.x, a minor release may change a component's API; the [changelog](https://ui.shab.boo/start/changelog/) says how to move.
|
|
73
|
+
|
|
74
|
+
## License
|
|
75
|
+
|
|
76
|
+
MIT
|
package/dist/motion.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Motion (framer-motion) setup for React islands.
|
|
3
|
+
* Wrap every animated island in <MotionRoot> so prefers-reduced-motion is always respected.
|
|
4
|
+
*/
|
|
5
|
+
import { type Transition, type Variants } from "motion/react";
|
|
6
|
+
import type { ReactNode } from "react";
|
|
7
|
+
export declare const ease: readonly [0.22, 1, 0.36, 1];
|
|
8
|
+
export declare const transition: Transition;
|
|
9
|
+
export declare const fadeUp: Variants;
|
|
10
|
+
export declare const fade: Variants;
|
|
11
|
+
export declare const stagger: (staggerChildren?: number) => Variants;
|
|
12
|
+
export declare function MotionRoot({ children }: {
|
|
13
|
+
children: ReactNode;
|
|
14
|
+
}): import("react").JSX.Element;
|
package/dist/motion.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Shared Motion (framer-motion) setup for React islands.
|
|
4
|
+
* Wrap every animated island in <MotionRoot> so prefers-reduced-motion is always respected.
|
|
5
|
+
*/
|
|
6
|
+
import { MotionConfig } from "motion/react";
|
|
7
|
+
export const ease = [0.22, 1, 0.36, 1];
|
|
8
|
+
export const transition = { duration: 0.6, ease };
|
|
9
|
+
export const fadeUp = {
|
|
10
|
+
hidden: { opacity: 0, y: 16 },
|
|
11
|
+
visible: { opacity: 1, y: 0, transition },
|
|
12
|
+
};
|
|
13
|
+
export const fade = {
|
|
14
|
+
hidden: { opacity: 0 },
|
|
15
|
+
visible: { opacity: 1, transition },
|
|
16
|
+
};
|
|
17
|
+
export const stagger = (staggerChildren = 0.08) => ({
|
|
18
|
+
hidden: {},
|
|
19
|
+
visible: { transition: { staggerChildren } },
|
|
20
|
+
});
|
|
21
|
+
export function MotionRoot({ children }) {
|
|
22
|
+
return (_jsx(MotionConfig, { reducedMotion: "user", transition: transition, children: children }));
|
|
23
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** Paths for <Icon>: a 24px grid, 1.5 stroke, round caps. Add an icon by adding a path. */
|
|
2
|
+
export declare const PATHS: {
|
|
3
|
+
readonly "arrow-right": "M4 12h15M13 6l6 6-6 6";
|
|
4
|
+
readonly "arrow-left": "M20 12H5M11 6l-6 6 6 6";
|
|
5
|
+
readonly "arrow-down": "M12 4v15M6 13l6 6 6-6";
|
|
6
|
+
readonly "arrow-up": "M12 20V5M6 11l6-6 6 6";
|
|
7
|
+
readonly download: "M12 4v11M7 10l5 5 5-5M5 20h14";
|
|
8
|
+
readonly external: "M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5";
|
|
9
|
+
readonly "chevron-down": "M6 9l6 6 6-6";
|
|
10
|
+
readonly "chevron-right": "M9 6l6 6-6 6";
|
|
11
|
+
readonly close: "M6 6l12 12M18 6L6 18";
|
|
12
|
+
readonly check: "M5 12.5l4.5 4.5L19 7";
|
|
13
|
+
readonly info: "M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18zM12 11v6M12 7.5v.01";
|
|
14
|
+
readonly warning: "M12 3.5l9.5 16.5h-19L12 3.5zM12 10v4.5M12 17.5v.01";
|
|
15
|
+
readonly search: "M10.5 18a7.5 7.5 0 1 0 0-15 7.5 7.5 0 0 0 0 15zM16 16l5 5";
|
|
16
|
+
readonly copy: "M9 9h11v11H9zM5 15H4V4h11v1";
|
|
17
|
+
readonly rss: "M5 5a14 14 0 0 1 14 14M5 11a8 8 0 0 1 8 8M6 19.01V19";
|
|
18
|
+
readonly mail: "M3 6h18v12H3zM3 6l9 7 9-7";
|
|
19
|
+
readonly github: "M9 19c-4.5 1.4-4.5-2.5-6-3m12 5v-3.5c0-1 .1-1.4-.5-2 2.8-.3 5.5-1.4 5.5-6a4.6 4.6 0 0 0-1.3-3.2 4.2 4.2 0 0 0-.1-3.2s-1.1-.3-3.5 1.3a12 12 0 0 0-6.2 0C6.5 2.8 5.4 3.1 5.4 3.1a4.2 4.2 0 0 0-.1 3.2A4.6 4.6 0 0 0 4 9.5c0 4.6 2.7 5.7 5.5 6-.6.6-.6 1.2-.5 2V21";
|
|
20
|
+
readonly moon: "M20 14.5A8.5 8.5 0 1 1 9.5 4a7 7 0 0 0 10.5 10.5z";
|
|
21
|
+
readonly flower: "M12 9a3 3 0 1 0 0 6 3 3 0 0 0 0-6zM12 9V4M12 15v5M9 12H4M15 12h5M9.9 9.9 6.3 6.3M14.1 14.1l3.6 3.6M14.1 9.9l3.6-3.6M9.9 14.1l-3.6 3.6";
|
|
22
|
+
};
|
|
23
|
+
export type IconName = keyof typeof PATHS;
|
|
24
|
+
export declare const ICON_NAMES: IconName[];
|
package/dist/ui/icons.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Paths for <Icon>: a 24px grid, 1.5 stroke, round caps. Add an icon by adding a path. */
|
|
2
|
+
export const PATHS = {
|
|
3
|
+
"arrow-right": "M4 12h15M13 6l6 6-6 6",
|
|
4
|
+
"arrow-left": "M20 12H5M11 6l-6 6 6 6",
|
|
5
|
+
"arrow-down": "M12 4v15M6 13l6 6 6-6",
|
|
6
|
+
"arrow-up": "M12 20V5M6 11l6-6 6 6",
|
|
7
|
+
download: "M12 4v11M7 10l5 5 5-5M5 20h14",
|
|
8
|
+
external: "M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5",
|
|
9
|
+
"chevron-down": "M6 9l6 6 6-6",
|
|
10
|
+
"chevron-right": "M9 6l6 6-6 6",
|
|
11
|
+
close: "M6 6l12 12M18 6L6 18",
|
|
12
|
+
check: "M5 12.5l4.5 4.5L19 7",
|
|
13
|
+
info: "M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18zM12 11v6M12 7.5v.01",
|
|
14
|
+
warning: "M12 3.5l9.5 16.5h-19L12 3.5zM12 10v4.5M12 17.5v.01",
|
|
15
|
+
search: "M10.5 18a7.5 7.5 0 1 0 0-15 7.5 7.5 0 0 0 0 15zM16 16l5 5",
|
|
16
|
+
copy: "M9 9h11v11H9zM5 15H4V4h11v1",
|
|
17
|
+
rss: "M5 5a14 14 0 0 1 14 14M5 11a8 8 0 0 1 8 8M6 19.01V19",
|
|
18
|
+
mail: "M3 6h18v12H3zM3 6l9 7 9-7",
|
|
19
|
+
github: "M9 19c-4.5 1.4-4.5-2.5-6-3m12 5v-3.5c0-1 .1-1.4-.5-2 2.8-.3 5.5-1.4 5.5-6a4.6 4.6 0 0 0-1.3-3.2 4.2 4.2 0 0 0-.1-3.2s-1.1-.3-3.5 1.3a12 12 0 0 0-6.2 0C6.5 2.8 5.4 3.1 5.4 3.1a4.2 4.2 0 0 0-.1 3.2A4.6 4.6 0 0 0 4 9.5c0 4.6 2.7 5.7 5.5 6-.6.6-.6 1.2-.5 2V21",
|
|
20
|
+
moon: "M20 14.5A8.5 8.5 0 1 1 9.5 4a7 7 0 0 0 10.5 10.5z",
|
|
21
|
+
flower: "M12 9a3 3 0 1 0 0 6 3 3 0 0 0 0-6zM12 9V4M12 15v5M9 12H4M15 12h5M9.9 9.9 6.3 6.3M14.1 14.1l3.6 3.6M14.1 9.9l3.6-3.6M9.9 14.1l-3.6 3.6",
|
|
22
|
+
};
|
|
23
|
+
export const ICON_NAMES = Object.keys(PATHS);
|
package/package.json
CHANGED
|
@@ -1,6 +1,86 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shabboo/kit",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "ShabUI, the night-first design system behind shab.boo: tokens, base CSS, fonts and RTL-ready Astro components.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Mehrad Rousta",
|
|
8
|
+
"homepage": "https://ui.shab.boo",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/mehrad77/matthiola.git",
|
|
12
|
+
"directory": "packages/kit"
|
|
13
|
+
},
|
|
14
|
+
"bugs": "https://github.com/mehrad77/matthiola/issues",
|
|
15
|
+
"keywords": [
|
|
16
|
+
"astro-component",
|
|
17
|
+
"design-system",
|
|
18
|
+
"design-tokens",
|
|
19
|
+
"css",
|
|
20
|
+
"rtl",
|
|
21
|
+
"dark-theme",
|
|
22
|
+
"shabui"
|
|
23
|
+
],
|
|
24
|
+
"sideEffects": [
|
|
25
|
+
"**/*.css"
|
|
26
|
+
],
|
|
27
|
+
"files": [
|
|
28
|
+
"src",
|
|
29
|
+
"dist",
|
|
30
|
+
"DESIGN.md",
|
|
31
|
+
"CHANGELOG.md"
|
|
32
|
+
],
|
|
33
|
+
"exports": {
|
|
34
|
+
"./tokens.css": "./src/styles/tokens.css",
|
|
35
|
+
"./styles.css": "./src/styles/styles.css",
|
|
36
|
+
"./print.css": "./src/styles/print.css",
|
|
37
|
+
"./fonts.css": "./src/styles/fonts.css",
|
|
38
|
+
"./icons": {
|
|
39
|
+
"types": "./dist/ui/icons.d.ts",
|
|
40
|
+
"default": "./dist/ui/icons.js"
|
|
41
|
+
},
|
|
42
|
+
"./motion": {
|
|
43
|
+
"types": "./dist/motion.d.ts",
|
|
44
|
+
"default": "./dist/motion.js"
|
|
45
|
+
},
|
|
46
|
+
"./*.astro": "./src/ui/*.astro",
|
|
47
|
+
"./DESIGN.md": "./DESIGN.md",
|
|
48
|
+
"./package.json": "./package.json"
|
|
49
|
+
},
|
|
50
|
+
"publishConfig": {
|
|
51
|
+
"access": "public"
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"@fontsource-variable/jetbrains-mono": "^5.3.0",
|
|
55
|
+
"@fontsource-variable/newsreader": "^5.3.0",
|
|
56
|
+
"@fontsource-variable/vazirmatn": "^5.3.0"
|
|
57
|
+
},
|
|
58
|
+
"peerDependencies": {
|
|
59
|
+
"astro": "^7.4.1",
|
|
60
|
+
"motion": "^14.4.0",
|
|
61
|
+
"react": "^19.3.1"
|
|
62
|
+
},
|
|
63
|
+
"peerDependenciesMeta": {
|
|
64
|
+
"astro": {
|
|
65
|
+
"optional": true
|
|
66
|
+
},
|
|
67
|
+
"motion": {
|
|
68
|
+
"optional": true
|
|
69
|
+
},
|
|
70
|
+
"react": {
|
|
71
|
+
"optional": true
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"devDependencies": {
|
|
75
|
+
"@types/react": "^19.3.0",
|
|
76
|
+
"astro": "^7.4.1",
|
|
77
|
+
"motion": "^14.4.0",
|
|
78
|
+
"publint": "^0.3.25",
|
|
79
|
+
"react": "^19.3.1",
|
|
80
|
+
"typescript": "^6.0.3"
|
|
81
|
+
},
|
|
82
|
+
"scripts": {
|
|
83
|
+
"build": "tsc -p tsconfig.build.json",
|
|
84
|
+
"check": "node scripts/check-ui.mjs && tsc -p tsconfig.build.json && publint"
|
|
85
|
+
}
|
|
6
86
|
}
|
package/src/motion.tsx
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Motion (framer-motion) setup for React islands.
|
|
3
|
+
* Wrap every animated island in <MotionRoot> so prefers-reduced-motion is always respected.
|
|
4
|
+
*/
|
|
5
|
+
import { MotionConfig, type Transition, type Variants } from "motion/react";
|
|
6
|
+
import type { ReactNode } from "react";
|
|
7
|
+
|
|
8
|
+
export const ease = [0.22, 1, 0.36, 1] as const;
|
|
9
|
+
|
|
10
|
+
export const transition: Transition = { duration: 0.6, ease };
|
|
11
|
+
|
|
12
|
+
export const fadeUp: Variants = {
|
|
13
|
+
hidden: { opacity: 0, y: 16 },
|
|
14
|
+
visible: { opacity: 1, y: 0, transition },
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const fade: Variants = {
|
|
18
|
+
hidden: { opacity: 0 },
|
|
19
|
+
visible: { opacity: 1, transition },
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const stagger = (staggerChildren = 0.08): Variants => ({
|
|
23
|
+
hidden: {},
|
|
24
|
+
visible: { transition: { staggerChildren } },
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export function MotionRoot({ children }: { children: ReactNode }) {
|
|
28
|
+
return (
|
|
29
|
+
<MotionConfig reducedMotion="user" transition={transition}>
|
|
30
|
+
{children}
|
|
31
|
+
</MotionConfig>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* ShabUI's three faces, self-hosted through Fontsource: Newsreader (serif, upright and italic),
|
|
3
|
+
* JetBrains Mono (labels and code) and Vazirmatn (Persian and Arabic). tokens.css names them in --font-*.
|
|
4
|
+
*/
|
|
5
|
+
@import "@fontsource-variable/newsreader/wght.css";
|
|
6
|
+
@import "@fontsource-variable/newsreader/wght-italic.css";
|
|
7
|
+
@import "@fontsource-variable/jetbrains-mono/wght.css";
|
|
8
|
+
@import "@fontsource-variable/vazirmatn/wght.css";
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Print: ink on white paper for every site, whatever the screen shows. It swaps the night palette the semantic
|
|
3
|
+
* layer reads from, so kit parts and app styles print alike: no grain, no glow, no washes, status in their day inks
|
|
4
|
+
* (read from the --day-* palette, so print and day can't drift apart).
|
|
5
|
+
* It lives apart from tokens.css because scripts read that file's hex values as the night palette (og cards,
|
|
6
|
+
* favicons, the painter, the landing's figure check, the ui showcase); global.css imports it right after.
|
|
7
|
+
*/
|
|
8
|
+
@media print {
|
|
9
|
+
:root {
|
|
10
|
+
color-scheme: light;
|
|
11
|
+
--ink: #fff;
|
|
12
|
+
--ink-2: #fff;
|
|
13
|
+
--ink-3: #f2f2ef;
|
|
14
|
+
--ink-4: #e8e8e4;
|
|
15
|
+
--line: #bbb;
|
|
16
|
+
--line-dim: #ddd;
|
|
17
|
+
--line-control: #777;
|
|
18
|
+
--paper: #111;
|
|
19
|
+
--paper-dim: #444;
|
|
20
|
+
--paper-faint: #555;
|
|
21
|
+
--paper-off: #888;
|
|
22
|
+
--accent-strong: var(--accent);
|
|
23
|
+
--accent-text: var(--accent);
|
|
24
|
+
--accent-glow: transparent;
|
|
25
|
+
--signal: var(--day-signal);
|
|
26
|
+
--wash-1: transparent;
|
|
27
|
+
--wash-2: transparent;
|
|
28
|
+
--red: var(--day-red);
|
|
29
|
+
--red-wash: transparent;
|
|
30
|
+
--amber: var(--day-amber);
|
|
31
|
+
--amber-wash: transparent;
|
|
32
|
+
--blue: var(--day-blue);
|
|
33
|
+
--blue-wash: transparent;
|
|
34
|
+
--grain-opacity: 0;
|
|
35
|
+
}
|
|
36
|
+
}
|