@runwisp/ui 0.4.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.
Files changed (108) hide show
  1. package/LICENSE +215 -0
  2. package/README.md +20 -0
  3. package/package.json +128 -0
  4. package/src/app.d.ts +8 -0
  5. package/src/app.html +12 -0
  6. package/src/astro/CTABand.astro +32 -0
  7. package/src/astro/Hero.astro +58 -0
  8. package/src/astro/SiteFooter.astro +47 -0
  9. package/src/astro/SiteHeader.astro +46 -0
  10. package/src/lib/actions/portal.ts +16 -0
  11. package/src/lib/assets/runwisp-logo.svg +16 -0
  12. package/src/lib/components/Accordion.svelte +20 -0
  13. package/src/lib/components/AccordionItem.svelte +74 -0
  14. package/src/lib/components/Alert.svelte +107 -0
  15. package/src/lib/components/AlertDialog.svelte +63 -0
  16. package/src/lib/components/Avatar.svelte +88 -0
  17. package/src/lib/components/Badge.svelte +131 -0
  18. package/src/lib/components/Breadcrumb.svelte +58 -0
  19. package/src/lib/components/Button.svelte +69 -0
  20. package/src/lib/components/Card.svelte +70 -0
  21. package/src/lib/components/Checkbox.svelte +90 -0
  22. package/src/lib/components/CodeBlock.svelte +66 -0
  23. package/src/lib/components/CronInput.svelte +130 -0
  24. package/src/lib/components/DataGrid.svelte +368 -0
  25. package/src/lib/components/Drawer.svelte +156 -0
  26. package/src/lib/components/Dropdown.svelte +195 -0
  27. package/src/lib/components/DurationInput.svelte +170 -0
  28. package/src/lib/components/EmptyState.svelte +46 -0
  29. package/src/lib/components/ErrorState.svelte +73 -0
  30. package/src/lib/components/FeatureCard.svelte +35 -0
  31. package/src/lib/components/FeatureGrid.svelte +37 -0
  32. package/src/lib/components/FormField.svelte +53 -0
  33. package/src/lib/components/Heading.svelte +46 -0
  34. package/src/lib/components/Input.svelte +114 -0
  35. package/src/lib/components/Kbd.svelte +31 -0
  36. package/src/lib/components/Link.svelte +56 -0
  37. package/src/lib/components/LinkButton.svelte +55 -0
  38. package/src/lib/components/LogConsole.svelte +424 -0
  39. package/src/lib/components/Logo.svelte +34 -0
  40. package/src/lib/components/Modal.svelte +138 -0
  41. package/src/lib/components/PageContainer.svelte +38 -0
  42. package/src/lib/components/Pagination.svelte +96 -0
  43. package/src/lib/components/Popover.svelte +130 -0
  44. package/src/lib/components/Progress.svelte +68 -0
  45. package/src/lib/components/Prose.svelte +43 -0
  46. package/src/lib/components/Radio.svelte +82 -0
  47. package/src/lib/components/RadioGroup.svelte +53 -0
  48. package/src/lib/components/Select.svelte +454 -0
  49. package/src/lib/components/Separator.svelte +30 -0
  50. package/src/lib/components/Skeleton.svelte +75 -0
  51. package/src/lib/components/Sparkline.svelte +58 -0
  52. package/src/lib/components/Spinner.svelte +44 -0
  53. package/src/lib/components/StatusIndicator.svelte +203 -0
  54. package/src/lib/components/Table.svelte +19 -0
  55. package/src/lib/components/TableBody.svelte +17 -0
  56. package/src/lib/components/TableCell.svelte +34 -0
  57. package/src/lib/components/TableHead.svelte +19 -0
  58. package/src/lib/components/TableRow.svelte +22 -0
  59. package/src/lib/components/Tabs.svelte +148 -0
  60. package/src/lib/components/Text.svelte +57 -0
  61. package/src/lib/components/Textarea.svelte +81 -0
  62. package/src/lib/components/ThemeToggle.svelte +47 -0
  63. package/src/lib/components/TimezoneSelect.svelte +127 -0
  64. package/src/lib/components/ToastContainer.svelte +84 -0
  65. package/src/lib/components/Toggle.svelte +84 -0
  66. package/src/lib/components/Tooltip.svelte +56 -0
  67. package/src/lib/components/button-styles.ts +51 -0
  68. package/src/lib/components/dashboard/RunDetailPanel.svelte +252 -0
  69. package/src/lib/components/dashboard/RunsList.svelte +331 -0
  70. package/src/lib/components/dashboard/run-helpers.ts +12 -0
  71. package/src/lib/components/dashboard/status-config.ts +141 -0
  72. package/src/lib/components/dashboard/types.ts +35 -0
  73. package/src/lib/index.ts +122 -0
  74. package/src/lib/log-console/LogCache.svelte.ts +93 -0
  75. package/src/lib/log-console/LogFetcher.svelte.ts +179 -0
  76. package/src/lib/log-console/types.ts +24 -0
  77. package/src/lib/theme-tokens.css +235 -0
  78. package/src/lib/theme.css +276 -0
  79. package/src/lib/utils/error.ts +18 -0
  80. package/src/lib/utils/format.ts +76 -0
  81. package/src/lib/utils/id.ts +6 -0
  82. package/src/lib/utils/toast.svelte.ts +87 -0
  83. package/src/lib/utils/toast.ts +60 -0
  84. package/src/routes/+layout.svelte +10 -0
  85. package/src/routes/+page.svelte +5 -0
  86. package/src/routes/layout.css +3 -0
  87. package/src/stories/Alert.stories.svelte +64 -0
  88. package/src/stories/Avatar.stories.svelte +76 -0
  89. package/src/stories/Badge.stories.svelte +76 -0
  90. package/src/stories/Breadcrumb.stories.svelte +64 -0
  91. package/src/stories/Button.stories.svelte +101 -0
  92. package/src/stories/Card.stories.svelte +106 -0
  93. package/src/stories/Checkbox.stories.svelte +77 -0
  94. package/src/stories/DataGrid.stories.svelte +130 -0
  95. package/src/stories/Dropdown.stories.svelte +81 -0
  96. package/src/stories/EmptyState.stories.svelte +74 -0
  97. package/src/stories/Input.stories.svelte +88 -0
  98. package/src/stories/Logo.stories.svelte +82 -0
  99. package/src/stories/Modal.stories.svelte +101 -0
  100. package/src/stories/Progress.stories.svelte +65 -0
  101. package/src/stories/Select.stories.svelte +158 -0
  102. package/src/stories/Tabs.stories.svelte +103 -0
  103. package/src/stories/Textarea.stories.svelte +45 -0
  104. package/src/stories/Toggle.stories.svelte +74 -0
  105. package/src/stories/Tooltip.stories.svelte +77 -0
  106. package/src/stories/Welcome.mdx +241 -0
  107. package/src/stories/assets/runwisp_c.svg +16 -0
  108. package/src/svelte-shims.d.ts +18 -0
