@vvedantb/ui 0.14.0 → 0.15.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 +4 -4
- package/app/README.md +1 -1
- package/package.json +3 -1
- package/shell/src/app-shell-classes.ts +2 -2
- package/src/ui/clearInputDissolve.ts +10 -5
- package/src/ui/dialog.tsx +1 -1
- package/tokens/README.md +30 -8
- package/tokens/src/css/clear-input.css +71 -0
- package/tokens/src/css/compat-shadcn-rgb.css +8 -7
- package/tokens/src/css/index.css +8 -5
- package/tokens/src/css/modal.css +3 -2
- package/tokens/src/css/motion.css +156 -0
- package/tokens/src/css/scrollbar-thin.css +54 -26
- package/tokens/src/css/tabs.css +16 -5
- package/tokens/src/tokens.css +52 -0
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ Shared React 19 web UI. Source-exported: no build step.
|
|
|
7
7
|
| `@vvedantb/ui` | The only JavaScript entry. Primitives (Radix-based), AI elements, audio (`playChime`, `useReplyChime`, `playTone`), `toast` and `SonnerToaster`, the composer (`InputArea`, deprecated 0.3 `Composer`), shell (`SidebarHeader`, `PillTabs`, `SessionsHoverCard`, and the app shell: `AppShell`, `AppSidebar`, `SidebarRail`, `RailTile`, `SidebarPanel`, `SidebarAccountMenu`, `SignOutDialog` and related helpers), app helpers (confirm skip, update watcher, settings chrome, `useStableAuth`, and from 0.8.0 `createThemeProvider`, `createPageTitleContext`, `PageMotionProvider` and `formatCompactRelativeTime`), marketing pieces from 0.9.0 (`createLandingKit` and the `Landing*` parts, `SiteFooter`, `PricingModal`), animated nav icons from 0.11.0 (`MemoryIcon`, `BoardIcon`, ... and `NavIconBase`; `SettingsIcon` `variant` from 0.12.0), artifact viewers from 0.13.0 (`ArtifactFrame`, `ArtifactList`, `ArtifactViewer`, ...), date pickers from 0.14.0 (`Calendar`, `DatePicker`, `DateTimePicker`, `MonthPicker`), `cn`, and the native tokens `tokens` and `Tokens`. See `app/README.md` in the repository for the app helpers. |
|
|
8
8
|
| `@vvedantb/ui/tokens` | `tokens.css`: colour, radius, shadow, ease and font tokens for Tailwind v4. CSS. |
|
|
9
9
|
| `@vvedantb/ui/tokens/tokens.css` | Same file as `@vvedantb/ui/tokens`. CSS. |
|
|
10
|
-
| `@vvedantb/ui/tokens/css/*.css` | `index`, `base`, `dialog`, `modal`, `tabs`, `tabs-pills`, `utilities`, `scrollbar-thin`, `animations`, `nav-icons`, `compat-shadcn-rgb`. CSS. |
|
|
10
|
+
| `@vvedantb/ui/tokens/css/*.css` | `index`, `base`, `dialog`, `modal`, `tabs`, `tabs-pills`, `utilities`, `scrollbar-thin`, `clear-input`, `motion`, `animations`, `nav-icons`, `compat-shadcn-rgb`. CSS. `tokens.css` imports `scrollbar-thin`, `clear-input` and `motion`. |
|
|
11
11
|
| `@vvedantb/ui/tokens/compat/shadcn-rgb.css` | Same file as `tokens/css/compat-shadcn-rgb.css`. CSS. |
|
|
12
12
|
| `@vvedantb/ui/tokens/tailwind-preset` | Tailwind preset (`.mjs`) for `@config "@vvedantb/ui/tokens/tailwind-preset"`. Kept as a build-tool entry: Tailwind needs a resolvable package path, and it is not a React API. |
|
|
13
13
|
| `@vvedantb/ui/landing.css` | Landing page classes (`landing-atmosphere`, `landing-grain`, `landing-pulse-dot`, ambient graph and preview animations, smooth `#top` scrolling). CSS. |
|
|
@@ -661,7 +661,7 @@ Rows in the panel beside the rail. Rail tiles are unchanged.
|
|
|
661
661
|
| Focus ring | none | `focus-visible:ring-2 focus-visible:ring-foreground/35`, no outline |
|
|
662
662
|
| Icon-only row | `justify-center px-0 py-1.5` | same, plus the radius, text, fill and focus classes above |
|
|
663
663
|
| Icon (`sidebarNavIconClass`) | none (apps used 18px in a 20px box) | `size-[19px] shrink-0`; `text-muted-foreground` idle, `text-foreground` active |
|
|
664
|
-
| Section label | `px-3 py-1 text-[11px]` | `px-4 py-1 text-[11px] leading-4` (16px line). Colour
|
|
664
|
+
| Section label | `px-3 py-1 text-[11px]` | `px-4 py-1 text-[11px] leading-4` (16px line). Colour comes from `.sidebar-section-label` in `tokens.css` (0.15.0; `--muted` at `--sidebar-section-label-mix` 55%, 80% on hover). |
|
|
665
665
|
|
|
666
666
|
The hover fill is static: it does not slide between rows. While another row is hovered, the active row keeps its fill.
|
|
667
667
|
|
|
@@ -1059,9 +1059,9 @@ Use this when the app defines shadcn-style variables as space-separated channels
|
|
|
1059
1059
|
@source "../node_modules/@vvedantb/ui/src/**/*.{ts,tsx}";
|
|
1060
1060
|
```
|
|
1061
1061
|
|
|
1062
|
-
Shared CSS that is safe without `tokens.css`: `compat-shadcn-rgb.css`, `dialog.css`, `utilities.css`, `scrollbar-thin.css` (reads `--scrollbar`, which the compat file defines), `modal.css` and `tabs.css` (both need the
|
|
1062
|
+
Shared CSS that is safe without `tokens.css`: `compat-shadcn-rgb.css`, `dialog.css`, `utilities.css`, `scrollbar-thin.css` (reads `--scrollbar`, which the compat file defines), `clear-input.css` and `motion.css` (import them yourself; `tokens.css` is what imports them otherwise), `modal.css` and `tabs.css` (both need the motion variables listed in `tokens/README.md` on the app `:root`, because `tokens.css` sets them), and `animations.css` (not with the Tailwind preset). `base.css` and `tabs-pills.css` read raw `--accent`, `--foreground`, `--muted`, `--segment` and `--default`; skip them unless the app defines those as full colour values.
|
|
1063
1063
|
|
|
1064
|
-
The compat file
|
|
1064
|
+
The compat file defines `.glass-panel-strong` for toasts, dialogs and hover cards as the solid popover colour (`rgb(var(--popover))`, as `bg-overlay`), the same as `tokens.css`. Before 0.15.0 it was `rgb(var(--card) / 0.95)` with a 12px blur. The rule is in `@layer components`, so an app `.glass-panel-strong` rule after the import wins.
|
|
1065
1065
|
|
|
1066
1066
|
A fixture that renders the main components against sample light and dark RGB variables is in `tokens/examples/compat-shadcn-rgb/`.
|
|
1067
1067
|
|
package/app/README.md
CHANGED
|
@@ -160,7 +160,7 @@ import { PageMotionProvider, useDisablePageMotion } from "@vvedantb/ui";
|
|
|
160
160
|
</PageMotionProvider>;
|
|
161
161
|
```
|
|
162
162
|
|
|
163
|
-
- Sets `html[data-page-motion]` to `"off"` or `"on"` in a layout effect
|
|
163
|
+
- Sets `html[data-page-motion]` to `"off"` or `"on"` in a layout effect. The attribute stays after unmount. From 0.15.0 `tokens.css` (through `tokens/css/motion.css`) ships the `"off"` rules: `.ui-page-enter`, `.ui-enter`, `.ui-enter-up` and `.ui-stagger` fade only, `animate-in` / `animate-out`, `.t-modal` and `.t-tabs-pill` stop transitioning, and view transitions stop.
|
|
164
164
|
- Renders `motionConfig` with `reducedMotion` `"always"` when disabled, else `"never"`.
|
|
165
165
|
- `useDisablePageMotion()`: the `disabled` value, `false` outside the provider.
|
|
166
166
|
- This module does not import `motion`. Pass `MotionConfig`, or an app component that wraps it, defined at module level, for example with `LazyMotion`:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vvedantb/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Shared React 19 UI for web apps: one JavaScript entry (primitives, shell pieces, app helpers including the Convex and Clerk provider, VITE env parsing and ensure-user, artifact viewers over the @vvedantb/server artifacts core, native tokens), design-token CSS, shared Tailwind v4 CSS and a Tailwind preset.",
|
|
6
6
|
"type": "module",
|
|
@@ -27,6 +27,8 @@
|
|
|
27
27
|
"./tokens/css/tabs-pills.css": "./tokens/src/css/tabs-pills.css",
|
|
28
28
|
"./tokens/css/utilities.css": "./tokens/src/css/utilities.css",
|
|
29
29
|
"./tokens/css/scrollbar-thin.css": "./tokens/src/css/scrollbar-thin.css",
|
|
30
|
+
"./tokens/css/clear-input.css": "./tokens/src/css/clear-input.css",
|
|
31
|
+
"./tokens/css/motion.css": "./tokens/src/css/motion.css",
|
|
30
32
|
"./tokens/css/animations.css": "./tokens/src/css/animations.css",
|
|
31
33
|
"./tokens/css/nav-icons.css": "./tokens/src/css/nav-icons.css",
|
|
32
34
|
"./tokens/css/compat-shadcn-rgb.css": "./tokens/src/css/compat-shadcn-rgb.css",
|
|
@@ -21,8 +21,8 @@ export const railBadgeClass = "absolute -bottom-0.5 -right-0.5 flex h-4 min-w-4
|
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Static section label above a group of panel nav rows. `px-4` lines the text
|
|
24
|
-
* up with the nav row icons; the colour comes from
|
|
25
|
-
*
|
|
24
|
+
* up with the nav row icons; the colour comes from `.sidebar-section-label` in
|
|
25
|
+
* tokens.css.
|
|
26
26
|
*/
|
|
27
27
|
export const sidebarSectionLabelClass =
|
|
28
28
|
"sidebar-section-label px-4 py-1 text-[11px] leading-4 font-medium tracking-[-0.01em]";
|
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
/** transitions.dev input clear with dissolve — see 13-input-clear-dissolve.md */
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
// Times come back in ms. CSS minifiers rewrite `1000ms` as `1s`, so a value
|
|
4
|
+
// in seconds is converted rather than read as 1.
|
|
5
|
+
export function readCssNumber(
|
|
4
6
|
root: HTMLElement,
|
|
5
7
|
name: string,
|
|
6
8
|
fallback: number,
|
|
7
9
|
): number {
|
|
8
|
-
const raw = getComputedStyle(root).getPropertyValue(name);
|
|
10
|
+
const raw = getComputedStyle(root).getPropertyValue(name).trim();
|
|
9
11
|
const parsed = parseFloat(raw);
|
|
10
|
-
|
|
12
|
+
if (!Number.isFinite(parsed)) {
|
|
13
|
+
return fallback;
|
|
14
|
+
}
|
|
15
|
+
return /\ds$/.test(raw) ? parsed * 1000 : parsed;
|
|
11
16
|
}
|
|
12
17
|
|
|
13
|
-
function readCssEase(root: HTMLElement, name: string): (t: number) => number {
|
|
18
|
+
export function readCssEase(root: HTMLElement, name: string): (t: number) => number {
|
|
14
19
|
const raw = getComputedStyle(root).getPropertyValue(name);
|
|
15
20
|
const match = raw.match(
|
|
16
|
-
/cubic-bezier\(([-\d.]+)
|
|
21
|
+
/cubic-bezier\(\s*([-\d.]+)\s*,\s*([-\d.]+)\s*,\s*([-\d.]+)\s*,\s*([-\d.]+)\s*\)/,
|
|
17
22
|
);
|
|
18
23
|
if (!match) {
|
|
19
24
|
return (t) => t;
|
package/src/ui/dialog.tsx
CHANGED
|
@@ -213,7 +213,7 @@ DialogBody.displayName = "DialogBody";
|
|
|
213
213
|
|
|
214
214
|
// no fill of its own: the footer is not sticky, so it shows the content's
|
|
215
215
|
// surface. a token here (it was `bg-overlay`) showed as an inset block when
|
|
216
|
-
// that surface differs (`glass-panel-strong
|
|
216
|
+
// that surface differs (an app's own `glass-panel-strong`, or `bg-*` on the
|
|
217
217
|
// content)
|
|
218
218
|
const DialogFooter = ({
|
|
219
219
|
className,
|
package/tokens/README.md
CHANGED
|
@@ -6,18 +6,20 @@ Design tokens and shared Tailwind v4 CSS for the vvedantb web apps. The CSS and
|
|
|
6
6
|
|
|
7
7
|
| Export | File | What it is |
|
|
8
8
|
| --- | --- | --- |
|
|
9
|
-
| `@vvedantb/ui/tokens`, `@vvedantb/ui/tokens/tokens.css` | `src/tokens.css` | Colour, radius, shadow, ease and font tokens (`@theme`), light/dark variables, `dark` variant, the radius utilities `rounded-surface` (`clamp(0.75rem, var(--radius), 1rem)`), `rounded-menu-item` (`min(var(--radius), 0.5rem)`) and `rounded-control` (`min(var(--radius), 0.625rem)`) (0.7.1; `rounded-surface` was in `utilities.css` before), `*` border and `body` defaults. 0.7.2 adds `--sidebar-accent` / `sidebar-accent` (sidebar nav row fill: light `var(--surface-tertiary)`, dark `oklch(22.64% 0 0)`). In 0.2.1 it also defines shadcn-style aliases (`primary`, `muted-foreground`, `secondary`, `destructive`, `card`, `popover`, `input`, `ring`) that point at the same tokens. |
|
|
9
|
+
| `@vvedantb/ui/tokens`, `@vvedantb/ui/tokens/tokens.css` | `src/tokens.css` | Colour, radius, shadow, ease and font tokens (`@theme`), light/dark variables, `dark` variant, the radius utilities `rounded-surface` (`clamp(0.75rem, var(--radius), 1rem)`), `rounded-menu-item` (`min(var(--radius), 0.5rem)`) and `rounded-control` (`min(var(--radius), 0.625rem)`) (0.7.1; `rounded-surface` was in `utilities.css` before), `*` border and `body` defaults. 0.7.2 adds `--sidebar-accent` / `sidebar-accent` (sidebar nav row fill: light `var(--surface-tertiary)`, dark `oklch(22.64% 0 0)`). In 0.2.1 it also defines shadcn-style aliases (`primary`, `muted-foreground`, `secondary`, `destructive`, `card`, `popover`, `input`, `ring`) that point at the same tokens. From 0.15.0 it imports `clear-input.css`, `scrollbar-thin.css` and `motion.css`, sets the `--modal-*` and `--tabs-*` motion variables on `:root`, and defines `.glass-panel-strong` (`var(--overlay)`) and `.sidebar-section-label`. |
|
|
10
10
|
| `tokens` and `Tokens` from `@vvedantb/ui` | `src/native.ts` | JS colours, radii and spacing for React Native. `@vvedantb/native-ui` keeps its own copy in `src/tokens.ts`; a test keeps the two equal. |
|
|
11
11
|
| `@vvedantb/ui/tokens/css/base.css` | `src/css/base.css` | `html` touch/accent, `::selection`, control transitions, pointer cursor, range accent (`@layer base`). |
|
|
12
12
|
| `@vvedantb/ui/tokens/css/dialog.css` | `src/css/dialog.css` | Unlayered `max-width: none` for `@vvedantb/ui` compact (bottom-sheet) dialogs. |
|
|
13
13
|
| `@vvedantb/ui/tokens/css/modal.css` | `src/css/modal.css` | `.t-modal`, `.is-open`, `.is-closing` and `t-modal-presence-wait` (`@layer components`). |
|
|
14
|
-
| `@vvedantb/ui/tokens/css/tabs.css` | `src/css/tabs.css` | `.t-tab
|
|
14
|
+
| `@vvedantb/ui/tokens/css/tabs.css` | `src/css/tabs.css` | `.t-tabs` container (0.15.0), `.t-tab` with its press scale, active colour, `.t-tabs-pill`, small-screen `.t-tabs` scrolling. |
|
|
15
15
|
| `@vvedantb/ui/tokens/css/tabs-pills.css` | `src/css/tabs-pills.css` | `--tabs-*` colour variables, `.t-tabs--segmented`, `.t-tabs--pills` and pill hover / active fills. |
|
|
16
16
|
| `@vvedantb/ui/tokens/css/utilities.css` | `src/css/utilities.css` | `@utility hit-target` and `@utility reveal-on-hover`. `rounded-surface` moved to `tokens.css` in 0.7.1. |
|
|
17
|
-
| `@vvedantb/ui/tokens/css/scrollbar-thin.css` | `src/css/scrollbar-thin.css` | `.scrollbar-thin` (`@layer utilities`, always emitted). |
|
|
17
|
+
| `@vvedantb/ui/tokens/css/scrollbar-thin.css` | `src/css/scrollbar-thin.css` | `.scrollbar-thin` (`@layer utilities`, always emitted). Imported by `tokens.css` from 0.15.0. |
|
|
18
|
+
| `@vvedantb/ui/tokens/css/clear-input.css` | `src/css/clear-input.css` | `ClearInput` layers (`.t-clear*`) and the `--clear-*` / `--glow-*` timings. Imported by `tokens.css`. |
|
|
19
|
+
| `@vvedantb/ui/tokens/css/motion.css` | `src/css/motion.css` | `.ui-page-enter`, `.ui-enter`, `.ui-enter-up`, `.ui-stagger`, their keyframes and reduced-motion rules, and the `html[data-page-motion="off"]` overrides for `PageMotionProvider`. Imported by `tokens.css`. |
|
|
18
20
|
| `@vvedantb/ui/tokens/css/animations.css` | `src/css/animations.css` | `animate-aurora`, `animate-fade-in-up`, `animate-indeterminate` as `@theme` (CSS-first apps). |
|
|
19
|
-
| `@vvedantb/ui/tokens/css/compat-shadcn-rgb.css`, `@vvedantb/ui/tokens/compat/shadcn-rgb.css` | `src/css/compat-shadcn-rgb.css` | Replaces `tokens.css` for apps with shadcn-style `R G B` channel variables. Defines only the UI-only `--color-*` names as `rgb(var(--x) / alpha)` references, `--radius-field`, `--scrollbar`, `--field-radius`, the same three radius utilities as `tokens.css` and
|
|
20
|
-
| `@vvedantb/ui/tokens/css/index.css` | `src/css/index.css` | base + dialog +
|
|
21
|
+
| `@vvedantb/ui/tokens/css/compat-shadcn-rgb.css`, `@vvedantb/ui/tokens/compat/shadcn-rgb.css` | `src/css/compat-shadcn-rgb.css` | Replaces `tokens.css` for apps with shadcn-style `R G B` channel variables. Defines only the UI-only `--color-*` names as `rgb(var(--x) / alpha)` references, `--radius-field`, `--scrollbar`, `--field-radius`, the same three radius utilities as `tokens.css` and `.glass-panel-strong` (solid `--popover` from 0.15.0). Import it **or** `tokens.css`, never both. |
|
|
22
|
+
| `@vvedantb/ui/tokens/css/index.css` | `src/css/index.css` | base + dialog + modal + tabs + tabs-pills + utilities + animations + nav-icons, for new CSS-first apps (`tokens.css` brings scrollbar-thin). |
|
|
21
23
|
| `@vvedantb/ui/tokens/tailwind-preset` | `src/tailwind-preset.mjs` (+ `.d.mts`) | Tailwind preset for apps that load a JS config with `@config`. |
|
|
22
24
|
|
|
23
25
|
Every file was extracted because the same rule (same at-rule context, selector and body) sits in 3 or more of the five apps. The measured duplication is in `verify/ANALYSIS.md`, and the proof that each app compiles to the same CSS after migrating is in `verify/RESULTS.md`. Blocks that only 2 apps share, or that drift in a way that would change an app's CSS, stay in the apps; `verify/ANALYSIS.md` lists them.
|
|
@@ -35,6 +37,7 @@ CSS-first app (no `tailwind.config`):
|
|
|
35
37
|
@import "@vvedantb/ui/tokens/css/modal.css";
|
|
36
38
|
@import "@vvedantb/ui/tokens/css/tabs.css";
|
|
37
39
|
/* ...app @layer components rules... */
|
|
40
|
+
/* no --modal-* / --tabs-* needed: tokens.css sets them */
|
|
38
41
|
```
|
|
39
42
|
|
|
40
43
|
App with a JS config (`@config "../tailwind.config.ts"`):
|
|
@@ -65,17 +68,18 @@ Tailwind inlines an `@import` where it sits, even in the middle of a file (it mu
|
|
|
65
68
|
| --- | --- | --- |
|
|
66
69
|
| `base.css` | `--accent`, `--foreground` | tokens.css or the app theme |
|
|
67
70
|
| `dialog.css` | none | |
|
|
68
|
-
| `modal.css` | `--modal-open-dur`, `--modal-close-dur`, `--modal-scale`, `--modal-scale-close`, `--modal-ease` | app `:root` |
|
|
69
|
-
| `tabs.css` | `--tabs-dur`, `--tabs-ease` (app `:root`); `--tabs-text-muted`, `--tabs-text-active`, `--tabs-pill-bg` | colours: tabs-pills.css or the app theme |
|
|
71
|
+
| `modal.css` | `--modal-open-dur`, `--modal-close-dur`, `--modal-scale`, `--modal-scale-close`, `--modal-ease` | tokens.css (0.15.0), or app `:root` with the compat file |
|
|
72
|
+
| `tabs.css` | `--tabs-dur`, `--tabs-ease` (tokens.css, or app `:root` with the compat file); `--tabs-text-muted`, `--tabs-text-active`, `--tabs-pill-bg` | colours: tabs-pills.css or the app theme |
|
|
70
73
|
| `tabs-pills.css` | `--muted`, `--segment`, `--segment-foreground`, `--default` | tokens.css or the app theme |
|
|
71
74
|
| `utilities.css` | `--breakpoint-sm` (Tailwind default or app theme) | Tailwind |
|
|
72
75
|
| `scrollbar-thin.css` | `--scrollbar` | tokens.css or the app theme |
|
|
76
|
+
| `clear-input.css`, `motion.css` | none (own `:root` defaults) | |
|
|
73
77
|
| `animations.css` | none | |
|
|
74
78
|
| `tailwind-preset` | the CSS variables named in its colour map, `--radius`, `--field-radius` | tokens.css or the app theme |
|
|
75
79
|
|
|
76
80
|
### Using an existing shadcn RGB theme
|
|
77
81
|
|
|
78
|
-
See the package `README.md`. With the compat file, `base.css`, `scrollbar-thin.css`, `utilities.css`, `dialog.css`, `modal.css` and `tabs.css` need no `tokens.css
|
|
82
|
+
See the package `README.md`. With the compat file, `base.css`, `scrollbar-thin.css`, `clear-input.css`, `motion.css`, `utilities.css`, `dialog.css`, `modal.css` and `tabs.css` need no `tokens.css` (`modal.css` and `tabs.css` then need the `--modal-*` / `--tabs-*` values on the app `:root`). `base.css` reads `--accent` and `--foreground` and `tabs-pills.css` reads `--muted`, `--segment` and `--default`. Those are not channel-compatible, so skip `tabs-pills.css` and `index.css` (which includes `base.css`) unless the app defines those variables as full colours.
|
|
79
83
|
|
|
80
84
|
### Parameters
|
|
81
85
|
|
|
@@ -86,6 +90,24 @@ Where apps share a rule but drifted in one value, the value is a custom property
|
|
|
86
90
|
| `base.css` | `--tokens-control-transition-property` | `background-color, border-color, color, box-shadow, transform, opacity` | app-c: `background-color, color, transform, opacity` |
|
|
87
91
|
| `base.css` | `--tokens-control-transition-duration` | `240ms` | app-c: `100ms` |
|
|
88
92
|
|
|
93
|
+
From 0.15.0 the files that moved out of the apps take `:root` variables too. Every rule is in a Tailwind layer, so an app rule for the same selector (unlayered, or later in the same layer) also wins.
|
|
94
|
+
|
|
95
|
+
| File | Property | Default |
|
|
96
|
+
| --- | --- | --- |
|
|
97
|
+
| `tokens.css` | `--modal-open-dur`, `--modal-close-dur` | `180ms`, `120ms` |
|
|
98
|
+
| `tokens.css` | `--modal-scale`, `--modal-scale-close` | `0.96`, `0.96` |
|
|
99
|
+
| `tokens.css` | `--modal-ease`, `--tabs-ease` | `cubic-bezier(0.22, 1, 0.36, 1)` |
|
|
100
|
+
| `tokens.css` | `--tabs-dur` | `200ms` |
|
|
101
|
+
| `tokens.css` | `--sidebar-section-label-mix`, `--sidebar-section-label-hover-mix` | `55%`, `80%` (share of `--muted`) |
|
|
102
|
+
| `scrollbar-thin.css` | `--scrollbar-thin-rest`, `--scrollbar-thin-hover` | `40%`, `80%` (share of `--scrollbar`) |
|
|
103
|
+
| `clear-input.css` | `--clear-dur`, `--clear-out-dur`, `--clear-in-dur` | `1000ms`, `400ms`, `400ms` |
|
|
104
|
+
| `clear-input.css` | `--clear-out-fly`, `--clear-in-fly` | `12px`, `12px` |
|
|
105
|
+
| `clear-input.css` | `--clear-out-ease`, `--clear-in-ease` | `cubic-bezier(0.22, 1, 0.36, 1)` |
|
|
106
|
+
| `clear-input.css` | `--glow-delay`, `--glow-peak-at`, `--glow-opacity`, `--glow-spread` | `50ms`, `0.15`, `0.85`, `1.5` |
|
|
107
|
+
| `motion.css` | `--ui-enter-ease` | `cubic-bezier(0.22, 1, 0.36, 1)` |
|
|
108
|
+
| `motion.css` | `--ui-page-enter-dur`, `--ui-enter-dur`, `--ui-enter-up-dur` | `160ms`, `200ms`, `220ms` |
|
|
109
|
+
| `motion.css` | `--ui-stagger-step` | `40ms` (children 1 to 8) |
|
|
110
|
+
|
|
89
111
|
## Develop
|
|
90
112
|
|
|
91
113
|
```sh
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @vvedantb/ui/tokens/css/clear-input.css: layers for @vvedantb/ui
|
|
3
|
+
* ClearInput (`.t-clear`, mirror, placeholder and glow), the transitions.dev
|
|
4
|
+
* input clear with dissolve. tokens.css imports it.
|
|
5
|
+
*
|
|
6
|
+
* clearInputDissolve reads the variables below from `html`. Set any of them
|
|
7
|
+
* on the app `:root` to change the timing (numbers in ms or px):
|
|
8
|
+
* --clear-dur, --clear-out-dur, --clear-in-dur, --clear-out-fly,
|
|
9
|
+
* --clear-in-fly, --clear-out-ease, --clear-in-ease, --glow-delay,
|
|
10
|
+
* --glow-peak-at, --glow-opacity, --glow-spread
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
@layer base {
|
|
14
|
+
:root {
|
|
15
|
+
--clear-dur: 1000ms;
|
|
16
|
+
--clear-out-dur: 400ms;
|
|
17
|
+
--clear-in-dur: 400ms;
|
|
18
|
+
--clear-out-fly: 12px;
|
|
19
|
+
--clear-in-fly: 12px;
|
|
20
|
+
--clear-out-ease: cubic-bezier(0.22, 1, 0.36, 1);
|
|
21
|
+
--clear-in-ease: cubic-bezier(0.22, 1, 0.36, 1);
|
|
22
|
+
--glow-delay: 50ms;
|
|
23
|
+
--glow-peak-at: 0.15;
|
|
24
|
+
--glow-opacity: 0.85;
|
|
25
|
+
--glow-spread: 1.5;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@layer components {
|
|
30
|
+
.t-clear {
|
|
31
|
+
position: relative;
|
|
32
|
+
overflow: hidden;
|
|
33
|
+
}
|
|
34
|
+
.t-clear-mirror,
|
|
35
|
+
.t-clear-placeholder {
|
|
36
|
+
position: absolute;
|
|
37
|
+
inset: 0;
|
|
38
|
+
display: flex;
|
|
39
|
+
align-items: center;
|
|
40
|
+
pointer-events: none;
|
|
41
|
+
white-space: nowrap;
|
|
42
|
+
overflow: hidden;
|
|
43
|
+
z-index: 2;
|
|
44
|
+
}
|
|
45
|
+
.t-clear-mirror {
|
|
46
|
+
opacity: 0;
|
|
47
|
+
}
|
|
48
|
+
.t-clear.has-value .t-clear-mirror,
|
|
49
|
+
.t-clear.is-clearing .t-clear-mirror {
|
|
50
|
+
opacity: 1;
|
|
51
|
+
}
|
|
52
|
+
.t-clear.has-value > input,
|
|
53
|
+
.t-clear.is-clearing > input {
|
|
54
|
+
-webkit-text-fill-color: transparent;
|
|
55
|
+
}
|
|
56
|
+
.t-clear.has-value .t-clear-placeholder {
|
|
57
|
+
opacity: 0;
|
|
58
|
+
}
|
|
59
|
+
.t-clear-glow {
|
|
60
|
+
position: absolute;
|
|
61
|
+
inset: 0;
|
|
62
|
+
pointer-events: none;
|
|
63
|
+
opacity: 0;
|
|
64
|
+
z-index: 3;
|
|
65
|
+
mix-blend-mode: multiply;
|
|
66
|
+
}
|
|
67
|
+
.dark .t-clear-glow,
|
|
68
|
+
[data-theme="dark"] .t-clear-glow {
|
|
69
|
+
mix-blend-mode: screen;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -89,12 +89,13 @@
|
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
/*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
92
|
+
* Fill for toasts, dialogs and hover cards (`glass-panel-strong`): the solid
|
|
93
|
+
* popover colour, as `bg-overlay`, matching tokens.css. Any app
|
|
94
|
+
* `.glass-panel-strong` rule (unlayered, or in @layer components after this
|
|
95
|
+
* import) wins.
|
|
95
96
|
*/
|
|
96
|
-
@
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
97
|
+
@layer components {
|
|
98
|
+
.glass-panel-strong {
|
|
99
|
+
background-color: rgb(var(--popover));
|
|
100
|
+
}
|
|
100
101
|
}
|
package/tokens/src/css/index.css
CHANGED
|
@@ -6,15 +6,18 @@
|
|
|
6
6
|
* @import "@vvedantb/ui/tokens";
|
|
7
7
|
* @import "@vvedantb/ui/tokens/css/index.css";
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* the tailwind preset must not import animations.css;
|
|
12
|
-
* files one by one instead. nav-icons.css styles the
|
|
9
|
+
* tokens.css already brings scrollbar-thin.css, clear-input.css and
|
|
10
|
+
* motion.css, and the --modal-* / --tabs-* variables modal.css and tabs.css
|
|
11
|
+
* read. Apps that use the tailwind preset must not import animations.css;
|
|
12
|
+
* import the other files one by one instead. nav-icons.css styles the
|
|
13
|
+
* animated nav icons.
|
|
13
14
|
*/
|
|
14
15
|
|
|
15
16
|
@import "./base.css";
|
|
16
17
|
@import "./dialog.css";
|
|
18
|
+
@import "./modal.css";
|
|
19
|
+
@import "./tabs.css";
|
|
20
|
+
@import "./tabs-pills.css";
|
|
17
21
|
@import "./utilities.css";
|
|
18
|
-
@import "./scrollbar-thin.css";
|
|
19
22
|
@import "./animations.css";
|
|
20
23
|
@import "./nav-icons.css";
|
package/tokens/src/css/modal.css
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* @vvedantb/ui/tokens/css/modal.css: .t-modal open / close transition used by
|
|
3
3
|
* @vvedantb/ui Dialog (transitions.dev pattern).
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* --modal-scale-close
|
|
5
|
+
* Reads --modal-open-dur, --modal-close-dur, --modal-scale,
|
|
6
|
+
* --modal-scale-close and --modal-ease. tokens.css sets them on :root; set
|
|
7
|
+
* them on the app :root to change them (apps on compat-shadcn-rgb.css must).
|
|
7
8
|
*/
|
|
8
9
|
|
|
9
10
|
@layer components {
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @vvedantb/ui/tokens/css/motion.css: page and list enter animations
|
|
3
|
+
* (`.ui-page-enter`, `.ui-enter`, `.ui-enter-up`, `.ui-stagger`) and the
|
|
4
|
+
* overrides for PageMotionProvider's `html[data-page-motion="off"]`.
|
|
5
|
+
* tokens.css imports it. Keyframe names (`ui-*`) do not clash with
|
|
6
|
+
* animations.css or the tailwind preset.
|
|
7
|
+
*
|
|
8
|
+
* Set on :root to change (defaults shown):
|
|
9
|
+
* --ui-enter-ease: cubic-bezier(0.22, 1, 0.36, 1)
|
|
10
|
+
* --ui-page-enter-dur: 160ms
|
|
11
|
+
* --ui-enter-dur: 200ms
|
|
12
|
+
* --ui-enter-up-dur: 220ms
|
|
13
|
+
* --ui-stagger-step: 40ms (delay between the first 8 children)
|
|
14
|
+
*
|
|
15
|
+
* The app keeps its own view transition setup (names, timings, morphs); this
|
|
16
|
+
* file only turns those animations off for reduced motion and page motion off.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
@layer base {
|
|
20
|
+
:root {
|
|
21
|
+
--ui-enter-ease: cubic-bezier(0.22, 1, 0.36, 1);
|
|
22
|
+
--ui-page-enter-dur: 160ms;
|
|
23
|
+
--ui-enter-dur: 200ms;
|
|
24
|
+
--ui-enter-up-dur: 220ms;
|
|
25
|
+
--ui-stagger-step: 40ms;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@layer components {
|
|
30
|
+
.ui-page-enter {
|
|
31
|
+
animation: ui-page-enter var(--ui-page-enter-dur) var(--ui-enter-ease)
|
|
32
|
+
backwards;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.ui-enter,
|
|
36
|
+
.ui-stagger > * {
|
|
37
|
+
animation: ui-enter var(--ui-enter-dur) var(--ui-enter-ease) backwards;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.ui-enter-up {
|
|
41
|
+
animation: ui-enter-up var(--ui-enter-up-dur) var(--ui-enter-ease)
|
|
42
|
+
backwards;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.ui-stagger > *:nth-child(2) {
|
|
46
|
+
animation-delay: calc(var(--ui-stagger-step) * 1);
|
|
47
|
+
}
|
|
48
|
+
.ui-stagger > *:nth-child(3) {
|
|
49
|
+
animation-delay: calc(var(--ui-stagger-step) * 2);
|
|
50
|
+
}
|
|
51
|
+
.ui-stagger > *:nth-child(4) {
|
|
52
|
+
animation-delay: calc(var(--ui-stagger-step) * 3);
|
|
53
|
+
}
|
|
54
|
+
.ui-stagger > *:nth-child(5) {
|
|
55
|
+
animation-delay: calc(var(--ui-stagger-step) * 4);
|
|
56
|
+
}
|
|
57
|
+
.ui-stagger > *:nth-child(6) {
|
|
58
|
+
animation-delay: calc(var(--ui-stagger-step) * 5);
|
|
59
|
+
}
|
|
60
|
+
.ui-stagger > *:nth-child(7) {
|
|
61
|
+
animation-delay: calc(var(--ui-stagger-step) * 6);
|
|
62
|
+
}
|
|
63
|
+
.ui-stagger > *:nth-child(8) {
|
|
64
|
+
animation-delay: calc(var(--ui-stagger-step) * 7);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@keyframes ui-page-enter {
|
|
68
|
+
from {
|
|
69
|
+
opacity: 0;
|
|
70
|
+
transform: translateY(4px);
|
|
71
|
+
}
|
|
72
|
+
to {
|
|
73
|
+
opacity: 1;
|
|
74
|
+
transform: translateY(0);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@keyframes ui-enter {
|
|
79
|
+
from {
|
|
80
|
+
opacity: 0;
|
|
81
|
+
transform: translateY(6px);
|
|
82
|
+
}
|
|
83
|
+
to {
|
|
84
|
+
opacity: 1;
|
|
85
|
+
transform: translateY(0);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
@keyframes ui-enter-up {
|
|
90
|
+
from {
|
|
91
|
+
opacity: 0;
|
|
92
|
+
transform: translateY(12px);
|
|
93
|
+
}
|
|
94
|
+
to {
|
|
95
|
+
opacity: 1;
|
|
96
|
+
transform: translateY(0);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@keyframes ui-fade-only {
|
|
101
|
+
from {
|
|
102
|
+
opacity: 0;
|
|
103
|
+
}
|
|
104
|
+
to {
|
|
105
|
+
opacity: 1;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
@media (prefers-reduced-motion: reduce) {
|
|
110
|
+
.ui-page-enter,
|
|
111
|
+
.ui-enter,
|
|
112
|
+
.ui-enter-up,
|
|
113
|
+
.ui-stagger > * {
|
|
114
|
+
animation-duration: 1ms;
|
|
115
|
+
animation-name: ui-fade-only;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
::view-transition-group(*),
|
|
119
|
+
::view-transition-old(*),
|
|
120
|
+
::view-transition-new(*) {
|
|
121
|
+
animation: none !important;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/*
|
|
126
|
+
* PageMotionProvider `disabled` sets `html[data-page-motion="off"]`. Page and
|
|
127
|
+
* route enters, list stagger, `animate-in` / `animate-out`, the modal and
|
|
128
|
+
* tab pill transitions and view transitions stop. Spinners keep running and
|
|
129
|
+
* the modal still reaches its open state, so dialogs still appear.
|
|
130
|
+
*/
|
|
131
|
+
html[data-page-motion="off"] .ui-page-enter,
|
|
132
|
+
html[data-page-motion="off"] .ui-enter,
|
|
133
|
+
html[data-page-motion="off"] .ui-enter-up,
|
|
134
|
+
html[data-page-motion="off"] .ui-stagger > * {
|
|
135
|
+
animation-duration: 1ms;
|
|
136
|
+
animation-name: ui-fade-only;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
html[data-page-motion="off"] .animate-in,
|
|
140
|
+
html[data-page-motion="off"] .animate-out {
|
|
141
|
+
animation-duration: 0s !important;
|
|
142
|
+
animation-delay: 0s !important;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
html[data-page-motion="off"] .t-modal,
|
|
146
|
+
html[data-page-motion="off"] .t-modal.is-closing,
|
|
147
|
+
html[data-page-motion="off"] .t-tabs-pill {
|
|
148
|
+
transition-duration: 0s !important;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
html[data-page-motion="off"]::view-transition-group(*),
|
|
152
|
+
html[data-page-motion="off"]::view-transition-old(*),
|
|
153
|
+
html[data-page-motion="off"]::view-transition-new(*) {
|
|
154
|
+
animation: none !important;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -1,40 +1,68 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* @vvedantb/ui/tokens/css/scrollbar-thin.css: `.scrollbar-thin` (always emitted,
|
|
3
|
-
* plain @layer utilities). Needs --scrollbar.
|
|
3
|
+
* plain @layer utilities). Needs --scrollbar. tokens.css imports it; apps on
|
|
4
|
+
* compat-shadcn-rgb.css import it themselves.
|
|
4
5
|
*
|
|
5
|
-
* Standard
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* Standard properties first (Chrome 121+, Firefox). Chrome ignores webkit
|
|
7
|
+
* scrollbar rules once `scrollbar-color` is set, so the 6px webkit thumb is
|
|
8
|
+
* only a fallback for browsers without `scrollbar-color`.
|
|
9
|
+
*
|
|
10
|
+
* Thumb strength (share of --scrollbar), set on :root to change:
|
|
11
|
+
* --scrollbar-thin-rest: 40%
|
|
12
|
+
* --scrollbar-thin-hover: 80%
|
|
8
13
|
*/
|
|
9
14
|
|
|
10
|
-
@layer
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
scrollbar-color: color-mix(in oklch, var(--scrollbar) 80%, transparent)
|
|
15
|
-
transparent;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
.scrollbar-thin:hover {
|
|
19
|
-
scrollbar-color: color-mix(in oklch, var(--scrollbar) 100%, transparent)
|
|
20
|
-
transparent;
|
|
21
|
-
}
|
|
15
|
+
@layer base {
|
|
16
|
+
:root {
|
|
17
|
+
--scrollbar-thin-rest: 40%;
|
|
18
|
+
--scrollbar-thin-hover: 80%;
|
|
22
19
|
}
|
|
20
|
+
}
|
|
23
21
|
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
@layer utilities {
|
|
23
|
+
.scrollbar-thin {
|
|
24
|
+
scrollbar-width: thin;
|
|
25
|
+
scrollbar-color: color-mix(
|
|
26
|
+
in oklch,
|
|
27
|
+
var(--scrollbar) var(--scrollbar-thin-rest),
|
|
28
|
+
transparent
|
|
29
|
+
)
|
|
30
|
+
transparent;
|
|
26
31
|
}
|
|
27
32
|
|
|
28
|
-
.scrollbar-thin
|
|
29
|
-
|
|
33
|
+
.scrollbar-thin:hover {
|
|
34
|
+
scrollbar-color: color-mix(
|
|
35
|
+
in oklch,
|
|
36
|
+
var(--scrollbar) var(--scrollbar-thin-hover),
|
|
37
|
+
transparent
|
|
38
|
+
)
|
|
39
|
+
transparent;
|
|
30
40
|
}
|
|
31
41
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
42
|
+
@supports not (scrollbar-color: auto) {
|
|
43
|
+
.scrollbar-thin::-webkit-scrollbar {
|
|
44
|
+
width: 6px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.scrollbar-thin::-webkit-scrollbar-track {
|
|
48
|
+
background: transparent;
|
|
49
|
+
}
|
|
36
50
|
|
|
37
|
-
|
|
38
|
-
|
|
51
|
+
.scrollbar-thin::-webkit-scrollbar-thumb {
|
|
52
|
+
background-color: color-mix(
|
|
53
|
+
in oklch,
|
|
54
|
+
var(--scrollbar) var(--scrollbar-thin-rest),
|
|
55
|
+
transparent
|
|
56
|
+
);
|
|
57
|
+
border-radius: 3px;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.scrollbar-thin:hover::-webkit-scrollbar-thumb {
|
|
61
|
+
background-color: color-mix(
|
|
62
|
+
in oklch,
|
|
63
|
+
var(--scrollbar) var(--scrollbar-thin-hover),
|
|
64
|
+
transparent
|
|
65
|
+
);
|
|
66
|
+
}
|
|
39
67
|
}
|
|
40
68
|
}
|
package/tokens/src/css/tabs.css
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* @vvedantb/ui/tokens/css/tabs.css: sliding tab bar (.t-tab, .t-tabs-pill)
|
|
3
|
-
* used by @vvedantb/ui tabsSliding (transitions.dev pattern)
|
|
4
|
-
* container rule
|
|
3
|
+
* used by @vvedantb/ui tabsSliding (transitions.dev pattern), and the .t-tabs
|
|
4
|
+
* container. An app rule for any of them wins (@layer components).
|
|
5
5
|
*
|
|
6
|
-
* Needs: --tabs-dur, --tabs-ease, --tabs-text-muted,
|
|
7
|
-
* --tabs-pill-bg. tabs-pills.css sets the three colour
|
|
6
|
+
* Needs: --tabs-dur, --tabs-ease (defaults in tokens.css), --tabs-text-muted,
|
|
7
|
+
* --tabs-text-active, --tabs-pill-bg. tabs-pills.css sets the three colour
|
|
8
|
+
* variables.
|
|
8
9
|
*/
|
|
9
10
|
|
|
10
11
|
@layer components {
|
|
12
|
+
.t-tabs {
|
|
13
|
+
position: relative;
|
|
14
|
+
display: inline-flex;
|
|
15
|
+
align-items: center;
|
|
16
|
+
}
|
|
11
17
|
@media (max-width: 639px) {
|
|
12
18
|
.t-tabs {
|
|
13
19
|
justify-content: safe center;
|
|
@@ -29,7 +35,12 @@
|
|
|
29
35
|
cursor: pointer;
|
|
30
36
|
border-radius: 48px;
|
|
31
37
|
z-index: 1;
|
|
32
|
-
transition:
|
|
38
|
+
transition:
|
|
39
|
+
color var(--tabs-dur) var(--tabs-ease),
|
|
40
|
+
transform 100ms ease-out;
|
|
41
|
+
}
|
|
42
|
+
.t-tab:active {
|
|
43
|
+
transform: scale(0.97);
|
|
33
44
|
}
|
|
34
45
|
.t-tab:not([aria-selected="true"]):not([data-state="active"]):hover,
|
|
35
46
|
.t-tab[aria-selected="true"],
|
package/tokens/src/tokens.css
CHANGED
|
@@ -16,8 +16,19 @@
|
|
|
16
16
|
* @import url("https://fonts.googleapis.com/css2?family=Instrument+Sans:ital,wght@0,400..700;1,400..700&display=swap");
|
|
17
17
|
*
|
|
18
18
|
* Without it, --font-sans falls back to system-ui.
|
|
19
|
+
*
|
|
20
|
+
* From 0.15.0 this file also brings, on by default: the ClearInput layers,
|
|
21
|
+
* `.scrollbar-thin`, the `.ui-enter` family with the PageMotionProvider
|
|
22
|
+
* overrides, `.glass-panel-strong`, `.sidebar-section-label` and the
|
|
23
|
+
* modal / tabs motion variables. Every rule sits in a Tailwind layer and the
|
|
24
|
+
* timings and strengths are `:root` variables, so app rules and app `:root`
|
|
25
|
+
* values win.
|
|
19
26
|
*/
|
|
20
27
|
|
|
28
|
+
@import "./css/clear-input.css";
|
|
29
|
+
@import "./css/scrollbar-thin.css";
|
|
30
|
+
@import "./css/motion.css";
|
|
31
|
+
|
|
21
32
|
@custom-variant dark (&:where(.dark, .dark *));
|
|
22
33
|
|
|
23
34
|
@theme {
|
|
@@ -226,3 +237,44 @@
|
|
|
226
237
|
-moz-osx-font-smoothing: grayscale;
|
|
227
238
|
}
|
|
228
239
|
}
|
|
240
|
+
|
|
241
|
+
/* Motion for css/modal.css (`.t-modal`) and css/tabs.css (`.t-tab`,
|
|
242
|
+
`.t-tabs-pill`). Set any of them on the app `:root` to change it. */
|
|
243
|
+
@layer base {
|
|
244
|
+
:root {
|
|
245
|
+
--modal-open-dur: 180ms;
|
|
246
|
+
--modal-close-dur: 120ms;
|
|
247
|
+
--modal-scale: 0.96;
|
|
248
|
+
--modal-scale-close: 0.96;
|
|
249
|
+
--modal-ease: cubic-bezier(0.22, 1, 0.36, 1);
|
|
250
|
+
--tabs-dur: 200ms;
|
|
251
|
+
--tabs-ease: cubic-bezier(0.22, 1, 0.36, 1);
|
|
252
|
+
--sidebar-section-label-mix: 55%;
|
|
253
|
+
--sidebar-section-label-hover-mix: 80%;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
@layer components {
|
|
258
|
+
/* Solid overlay fill for Dialog, SonnerToaster, SlideOverPanel and
|
|
259
|
+
SessionsHoverCard `surface="glass"`. Same as `bg-overlay`. */
|
|
260
|
+
.glass-panel-strong {
|
|
261
|
+
background-color: var(--overlay);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/* Shell section label (`sidebarSectionLabelClass`). */
|
|
265
|
+
.sidebar-section-label {
|
|
266
|
+
color: color-mix(
|
|
267
|
+
in oklch,
|
|
268
|
+
var(--muted) var(--sidebar-section-label-mix),
|
|
269
|
+
transparent
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.sidebar-section-label:hover {
|
|
274
|
+
color: color-mix(
|
|
275
|
+
in oklch,
|
|
276
|
+
var(--muted) var(--sidebar-section-label-hover-mix),
|
|
277
|
+
transparent
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
}
|