@refraction-ui/astro 0.12.0 → 0.14.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-audience-feature-card/AudienceFeatureCard.astro +53 -0
- package/dist/astro-audience-feature-card/index.ts +1 -0
- package/dist/astro-audio-room/AudioRoom.astro +81 -0
- package/dist/astro-audio-room/index.ts +1 -0
- package/dist/astro-brand-network-cell/BrandNetworkCell.astro +77 -0
- package/dist/astro-brand-network-cell/index.ts +1 -0
- package/dist/astro-browser-chrome-mock/BrowserChromeMock.astro +62 -0
- package/dist/astro-browser-chrome-mock/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-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-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-marquee-strip/MarqueeStrip.astro +63 -0
- package/dist/astro-marquee-strip/index.ts +1 -0
- package/dist/astro-mastery-bar/MasteryBar.astro +56 -0
- package/dist/astro-mastery-bar/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-numbered-steps/NumberedSteps.astro +47 -0
- package/dist/astro-numbered-steps/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-pricing-card/PricingCard.astro +114 -0
- package/dist/astro-pricing-card/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-section-head/SectionHead.astro +44 -0
- package/dist/astro-section-head/index.ts +1 -0
- package/dist/astro-stat-grid/StatGrid.astro +46 -0
- package/dist/astro-stat-grid/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/audience-feature-card/audience-feature-card.styles.ts +23 -0
- package/dist/audience-feature-card/audience-feature-card.ts +39 -0
- package/dist/audience-feature-card/index.ts +13 -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/brand-network-cell/brand-network-cell.styles.ts +46 -0
- package/dist/brand-network-cell/brand-network-cell.ts +35 -0
- package/dist/brand-network-cell/index.ts +14 -0
- package/dist/browser-chrome-mock/browser-chrome-mock.styles.ts +43 -0
- package/dist/browser-chrome-mock/browser-chrome-mock.ts +52 -0
- package/dist/browser-chrome-mock/index.ts +17 -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/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 +32 -0
- 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/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/marquee-strip/index.ts +14 -0
- package/dist/marquee-strip/marquee-strip.styles.ts +61 -0
- package/dist/marquee-strip/marquee-strip.ts +35 -0
- package/dist/mastery-bar/index.ts +15 -0
- package/dist/mastery-bar/mastery-bar.styles.ts +45 -0
- package/dist/mastery-bar/mastery-bar.ts +55 -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/numbered-steps/index.ts +16 -0
- package/dist/numbered-steps/numbered-steps.styles.ts +36 -0
- package/dist/numbered-steps/numbered-steps.ts +64 -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/pricing-card/index.ts +19 -0
- package/dist/pricing-card/pricing-card.styles.ts +71 -0
- package/dist/pricing-card/pricing-card.ts +37 -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/section-head/index.ts +13 -0
- package/dist/section-head/section-head.styles.ts +30 -0
- package/dist/section-head/section-head.ts +28 -0
- package/dist/stat-grid/index.ts +13 -0
- package/dist/stat-grid/stat-grid.styles.ts +25 -0
- package/dist/stat-grid/stat-grid.ts +41 -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 +33 -1
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
createPreCallLobby,
|
|
4
|
+
micLevelToBars,
|
|
5
|
+
preCallLobbyVariants,
|
|
6
|
+
preCallCameraVariants,
|
|
7
|
+
preCallCameraPlaceholderClass,
|
|
8
|
+
preCallDeviceRowClass,
|
|
9
|
+
preCallDeviceLabelClass,
|
|
10
|
+
preCallDeviceSelectClass,
|
|
11
|
+
preCallMicMeterClass,
|
|
12
|
+
preCallMicBarVariants,
|
|
13
|
+
preCallControlsRowClass,
|
|
14
|
+
preCallToggleVariants,
|
|
15
|
+
preCallJoinButtonClass,
|
|
16
|
+
type MediaDeviceOption,
|
|
17
|
+
} from '../pre-call-lobby/index.ts'
|
|
18
|
+
import { cn } from '../shared/index.ts'
|
|
19
|
+
|
|
20
|
+
const MIC_BAR_COUNT = 8
|
|
21
|
+
|
|
22
|
+
interface Props extends astroHTML.JSX.HTMLAttributes {
|
|
23
|
+
/** Whether the camera is on. */
|
|
24
|
+
cameraOn?: boolean
|
|
25
|
+
/** Whether the microphone is on. */
|
|
26
|
+
micOn?: boolean
|
|
27
|
+
/** Current microphone level (0..1). */
|
|
28
|
+
micLevel?: number
|
|
29
|
+
/** Available cameras. */
|
|
30
|
+
cameras?: MediaDeviceOption[]
|
|
31
|
+
/** Available microphones. */
|
|
32
|
+
microphones?: MediaDeviceOption[]
|
|
33
|
+
/** Available speakers. */
|
|
34
|
+
speakers?: MediaDeviceOption[]
|
|
35
|
+
/** Currently selected camera id. */
|
|
36
|
+
selectedCamera?: string
|
|
37
|
+
/** Currently selected microphone id. */
|
|
38
|
+
selectedMicrophone?: string
|
|
39
|
+
/** Currently selected speaker id. */
|
|
40
|
+
selectedSpeaker?: string
|
|
41
|
+
/** Label for the join button. */
|
|
42
|
+
joinLabel?: string
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const {
|
|
46
|
+
cameraOn = true,
|
|
47
|
+
micOn = true,
|
|
48
|
+
micLevel = 0,
|
|
49
|
+
cameras = [],
|
|
50
|
+
microphones = [],
|
|
51
|
+
speakers = [],
|
|
52
|
+
selectedCamera,
|
|
53
|
+
selectedMicrophone,
|
|
54
|
+
selectedSpeaker,
|
|
55
|
+
joinLabel = 'Join',
|
|
56
|
+
class: className,
|
|
57
|
+
...rest
|
|
58
|
+
} = Astro.props
|
|
59
|
+
|
|
60
|
+
const { ariaProps, dataAttributes } = createPreCallLobby({ cameraOn, micOn })
|
|
61
|
+
const litBars = micLevelToBars(micLevel, MIC_BAR_COUNT)
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
<div class={cn(preCallLobbyVariants(), className)} {...ariaProps} {...dataAttributes} {...rest}>
|
|
65
|
+
<!-- Camera preview -->
|
|
66
|
+
<div class={preCallCameraVariants({ camera: cameraOn ? 'on' : 'off' })}>
|
|
67
|
+
{cameraOn ? (
|
|
68
|
+
<slot name="preview">
|
|
69
|
+
<div class={preCallCameraPlaceholderClass}>
|
|
70
|
+
<span class="text-xs">No preview</span>
|
|
71
|
+
</div>
|
|
72
|
+
</slot>
|
|
73
|
+
) : (
|
|
74
|
+
<div class={preCallCameraPlaceholderClass}>
|
|
75
|
+
<svg
|
|
76
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
77
|
+
width="40"
|
|
78
|
+
height="40"
|
|
79
|
+
viewBox="0 0 24 24"
|
|
80
|
+
fill="none"
|
|
81
|
+
stroke="currentColor"
|
|
82
|
+
stroke-width="1.5"
|
|
83
|
+
stroke-linecap="round"
|
|
84
|
+
stroke-linejoin="round"
|
|
85
|
+
aria-hidden="true"
|
|
86
|
+
>
|
|
87
|
+
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" />
|
|
88
|
+
<circle cx="9" cy="7" r="4" />
|
|
89
|
+
<line x1="2" y1="2" x2="22" y2="22" />
|
|
90
|
+
</svg>
|
|
91
|
+
<span class="text-xs">Camera is off</span>
|
|
92
|
+
</div>
|
|
93
|
+
)}
|
|
94
|
+
</div>
|
|
95
|
+
|
|
96
|
+
<!-- Mic level meter -->
|
|
97
|
+
<div class="flex items-center gap-2">
|
|
98
|
+
<span class="text-xs text-muted-foreground">Mic</span>
|
|
99
|
+
<div class={preCallMicMeterClass} aria-label={`Mic level: ${litBars} of ${MIC_BAR_COUNT}`}>
|
|
100
|
+
{Array.from({ length: MIC_BAR_COUNT }, (_, i) => {
|
|
101
|
+
const isLit = i < litBars
|
|
102
|
+
const heightClass = i < 2 ? 'h-2' : i < 4 ? 'h-3' : i < 6 ? 'h-4' : 'h-5'
|
|
103
|
+
return (
|
|
104
|
+
<div
|
|
105
|
+
class={`${preCallMicBarVariants({ lit: isLit ? 'true' : 'false' })} ${heightClass}`}
|
|
106
|
+
data-lit={isLit ? 'true' : 'false'}
|
|
107
|
+
/>
|
|
108
|
+
)
|
|
109
|
+
})}
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
<!-- Device selectors -->
|
|
114
|
+
{cameras.length > 0 && (
|
|
115
|
+
<div class={preCallDeviceRowClass}>
|
|
116
|
+
<label for="pcl-camera-select" class={preCallDeviceLabelClass}>Camera</label>
|
|
117
|
+
<select id="pcl-camera-select" class={preCallDeviceSelectClass} value={selectedCamera}>
|
|
118
|
+
{cameras.map((d) => (
|
|
119
|
+
<option value={d.id}>{d.label}</option>
|
|
120
|
+
))}
|
|
121
|
+
</select>
|
|
122
|
+
</div>
|
|
123
|
+
)}
|
|
124
|
+
|
|
125
|
+
{microphones.length > 0 && (
|
|
126
|
+
<div class={preCallDeviceRowClass}>
|
|
127
|
+
<label for="pcl-mic-select" class={preCallDeviceLabelClass}>Microphone</label>
|
|
128
|
+
<select id="pcl-mic-select" class={preCallDeviceSelectClass} value={selectedMicrophone}>
|
|
129
|
+
{microphones.map((d) => (
|
|
130
|
+
<option value={d.id}>{d.label}</option>
|
|
131
|
+
))}
|
|
132
|
+
</select>
|
|
133
|
+
</div>
|
|
134
|
+
)}
|
|
135
|
+
|
|
136
|
+
{speakers.length > 0 && (
|
|
137
|
+
<div class={preCallDeviceRowClass}>
|
|
138
|
+
<label for="pcl-speaker-select" class={preCallDeviceLabelClass}>Speaker</label>
|
|
139
|
+
<select id="pcl-speaker-select" class={preCallDeviceSelectClass} value={selectedSpeaker}>
|
|
140
|
+
{speakers.map((d) => (
|
|
141
|
+
<option value={d.id}>{d.label}</option>
|
|
142
|
+
))}
|
|
143
|
+
</select>
|
|
144
|
+
</div>
|
|
145
|
+
)}
|
|
146
|
+
|
|
147
|
+
<!-- Controls row -->
|
|
148
|
+
<div class={preCallControlsRowClass}>
|
|
149
|
+
<button
|
|
150
|
+
type="button"
|
|
151
|
+
aria-label={cameraOn ? 'Turn camera off' : 'Turn camera on'}
|
|
152
|
+
aria-pressed={cameraOn}
|
|
153
|
+
class={preCallToggleVariants({ active: cameraOn ? 'true' : 'false' })}
|
|
154
|
+
>
|
|
155
|
+
<svg
|
|
156
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
157
|
+
width="18"
|
|
158
|
+
height="18"
|
|
159
|
+
viewBox="0 0 24 24"
|
|
160
|
+
fill="none"
|
|
161
|
+
stroke="currentColor"
|
|
162
|
+
stroke-width="2"
|
|
163
|
+
stroke-linecap="round"
|
|
164
|
+
stroke-linejoin="round"
|
|
165
|
+
aria-hidden="true"
|
|
166
|
+
>
|
|
167
|
+
<path d="M23 7l-7 5 7 5V7z" />
|
|
168
|
+
<rect x="1" y="5" width="15" height="14" rx="2" ry="2" />
|
|
169
|
+
</svg>
|
|
170
|
+
</button>
|
|
171
|
+
|
|
172
|
+
<button
|
|
173
|
+
type="button"
|
|
174
|
+
aria-label={micOn ? 'Mute microphone' : 'Unmute microphone'}
|
|
175
|
+
aria-pressed={micOn}
|
|
176
|
+
class={preCallToggleVariants({ active: micOn ? 'true' : 'false' })}
|
|
177
|
+
>
|
|
178
|
+
<svg
|
|
179
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
180
|
+
width="18"
|
|
181
|
+
height="18"
|
|
182
|
+
viewBox="0 0 24 24"
|
|
183
|
+
fill="none"
|
|
184
|
+
stroke="currentColor"
|
|
185
|
+
stroke-width="2"
|
|
186
|
+
stroke-linecap="round"
|
|
187
|
+
stroke-linejoin="round"
|
|
188
|
+
aria-hidden="true"
|
|
189
|
+
>
|
|
190
|
+
<path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z" />
|
|
191
|
+
<path d="M19 10v2a7 7 0 0 1-14 0v-2" />
|
|
192
|
+
<line x1="12" y1="19" x2="12" y2="23" />
|
|
193
|
+
<line x1="8" y1="23" x2="16" y2="23" />
|
|
194
|
+
</svg>
|
|
195
|
+
</button>
|
|
196
|
+
</div>
|
|
197
|
+
|
|
198
|
+
<!-- Join button -->
|
|
199
|
+
<button type="button" class={preCallJoinButtonClass}>
|
|
200
|
+
{joinLabel}
|
|
201
|
+
</button>
|
|
202
|
+
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
createPricingCard,
|
|
4
|
+
pricingCardVariants,
|
|
5
|
+
pricingCardBadgeClass,
|
|
6
|
+
pricingCardNameClass,
|
|
7
|
+
pricingCardPriceClass,
|
|
8
|
+
pricingCardPeriodClass,
|
|
9
|
+
pricingCardDescriptionClass,
|
|
10
|
+
pricingCardFeatureListClass,
|
|
11
|
+
pricingCardFeatureRowClass,
|
|
12
|
+
pricingCardFeatureTickClass,
|
|
13
|
+
pricingCtaVariants,
|
|
14
|
+
type PricingCtaVariant,
|
|
15
|
+
} from '../pricing-card/index.ts'
|
|
16
|
+
import { cn } from '../shared/index.ts'
|
|
17
|
+
|
|
18
|
+
interface Props extends astroHTML.JSX.HTMLAttributes {
|
|
19
|
+
/** Optional badge label shown above the plan name (e.g. "Most popular"). */
|
|
20
|
+
badge?: string
|
|
21
|
+
/** Plan name (e.g. "Pro", "Starter"). */
|
|
22
|
+
name: string
|
|
23
|
+
/** Price string (e.g. "$29", "Free"). */
|
|
24
|
+
price: string
|
|
25
|
+
/** Billing period or qualifier (e.g. "/ month"). */
|
|
26
|
+
period?: string
|
|
27
|
+
/** Short marketing description. */
|
|
28
|
+
description?: string
|
|
29
|
+
/** List of included features to render as a checklist. */
|
|
30
|
+
features: string[]
|
|
31
|
+
/** CTA button/link label. */
|
|
32
|
+
cta: string
|
|
33
|
+
/** Visual variant for the CTA. */
|
|
34
|
+
ctaVariant?: PricingCtaVariant
|
|
35
|
+
/** When provided, the CTA renders as an `<a>` tag. */
|
|
36
|
+
ctaHref?: string
|
|
37
|
+
/** Highlights the card with a primary ring. */
|
|
38
|
+
featured?: boolean
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const {
|
|
42
|
+
badge,
|
|
43
|
+
name,
|
|
44
|
+
price,
|
|
45
|
+
period,
|
|
46
|
+
description,
|
|
47
|
+
features,
|
|
48
|
+
cta,
|
|
49
|
+
ctaVariant = 'default',
|
|
50
|
+
ctaHref,
|
|
51
|
+
featured = false,
|
|
52
|
+
class: className,
|
|
53
|
+
...rest
|
|
54
|
+
} = Astro.props
|
|
55
|
+
|
|
56
|
+
const { ariaProps, dataAttributes } = createPricingCard({ featured })
|
|
57
|
+
const ctaClass = pricingCtaVariants({ variant: ctaVariant })
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
<div
|
|
61
|
+
class={cn(pricingCardVariants({ featured: featured ? 'true' : 'false' }), className)}
|
|
62
|
+
{...ariaProps}
|
|
63
|
+
{...dataAttributes}
|
|
64
|
+
{...rest}
|
|
65
|
+
>
|
|
66
|
+
{badge && <span class={pricingCardBadgeClass}>{badge}</span>}
|
|
67
|
+
|
|
68
|
+
<p class={pricingCardNameClass}>{name}</p>
|
|
69
|
+
|
|
70
|
+
<div class="mt-4 flex items-baseline gap-1">
|
|
71
|
+
<span class={pricingCardPriceClass}>{price}</span>
|
|
72
|
+
{period && <span class={pricingCardPeriodClass}>{period}</span>}
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
{description && <p class={`mt-2 ${pricingCardDescriptionClass}`}>{description}</p>}
|
|
76
|
+
|
|
77
|
+
<ul class={`mt-6 ${pricingCardFeatureListClass}`}>
|
|
78
|
+
{
|
|
79
|
+
features.map((feature) => (
|
|
80
|
+
<li class={pricingCardFeatureRowClass}>
|
|
81
|
+
<svg
|
|
82
|
+
class={pricingCardFeatureTickClass}
|
|
83
|
+
viewBox="0 0 16 16"
|
|
84
|
+
fill="none"
|
|
85
|
+
aria-hidden="true"
|
|
86
|
+
>
|
|
87
|
+
<path
|
|
88
|
+
d="M3 8l3.5 3.5L13 4.5"
|
|
89
|
+
stroke="currentColor"
|
|
90
|
+
stroke-width="1.75"
|
|
91
|
+
stroke-linecap="round"
|
|
92
|
+
stroke-linejoin="round"
|
|
93
|
+
/>
|
|
94
|
+
</svg>
|
|
95
|
+
{feature}
|
|
96
|
+
</li>
|
|
97
|
+
))
|
|
98
|
+
}
|
|
99
|
+
</ul>
|
|
100
|
+
|
|
101
|
+
<div class="mt-6">
|
|
102
|
+
{
|
|
103
|
+
ctaHref ? (
|
|
104
|
+
<a href={ctaHref} class={ctaClass}>
|
|
105
|
+
{cta}
|
|
106
|
+
</a>
|
|
107
|
+
) : (
|
|
108
|
+
<button type="button" class={ctaClass}>
|
|
109
|
+
{cta}
|
|
110
|
+
</button>
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
clampValue,
|
|
4
|
+
valueToFraction,
|
|
5
|
+
gaugeStrokeDashoffset,
|
|
6
|
+
resolveZoneTone,
|
|
7
|
+
createRadialGauge,
|
|
8
|
+
radialGaugeRootVariants,
|
|
9
|
+
gaugeTrackClass,
|
|
10
|
+
gaugeArcClass,
|
|
11
|
+
gaugeArcToneVariants,
|
|
12
|
+
gaugeLabelClass,
|
|
13
|
+
gaugeSublabelClass,
|
|
14
|
+
GAUGE_SIZE_PX,
|
|
15
|
+
GAUGE_LABEL_FONT_SIZE,
|
|
16
|
+
GAUGE_SUBLABEL_FONT_SIZE,
|
|
17
|
+
type GaugeSize,
|
|
18
|
+
type GaugeZone,
|
|
19
|
+
} from '../radial-gauge/index.ts'
|
|
20
|
+
import { cn } from '../shared/index.ts'
|
|
21
|
+
|
|
22
|
+
interface Props extends astroHTML.JSX.SVGAttributes {
|
|
23
|
+
/** Current value. */
|
|
24
|
+
value: number
|
|
25
|
+
/** Minimum value. Defaults to 0. */
|
|
26
|
+
min?: number
|
|
27
|
+
/** Maximum value. Defaults to 100. */
|
|
28
|
+
max?: number
|
|
29
|
+
/** Visual size of the gauge. Defaults to 'md'. */
|
|
30
|
+
size?: GaugeSize
|
|
31
|
+
/** Stroke thickness in px. Defaults to 8. */
|
|
32
|
+
thickness?: number
|
|
33
|
+
/** Primary center label. When omitted and `showValue` is true, the numeric value is shown. */
|
|
34
|
+
label?: string
|
|
35
|
+
/** Secondary label shown below the primary label. */
|
|
36
|
+
sublabel?: string
|
|
37
|
+
/**
|
|
38
|
+
* Threshold zones that colour the arc based on the current value.
|
|
39
|
+
* List in ascending `upTo` order for clarity (internally sorted).
|
|
40
|
+
*/
|
|
41
|
+
zones?: GaugeZone[]
|
|
42
|
+
/** Show the numeric value in the center when no explicit label is given. Defaults to true. */
|
|
43
|
+
showValue?: boolean
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const {
|
|
47
|
+
value,
|
|
48
|
+
min = 0,
|
|
49
|
+
max = 100,
|
|
50
|
+
size = 'md',
|
|
51
|
+
thickness = 8,
|
|
52
|
+
label,
|
|
53
|
+
sublabel,
|
|
54
|
+
zones,
|
|
55
|
+
showValue = true,
|
|
56
|
+
class: className,
|
|
57
|
+
...rest
|
|
58
|
+
} = Astro.props
|
|
59
|
+
|
|
60
|
+
const diameter = GAUGE_SIZE_PX[size]
|
|
61
|
+
const cx = diameter / 2
|
|
62
|
+
const cy = diameter / 2
|
|
63
|
+
const r = cx - thickness / 2
|
|
64
|
+
|
|
65
|
+
const clamped = clampValue(value, min, max)
|
|
66
|
+
const fraction = valueToFraction(clamped, min, max)
|
|
67
|
+
|
|
68
|
+
const circumference = 2 * Math.PI * r
|
|
69
|
+
const dashoffset = gaugeStrokeDashoffset(fraction, circumference)
|
|
70
|
+
|
|
71
|
+
const tone = zones && zones.length > 0 ? resolveZoneTone(clamped, zones, max) : 'default'
|
|
72
|
+
|
|
73
|
+
const { ariaProps, dataAttributes } = createRadialGauge({ value, min, max, size })
|
|
74
|
+
|
|
75
|
+
const centerLabel = label ?? (showValue ? String(clamped) : null)
|
|
76
|
+
const labelFontSize = GAUGE_LABEL_FONT_SIZE[size]
|
|
77
|
+
const sublabelFontSize = GAUGE_SUBLABEL_FONT_SIZE[size]
|
|
78
|
+
const labelDy = sublabel ? -sublabelFontSize * 0.8 : 0
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
<svg
|
|
82
|
+
width={diameter}
|
|
83
|
+
height={diameter}
|
|
84
|
+
viewBox={`0 0 ${diameter} ${diameter}`}
|
|
85
|
+
role="meter"
|
|
86
|
+
aria-valuenow={ariaProps['aria-valuenow']}
|
|
87
|
+
aria-valuemin={ariaProps['aria-valuemin']}
|
|
88
|
+
aria-valuemax={ariaProps['aria-valuemax']}
|
|
89
|
+
class={cn(radialGaugeRootVariants({ size }), className)}
|
|
90
|
+
{...dataAttributes}
|
|
91
|
+
{...rest}
|
|
92
|
+
>
|
|
93
|
+
{/* Background track */}
|
|
94
|
+
<circle
|
|
95
|
+
cx={cx}
|
|
96
|
+
cy={cy}
|
|
97
|
+
r={r}
|
|
98
|
+
stroke-width={thickness}
|
|
99
|
+
class={gaugeTrackClass}
|
|
100
|
+
/>
|
|
101
|
+
|
|
102
|
+
{/* Value arc */}
|
|
103
|
+
<circle
|
|
104
|
+
cx={cx}
|
|
105
|
+
cy={cy}
|
|
106
|
+
r={r}
|
|
107
|
+
stroke-width={thickness}
|
|
108
|
+
stroke-dasharray={`${circumference} ${circumference}`}
|
|
109
|
+
stroke-dashoffset={dashoffset}
|
|
110
|
+
stroke-linecap="round"
|
|
111
|
+
transform={`rotate(-90 ${cx} ${cy})`}
|
|
112
|
+
class={cn(gaugeArcClass, gaugeArcToneVariants({ tone }))}
|
|
113
|
+
/>
|
|
114
|
+
|
|
115
|
+
{/* Center label */}
|
|
116
|
+
{centerLabel != null && (
|
|
117
|
+
<text
|
|
118
|
+
x={cx}
|
|
119
|
+
y={cy}
|
|
120
|
+
text-anchor="middle"
|
|
121
|
+
dominant-baseline="central"
|
|
122
|
+
font-size={labelFontSize}
|
|
123
|
+
dy={labelDy}
|
|
124
|
+
class={gaugeLabelClass}
|
|
125
|
+
>
|
|
126
|
+
{centerLabel}
|
|
127
|
+
</text>
|
|
128
|
+
)}
|
|
129
|
+
|
|
130
|
+
{/* Sub-label */}
|
|
131
|
+
{sublabel != null && (
|
|
132
|
+
<text
|
|
133
|
+
x={cx}
|
|
134
|
+
y={cy}
|
|
135
|
+
text-anchor="middle"
|
|
136
|
+
dominant-baseline="central"
|
|
137
|
+
font-size={sublabelFontSize}
|
|
138
|
+
dy={labelDy + labelFontSize * 1.1}
|
|
139
|
+
class={gaugeSublabelClass}
|
|
140
|
+
>
|
|
141
|
+
{sublabel}
|
|
142
|
+
</text>
|
|
143
|
+
)}
|
|
144
|
+
</svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
createRatingScale,
|
|
4
|
+
resolveRatingPoints,
|
|
5
|
+
ratingScaleVariants,
|
|
6
|
+
ratingScaleTrackClass,
|
|
7
|
+
ratingScaleItemVariants,
|
|
8
|
+
ratingScaleLabelClass,
|
|
9
|
+
type RatingScaleSize,
|
|
10
|
+
type RatingScalePoint,
|
|
11
|
+
} from '../rating-scale/index.ts'
|
|
12
|
+
import { cn } from '../shared/index.ts'
|
|
13
|
+
|
|
14
|
+
interface Props extends astroHTML.JSX.HTMLAttributes {
|
|
15
|
+
/** Selected value. */
|
|
16
|
+
value?: number
|
|
17
|
+
/** Number of points (1..count). Ignored when `points` is provided. */
|
|
18
|
+
count?: number
|
|
19
|
+
/** Explicit points with accessible labels. */
|
|
20
|
+
points?: RatingScalePoint[]
|
|
21
|
+
/** Label shown before the scale (low end). */
|
|
22
|
+
minLabel?: string
|
|
23
|
+
/** Label shown after the scale (high end). */
|
|
24
|
+
maxLabel?: string
|
|
25
|
+
/** Visual size. */
|
|
26
|
+
size?: RatingScaleSize
|
|
27
|
+
/** Disables the whole scale. */
|
|
28
|
+
disabled?: boolean
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const {
|
|
32
|
+
value,
|
|
33
|
+
count = 5,
|
|
34
|
+
points,
|
|
35
|
+
minLabel,
|
|
36
|
+
maxLabel,
|
|
37
|
+
size = 'md',
|
|
38
|
+
disabled = false,
|
|
39
|
+
class: className,
|
|
40
|
+
...rest
|
|
41
|
+
} = Astro.props
|
|
42
|
+
|
|
43
|
+
const resolved = resolveRatingPoints(points, count)
|
|
44
|
+
const selectedIndex = resolved.findIndex((p) => p.value === value)
|
|
45
|
+
const tabbableIndex = selectedIndex === -1 ? 0 : selectedIndex
|
|
46
|
+
const { ariaProps, dataAttributes } = createRatingScale({ value, size })
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
<div class={cn(ratingScaleVariants({ size }), className)} {...ariaProps} {...dataAttributes} {...rest}>
|
|
50
|
+
{minLabel && <span class={ratingScaleLabelClass}>{minLabel}</span>}
|
|
51
|
+
<div class={ratingScaleTrackClass}>
|
|
52
|
+
{
|
|
53
|
+
resolved.map((point, index) => {
|
|
54
|
+
const checked = point.value === value
|
|
55
|
+
return (
|
|
56
|
+
<button
|
|
57
|
+
type="button"
|
|
58
|
+
role="radio"
|
|
59
|
+
aria-checked={checked}
|
|
60
|
+
aria-label={point.label ?? String(point.value)}
|
|
61
|
+
tabindex={index === tabbableIndex ? 0 : -1}
|
|
62
|
+
disabled={disabled}
|
|
63
|
+
data-state={checked ? 'checked' : 'unchecked'}
|
|
64
|
+
class={ratingScaleItemVariants({ size, state: checked ? 'checked' : 'unchecked' })}
|
|
65
|
+
>
|
|
66
|
+
{point.label ?? point.value}
|
|
67
|
+
</button>
|
|
68
|
+
)
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
</div>
|
|
72
|
+
{maxLabel && <span class={ratingScaleLabelClass}>{maxLabel}</span>}
|
|
73
|
+
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
createSectionHead,
|
|
4
|
+
sectionHeadVariants,
|
|
5
|
+
sectionHeadKickerClass,
|
|
6
|
+
sectionHeadTitleClass,
|
|
7
|
+
sectionHeadLedeClass,
|
|
8
|
+
type SectionHeadAlign,
|
|
9
|
+
} from '../section-head/index.ts'
|
|
10
|
+
import { cn } from '../shared/index.ts'
|
|
11
|
+
|
|
12
|
+
interface Props extends astroHTML.JSX.HTMLAttributes {
|
|
13
|
+
/** Optional eyebrow / kicker rendered above the title. */
|
|
14
|
+
kicker?: string
|
|
15
|
+
/** Primary heading content. Falls back to the default slot when not set. */
|
|
16
|
+
title?: string
|
|
17
|
+
/** Optional lede paragraph rendered below the title. */
|
|
18
|
+
lede?: string
|
|
19
|
+
/** Horizontal alignment of the cluster. */
|
|
20
|
+
align?: SectionHeadAlign
|
|
21
|
+
/** Override the heading element rendered for the title. Defaults to `h2`. */
|
|
22
|
+
as?: 'h1' | 'h2' | 'h3'
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const {
|
|
26
|
+
kicker,
|
|
27
|
+
title,
|
|
28
|
+
lede,
|
|
29
|
+
align = 'center',
|
|
30
|
+
as: Tag = 'h2',
|
|
31
|
+
class: className,
|
|
32
|
+
...rest
|
|
33
|
+
} = Astro.props
|
|
34
|
+
|
|
35
|
+
const { dataAttributes } = createSectionHead({ align })
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
<div class={cn(sectionHeadVariants({ align }), className)} {...dataAttributes} {...rest}>
|
|
39
|
+
{kicker && <p class={sectionHeadKickerClass}>{kicker}</p>}
|
|
40
|
+
<Tag class={sectionHeadTitleClass}>
|
|
41
|
+
{title ?? <slot />}
|
|
42
|
+
</Tag>
|
|
43
|
+
{lede && <p class={sectionHeadLedeClass}>{lede}</p>}
|
|
44
|
+
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
createStatGrid,
|
|
4
|
+
statColumns,
|
|
5
|
+
statGridVariants,
|
|
6
|
+
statItemClass,
|
|
7
|
+
statValueClass,
|
|
8
|
+
statLabelClass,
|
|
9
|
+
type StatItem,
|
|
10
|
+
} from '../stat-grid/index.ts'
|
|
11
|
+
import { cn } from '../shared/index.ts'
|
|
12
|
+
|
|
13
|
+
interface Props extends astroHTML.JSX.HTMLAttributes {
|
|
14
|
+
/** The stat items to display in the grid (value and label as strings). */
|
|
15
|
+
items: StatItem[]
|
|
16
|
+
/**
|
|
17
|
+
* Number of columns. Defaults to statColumns(items.length):
|
|
18
|
+
* 1 item → 1, 2 items → 2, 3+ items → 3.
|
|
19
|
+
*/
|
|
20
|
+
columns?: number
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const { items, columns, class: className, ...rest } = Astro.props
|
|
24
|
+
|
|
25
|
+
const cols = columns ?? statColumns(items.length)
|
|
26
|
+
const colsKey = String(cols) as '1' | '2' | '3'
|
|
27
|
+
const { ariaProps, dataAttributes } = createStatGrid()
|
|
28
|
+
const gridStyle = `grid-template-columns:repeat(${cols}, 1fr)`
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
<div
|
|
32
|
+
class={cn(statGridVariants({ columns: colsKey }), className)}
|
|
33
|
+
style={gridStyle}
|
|
34
|
+
{...ariaProps}
|
|
35
|
+
{...dataAttributes}
|
|
36
|
+
{...rest}
|
|
37
|
+
>
|
|
38
|
+
{
|
|
39
|
+
items.map((item) => (
|
|
40
|
+
<div role="listitem" class={statItemClass}>
|
|
41
|
+
<span class={statValueClass}>{item.value}</span>
|
|
42
|
+
<span class={statLabelClass}>{item.label}</span>
|
|
43
|
+
</div>
|
|
44
|
+
))
|
|
45
|
+
}
|
|
46
|
+
</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 {}
|