terminoir 0.10.0 → 0.11.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 CHANGED
@@ -123,6 +123,7 @@ Import from **`terminoir`**:
123
123
  | `Button`, `IconButton` | Variants: primary, secondary, ghost, destructive, outline · sizes sm/md/lg · `Button href` renders a link |
124
124
  | `Input`, `Textarea`, `Select`, `Checkbox`, `Switch` | `hideLabel` (screen-reader only), `hint`, `error`, `quiet` (borderless until hover/focus, for inline property editing); `Input` `width` for toolbar fields |
125
125
  | `Chip`, `Badge` | Status tones; `Chip` `color` dot, `onclick`, removable `onremove` |
126
+ | `StatusChip` | On/off status: green dot + `activeLabel`, or muted `inactiveLabel` (defaults Connected / Not connected) |
126
127
  | `Card`, `CardGrid` | Accent tint, badge, chips, progress, meta, hover lift |
127
128
  | `Panel` | Glass panel surface |
128
129
  | `Dialog` | Modal with focus trap-ish behavior + Escape |
@@ -147,7 +148,8 @@ Building blocks so apps compose screens without CSS of their own. See the demo's
147
148
  | Component | Notes |
148
149
  |-----------|--------|
149
150
  | `Page`, `PageHeader`, `Section` | Readable page column (`narrow`/`default`/`wide`/`full`, `fill` for canvases); title + meta + actions; titled section with actions |
150
- | `Stack`, `Inline`, `Spacer`, `Centered` | Vertical / horizontal layout with `--space-*` gaps (`Inline fill` splits evenly); fill space; full-viewport centred column |
151
+ | `PanelHeader` | Heading inside a `Panel`: `logo` (round avatar, initials until `src`), `icon` or `leading` mark, title, description, `actions` (stacks under on phones) |
152
+ | `Stack`, `Inline`, `Spacer`, `Centered` | Vertical / horizontal layout with `--space-*` gaps (`Inline fill` splits evenly, `collapse` stacks on phones); fill space; full-viewport centred column |
151
153
  | `Text`, `Prose`, `Disclosure` | Tone/size/weight text; long-form typography; collapsible details |
152
154
  | `NavSection` | Sidebar section with title and action |
153
155
  | `DataTable` | Columns, `cell` snippet, clickable rows, `hideOnMobile`, empty state |
@@ -10,6 +10,7 @@
10
10
  justify = 'start',
11
11
  wrap = true,
12
12
  fill = false,
13
+ collapse = false,
13
14
  class: className = '',
14
15
  children,
15
16
  ...rest
@@ -21,6 +22,8 @@
21
22
  wrap?: boolean;
22
23
  /** Children share the row equally (e.g. two inputs side by side). */
23
24
  fill?: boolean;
25
+ /** Stack the children full-width on narrow screens (phones), e.g. a row of form fields. */
26
+ collapse?: boolean;
24
27
  class?: string;
25
28
  children?: Snippet;
26
29
  } & Record<string, unknown> = $props();
@@ -30,7 +33,7 @@
30
33
  </script>
31
34
 
32
35
  <div
33
- class={cn('terminoir-inline', fill && 'terminoir-inline--fill', className)}
36
+ class={cn('terminoir-inline', fill && 'terminoir-inline--fill', collapse && 'terminoir-inline--collapse', className)}
34
37
  style:gap={`var(--space-${gap})`}
35
38
  style:align-items={ALIGN[align]}
36
39
  style:justify-content={JUSTIFY[justify]}
@@ -49,4 +52,13 @@
49
52
  flex: 1 1 0;
50
53
  min-width: 0;
51
54
  }
55
+ @media (max-width: 700px) {
56
+ .terminoir-inline--collapse {
57
+ flex-direction: column;
58
+ }
59
+ .terminoir-inline--collapse > :global(*) {
60
+ flex: 0 0 auto;
61
+ width: 100%;
62
+ }
63
+ }
52
64
  </style>
@@ -8,6 +8,8 @@ type $$ComponentProps = {
8
8
  wrap?: boolean;
9
9
  /** Children share the row equally (e.g. two inputs side by side). */
10
10
  fill?: boolean;
11
+ /** Stack the children full-width on narrow screens (phones), e.g. a row of form fields. */
12
+ collapse?: boolean;
11
13
  class?: string;
12
14
  children?: Snippet;
13
15
  } & Record<string, unknown>;
