@refraction-ui/astro 0.11.1 → 0.13.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/dist/astro-audio-room/AudioRoom.astro +81 -0
- package/dist/astro-audio-room/index.ts +1 -0
- package/dist/astro-call-controls/CallControls.astro +57 -0
- package/dist/astro-call-controls/index.ts +1 -0
- package/dist/astro-checklist/Checklist.astro +76 -0
- package/dist/astro-checklist/index.ts +1 -0
- package/dist/astro-editor-status-bar/EditorStatusBar.astro +92 -0
- package/dist/astro-editor-status-bar/index.ts +1 -0
- package/dist/astro-editor-tabs/EditorTabs.astro +74 -0
- package/dist/astro-editor-tabs/index.ts +1 -0
- package/dist/astro-empty-state/EmptyState.astro +57 -0
- package/dist/astro-empty-state/index.ts +1 -0
- package/dist/astro-floating-reactions/FloatingReactions.astro +56 -0
- package/dist/astro-floating-reactions/index.ts +1 -0
- package/dist/astro-flow-editor/FlowEditor.astro +99 -0
- package/dist/astro-flow-editor/index.ts +3 -0
- package/dist/astro-graph-view/GraphView.astro +109 -0
- package/dist/astro-graph-view/index.ts +1 -0
- package/dist/astro-infinite-canvas/InfiniteCanvas.astro +43 -0
- package/dist/astro-infinite-canvas/index.ts +1 -0
- package/dist/astro-input/Input.astro +5 -1
- package/dist/astro-live-captions/LiveCaptions.astro +54 -0
- package/dist/astro-live-captions/index.ts +1 -0
- package/dist/astro-live-cursors/LiveCursors.astro +55 -0
- package/dist/astro-live-cursors/index.ts +1 -0
- package/dist/astro-live-transcript/LiveTranscript.astro +55 -0
- package/dist/astro-live-transcript/index.ts +1 -0
- package/dist/astro-mini-map/MiniMap.astro +74 -0
- package/dist/astro-mini-map/index.ts +1 -0
- package/dist/astro-password-input/PasswordInput.astro +102 -0
- package/dist/astro-password-input/index.ts +1 -0
- package/dist/astro-pre-call-lobby/PreCallLobby.astro +202 -0
- package/dist/astro-pre-call-lobby/index.ts +1 -0
- package/dist/astro-radial-gauge/RadialGauge.astro +144 -0
- package/dist/astro-radial-gauge/index.ts +1 -0
- package/dist/astro-rating-scale/RatingScale.astro +73 -0
- package/dist/astro-rating-scale/index.ts +1 -0
- package/dist/astro-segmented-control/SegmentedControl.astro +106 -0
- package/dist/astro-segmented-control/SegmentedControlItem.astro +32 -0
- package/dist/astro-segmented-control/index.ts +1 -0
- package/dist/astro-separator/Separator.astro +49 -0
- package/dist/astro-separator/index.ts +1 -0
- package/dist/astro-social-auth-button/SocialAuthButton.astro +110 -0
- package/dist/astro-social-auth-button/SocialAuthRow.astro +13 -0
- package/dist/astro-social-auth-button/index.ts +1 -0
- package/dist/astro-sticky-note/StickyNote.astro +55 -0
- package/dist/astro-sticky-note/index.ts +1 -0
- package/dist/astro-terminal/Terminal.astro +67 -0
- package/dist/astro-terminal/index.ts +1 -0
- package/dist/astro-test-results/TestResults.astro +76 -0
- package/dist/astro-test-results/index.ts +1 -0
- package/dist/astro-timeline/Timeline.astro +59 -0
- package/dist/astro-timeline/index.ts +1 -0
- package/dist/astro-video-grid/VideoGrid.astro +182 -0
- package/dist/astro-video-grid/index.ts +1 -0
- package/dist/astro-video-tile/VideoTile.astro +104 -0
- package/dist/astro-video-tile/index.ts +1 -0
- package/dist/astro-wizard/Wizard.astro +137 -0
- package/dist/astro-wizard/index.ts +1 -0
- package/dist/audio-room/audio-room.styles.ts +88 -0
- package/dist/audio-room/audio-room.ts +70 -0
- package/dist/audio-room/index.ts +16 -0
- package/dist/call-controls/call-controls.styles.ts +63 -0
- package/dist/call-controls/call-controls.ts +79 -0
- package/dist/call-controls/index.ts +15 -0
- package/dist/checklist/checklist.styles.ts +76 -0
- package/dist/checklist/checklist.ts +62 -0
- package/dist/checklist/index.ts +18 -0
- package/dist/editor-status-bar/editor-status-bar.styles.ts +40 -0
- package/dist/editor-status-bar/editor-status-bar.ts +78 -0
- package/dist/editor-status-bar/index.ts +15 -0
- package/dist/editor-tabs/editor-tabs.styles.ts +52 -0
- package/dist/editor-tabs/editor-tabs.ts +82 -0
- package/dist/editor-tabs/index.ts +15 -0
- package/dist/empty-state/empty-state.styles.ts +42 -0
- package/dist/empty-state/empty-state.ts +27 -0
- package/dist/empty-state/index.ts +14 -0
- package/dist/floating-reactions/floating-reactions.styles.ts +54 -0
- package/dist/floating-reactions/floating-reactions.ts +85 -0
- package/dist/floating-reactions/index.ts +14 -0
- package/dist/flow-editor/flow-editor.styles.ts +56 -0
- package/dist/flow-editor/flow-editor.ts +126 -0
- package/dist/flow-editor/index.ts +18 -0
- package/dist/graph-view/graph-view.styles.ts +66 -0
- package/dist/graph-view/graph-view.ts +130 -0
- package/dist/graph-view/index.ts +21 -0
- package/dist/index.ts +45 -17
- package/dist/infinite-canvas/index.ts +17 -0
- package/dist/infinite-canvas/infinite-canvas.styles.ts +49 -0
- package/dist/infinite-canvas/infinite-canvas.ts +97 -0
- package/dist/input/index.ts +2 -0
- package/dist/input/input.styles.ts +4 -0
- package/dist/input/input.ts +39 -3
- package/dist/live-captions/index.ts +13 -0
- package/dist/live-captions/live-captions.styles.ts +45 -0
- package/dist/live-captions/live-captions.ts +57 -0
- package/dist/live-cursors/index.ts +14 -0
- package/dist/live-cursors/live-cursors.styles.ts +41 -0
- package/dist/live-cursors/live-cursors.ts +73 -0
- package/dist/live-transcript/index.ts +16 -0
- package/dist/live-transcript/live-transcript.styles.ts +48 -0
- package/dist/live-transcript/live-transcript.ts +82 -0
- package/dist/mini-map/index.ts +16 -0
- package/dist/mini-map/mini-map.styles.ts +32 -0
- package/dist/mini-map/mini-map.ts +122 -0
- package/dist/password-input/index.ts +9 -0
- package/dist/password-input/password-input.styles.ts +10 -0
- package/dist/password-input/password-input.ts +45 -0
- package/dist/pre-call-lobby/index.ts +22 -0
- package/dist/pre-call-lobby/pre-call-lobby.styles.ts +108 -0
- package/dist/pre-call-lobby/pre-call-lobby.ts +61 -0
- package/dist/radial-gauge/index.ts +26 -0
- package/dist/radial-gauge/radial-gauge.styles.ts +75 -0
- package/dist/radial-gauge/radial-gauge.ts +183 -0
- package/dist/rating-scale/index.ts +16 -0
- package/dist/rating-scale/rating-scale.styles.ts +48 -0
- package/dist/rating-scale/rating-scale.ts +101 -0
- package/dist/segmented-control/index.ts +13 -0
- package/dist/segmented-control/segmented-control.styles.ts +42 -0
- package/dist/segmented-control/segmented-control.ts +80 -0
- package/dist/separator/index.ts +12 -0
- package/dist/separator/separator.styles.ts +34 -0
- package/dist/separator/separator.ts +53 -0
- package/dist/social-auth-button/index.ts +14 -0
- package/dist/social-auth-button/social-auth-button.styles.ts +16 -0
- package/dist/social-auth-button/social-auth-button.ts +51 -0
- package/dist/sticky-note/index.ts +14 -0
- package/dist/sticky-note/sticky-note.styles.ts +37 -0
- package/dist/sticky-note/sticky-note.ts +47 -0
- package/dist/terminal/index.ts +13 -0
- package/dist/terminal/terminal.styles.ts +56 -0
- package/dist/terminal/terminal.ts +60 -0
- package/dist/test-results/index.ts +19 -0
- package/dist/test-results/test-results.styles.ts +93 -0
- package/dist/test-results/test-results.ts +83 -0
- package/dist/timeline/index.ts +22 -0
- package/dist/timeline/timeline.styles.ts +98 -0
- package/dist/timeline/timeline.ts +86 -0
- package/dist/video-grid/index.ts +16 -0
- package/dist/video-grid/video-grid.styles.ts +38 -0
- package/dist/video-grid/video-grid.ts +93 -0
- package/dist/video-tile/index.ts +17 -0
- package/dist/video-tile/video-tile.styles.ts +59 -0
- package/dist/video-tile/video-tile.ts +74 -0
- package/dist/wizard/index.ts +28 -0
- package/dist/wizard/wizard.styles.ts +147 -0
- package/dist/wizard/wizard.ts +128 -0
- package/package.json +47 -19
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
createSocialAuthButton,
|
|
4
|
+
socialAuthButtonVariants,
|
|
5
|
+
lastUsedBadgeVariants,
|
|
6
|
+
type SocialProvider,
|
|
7
|
+
} from '../social-auth-button/index.ts'
|
|
8
|
+
import { cn } from '../shared/index.ts'
|
|
9
|
+
|
|
10
|
+
interface Props extends astroHTML.JSX.HTMLAttributes {
|
|
11
|
+
provider: SocialProvider
|
|
12
|
+
lastUsed?: boolean
|
|
13
|
+
loading?: boolean
|
|
14
|
+
disabled?: boolean
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const {
|
|
18
|
+
provider,
|
|
19
|
+
lastUsed,
|
|
20
|
+
loading,
|
|
21
|
+
disabled,
|
|
22
|
+
class: className,
|
|
23
|
+
...props
|
|
24
|
+
} = Astro.props
|
|
25
|
+
|
|
26
|
+
const { label, mono, dataAttributes } = createSocialAuthButton({ provider })
|
|
27
|
+
|
|
28
|
+
// Mirrors the react-button outline variant base + outline classes so the Astro
|
|
29
|
+
// and React buttons render identically.
|
|
30
|
+
const buttonClasses = cn(
|
|
31
|
+
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0',
|
|
32
|
+
'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',
|
|
33
|
+
'w-full justify-center gap-2',
|
|
34
|
+
className,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
const iconFill = (color: string) => (mono ? 'currentColor' : color)
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
<div class={socialAuthButtonVariants()}>
|
|
41
|
+
<button
|
|
42
|
+
type="button"
|
|
43
|
+
class={buttonClasses}
|
|
44
|
+
disabled={disabled || loading}
|
|
45
|
+
{...dataAttributes}
|
|
46
|
+
{...props}
|
|
47
|
+
>
|
|
48
|
+
{loading ? (
|
|
49
|
+
<svg
|
|
50
|
+
class="animate-spin h-4 w-4"
|
|
51
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
52
|
+
fill="none"
|
|
53
|
+
viewBox="0 0 24 24"
|
|
54
|
+
aria-hidden="true"
|
|
55
|
+
>
|
|
56
|
+
<circle
|
|
57
|
+
class="opacity-25"
|
|
58
|
+
cx="12"
|
|
59
|
+
cy="12"
|
|
60
|
+
r="10"
|
|
61
|
+
stroke="currentColor"
|
|
62
|
+
stroke-width="4"
|
|
63
|
+
/>
|
|
64
|
+
<path
|
|
65
|
+
class="opacity-75"
|
|
66
|
+
fill="currentColor"
|
|
67
|
+
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
68
|
+
/>
|
|
69
|
+
</svg>
|
|
70
|
+
) : (
|
|
71
|
+
<svg
|
|
72
|
+
class="shrink-0"
|
|
73
|
+
width="18"
|
|
74
|
+
height="18"
|
|
75
|
+
viewBox="0 0 24 24"
|
|
76
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
77
|
+
aria-hidden="true"
|
|
78
|
+
>
|
|
79
|
+
{provider === 'google' && (
|
|
80
|
+
<path
|
|
81
|
+
fill={iconFill('#4285F4')}
|
|
82
|
+
d="M21.35 11.1H12v2.92h5.35c-.23 1.4-1.65 4.1-5.35 4.1a5.99 5.99 0 0 1 0-11.98c1.71 0 2.86.73 3.52 1.36l2.4-2.31C16.46 3.7 14.43 2.8 12 2.8a9.2 9.2 0 1 0 0 18.4c5.31 0 8.82-3.73 8.82-8.99 0-.6-.07-1.06-.17-1.51Z"
|
|
83
|
+
/>
|
|
84
|
+
)}
|
|
85
|
+
{provider === 'github' && (
|
|
86
|
+
<path
|
|
87
|
+
fill="currentColor"
|
|
88
|
+
d="M12 2a10 10 0 0 0-3.16 19.49c.5.09.68-.22.68-.48l-.01-1.7c-2.78.6-3.37-1.34-3.37-1.34-.45-1.16-1.11-1.46-1.11-1.46-.91-.62.07-.61.07-.61 1 .07 1.53 1.03 1.53 1.03.9 1.53 2.36 1.09 2.94.83.09-.65.35-1.09.63-1.34-2.22-.25-4.55-1.11-4.55-4.94 0-1.09.39-1.98 1.03-2.68-.1-.25-.45-1.27.1-2.65 0 0 .84-.27 2.75 1.02a9.6 9.6 0 0 1 5 0c1.91-1.29 2.75-1.02 2.75-1.02.55 1.38.2 2.4.1 2.65.64.7 1.03 1.59 1.03 2.68 0 3.84-2.34 4.69-4.57 4.94.36.31.68.92.68 1.85l-.01 2.74c0 .27.18.58.69.48A10 10 0 0 0 12 2Z"
|
|
89
|
+
/>
|
|
90
|
+
)}
|
|
91
|
+
{provider === 'microsoft' && (
|
|
92
|
+
<Fragment>
|
|
93
|
+
<path fill={iconFill('#F25022')} d="M3 3h8v8H3z" />
|
|
94
|
+
<path fill={iconFill('#7FBA00')} d="M13 3h8v8h-8z" />
|
|
95
|
+
<path fill={iconFill('#00A4EF')} d="M3 13h8v8H3z" />
|
|
96
|
+
<path fill={iconFill('#FFB900')} d="M13 13h8v8h-8z" />
|
|
97
|
+
</Fragment>
|
|
98
|
+
)}
|
|
99
|
+
{provider === 'apple' && (
|
|
100
|
+
<path
|
|
101
|
+
fill="currentColor"
|
|
102
|
+
d="M16.37 12.78c-.03-2.62 2.14-3.88 2.24-3.94-1.22-1.79-3.12-2.03-3.79-2.06-1.61-.16-3.15.95-3.97.95-.82 0-2.08-.93-3.42-.9-1.76.03-3.39 1.02-4.29 2.6-1.83 3.18-.47 7.88 1.31 10.46.87 1.26 1.91 2.67 3.27 2.62 1.31-.05 1.81-.85 3.4-.85 1.58 0 2.03.85 3.42.82 1.41-.02 2.31-1.28 3.17-2.55.99-1.46 1.4-2.88 1.42-2.95-.03-.01-2.73-1.05-2.76-4.15M13.9 5.1c.72-.88 1.21-2.09 1.08-3.3-1.04.04-2.3.69-3.04 1.56-.66.77-1.24 2.01-1.09 3.19 1.16.09 2.34-.59 3.05-1.45"
|
|
103
|
+
/>
|
|
104
|
+
)}
|
|
105
|
+
</svg>
|
|
106
|
+
)}
|
|
107
|
+
{label}
|
|
108
|
+
</button>
|
|
109
|
+
{lastUsed && <span class={lastUsedBadgeVariants()}>Last used</span>}
|
|
110
|
+
</div>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { socialAuthRowVariants } from '../social-auth-button/index.ts'
|
|
3
|
+
import { cn } from '../shared/index.ts'
|
|
4
|
+
|
|
5
|
+
interface Props extends astroHTML.JSX.HTMLAttributes {}
|
|
6
|
+
|
|
7
|
+
const { class: className, ...props } = Astro.props
|
|
8
|
+
const classes = cn(socialAuthRowVariants(), className)
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
<div class={classes} {...props}>
|
|
12
|
+
<slot />
|
|
13
|
+
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
createStickyNote,
|
|
4
|
+
stickyNoteVariants,
|
|
5
|
+
stickyNoteTextClass,
|
|
6
|
+
stickyNoteAuthorClass,
|
|
7
|
+
type StickyNoteColor,
|
|
8
|
+
} from '../sticky-note/index.ts'
|
|
9
|
+
import { cn } from '../shared/index.ts'
|
|
10
|
+
|
|
11
|
+
interface Props extends astroHTML.JSX.HTMLAttributes {
|
|
12
|
+
/** Color of the sticky note. */
|
|
13
|
+
color?: StickyNoteColor
|
|
14
|
+
/** Text content of the note. */
|
|
15
|
+
text?: string
|
|
16
|
+
/** Optional author name shown in the note footer. */
|
|
17
|
+
author?: string
|
|
18
|
+
/** Absolute x position in pixels (for board/canvas placement). */
|
|
19
|
+
x?: number
|
|
20
|
+
/** Absolute y position in pixels (for board/canvas placement). */
|
|
21
|
+
y?: number
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const {
|
|
25
|
+
color = 'yellow',
|
|
26
|
+
text,
|
|
27
|
+
author,
|
|
28
|
+
x,
|
|
29
|
+
y,
|
|
30
|
+
class: className,
|
|
31
|
+
...rest
|
|
32
|
+
} = Astro.props
|
|
33
|
+
|
|
34
|
+
const { ariaProps, dataAttributes } = createStickyNote({ color })
|
|
35
|
+
|
|
36
|
+
const positionStyle =
|
|
37
|
+
x !== undefined && y !== undefined
|
|
38
|
+
? `position:absolute;left:${x}px;top:${y}px;`
|
|
39
|
+
: ''
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
<div
|
|
43
|
+
class={cn(stickyNoteVariants({ color }), className)}
|
|
44
|
+
style={positionStyle || undefined}
|
|
45
|
+
{...ariaProps}
|
|
46
|
+
{...dataAttributes}
|
|
47
|
+
{...rest}
|
|
48
|
+
>
|
|
49
|
+
{text ? (
|
|
50
|
+
<p class={`${stickyNoteTextClass} whitespace-pre-wrap`}>{text}</p>
|
|
51
|
+
) : (
|
|
52
|
+
<p class={`${stickyNoteTextClass} whitespace-pre-wrap`}><slot /></p>
|
|
53
|
+
)}
|
|
54
|
+
{author && <span class={stickyNoteAuthorClass}>{author}</span>}
|
|
55
|
+
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
createTerminal,
|
|
4
|
+
formatPrompt,
|
|
5
|
+
terminalVariants,
|
|
6
|
+
terminalLineVariants,
|
|
7
|
+
terminalPromptClass,
|
|
8
|
+
type TerminalLine,
|
|
9
|
+
} from '../terminal/index.ts'
|
|
10
|
+
import { cn } from '../shared/index.ts'
|
|
11
|
+
|
|
12
|
+
type TerminalMaxHeight = 'sm' | 'md' | 'lg' | 'none'
|
|
13
|
+
|
|
14
|
+
interface Props extends astroHTML.JSX.HTMLAttributes {
|
|
15
|
+
/** Lines to render in order. Each line's `kind` determines its styling. */
|
|
16
|
+
lines: TerminalLine[]
|
|
17
|
+
/**
|
|
18
|
+
* Prompt symbol prepended to `command` lines.
|
|
19
|
+
* @default '$'
|
|
20
|
+
*/
|
|
21
|
+
promptSymbol?: string
|
|
22
|
+
/**
|
|
23
|
+
* Maximum height of the scroll region before it becomes scrollable.
|
|
24
|
+
* @default 'md'
|
|
25
|
+
*/
|
|
26
|
+
maxHeight?: TerminalMaxHeight
|
|
27
|
+
/** Accessible label for the live region. */
|
|
28
|
+
'aria-label'?: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const {
|
|
32
|
+
lines,
|
|
33
|
+
promptSymbol = '$',
|
|
34
|
+
maxHeight = 'md',
|
|
35
|
+
'aria-label': ariaLabel,
|
|
36
|
+
class: className,
|
|
37
|
+
...rest
|
|
38
|
+
} = Astro.props
|
|
39
|
+
|
|
40
|
+
const { ariaProps, dataAttributes } = createTerminal({ label: ariaLabel })
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
<div
|
|
44
|
+
class={cn(terminalVariants({ maxHeight }), className)}
|
|
45
|
+
{...ariaProps}
|
|
46
|
+
{...dataAttributes}
|
|
47
|
+
{...rest}
|
|
48
|
+
>
|
|
49
|
+
{
|
|
50
|
+
lines.map((line, index) => {
|
|
51
|
+
const lineClass = terminalLineVariants({ kind: line.kind })
|
|
52
|
+
if (line.kind === 'command') {
|
|
53
|
+
return (
|
|
54
|
+
<span key={line.id ?? index} class={lineClass}>
|
|
55
|
+
<span class={terminalPromptClass}>{promptSymbol}</span>
|
|
56
|
+
{line.text}
|
|
57
|
+
</span>
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
return (
|
|
61
|
+
<span key={line.id ?? index} class={lineClass}>
|
|
62
|
+
{line.text}
|
|
63
|
+
</span>
|
|
64
|
+
)
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
summarizeTests,
|
|
4
|
+
createTestResults,
|
|
5
|
+
testResultsContainerVariants,
|
|
6
|
+
testResultsSummaryVariants,
|
|
7
|
+
testRowVariants,
|
|
8
|
+
testStatusBadgeVariants,
|
|
9
|
+
testNameClass,
|
|
10
|
+
testDurationClass,
|
|
11
|
+
testDiffBlockVariants,
|
|
12
|
+
testMessageClass,
|
|
13
|
+
type TestResultData,
|
|
14
|
+
} from '../test-results/index.ts'
|
|
15
|
+
import { cn } from '../shared/index.ts'
|
|
16
|
+
|
|
17
|
+
interface Props extends astroHTML.JSX.HTMLAttributes {
|
|
18
|
+
/** Array of test case results to display. */
|
|
19
|
+
results: TestResultData[]
|
|
20
|
+
/** When true, renders a summary bar showing "{passed}/{total} passed". */
|
|
21
|
+
showSummary?: boolean
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const { results, showSummary = true, class: className, ...rest } = Astro.props
|
|
25
|
+
|
|
26
|
+
const summary = summarizeTests(results)
|
|
27
|
+
const { ariaProps, dataAttributes } = createTestResults()
|
|
28
|
+
const summaryOutcome = summary.failed > 0 ? 'fail' : summary.skipped > 0 ? 'skip' : 'pass'
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
<div class={cn(testResultsContainerVariants(), className)} {...dataAttributes} {...rest}>
|
|
32
|
+
{showSummary && results.length > 0 && (
|
|
33
|
+
<div class={testResultsSummaryVariants({ outcome: summaryOutcome })} aria-live="polite">
|
|
34
|
+
<span>{summary.passed}/{summary.total} passed</span>
|
|
35
|
+
{summary.failed > 0 && <span>· {summary.failed} failed</span>}
|
|
36
|
+
{summary.skipped > 0 && <span>· {summary.skipped} skipped</span>}
|
|
37
|
+
</div>
|
|
38
|
+
)}
|
|
39
|
+
|
|
40
|
+
<ul {...ariaProps} class="flex flex-col gap-2">
|
|
41
|
+
{
|
|
42
|
+
results.map((result) => (
|
|
43
|
+
<li role="listitem" class={testRowVariants({ status: result.status })}>
|
|
44
|
+
<div class="flex items-center justify-between gap-2">
|
|
45
|
+
<div class="flex items-center gap-2 min-w-0">
|
|
46
|
+
<span class={testStatusBadgeVariants({ status: result.status })}>
|
|
47
|
+
{result.status}
|
|
48
|
+
</span>
|
|
49
|
+
<span class={cn(testNameClass, 'truncate')}>{result.name}</span>
|
|
50
|
+
</div>
|
|
51
|
+
{result.durationMs !== undefined && (
|
|
52
|
+
<span class={testDurationClass}>{result.durationMs} ms</span>
|
|
53
|
+
)}
|
|
54
|
+
</div>
|
|
55
|
+
|
|
56
|
+
{result.status === 'fail' && result.expected !== undefined && (
|
|
57
|
+
<div class="flex flex-col gap-1 mt-1">
|
|
58
|
+
<div class={testDiffBlockVariants({ side: 'expected' })}>
|
|
59
|
+
<span class="opacity-60 mr-1 select-none">expected</span>
|
|
60
|
+
{result.expected}
|
|
61
|
+
</div>
|
|
62
|
+
{result.actual !== undefined && (
|
|
63
|
+
<div class={testDiffBlockVariants({ side: 'actual' })}>
|
|
64
|
+
<span class="opacity-60 mr-1 select-none">actual</span>
|
|
65
|
+
{result.actual}
|
|
66
|
+
</div>
|
|
67
|
+
)}
|
|
68
|
+
</div>
|
|
69
|
+
)}
|
|
70
|
+
|
|
71
|
+
{result.message && <p class={testMessageClass}>{result.message}</p>}
|
|
72
|
+
</li>
|
|
73
|
+
))
|
|
74
|
+
}
|
|
75
|
+
</ul>
|
|
76
|
+
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
createTimeline,
|
|
4
|
+
resolveTimelineItems,
|
|
5
|
+
timelineVariants,
|
|
6
|
+
timelineItemVariants,
|
|
7
|
+
timelineMarkerVariants,
|
|
8
|
+
timelineConnectorVariants,
|
|
9
|
+
timelineGutterClass,
|
|
10
|
+
timelineTimeClass,
|
|
11
|
+
timelineTitleClass,
|
|
12
|
+
timelineDescriptionClass,
|
|
13
|
+
timelineContentClass,
|
|
14
|
+
type TimelineOrientation,
|
|
15
|
+
type TimelineItemData,
|
|
16
|
+
} from '../timeline/index.ts'
|
|
17
|
+
import { cn } from '../shared/index.ts'
|
|
18
|
+
|
|
19
|
+
interface Props extends astroHTML.JSX.HTMLAttributes {
|
|
20
|
+
/** Ordered list of events to render. */
|
|
21
|
+
items: TimelineItemData[]
|
|
22
|
+
/** Layout direction. Defaults to `'vertical'`. */
|
|
23
|
+
orientation?: TimelineOrientation
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const {
|
|
27
|
+
items,
|
|
28
|
+
orientation = 'vertical',
|
|
29
|
+
class: className,
|
|
30
|
+
...rest
|
|
31
|
+
} = Astro.props
|
|
32
|
+
|
|
33
|
+
const resolved = resolveTimelineItems(items)
|
|
34
|
+
const { ariaProps, dataAttributes } = createTimeline({ orientation })
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
<ul class={cn(timelineVariants({ orientation }), className)} {...ariaProps} {...dataAttributes} {...rest}>
|
|
38
|
+
{
|
|
39
|
+
resolved.map((item, index) => {
|
|
40
|
+
const isLast = index === resolved.length - 1
|
|
41
|
+
return (
|
|
42
|
+
<li role="listitem" class={timelineItemVariants({ orientation })} data-status={item.status}>
|
|
43
|
+
{/* Gutter: marker + connector */}
|
|
44
|
+
<div class={timelineGutterClass}>
|
|
45
|
+
<div class={timelineMarkerVariants({ status: item.status })} />
|
|
46
|
+
{!isLast && <div class={timelineConnectorVariants({ orientation })} />}
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
{/* Content */}
|
|
50
|
+
<div class={timelineContentClass}>
|
|
51
|
+
{item.time && <span class={timelineTimeClass}>{item.time}</span>}
|
|
52
|
+
<span class={timelineTitleClass}>{item.title}</span>
|
|
53
|
+
{item.description && <p class={timelineDescriptionClass}>{item.description}</p>}
|
|
54
|
+
</div>
|
|
55
|
+
</li>
|
|
56
|
+
)
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
</ul>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
createVideoGrid,
|
|
4
|
+
computeGridColumns,
|
|
5
|
+
videoGridVariants,
|
|
6
|
+
videoGridSpotlightClass,
|
|
7
|
+
videoGridFilmstripClass,
|
|
8
|
+
videoGridFilmstripTileClass,
|
|
9
|
+
type VideoGridLayout,
|
|
10
|
+
} from '../video-grid/index.ts'
|
|
11
|
+
import { getInitials, type VideoTileData } from '../video-tile/index.ts'
|
|
12
|
+
import { cn } from '../shared/index.ts'
|
|
13
|
+
|
|
14
|
+
interface Props extends astroHTML.JSX.HTMLAttributes {
|
|
15
|
+
/** List of participant data to render as tiles. */
|
|
16
|
+
participants: VideoTileData[]
|
|
17
|
+
/**
|
|
18
|
+
* Grid layout mode.
|
|
19
|
+
* - 'auto' — grid unless ≤1 participant (falls back to speaker)
|
|
20
|
+
* - 'grid' — always uniform CSS grid
|
|
21
|
+
* - 'speaker' — spotlight for `spotlightId` (or first participant) + filmstrip
|
|
22
|
+
*/
|
|
23
|
+
layout?: VideoGridLayout
|
|
24
|
+
/**
|
|
25
|
+
* Participant `id` to spotlight in speaker view.
|
|
26
|
+
* Falls back to the first participant when omitted.
|
|
27
|
+
*/
|
|
28
|
+
spotlightId?: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const {
|
|
32
|
+
participants,
|
|
33
|
+
layout = 'auto',
|
|
34
|
+
spotlightId,
|
|
35
|
+
class: className,
|
|
36
|
+
style,
|
|
37
|
+
...rest
|
|
38
|
+
} = Astro.props
|
|
39
|
+
|
|
40
|
+
const count = participants.length
|
|
41
|
+
|
|
42
|
+
// Resolve effective layout: 'auto' with ≤1 participant shows speaker view.
|
|
43
|
+
const effectiveLayout: VideoGridLayout =
|
|
44
|
+
layout === 'auto' ? (count <= 1 ? 'speaker' : 'grid') : layout
|
|
45
|
+
|
|
46
|
+
const { ariaProps, dataAttributes } = createVideoGrid({ layout: effectiveLayout })
|
|
47
|
+
const columns = computeGridColumns(count)
|
|
48
|
+
|
|
49
|
+
const gridStyle =
|
|
50
|
+
effectiveLayout !== 'speaker'
|
|
51
|
+
? `grid-template-columns: repeat(${columns}, 1fr);${style ? ` ${style}` : ''}`
|
|
52
|
+
: (style as string | undefined)
|
|
53
|
+
|
|
54
|
+
const spotlightParticipant =
|
|
55
|
+
effectiveLayout === 'speaker'
|
|
56
|
+
? (participants.find((p) => p.id === spotlightId) ?? participants[0])
|
|
57
|
+
: undefined
|
|
58
|
+
|
|
59
|
+
const filmstrip =
|
|
60
|
+
effectiveLayout === 'speaker'
|
|
61
|
+
? participants.filter((p) => p.id !== spotlightParticipant?.id)
|
|
62
|
+
: []
|
|
63
|
+
|
|
64
|
+
// Inline tile helper — renders VideoTile markup without importing the .astro
|
|
65
|
+
// file (which may not be built yet in a parallel-build context). When
|
|
66
|
+
// astro-video-tile ships its own VideoTile.astro, replace this with:
|
|
67
|
+
// import VideoTile from '../astro-video-tile/src/VideoTile.astro.ts'
|
|
68
|
+
function renderTileAttrs(p: VideoTileData): Record<string, string> {
|
|
69
|
+
const speaking = p.speaking ?? false
|
|
70
|
+
const pinned = p.pinned ?? false
|
|
71
|
+
return {
|
|
72
|
+
role: 'group',
|
|
73
|
+
'data-speaking': speaking ? 'true' : 'false',
|
|
74
|
+
'data-pinned': pinned ? 'true' : 'false',
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
{effectiveLayout === 'speaker' ? (
|
|
80
|
+
<div
|
|
81
|
+
class={cn(videoGridVariants({ layout: 'speaker' }), className)}
|
|
82
|
+
style={style as string | undefined}
|
|
83
|
+
{...ariaProps}
|
|
84
|
+
{...dataAttributes}
|
|
85
|
+
{...rest}
|
|
86
|
+
>
|
|
87
|
+
{spotlightParticipant && (
|
|
88
|
+
<div class={videoGridSpotlightClass}>
|
|
89
|
+
{/* Inline VideoTile markup for the spotlight participant */}
|
|
90
|
+
<div
|
|
91
|
+
{...renderTileAttrs(spotlightParticipant)}
|
|
92
|
+
class="relative flex h-full w-full flex-col items-center justify-center bg-muted rounded-xl overflow-hidden"
|
|
93
|
+
aria-label={spotlightParticipant.name}
|
|
94
|
+
>
|
|
95
|
+
{spotlightParticipant.avatarUrl ? (
|
|
96
|
+
<img
|
|
97
|
+
src={spotlightParticipant.avatarUrl}
|
|
98
|
+
alt={spotlightParticipant.name}
|
|
99
|
+
class="h-full w-full object-cover"
|
|
100
|
+
/>
|
|
101
|
+
) : (
|
|
102
|
+
<span class="flex h-20 w-20 items-center justify-center rounded-full bg-primary text-3xl font-semibold text-primary-foreground">
|
|
103
|
+
{getInitials(spotlightParticipant.name)}
|
|
104
|
+
</span>
|
|
105
|
+
)}
|
|
106
|
+
<div class="absolute bottom-2 left-2 flex items-center gap-1 rounded-md bg-black/60 px-2 py-0.5 text-xs text-white">
|
|
107
|
+
{(spotlightParticipant.micState ?? 'on') === 'muted' && (
|
|
108
|
+
<span aria-label="Muted" role="img">🔇</span>
|
|
109
|
+
)}
|
|
110
|
+
<span>{spotlightParticipant.name}</span>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
)}
|
|
115
|
+
|
|
116
|
+
{filmstrip.length > 0 && (
|
|
117
|
+
<div class={videoGridFilmstripClass}>
|
|
118
|
+
{filmstrip.map((p) => (
|
|
119
|
+
<div class={videoGridFilmstripTileClass}>
|
|
120
|
+
<div
|
|
121
|
+
{...renderTileAttrs(p)}
|
|
122
|
+
class="relative flex h-24 flex-col items-center justify-center bg-muted rounded-lg overflow-hidden"
|
|
123
|
+
aria-label={p.name}
|
|
124
|
+
>
|
|
125
|
+
{p.avatarUrl ? (
|
|
126
|
+
<img
|
|
127
|
+
src={p.avatarUrl}
|
|
128
|
+
alt={p.name}
|
|
129
|
+
class="h-full w-full object-cover"
|
|
130
|
+
/>
|
|
131
|
+
) : (
|
|
132
|
+
<span class="flex h-10 w-10 items-center justify-center rounded-full bg-primary text-sm font-semibold text-primary-foreground">
|
|
133
|
+
{getInitials(p.name)}
|
|
134
|
+
</span>
|
|
135
|
+
)}
|
|
136
|
+
<div class="absolute bottom-1 left-1 flex items-center gap-0.5 rounded bg-black/60 px-1 py-0.5 text-[10px] text-white">
|
|
137
|
+
{(p.micState ?? 'on') === 'muted' && (
|
|
138
|
+
<span aria-label="Muted" role="img">🔇</span>
|
|
139
|
+
)}
|
|
140
|
+
<span>{p.name}</span>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
))}
|
|
145
|
+
</div>
|
|
146
|
+
)}
|
|
147
|
+
</div>
|
|
148
|
+
) : (
|
|
149
|
+
<div
|
|
150
|
+
class={cn(videoGridVariants({ layout: effectiveLayout }), className)}
|
|
151
|
+
style={gridStyle}
|
|
152
|
+
{...ariaProps}
|
|
153
|
+
{...dataAttributes}
|
|
154
|
+
{...rest}
|
|
155
|
+
>
|
|
156
|
+
{participants.map((p) => (
|
|
157
|
+
<div
|
|
158
|
+
{...renderTileAttrs(p)}
|
|
159
|
+
class="relative flex flex-col items-center justify-center bg-muted rounded-xl overflow-hidden aspect-video"
|
|
160
|
+
aria-label={p.name}
|
|
161
|
+
>
|
|
162
|
+
{p.avatarUrl ? (
|
|
163
|
+
<img
|
|
164
|
+
src={p.avatarUrl}
|
|
165
|
+
alt={p.name}
|
|
166
|
+
class="h-full w-full object-cover"
|
|
167
|
+
/>
|
|
168
|
+
) : (
|
|
169
|
+
<span class="flex h-14 w-14 items-center justify-center rounded-full bg-primary text-xl font-semibold text-primary-foreground">
|
|
170
|
+
{getInitials(p.name)}
|
|
171
|
+
</span>
|
|
172
|
+
)}
|
|
173
|
+
<div class="absolute bottom-2 left-2 flex items-center gap-1 rounded-md bg-black/60 px-2 py-0.5 text-xs text-white">
|
|
174
|
+
{(p.micState ?? 'on') === 'muted' && (
|
|
175
|
+
<span aria-label="Muted" role="img">🔇</span>
|
|
176
|
+
)}
|
|
177
|
+
<span>{p.name}</span>
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
))}
|
|
181
|
+
</div>
|
|
182
|
+
)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
createVideoTile,
|
|
4
|
+
getInitials,
|
|
5
|
+
videoTileVariants,
|
|
6
|
+
videoTileNameChipClass,
|
|
7
|
+
videoTileMicIconClass,
|
|
8
|
+
videoTileAvatarFallbackClass,
|
|
9
|
+
videoTileAvatarCircleClass,
|
|
10
|
+
videoTileReactionBadgeClass,
|
|
11
|
+
type VideoTileMicState,
|
|
12
|
+
} from '../video-tile/index.ts'
|
|
13
|
+
import { cn } from '../shared/index.ts'
|
|
14
|
+
|
|
15
|
+
interface Props extends astroHTML.JSX.HTMLAttributes {
|
|
16
|
+
/** Participant display name — shown in the name chip and used for initials. */
|
|
17
|
+
name: string
|
|
18
|
+
/** Current microphone state. Defaults to 'on'. */
|
|
19
|
+
micState?: VideoTileMicState
|
|
20
|
+
/** Whether the participant is actively speaking. Adds an emerald ring. */
|
|
21
|
+
speaking?: boolean
|
|
22
|
+
/** Whether the tile is pinned in the grid. Adds a primary ring. */
|
|
23
|
+
pinned?: boolean
|
|
24
|
+
/** URL of the participant's avatar image, used in the fallback circle. */
|
|
25
|
+
avatarUrl?: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const {
|
|
29
|
+
name,
|
|
30
|
+
micState = 'on',
|
|
31
|
+
speaking = false,
|
|
32
|
+
pinned = false,
|
|
33
|
+
avatarUrl,
|
|
34
|
+
class: className,
|
|
35
|
+
...rest
|
|
36
|
+
} = Astro.props
|
|
37
|
+
|
|
38
|
+
const { ariaProps, dataAttributes } = createVideoTile({ speaking, pinned })
|
|
39
|
+
const initials = getInitials(name)
|
|
40
|
+
const isMuted = micState === 'muted'
|
|
41
|
+
const hasDefaultSlot = Astro.slots.has('default')
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
<div
|
|
45
|
+
class={cn(
|
|
46
|
+
videoTileVariants({
|
|
47
|
+
speaking: speaking ? 'true' : 'false',
|
|
48
|
+
pinned: pinned ? 'true' : 'false',
|
|
49
|
+
}),
|
|
50
|
+
className,
|
|
51
|
+
)}
|
|
52
|
+
aria-label={name}
|
|
53
|
+
{...ariaProps}
|
|
54
|
+
{...dataAttributes}
|
|
55
|
+
{...rest}
|
|
56
|
+
>
|
|
57
|
+
{hasDefaultSlot ? (
|
|
58
|
+
<!-- Media slot fills the tile -->
|
|
59
|
+
<div class="absolute inset-0 h-full w-full">
|
|
60
|
+
<slot />
|
|
61
|
+
</div>
|
|
62
|
+
) : avatarUrl ? (
|
|
63
|
+
<!-- Avatar image fallback -->
|
|
64
|
+
<div class={videoTileAvatarFallbackClass}>
|
|
65
|
+
<img src={avatarUrl} alt={name} class={videoTileAvatarCircleClass} />
|
|
66
|
+
</div>
|
|
67
|
+
) : (
|
|
68
|
+
<!-- Initials fallback -->
|
|
69
|
+
<div class={videoTileAvatarFallbackClass}>
|
|
70
|
+
<div class={videoTileAvatarCircleClass} aria-hidden="true">{initials}</div>
|
|
71
|
+
</div>
|
|
72
|
+
)}
|
|
73
|
+
|
|
74
|
+
{/* Reaction badge (top-right) — via named slot */}
|
|
75
|
+
<slot name="reaction" />
|
|
76
|
+
|
|
77
|
+
<!-- Name chip (bottom-left) -->
|
|
78
|
+
<div class={videoTileNameChipClass}>
|
|
79
|
+
<span>{name}</span>
|
|
80
|
+
{isMuted && (
|
|
81
|
+
<span class={videoTileMicIconClass} aria-label="Microphone muted">
|
|
82
|
+
<svg
|
|
83
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
84
|
+
width="12"
|
|
85
|
+
height="12"
|
|
86
|
+
viewBox="0 0 24 24"
|
|
87
|
+
fill="none"
|
|
88
|
+
stroke="currentColor"
|
|
89
|
+
stroke-width="2"
|
|
90
|
+
stroke-linecap="round"
|
|
91
|
+
stroke-linejoin="round"
|
|
92
|
+
aria-hidden="true"
|
|
93
|
+
>
|
|
94
|
+
<line x1="2" y1="2" x2="22" y2="22" />
|
|
95
|
+
<path d="M18.89 13.23A7.12 7.12 0 0 0 19 12v-2" />
|
|
96
|
+
<path d="M5 10v2a7 7 0 0 0 12 5" />
|
|
97
|
+
<path d="M15 9.34V5a3 3 0 0 0-5.68-1.33" />
|
|
98
|
+
<path d="M9 9v3a3 3 0 0 0 5.12 2.12" />
|
|
99
|
+
<line x1="12" y1="19" x2="12" y2="22" />
|
|
100
|
+
</svg>
|
|
101
|
+
</span>
|
|
102
|
+
)}
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|