@@ -0,0 +1,37 @@
1
+ <!-- SPDX-FileCopyrightText: PoppyCake, s.r.o. -->
2
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
3
+
4
+ <script lang="ts">
5
+ import type { Snippet } from "svelte";
6
+
7
+ interface Props {
8
+ columns?: 1 | 2 | 3 | 4;
9
+ gap?: "sm" | "md" | "lg";
10
+ children?: Snippet;
11
+ class?: string;
12
+ }
13
+
14
+ let { columns = 3, gap = "md", children, class: className = "" }: Props = $props();
15
+
16
+ const colClasses: Record<1 | 2 | 3 | 4, string> = {
17
+ 1: "grid-cols-1",
18
+ 2: "grid-cols-1 sm:grid-cols-2",
19
+ 3: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
20
+ 4: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-4",
21
+ };
22
+
23
+ const gapClasses: Record<"sm" | "md" | "lg", string> = {
24
+ sm: "gap-3",
25
+ md: "gap-4",
26
+ lg: "gap-6",
27
+ };
28
+
29
+ const colClass = $derived(colClasses[columns]);
30
+ const gapClass = $derived(gapClasses[gap]);
31
+ </script>
32
+
33
+ <div class="grid {colClass} {gapClass} {className}">
34
+ {#if children}
35
+ {@render children()}
36
+ {/if}
37
+ </div>
@@ -0,0 +1,53 @@
1
+ <!-- SPDX-FileCopyrightText: PoppyCake, s.r.o. -->
2
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
3
+
4
+ <script lang="ts">
5
+ import type { Snippet } from "svelte";
6
+
7
+ interface Props {
8
+ label?: string;
9
+ hint?: string;
10
+ error?: string;
11
+ description?: string;
12
+ required?: boolean;
13
+ children: Snippet;
14
+ class?: string;
15
+ }
16
+
17
+ let {
18
+ label,
19
+ hint,
20
+ error,
21
+ description,
22
+ required = false,
23
+ children,
24
+ class: className = "",
25
+ }: Props = $props();
26
+
27
+ const generatedId = `field-${Math.random().toString(36).slice(2, 10)}`;
28
+ </script>
29
+
30
+ <div class="space-y-1.5 {className}">
31
+ {#if label}
32
+ <label for={generatedId} class="block text-sm font-medium text-on-surface-muted">
33
+ {label}
34
+ {#if required}
35
+ <span class="text-danger-500">*</span>
36
+ {/if}
37
+ </label>
38
+ {/if}
39
+
40
+ {#if description}
41
+ <p class="text-sm text-on-surface-faint">{description}</p>
42
+ {/if}
43
+
44
+ {@render children()}
45
+
46
+ {#if error}
47
+ <p class="animate-in slide-in-from-top-1 fade-in text-sm text-danger-600 duration-200">
48
+ {error}
49
+ </p>
50
+ {:else if hint}
51
+ <p class="text-sm text-on-surface-muted">{hint}</p>
52
+ {/if}
53
+ </div>
@@ -0,0 +1,46 @@
1
+ <!-- SPDX-FileCopyrightText: PoppyCake, s.r.o. -->
2
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
3
+
4
+ <script lang="ts">
5
+ import type { Snippet } from "svelte";
6
+
7
+ type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
8
+ type HeadingSize = "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl";
9
+
10
+ interface Props {
11
+ level: HeadingLevel;
12
+ size?: HeadingSize;
13
+ children: Snippet;
14
+ class?: string;
15
+ }
16
+
17
+ let { level, size, children, class: className = "" }: Props = $props();
18
+
19
+ const defaultSizeMap: Record<HeadingLevel, HeadingSize> = {
20
+ 1: "4xl",
21
+ 2: "3xl",
22
+ 3: "2xl",
23
+ 4: "xl",
24
+ 5: "lg",
25
+ 6: "base" as HeadingSize,
26
+ };
27
+
28
+ const sizeClasses: Record<string, string> = {
29
+ xs: "text-xs font-semibold",
30
+ sm: "text-sm font-semibold",
31
+ base: "text-base font-semibold",
32
+ md: "text-base font-semibold",
33
+ lg: "text-lg font-semibold",
34
+ xl: "text-xl font-bold",
35
+ "2xl": "text-2xl font-bold",
36
+ "3xl": "text-3xl font-bold",
37
+ "4xl": "text-4xl font-bold tracking-tight",
38
+ };
39
+
40
+ const resolvedSize = $derived(size ?? defaultSizeMap[level]);
41
+ const tag = $derived(`h${level}` as const);
42
+ </script>
43
+
44
+ <svelte:element this={tag} class="text-on-surface {sizeClasses[resolvedSize]} {className}">
45
+ {@render children()}
46
+ </svelte:element>
@@ -0,0 +1,114 @@
1
+ <!-- SPDX-FileCopyrightText: PoppyCake, s.r.o. -->
2
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
3
+
4
+ <script lang="ts">
5
+ import type { Snippet } from "svelte";
6
+ import type { HTMLInputAttributes } from "svelte/elements";
7
+ import { CircleAlert } from "@lucide/svelte";
8
+
9
+ type InputSize = "sm" | "md" | "lg";
10
+
11
+ interface Props extends Omit<HTMLInputAttributes, "size"> {
12
+ size?: InputSize;
13
+ label?: string;
14
+ hint?: string;
15
+ error?: string | undefined;
16
+ leadingIcon?: Snippet;
17
+ trailingIcon?: Snippet;
18
+ class?: string;
19
+ }
20
+
21
+ let {
22
+ size = "md",
23
+ value = $bindable(),
24
+ id,
25
+ label,
26
+ hint,
27
+ error = $bindable(),
28
+ leadingIcon,
29
+ trailingIcon,
30
+ disabled = false,
31
+ class: className = "",
32
+ oninput,
33
+ ...restProps
34
+ }: Props = $props();
35
+
36
+ const generatedId = `input-${Math.random().toString(36).slice(2, 10)}`;
37
+ const inputId = $derived(id ?? generatedId);
38
+
39
+ const sizeClasses: Record<InputSize, string> = {
40
+ sm: "text-sm px-3 py-1.5",
41
+ md: "text-sm px-3.5 py-2",
42
+ lg: "text-base px-4 py-2.5",
43
+ };
44
+
45
+ const inputClasses = `
46
+ w-full rounded-lg border
47
+ bg-surface-raised text-on-surface placeholder:text-on-surface-faint
48
+ focus:outline-none focus:ring-4 focus:ring-ring/10 focus:border-ring
49
+ disabled:bg-surface-sunken disabled:text-on-surface-muted disabled:cursor-not-allowed
50
+ transition-all duration-normal ease-in-out
51
+ `;
52
+
53
+ const normalBorder = "border-outline hover:border-outline-hover shadow-sm";
54
+ const errorBorder = "border-danger-400 focus:border-danger-500 focus:ring-danger-500/20";
55
+ </script>
56
+
57
+ <div class="space-y-1.5 {className}">
58
+ {#if label}
59
+ <label for={inputId} class="block text-sm font-medium text-on-surface-muted">
60
+ {label}
61
+ </label>
62
+ {/if}
63
+
64
+ <div class="group relative">
65
+ {#if leadingIcon}
66
+ <div
67
+ class="pointer-events-none absolute top-1/2 left-3 -translate-y-1/2 text-on-surface-faint transition-colors group-focus-within:text-on-surface-muted"
68
+ >
69
+ {@render leadingIcon()}
70
+ </div>
71
+ {/if}
72
+
73
+ <input
74
+ id={inputId}
75
+ class="
76
+ {inputClasses}
77
+ {sizeClasses[size]}
78
+ {error ? errorBorder : normalBorder}
79
+ {leadingIcon ? 'pl-10' : ''}
80
+ {trailingIcon || error ? 'pr-10' : ''}
81
+ "
82
+ {disabled}
83
+ bind:value
84
+ aria-invalid={error ? "true" : undefined}
85
+ oninput={(e) => {
86
+ if (error) error = undefined;
87
+ oninput?.(e);
88
+ }}
89
+ {...restProps}
90
+ />
91
+
92
+ {#if error}
93
+ <div
94
+ class="pointer-events-none absolute top-1/2 right-3 -translate-y-1/2 text-danger-500"
95
+ >
96
+ <CircleAlert size={18} />
97
+ </div>
98
+ {:else if trailingIcon}
99
+ <div
100
+ class="pointer-events-none absolute top-1/2 right-3 -translate-y-1/2 text-on-surface-faint transition-colors group-focus-within:text-on-surface-muted"
101
+ >
102
+ {@render trailingIcon()}
103
+ </div>
104
+ {/if}
105
+ </div>
106
+
107
+ {#if error}
108
+ <p class="animate-in slide-in-from-top-1 fade-in text-sm text-danger-600 duration-200">
109
+ {error}
110
+ </p>
111
+ {:else if hint}
112
+ <p class="text-sm text-on-surface-muted">{hint}</p>
113
+ {/if}
114
+ </div>
@@ -0,0 +1,31 @@
1
+ <!-- SPDX-FileCopyrightText: PoppyCake, s.r.o. -->
2
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
3
+
4
+ <script lang="ts">
5
+ interface Props {
6
+ keys: string | string[];
7
+ class?: string;
8
+ }
9
+
10
+ let { keys, class: className = "" }: Props = $props();
11
+
12
+ const keyList = $derived(Array.isArray(keys) ? keys : [keys]);
13
+
14
+ const kbdClasses = `
15
+ inline-flex items-center justify-center
16
+ min-w-[1.5em] px-1.5 py-0.5
17
+ text-xs font-mono font-medium
18
+ bg-surface-sunken text-on-surface-muted
19
+ border border-outline rounded-md
20
+ shadow-sm
21
+ `;
22
+ </script>
23
+
24
+ <span class="inline-flex items-center gap-1 {className}">
25
+ {#each keyList as key, i (key)}
26
+ {#if i > 0}
27
+ <span class="text-xs text-on-surface-faint select-none">+</span>
28
+ {/if}
29
+ <kbd class={kbdClasses}>{key}</kbd>
30
+ {/each}
31
+ </span>
@@ -0,0 +1,56 @@
1
+ <!-- SPDX-FileCopyrightText: PoppyCake, s.r.o. -->
2
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
3
+
4
+ <script lang="ts">
5
+ import type { Snippet } from "svelte";
6
+
7
+ type LinkVariant = "default" | "muted" | "primary" | "danger";
8
+ type LinkUnderline = "always" | "hover" | "none";
9
+
10
+ interface Props {
11
+ href: string;
12
+ variant?: LinkVariant;
13
+ external?: boolean;
14
+ underline?: LinkUnderline;
15
+ children: Snippet;
16
+ class?: string;
17
+ }
18
+
19
+ let {
20
+ href,
21
+ variant = "default",
22
+ external = false,
23
+ underline = "hover",
24
+ children,
25
+ class: className = "",
26
+ }: Props = $props();
27
+
28
+ const baseClasses = `
29
+ inline-flex items-center gap-1
30
+ transition-colors duration-normal ease-out
31
+ focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-ring/10 focus-visible:border-ring
32
+ rounded-sm
33
+ `;
34
+
35
+ const variantClasses: Record<LinkVariant, string> = {
36
+ default: "text-on-surface hover:text-primary",
37
+ muted: "text-on-surface-muted hover:text-on-surface",
38
+ primary: "text-primary hover:text-primary-hover",
39
+ danger: "text-danger-surface hover:text-danger-hover",
40
+ };
41
+
42
+ const underlineClasses: Record<LinkUnderline, string> = {
43
+ always: "underline underline-offset-2",
44
+ hover: "hover:underline underline-offset-2",
45
+ none: "no-underline",
46
+ };
47
+ </script>
48
+
49
+ <a
50
+ {href}
51
+ class="{baseClasses} {variantClasses[variant]} {underlineClasses[underline]} {className}"
52
+ target={external ? "_blank" : undefined}
53
+ rel={external ? "noopener noreferrer" : undefined}
54
+ >
55
+ {@render children()}
56
+ </a>
@@ -0,0 +1,55 @@
1
+ <!-- SPDX-FileCopyrightText: PoppyCake, s.r.o. -->
2
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
3
+
4
+ <script lang="ts">
5
+ import type { Snippet } from "svelte";
6
+ import type { HTMLAnchorAttributes } from "svelte/elements";
7
+ import {
8
+ BUTTON_BASE,
9
+ BUTTON_SIZES,
10
+ BUTTON_VARIANTS,
11
+ type ButtonSize,
12
+ type ButtonVariant,
13
+ } from "./button-styles.js";
14
+
15
+ interface Props extends HTMLAnchorAttributes {
16
+ variant?: ButtonVariant;
17
+ size?: ButtonSize;
18
+ fullWidth?: boolean;
19
+ icon?: Snippet;
20
+ iconRight?: Snippet;
21
+ children?: Snippet;
22
+ }
23
+
24
+ let {
25
+ variant = "primary",
26
+ size = "md",
27
+ fullWidth = false,
28
+ icon,
29
+ iconRight,
30
+ children,
31
+ class: className = "",
32
+ ...restProps
33
+ }: Props = $props();
34
+ </script>
35
+
36
+ <a
37
+ class="{BUTTON_BASE} {BUTTON_VARIANTS[variant]} {BUTTON_SIZES[size]} {fullWidth
38
+ ? 'w-full'
39
+ : ''} {className}"
40
+ {...restProps}
41
+ >
42
+ {#if icon}
43
+ <span class="shrink-0 transition-transform group-active:scale-95">
44
+ {@render icon()}
45
+ </span>
46
+ {/if}
47
+ {#if children}
48
+ {@render children()}
49
+ {/if}
50
+ {#if iconRight}
51
+ <span class="shrink-0 transition-transform group-active:scale-95">
52
+ {@render iconRight()}
53
+ </span>
54
+ {/if}
55
+ </a>