@@ -0,0 +1,96 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import { cn } from '../utils/cn.js';
4
+ import Avatar from './Avatar.svelte';
5
+ import NavIcon from './NavIcon.svelte';
6
+
7
+ /**
8
+ * Heading inside a panel or card: a mark, a title, a one-line description and actions on the right.
9
+ * The mark is `logo` (an image, or the name's initials while there is no `src`), `icon`, or `leading`.
10
+ */
11
+ let {
12
+ title,
13
+ description,
14
+ icon,
15
+ logo,
16
+ class: className = '',
17
+ leading,
18
+ actions,
19
+ }: {
20
+ title: string;
21
+ description?: string;
22
+ /** Font Awesome name, as for `NavIcon`. */
23
+ icon?: string;
24
+ /** A service or brand mark, shown as a round `Avatar`. */
25
+ logo?: { name: string; src?: string };
26
+ class?: string;
27
+ /** Custom mark; overrides `logo` and `icon`. */
28
+ leading?: Snippet;
29
+ /** Status chips or buttons aligned to the right. */
30
+ actions?: Snippet;
31
+ } = $props();
32
+ </script>
33
+
34
+ <header class={cn('terminoir-panel-header', className)}>
35
+ {#if leading}
36
+ <span class="terminoir-panel-header__mark">{@render leading()}</span>
37
+ {:else if logo}
38
+ <Avatar name={logo.name} src={logo.src} size={36} />
39
+ {:else if icon}
40
+ <span class="terminoir-panel-header__mark"><NavIcon name={icon} /></span>
41
+ {/if}
42
+ <div class="terminoir-panel-header__text">
43
+ <h3 class="terminoir-panel-header__title">{title}</h3>
44
+ {#if description}<p class="terminoir-panel-header__description">{description}</p>{/if}
45
+ </div>
46
+ {#if actions}
47
+ <div class="terminoir-panel-header__actions">{@render actions()}</div>
48
+ {/if}
49
+ </header>
50
+
51
+ <style>
52
+ .terminoir-panel-header {
53
+ display: flex;
54
+ align-items: center;
55
+ gap: var(--space-3);
56
+ min-width: 0;
57
+ }
58
+ .terminoir-panel-header__mark {
59
+ display: inline-flex;
60
+ align-items: center;
61
+ justify-content: center;
62
+ flex-shrink: 0;
63
+ min-width: 1.25rem;
64
+ }
65
+ .terminoir-panel-header__text {
66
+ flex: 1;
67
+ min-width: 0;
68
+ display: flex;
69
+ flex-direction: column;
70
+ gap: 0.15rem;
71
+ }
72
+ .terminoir-panel-header__title {
73
+ margin: 0;
74
+ font-size: 0.9375rem;
75
+ font-weight: 600;
76
+ line-height: 1.35;
77
+ overflow-wrap: anywhere;
78
+ }
79
+ .terminoir-panel-header__description {
80
+ margin: 0;
81
+ color: var(--muted-foreground);
82
+ font-size: 0.8125rem;
83
+ line-height: 1.45;
84
+ }
85
+ .terminoir-panel-header__actions {
86
+ display: flex;
87
+ flex-wrap: wrap;
88
+ align-items: center;
89
+ gap: var(--space-3);
90
+ flex-shrink: 0;
91
+ }
92
+ @media (max-width: 700px) {
93
+ .terminoir-panel-header { flex-wrap: wrap; }
94
+ .terminoir-panel-header__actions { width: 100%; }
95
+ }
96
+ </style>
@@ -0,0 +1,20 @@
1
+ import type { Snippet } from 'svelte';
2
+ type $$ComponentProps = {
3
+ title: string;
4
+ description?: string;
5
+ /** Font Awesome name, as for `NavIcon`. */
6
+ icon?: string;
7
+ /** A service or brand mark, shown as a round `Avatar`. */
8
+ logo?: {
9
+ name: string;
10
+ src?: string;
11
+ };
12
+ class?: string;
13
+ /** Custom mark; overrides `logo` and `icon`. */
14
+ leading?: Snippet;
15
+ /** Status chips or buttons aligned to the right. */
16
+ actions?: Snippet;
17
+ };
18
+ declare const PanelHeader: import("svelte").Component<$$ComponentProps, {}, "">;
19
+ type PanelHeader = ReturnType<typeof PanelHeader>;
20
+ export default PanelHeader;
@@ -0,0 +1,21 @@
1
+ <script lang="ts">
2
+ import Chip from './Chip.svelte';
3
+
4
+ /** On/off status: `active` shows a green dot and `activeLabel`; otherwise a muted `inactiveLabel`. */
5
+ let {
6
+ active,
7
+ activeLabel = 'Connected',
8
+ inactiveLabel = 'Not connected',
9
+ class: className = '',
10
+ ...rest
11
+ }: {
12
+ active: boolean;
13
+ activeLabel?: string;
14
+ inactiveLabel?: string;
15
+ class?: string;
16
+ } & Record<string, unknown> = $props();
17
+ </script>
18
+
19
+ <Chip tone={active ? 'default' : 'done'} color={active ? 'green' : undefined} class={className} {...rest}>
20
+ {active ? activeLabel : inactiveLabel}
21
+ </Chip>
@@ -0,0 +1,9 @@
1
+ type $$ComponentProps = {
2
+ active: boolean;
3
+ activeLabel?: string;
4
+ inactiveLabel?: string;
5
+ class?: string;
6
+ } & Record<string, unknown>;
7
+ declare const StatusChip: import("svelte").Component<$$ComponentProps, {}, "">;
8
+ type StatusChip = ReturnType<typeof StatusChip>;
9
+ export default StatusChip;
package/dist/index.d.ts CHANGED
@@ -34,6 +34,7 @@ export { default as Panel } from './components/Panel.svelte';
34
34
  export { default as Popover } from './components/Popover.svelte';
35
35
  export { default as Select } from './components/Select.svelte';
36
36
  export { default as Skeleton } from './components/Skeleton.svelte';
37
+ export { default as StatusChip } from './components/StatusChip.svelte';
37
38
  export { default as Switch } from './components/Switch.svelte';
38
39
  export { default as Tabs } from './components/Tabs.svelte';
39
40
  export { default as Textarea } from './components/Textarea.svelte';
@@ -41,6 +42,7 @@ export { default as Toaster } from './components/Toaster.svelte';
41
42
  export { default as Tooltip } from './components/Tooltip.svelte';
42
43
  export { default as Page } from './components/Page.svelte';
43
44
  export { default as PageHeader } from './components/PageHeader.svelte';
45
+ export { default as PanelHeader } from './components/PanelHeader.svelte';
44
46
  export { default as Section } from './components/Section.svelte';
45
47
  export { default as Stack } from './components/Stack.svelte';
46
48
  export { default as Inline } from './components/Inline.svelte';
package/dist/index.js CHANGED
@@ -32,6 +32,7 @@ export { default as Panel } from './components/Panel.svelte';
32
32
  export { default as Popover } from './components/Popover.svelte';
33
33
  export { default as Select } from './components/Select.svelte';
34
34
  export { default as Skeleton } from './components/Skeleton.svelte';
35
+ export { default as StatusChip } from './components/StatusChip.svelte';
35
36
  export { default as Switch } from './components/Switch.svelte';
36
37
  export { default as Tabs } from './components/Tabs.svelte';
37
38
  export { default as Textarea } from './components/Textarea.svelte';
@@ -40,6 +41,7 @@ export { default as Tooltip } from './components/Tooltip.svelte';
40
41
  // Layout
41
42
  export { default as Page } from './components/Page.svelte';
42
43
  export { default as PageHeader } from './components/PageHeader.svelte';
44
+ export { default as PanelHeader } from './components/PanelHeader.svelte';
43
45
  export { default as Section } from './components/Section.svelte';
44
46
  export { default as Stack } from './components/Stack.svelte';
45
47
  export { default as Inline } from './components/Inline.svelte';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "terminoir",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "Terminoir — Liquid Glass design tokens and Svelte 5 UI components.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",