@rimelight/ui 0.0.38 → 0.0.39
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/package.json +3 -3
- package/src/components/icon/icon.theme.ts +8 -1
- package/src/components/image/RLAImage.astro +1 -3
- package/src/components/page-section/RLAPageSection.astro +8 -0
- package/src/components/post/RLAPost.astro +70 -70
- package/src/components/tabs/RLATabs.astro +116 -32
- package/src/components/tabs/tabs.theme.ts +51 -23
- package/src/components/tabs/tabs.ts +41 -6
- package/src/components/timeline/RLATimeline.astro +194 -20
- package/src/components/timeline/timeline.theme.ts +307 -9
- package/src/components/timeline/timeline.ts +54 -4
- package/src/components/video/RLAVideo.astro +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rimelight/ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.39",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Rimelight Entertainment UI Library.",
|
|
6
6
|
"keywords": [
|
|
@@ -54,11 +54,11 @@
|
|
|
54
54
|
"@astrojs/solid-js": "7.0.1",
|
|
55
55
|
"@astrojs/ts-plugin": "1.10.10",
|
|
56
56
|
"@astrojs/vue": "7.0.1",
|
|
57
|
-
"astro": "7.1.
|
|
57
|
+
"astro": "7.1.3",
|
|
58
58
|
"solid-js": "1.9.14",
|
|
59
59
|
"typescript": "6.0.3",
|
|
60
60
|
"unocss": "66.7.5",
|
|
61
|
-
"vue": "3.5.
|
|
61
|
+
"vue": "3.5.40"
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
64
|
"@astrojs/solid-js": ">=7.0.1",
|
|
@@ -4,7 +4,14 @@ export const createIconTheme = () =>
|
|
|
4
4
|
defineTheme({
|
|
5
5
|
slots: ["root"],
|
|
6
6
|
base: {
|
|
7
|
-
root: [
|
|
7
|
+
root: [
|
|
8
|
+
"shrink-0",
|
|
9
|
+
"inline-flex",
|
|
10
|
+
"items-center",
|
|
11
|
+
"justify-center",
|
|
12
|
+
"align-middle",
|
|
13
|
+
"leading-none"
|
|
14
|
+
]
|
|
8
15
|
},
|
|
9
16
|
variants: {
|
|
10
17
|
size: {
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
import { getImage } from "astro:assets"
|
|
2
|
+
import { Image, Picture, getImage } from "astro:assets"
|
|
3
3
|
import type { ImageMetadata } from "astro"
|
|
4
|
-
import Image from "astro/components/Image.astro"
|
|
5
|
-
import Picture from "astro/components/Picture.astro"
|
|
6
4
|
import RLAIcon from "../icon/RLAIcon.astro"
|
|
7
5
|
import { scv } from "css-variants"
|
|
8
6
|
import { useUi } from "../../utils/useUi"
|
|
@@ -42,6 +42,7 @@ const classes = resolveClasses(pageSection, {
|
|
|
42
42
|
}, useUi("pageSection", uiProp), className);
|
|
43
43
|
|
|
44
44
|
const hasDefaultSlot = Astro.slots.has("default");
|
|
45
|
+
const hasContentSlot = Astro.slots.has("content");
|
|
45
46
|
|
|
46
47
|
const Tag = as;
|
|
47
48
|
const TitleTag = variant === "hero" ? "h1" : "h2";
|
|
@@ -152,7 +153,14 @@ const TitleTag = variant === "hero" ? "h1" : "h2";
|
|
|
152
153
|
) : orientation === "horizontal" ? (
|
|
153
154
|
<div class="hidden lg:block" />
|
|
154
155
|
) : null}
|
|
156
|
+
|
|
157
|
+
{hasContentSlot && (
|
|
158
|
+
<div class="col-span-full w-full">
|
|
159
|
+
<slot name="content" />
|
|
160
|
+
</div>
|
|
161
|
+
)}
|
|
155
162
|
</div>
|
|
156
163
|
|
|
157
164
|
<slot name="bottom" />
|
|
158
165
|
</Tag>
|
|
166
|
+
|
|
@@ -1,72 +1,72 @@
|
|
|
1
|
-
---
|
|
2
|
-
import { scv } from "css-variants"
|
|
1
|
+
---
|
|
2
|
+
import { scv } from "css-variants"
|
|
3
3
|
import { useUi } from "../../utils/useUi"
|
|
4
|
-
import { resolveClasses } from "../../utils/resolveClasses"
|
|
5
|
-
import type { PostProps } from "./post"
|
|
6
|
-
import postTheme from "./post.theme"
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import RLABadge from "../badge/RLABadge.astro"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const post = scv(postTheme)
|
|
13
|
-
|
|
14
|
-
const {
|
|
15
|
-
title,
|
|
16
|
-
description,
|
|
17
|
-
date,
|
|
18
|
-
image,
|
|
19
|
-
to,
|
|
20
|
-
badge,
|
|
21
|
-
badgeColor = "primary",
|
|
22
|
-
variant = "soft",
|
|
23
|
-
orientation = "vertical",
|
|
24
|
-
ui: uiProp,
|
|
25
|
-
class: className,
|
|
26
|
-
...rest
|
|
27
|
-
} = Astro.props as PostProps
|
|
28
|
-
|
|
29
|
-
const classes = resolveClasses(post, { variant, orientation }, useUi("post", uiProp), className);
|
|
30
|
-
|
|
31
|
-
const Tag = to ? "a" : "div";
|
|
32
|
-
const formattedDate = date ? (date instanceof Date ? date.toLocaleDateString() : date) : null;
|
|
33
|
-
---
|
|
34
|
-
<Tag class={classes.root} data-slot="root" {...(to ? { href: to } : {})} {...rest}>
|
|
35
|
-
<slot name="image" {...{ ui: classes }}>
|
|
36
|
-
{image && (
|
|
37
|
-
<div class={classes.imageWrapper} data-slot="image-wrapper">
|
|
38
|
-
{typeof image === 'string' ? (
|
|
39
|
-
<img src={image} alt={title} class={classes.image} data-slot="image" />
|
|
40
|
-
) : (
|
|
41
|
-
<Image src={image as ImageMetadata} alt={title || ""} class={classes.image} data-slot="image" />
|
|
42
|
-
)}
|
|
43
|
-
</div>
|
|
44
|
-
)}
|
|
45
|
-
</slot>
|
|
46
|
-
|
|
47
|
-
<div class={classes.content} data-slot="content">
|
|
48
|
-
<slot name="title" {...{ ui: classes }}>
|
|
49
|
-
{title && <h3 class={classes.title} data-slot="title">{title}</h3>}
|
|
50
|
-
</slot>
|
|
51
|
-
|
|
52
|
-
<slot name="description" {...{ ui: classes }}>
|
|
53
|
-
{description && <p class={classes.description} data-slot="description">{description}</p>}
|
|
54
|
-
</slot>
|
|
55
|
-
|
|
56
|
-
<slot name="badge" {...{ ui: classes }}>
|
|
57
|
-
{badge && <RLABadge color={badgeColor as any} size="sm" shape="pill" class={classes.badge} data-slot="badge">{badge}</RLABadge>}
|
|
58
|
-
</slot>
|
|
59
|
-
|
|
60
|
-
<slot name="date" {...{ ui: classes }}>
|
|
61
|
-
{formattedDate && <time class={classes.date} data-slot="date">{formattedDate}</time>}
|
|
62
|
-
</slot>
|
|
63
|
-
|
|
64
|
-
<slot />
|
|
65
|
-
</div>
|
|
66
|
-
|
|
67
|
-
{Astro.slots.has("footer") && (
|
|
68
|
-
<div class={classes.footer} data-slot="footer">
|
|
69
|
-
<slot name="footer" {...{ ui: classes }} />
|
|
70
|
-
</div>
|
|
71
|
-
)}
|
|
4
|
+
import { resolveClasses } from "../../utils/resolveClasses"
|
|
5
|
+
import type { PostProps } from "./post"
|
|
6
|
+
import postTheme from "./post.theme"
|
|
7
|
+
import { Image } from "astro:assets"
|
|
8
|
+
import type { ImageMetadata } from "astro"
|
|
9
|
+
import RLABadge from "../badge/RLABadge.astro"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
const post = scv(postTheme)
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
title,
|
|
16
|
+
description,
|
|
17
|
+
date,
|
|
18
|
+
image,
|
|
19
|
+
to,
|
|
20
|
+
badge,
|
|
21
|
+
badgeColor = "primary",
|
|
22
|
+
variant = "soft",
|
|
23
|
+
orientation = "vertical",
|
|
24
|
+
ui: uiProp,
|
|
25
|
+
class: className,
|
|
26
|
+
...rest
|
|
27
|
+
} = Astro.props as PostProps
|
|
28
|
+
|
|
29
|
+
const classes = resolveClasses(post, { variant, orientation }, useUi("post", uiProp), className);
|
|
30
|
+
|
|
31
|
+
const Tag = to ? "a" : "div";
|
|
32
|
+
const formattedDate = date ? (date instanceof Date ? date.toLocaleDateString() : date) : null;
|
|
33
|
+
---
|
|
34
|
+
<Tag class={classes.root} data-slot="root" {...(to ? { href: to } : {})} {...rest}>
|
|
35
|
+
<slot name="image" {...{ ui: classes }}>
|
|
36
|
+
{image && (
|
|
37
|
+
<div class={classes.imageWrapper} data-slot="image-wrapper">
|
|
38
|
+
{typeof image === 'string' ? (
|
|
39
|
+
<img src={image} alt={title} class={classes.image} data-slot="image" />
|
|
40
|
+
) : (
|
|
41
|
+
<Image src={image as ImageMetadata} alt={title || ""} class={classes.image} data-slot="image" />
|
|
42
|
+
)}
|
|
43
|
+
</div>
|
|
44
|
+
)}
|
|
45
|
+
</slot>
|
|
46
|
+
|
|
47
|
+
<div class={classes.content} data-slot="content">
|
|
48
|
+
<slot name="title" {...{ ui: classes }}>
|
|
49
|
+
{title && <h3 class={classes.title} data-slot="title">{title}</h3>}
|
|
50
|
+
</slot>
|
|
51
|
+
|
|
52
|
+
<slot name="description" {...{ ui: classes }}>
|
|
53
|
+
{description && <p class={classes.description} data-slot="description">{description}</p>}
|
|
54
|
+
</slot>
|
|
55
|
+
|
|
56
|
+
<slot name="badge" {...{ ui: classes }}>
|
|
57
|
+
{badge && <RLABadge color={badgeColor as any} size="sm" shape="pill" class={classes.badge} data-slot="badge">{badge}</RLABadge>}
|
|
58
|
+
</slot>
|
|
59
|
+
|
|
60
|
+
<slot name="date" {...{ ui: classes }}>
|
|
61
|
+
{formattedDate && <time class={classes.date} data-slot="date">{formattedDate}</time>}
|
|
62
|
+
</slot>
|
|
63
|
+
|
|
64
|
+
<slot />
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
{Astro.slots.has("footer") && (
|
|
68
|
+
<div class={classes.footer} data-slot="footer">
|
|
69
|
+
<slot name="footer" {...{ ui: classes }} />
|
|
70
|
+
</div>
|
|
71
|
+
)}
|
|
72
72
|
</Tag>
|
|
@@ -2,71 +2,96 @@
|
|
|
2
2
|
import { scv } from "css-variants"
|
|
3
3
|
import { useUi } from "../../utils/useUi"
|
|
4
4
|
import { resolveClasses } from "../../utils/resolveClasses"
|
|
5
|
-
import type { TabsProps } from "./tabs"
|
|
5
|
+
import type { TabsProps, TabItem } from "./tabs"
|
|
6
6
|
import tabsTheme from "./tabs.theme"
|
|
7
|
-
|
|
7
|
+
import RLABadge from "../badge/RLABadge.astro"
|
|
8
8
|
|
|
9
9
|
const tabs = scv(tabsTheme)
|
|
10
10
|
|
|
11
11
|
const {
|
|
12
12
|
items = [],
|
|
13
13
|
value = "",
|
|
14
|
-
|
|
14
|
+
defaultValue = "",
|
|
15
|
+
variant = "pill",
|
|
15
16
|
orientation = "horizontal",
|
|
16
17
|
size = "md",
|
|
17
18
|
color = "primary",
|
|
19
|
+
content = true,
|
|
20
|
+
unmountOnHide = true,
|
|
21
|
+
valueKey = "value",
|
|
22
|
+
labelKey = "label",
|
|
18
23
|
ui: uiProp,
|
|
19
24
|
class: className,
|
|
20
25
|
...rest
|
|
21
26
|
} = Astro.props as TabsProps
|
|
22
27
|
|
|
28
|
+
// Normalize variant names for backward compatibility (solid -> pill, pills -> pill, underline -> underline, link -> underline)
|
|
29
|
+
const normalizedVariant = (variant === "solid" || variant === "pills") ? "pill" : (variant === "link" ? "underline" : variant);
|
|
30
|
+
|
|
23
31
|
const classes = resolveClasses(tabs, {
|
|
24
|
-
variant,
|
|
32
|
+
variant: normalizedVariant,
|
|
25
33
|
orientation,
|
|
26
34
|
size
|
|
27
35
|
}, useUi("tabs", uiProp), className);
|
|
28
36
|
|
|
29
|
-
const initialValue = value || (items.length > 0 ? items[0]
|
|
37
|
+
const initialValue = value || defaultValue || (items.length > 0 ? (items[0][valueKey] ?? items[0].value ?? "0") : "")
|
|
30
38
|
---
|
|
31
|
-
<rla-tabs {...rest}>
|
|
39
|
+
<rla-tabs {...rest} data-orientation={orientation} data-variant={normalizedVariant}>
|
|
32
40
|
<div class={classes.root} data-slot="root" data-tabs-container data-value={initialValue}>
|
|
33
41
|
<div class={classes.list} data-slot="list" role="tablist">
|
|
34
|
-
{
|
|
35
|
-
|
|
42
|
+
<div class={classes.indicator} data-slot="indicator" style="display: none;"></div>
|
|
43
|
+
{items.map((item, index) => {
|
|
44
|
+
const itemVal = item[valueKey] ?? item.value ?? String(index)
|
|
45
|
+
const itemLabel = item[labelKey] ?? item.label
|
|
46
|
+
const active = itemVal === initialValue
|
|
36
47
|
return (
|
|
37
48
|
<button
|
|
38
49
|
type="button"
|
|
39
50
|
class={classes.trigger}
|
|
40
51
|
data-slot="trigger"
|
|
41
52
|
role="tab"
|
|
42
|
-
data-value={
|
|
53
|
+
data-value={itemVal}
|
|
43
54
|
data-state={active ? "active" : "inactive"}
|
|
44
55
|
disabled={item.disabled}
|
|
45
56
|
>
|
|
46
|
-
{item.icon && <span class={item.icon + "
|
|
47
|
-
{
|
|
57
|
+
{item.icon && <span class={item.icon + " " + classes.leadingIcon} data-slot="leadingIcon" />}
|
|
58
|
+
{itemLabel && <span class={classes.label} data-slot="label">{itemLabel}</span>}
|
|
59
|
+
{item.badge !== undefined && item.badge !== null && (
|
|
60
|
+
<RLABadge
|
|
61
|
+
size="sm"
|
|
62
|
+
variant="subtle"
|
|
63
|
+
color="neutral"
|
|
64
|
+
class={classes.trailingBadge}
|
|
65
|
+
data-slot="trailingBadge"
|
|
66
|
+
>
|
|
67
|
+
{typeof item.badge === "object" ? item.badge.label : item.badge}
|
|
68
|
+
</RLABadge>
|
|
69
|
+
)}
|
|
48
70
|
</button>
|
|
49
71
|
)
|
|
50
72
|
})}
|
|
51
73
|
</div>
|
|
52
|
-
|
|
53
|
-
<
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
74
|
+
{content && (
|
|
75
|
+
<div class="flex-1">
|
|
76
|
+
<slot>
|
|
77
|
+
{items.map((item, index) => {
|
|
78
|
+
const itemVal = item[valueKey] ?? item.value ?? String(index)
|
|
79
|
+
const active = itemVal === initialValue
|
|
80
|
+
return (
|
|
81
|
+
<div
|
|
82
|
+
class={classes.content}
|
|
83
|
+
data-slot="content"
|
|
84
|
+
role="tabpanel"
|
|
85
|
+
data-value={itemVal}
|
|
86
|
+
hidden={active ? undefined : "until-found"}
|
|
87
|
+
>
|
|
88
|
+
{item.content}
|
|
89
|
+
</div>
|
|
90
|
+
)
|
|
91
|
+
})}
|
|
92
|
+
</slot>
|
|
93
|
+
</div>
|
|
94
|
+
)}
|
|
70
95
|
</div>
|
|
71
96
|
</rla-tabs>
|
|
72
97
|
|
|
@@ -74,19 +99,59 @@ const initialValue = value || (items.length > 0 ? items[0]?.value : "")
|
|
|
74
99
|
if (typeof HTMLElement !== 'undefined') {
|
|
75
100
|
class RLATabs extends HTMLElement {
|
|
76
101
|
private tabsCleanup: (() => void) | null = null;
|
|
102
|
+
private resizeObserver: ResizeObserver | null = null;
|
|
77
103
|
|
|
78
104
|
connectedCallback() {
|
|
79
105
|
this.style.display = 'contents';
|
|
80
106
|
const container = this.querySelector("[data-tabs-container]") as HTMLElement | null;
|
|
81
107
|
if (!container) return;
|
|
82
108
|
|
|
109
|
+
const list = container.querySelector("[data-slot=list]") as HTMLElement | null;
|
|
110
|
+
const indicator = container.querySelector("[data-slot=indicator]") as HTMLElement | null;
|
|
111
|
+
const orientation = this.dataset.orientation || "horizontal";
|
|
112
|
+
const isVertical = orientation === "vertical";
|
|
113
|
+
|
|
114
|
+
const updateIndicator = (activeTrigger: HTMLElement | null) => {
|
|
115
|
+
if (!indicator || !list || !activeTrigger) {
|
|
116
|
+
if (indicator) indicator.style.display = 'none';
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const listRect = list.getBoundingClientRect();
|
|
121
|
+
const triggerRect = activeTrigger.getBoundingClientRect();
|
|
122
|
+
|
|
123
|
+
if (triggerRect.width === 0 && triggerRect.height === 0) {
|
|
124
|
+
indicator.style.display = 'none';
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
indicator.style.display = 'block';
|
|
129
|
+
|
|
130
|
+
if (isVertical) {
|
|
131
|
+
const top = triggerRect.top - listRect.top + list.scrollTop;
|
|
132
|
+
const height = triggerRect.height;
|
|
133
|
+
indicator.style.transform = `translateY(${top}px)`;
|
|
134
|
+
indicator.style.height = `${height}px`;
|
|
135
|
+
} else {
|
|
136
|
+
const left = triggerRect.left - listRect.left + list.scrollLeft;
|
|
137
|
+
const width = triggerRect.width;
|
|
138
|
+
indicator.style.transform = `translateX(${left}px)`;
|
|
139
|
+
indicator.style.width = `${width}px`;
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
83
143
|
const containerValue = container.dataset.value;
|
|
84
144
|
const triggers = container.querySelectorAll("[role=tab]");
|
|
85
145
|
const panels = container.querySelectorAll("[role=tabpanel]");
|
|
86
146
|
|
|
147
|
+
let activeTrigger: HTMLElement | null = null;
|
|
148
|
+
|
|
87
149
|
triggers.forEach(trigger => {
|
|
88
|
-
const
|
|
89
|
-
|
|
150
|
+
const el = trigger as HTMLElement;
|
|
151
|
+
const val = el.dataset.value;
|
|
152
|
+
const isActive = val === containerValue;
|
|
153
|
+
el.setAttribute("data-state", isActive ? "active" : "inactive");
|
|
154
|
+
if (isActive) activeTrigger = el;
|
|
90
155
|
});
|
|
91
156
|
|
|
92
157
|
panels.forEach(panel => {
|
|
@@ -98,6 +163,17 @@ const initialValue = value || (items.length > 0 ? items[0]?.value : "")
|
|
|
98
163
|
}
|
|
99
164
|
});
|
|
100
165
|
|
|
166
|
+
// Initialize indicator position
|
|
167
|
+
requestAnimationFrame(() => updateIndicator(activeTrigger));
|
|
168
|
+
|
|
169
|
+
if (window.ResizeObserver && list) {
|
|
170
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
171
|
+
const currentActive = list.querySelector("[role=tab][data-state=active]") as HTMLElement | null;
|
|
172
|
+
updateIndicator(currentActive);
|
|
173
|
+
});
|
|
174
|
+
this.resizeObserver.observe(list);
|
|
175
|
+
}
|
|
176
|
+
|
|
101
177
|
const clickCleanups: (() => void)[] = [];
|
|
102
178
|
const beforeMatchCleanups: (() => void)[] = [];
|
|
103
179
|
|
|
@@ -117,11 +193,14 @@ const initialValue = value || (items.length > 0 ? items[0]?.value : "")
|
|
|
117
193
|
triggers.forEach(triggerNode => {
|
|
118
194
|
const trigger = triggerNode as HTMLButtonElement;
|
|
119
195
|
const onClick = () => {
|
|
196
|
+
if (trigger.disabled) return;
|
|
120
197
|
const targetValue = trigger.dataset.value;
|
|
121
198
|
|
|
122
199
|
triggers.forEach(tNode => {
|
|
123
200
|
const t = tNode as HTMLButtonElement;
|
|
124
|
-
|
|
201
|
+
const isTarget = t.dataset.value === targetValue;
|
|
202
|
+
t.setAttribute("data-state", isTarget ? "active" : "inactive");
|
|
203
|
+
if (isTarget) updateIndicator(t);
|
|
125
204
|
});
|
|
126
205
|
|
|
127
206
|
panels.forEach(panel => {
|
|
@@ -139,6 +218,10 @@ const initialValue = value || (items.length > 0 ? items[0]?.value : "")
|
|
|
139
218
|
this.tabsCleanup = () => {
|
|
140
219
|
clickCleanups.forEach(fn => fn());
|
|
141
220
|
beforeMatchCleanups.forEach(fn => fn());
|
|
221
|
+
if (this.resizeObserver) {
|
|
222
|
+
this.resizeObserver.disconnect();
|
|
223
|
+
this.resizeObserver = null;
|
|
224
|
+
}
|
|
142
225
|
};
|
|
143
226
|
}
|
|
144
227
|
|
|
@@ -155,3 +238,4 @@ const initialValue = value || (items.length > 0 ? items[0]?.value : "")
|
|
|
155
238
|
}
|
|
156
239
|
}
|
|
157
240
|
</script>
|
|
241
|
+
|
|
@@ -2,51 +2,79 @@ import { defineTheme } from "../../utils/defineTheme"
|
|
|
2
2
|
|
|
3
3
|
export const createTabsTheme = () =>
|
|
4
4
|
defineTheme({
|
|
5
|
-
slots: ["root", "list", "trigger", "content"],
|
|
5
|
+
slots: ["root", "list", "indicator", "trigger", "leadingIcon", "leadingAvatar", "label", "trailingBadge", "content"],
|
|
6
6
|
base: {
|
|
7
|
-
root: "
|
|
8
|
-
list: "
|
|
7
|
+
root: "flex gap-2 w-full",
|
|
8
|
+
list: "relative flex p-1 group items-center min-w-0",
|
|
9
|
+
indicator: "absolute transition-[translate,width,height,top,left] duration-200 ease-out pointer-events-none",
|
|
9
10
|
trigger:
|
|
10
|
-
"inline-flex items-center justify-center
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
"group relative inline-flex items-center justify-center min-w-0 whitespace-nowrap font-medium transition-colors cursor-pointer disabled:cursor-not-allowed disabled:opacity-75 focus-visible:outline-none data-[state=inactive]:text-muted-foreground hover:data-[state=inactive]:text-foreground",
|
|
12
|
+
leadingIcon: "shrink-0",
|
|
13
|
+
leadingAvatar: "shrink-0",
|
|
14
|
+
label: "truncate",
|
|
15
|
+
trailingBadge: "shrink-0",
|
|
16
|
+
content: "w-full focus-visible:outline-none"
|
|
13
17
|
},
|
|
14
18
|
variants: {
|
|
15
19
|
variant: {
|
|
16
|
-
|
|
17
|
-
list: "bg-muted
|
|
18
|
-
trigger:
|
|
19
|
-
|
|
20
|
+
pill: {
|
|
21
|
+
list: "bg-muted/60 dark:bg-muted/40 rounded-lg p-1",
|
|
22
|
+
trigger: "grow rounded-md data-[state=active]:text-foreground z-10",
|
|
23
|
+
indicator: "bg-background rounded-md shadow-xs top-1 bottom-1 h-[calc(100%-8px)]"
|
|
20
24
|
},
|
|
21
25
|
underline: {
|
|
22
|
-
list: "bg-transparent border-b border-border
|
|
23
|
-
trigger:
|
|
24
|
-
|
|
26
|
+
list: "bg-transparent border-b border-border p-0 gap-2 -mb-px",
|
|
27
|
+
trigger: "rounded-md data-[state=active]:text-primary pb-2 pt-1 px-3 z-10",
|
|
28
|
+
indicator: "bg-primary rounded-full -bottom-px h-0.5 left-0"
|
|
25
29
|
},
|
|
26
|
-
|
|
27
|
-
list: "bg-transparent p-0 gap-2",
|
|
28
|
-
trigger:
|
|
29
|
-
|
|
30
|
+
link: {
|
|
31
|
+
list: "bg-transparent border-b border-border p-0 gap-2 -mb-px",
|
|
32
|
+
trigger: "rounded-md data-[state=active]:text-primary pb-2 pt-1 px-3 z-10",
|
|
33
|
+
indicator: "bg-primary rounded-full -bottom-px h-0.5 left-0"
|
|
30
34
|
}
|
|
31
35
|
},
|
|
32
36
|
orientation: {
|
|
33
|
-
horizontal: {
|
|
37
|
+
horizontal: {
|
|
38
|
+
root: "flex-col",
|
|
39
|
+
list: "w-full",
|
|
40
|
+
indicator: "",
|
|
41
|
+
trigger: "justify-center"
|
|
42
|
+
},
|
|
34
43
|
vertical: {
|
|
35
44
|
root: "flex-row gap-6",
|
|
36
|
-
list: "flex-col items-stretch
|
|
45
|
+
list: "flex-col items-stretch w-48 border-r border-border p-0",
|
|
46
|
+
trigger: "justify-start text-left"
|
|
37
47
|
}
|
|
38
48
|
},
|
|
39
49
|
size: {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
50
|
+
xs: {
|
|
51
|
+
trigger: "px-2 py-1 text-xs gap-1",
|
|
52
|
+
leadingIcon: "size-3.5"
|
|
53
|
+
},
|
|
54
|
+
sm: {
|
|
55
|
+
trigger: "px-2.5 py-1.5 text-xs gap-1.5",
|
|
56
|
+
leadingIcon: "size-4"
|
|
57
|
+
},
|
|
58
|
+
md: {
|
|
59
|
+
trigger: "px-3 py-1.5 text-sm gap-1.5",
|
|
60
|
+
leadingIcon: "size-4"
|
|
61
|
+
},
|
|
62
|
+
lg: {
|
|
63
|
+
trigger: "px-3.5 py-2 text-sm gap-2",
|
|
64
|
+
leadingIcon: "size-5"
|
|
65
|
+
},
|
|
66
|
+
xl: {
|
|
67
|
+
trigger: "px-4 py-2.5 text-base gap-2",
|
|
68
|
+
leadingIcon: "size-5"
|
|
69
|
+
}
|
|
43
70
|
}
|
|
44
71
|
},
|
|
45
72
|
defaultVariants: {
|
|
46
|
-
variant: "
|
|
73
|
+
variant: "pill",
|
|
47
74
|
orientation: "horizontal",
|
|
48
75
|
size: "md"
|
|
49
76
|
}
|
|
50
77
|
})
|
|
51
78
|
|
|
52
79
|
export default createTabsTheme()
|
|
80
|
+
|
|
@@ -1,37 +1,71 @@
|
|
|
1
1
|
import type { ThemeColor } from "../../types/component"
|
|
2
|
+
|
|
2
3
|
export interface TabItem {
|
|
3
|
-
label
|
|
4
|
-
value
|
|
4
|
+
label?: string
|
|
5
|
+
value?: string
|
|
5
6
|
icon?: string
|
|
7
|
+
badge?: string | number | { label?: string | number; color?: string; variant?: string }
|
|
6
8
|
content?: string
|
|
7
9
|
disabled?: boolean
|
|
10
|
+
slot?: string
|
|
11
|
+
class?: any
|
|
12
|
+
ui?: any
|
|
13
|
+
[key: string]: any
|
|
8
14
|
}
|
|
9
15
|
|
|
10
|
-
export interface TabsProps {
|
|
16
|
+
export interface TabsProps<T extends TabItem = TabItem> {
|
|
11
17
|
/**
|
|
12
18
|
* The tab items.
|
|
13
19
|
*/
|
|
14
|
-
items?:
|
|
20
|
+
items?: T[]
|
|
15
21
|
/**
|
|
16
22
|
* Active tab value.
|
|
17
23
|
*/
|
|
18
24
|
value?: string
|
|
25
|
+
/**
|
|
26
|
+
* Default active tab value when uncontrolled.
|
|
27
|
+
*/
|
|
28
|
+
defaultValue?: string
|
|
19
29
|
/**
|
|
20
30
|
* Tab variant.
|
|
31
|
+
* @defaultValue 'pill'
|
|
21
32
|
*/
|
|
22
|
-
variant?: "
|
|
33
|
+
variant?: "pill" | "underline" | "link" | "solid" | "pills"
|
|
23
34
|
/**
|
|
24
35
|
* Layout orientation.
|
|
36
|
+
* @defaultValue 'horizontal'
|
|
25
37
|
*/
|
|
26
38
|
orientation?: "horizontal" | "vertical"
|
|
27
39
|
/**
|
|
28
40
|
* Size scale.
|
|
41
|
+
* @defaultValue 'md'
|
|
29
42
|
*/
|
|
30
|
-
size?: "sm" | "md" | "lg"
|
|
43
|
+
size?: "xs" | "sm" | "md" | "lg" | "xl"
|
|
31
44
|
/**
|
|
32
45
|
* Color theme.
|
|
33
46
|
*/
|
|
34
47
|
color?: ThemeColor
|
|
48
|
+
/**
|
|
49
|
+
* Whether to render content panels automatically. Set to false for tab bar only.
|
|
50
|
+
* @defaultValue true
|
|
51
|
+
*/
|
|
52
|
+
content?: boolean
|
|
53
|
+
/**
|
|
54
|
+
* Unmount hidden tab panels from DOM. Defaults to true.
|
|
55
|
+
* If false, panel is hidden via CSS/attribute.
|
|
56
|
+
* @defaultValue true
|
|
57
|
+
*/
|
|
58
|
+
unmountOnHide?: boolean
|
|
59
|
+
/**
|
|
60
|
+
* Property key for value on item object.
|
|
61
|
+
* @defaultValue 'value'
|
|
62
|
+
*/
|
|
63
|
+
valueKey?: string
|
|
64
|
+
/**
|
|
65
|
+
* Property key for label on item object.
|
|
66
|
+
* @defaultValue 'label'
|
|
67
|
+
*/
|
|
68
|
+
labelKey?: string
|
|
35
69
|
/**
|
|
36
70
|
* Slot-specific CSS class overrides.
|
|
37
71
|
*/
|
|
@@ -42,3 +76,4 @@ export interface TabsProps {
|
|
|
42
76
|
class?: any
|
|
43
77
|
[key: string]: unknown
|
|
44
78
|
}
|
|
79
|
+
|
|
@@ -1,21 +1,195 @@
|
|
|
1
|
-
---
|
|
2
|
-
import { scv } from "css-variants"
|
|
1
|
+
---
|
|
2
|
+
import { scv, cx } from "css-variants"
|
|
3
3
|
import { useUi } from "../../utils/useUi"
|
|
4
|
-
import { resolveClasses } from "../../utils/resolveClasses"
|
|
5
|
-
import type { TimelineProps } from "./timeline"
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
4
|
+
import { resolveClasses } from "../../utils/resolveClasses"
|
|
5
|
+
import type { TimelineProps, TimelineItem } from "./timeline"
|
|
6
|
+
import { resolveTheme } from "../../utils/resolveTheme"
|
|
7
|
+
import timelineThemeDefault, { createTimelineTheme } from "./timeline.theme"
|
|
8
|
+
const timelineTheme = resolveTheme(timelineThemeDefault, createTimelineTheme)
|
|
9
|
+
import RLAAvatar from "../avatar/RLAAvatar.astro"
|
|
10
|
+
import RLAIcon from "../icon/RLAIcon.astro"
|
|
11
|
+
|
|
12
|
+
const timeline = scv(timelineTheme)
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
as: Component = "div",
|
|
16
|
+
items,
|
|
17
|
+
size = "md",
|
|
18
|
+
color = "primary",
|
|
19
|
+
orientation = "vertical",
|
|
20
|
+
valueKey = "value",
|
|
21
|
+
defaultValue,
|
|
22
|
+
modelValue,
|
|
23
|
+
reverse = false,
|
|
24
|
+
ui: uiProp,
|
|
25
|
+
class: className,
|
|
26
|
+
...rest
|
|
27
|
+
} = Astro.props as TimelineProps
|
|
28
|
+
|
|
29
|
+
const classes = resolveClasses(
|
|
30
|
+
timeline,
|
|
31
|
+
{
|
|
32
|
+
orientation,
|
|
33
|
+
size,
|
|
34
|
+
color,
|
|
35
|
+
reverse
|
|
36
|
+
},
|
|
37
|
+
useUi("timeline", uiProp),
|
|
38
|
+
className
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
const activeVal = modelValue !== undefined ? modelValue : defaultValue
|
|
42
|
+
|
|
43
|
+
function getItemValue(item: TimelineItem, index: number) {
|
|
44
|
+
return item[valueKey] !== undefined ? item[valueKey] : index
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function getItemState(item: TimelineItem, index: number): "active" | "completed" | undefined {
|
|
48
|
+
if (activeVal === undefined) return undefined
|
|
49
|
+
|
|
50
|
+
let currentIndex = -1
|
|
51
|
+
if (items && items.length > 0) {
|
|
52
|
+
if (typeof activeVal === "string") {
|
|
53
|
+
currentIndex = items.findIndex((i) => getItemValue(i, items.indexOf(i)) === activeVal)
|
|
54
|
+
} else if (typeof activeVal === "number") {
|
|
55
|
+
if (reverse) {
|
|
56
|
+
currentIndex = items.length - 1 - activeVal
|
|
57
|
+
} else {
|
|
58
|
+
currentIndex = activeVal
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (currentIndex === -1) return undefined
|
|
64
|
+
if (index === currentIndex) return "active"
|
|
65
|
+
|
|
66
|
+
if (reverse) {
|
|
67
|
+
return index > currentIndex ? "completed" : undefined
|
|
68
|
+
} else {
|
|
69
|
+
return index < currentIndex ? "completed" : undefined
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function getSlotName(item: TimelineItem, slotType: string): string {
|
|
74
|
+
return item.slot ? `${item.slot}-${slotType}` : slotType
|
|
75
|
+
}
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
<Component
|
|
79
|
+
data-orientation={orientation}
|
|
80
|
+
data-slot="root"
|
|
81
|
+
class={classes.root}
|
|
82
|
+
{...rest}
|
|
83
|
+
>
|
|
84
|
+
{items && items.length > 0 ? (
|
|
85
|
+
items.map((item, index) => {
|
|
86
|
+
const state = getItemState(item, index)
|
|
87
|
+
const isLast = index === items.length - 1
|
|
88
|
+
|
|
89
|
+
const itemIndicatorSlot = getSlotName(item, "indicator")
|
|
90
|
+
const itemWrapperSlot = getSlotName(item, "wrapper")
|
|
91
|
+
const itemDateSlot = getSlotName(item, "date")
|
|
92
|
+
const itemTitleSlot = getSlotName(item, "title")
|
|
93
|
+
const itemDescriptionSlot = getSlotName(item, "description")
|
|
94
|
+
|
|
95
|
+
const hasCustomIndicator = Astro.slots.has(itemIndicatorSlot) || (item.slot && Astro.slots.has("indicator"))
|
|
96
|
+
const hasCustomWrapper = Astro.slots.has(itemWrapperSlot) || (item.slot && Astro.slots.has("wrapper"))
|
|
97
|
+
const hasCustomDate = Astro.slots.has(itemDateSlot) || (item.slot && Astro.slots.has("date"))
|
|
98
|
+
const hasCustomTitle = Astro.slots.has(itemTitleSlot) || (item.slot && Astro.slots.has("title"))
|
|
99
|
+
const hasCustomDescription = Astro.slots.has(itemDescriptionSlot) || (item.slot && Astro.slots.has("description"))
|
|
100
|
+
|
|
101
|
+
return (
|
|
102
|
+
<div
|
|
103
|
+
data-slot="item"
|
|
104
|
+
class={cx(classes.item, item.ui?.item, item.class)}
|
|
105
|
+
data-state={state}
|
|
106
|
+
>
|
|
107
|
+
<div
|
|
108
|
+
data-slot="container"
|
|
109
|
+
class={cx(classes.container, item.ui?.container)}
|
|
110
|
+
>
|
|
111
|
+
<RLAAvatar
|
|
112
|
+
size={size as any}
|
|
113
|
+
src={item.avatar?.src}
|
|
114
|
+
alt={item.avatar?.alt}
|
|
115
|
+
{...(typeof item.avatar === "object" ? item.avatar : {})}
|
|
116
|
+
data-slot="indicator"
|
|
117
|
+
class={cx(classes.indicator, item.ui?.indicator)}
|
|
118
|
+
ui={{ icon: "text-highlighted group-data-[state=completed]:text-inverted group-data-[state=active]:text-inverted", fallback: "text-highlighted group-data-[state=completed]:text-inverted group-data-[state=active]:text-inverted" }}
|
|
119
|
+
>
|
|
120
|
+
{hasCustomIndicator ? (
|
|
121
|
+
<slot name={itemIndicatorSlot} item={item}>
|
|
122
|
+
<slot name="indicator" item={item} />
|
|
123
|
+
</slot>
|
|
124
|
+
) : item.icon ? (
|
|
125
|
+
<RLAIcon name={item.icon} class="text-inherit" />
|
|
126
|
+
) : null}
|
|
127
|
+
</RLAAvatar>
|
|
128
|
+
|
|
129
|
+
{!isLast && (
|
|
130
|
+
<div
|
|
131
|
+
data-slot="separator"
|
|
132
|
+
class={cx(classes.separator, item.ui?.separator)}
|
|
133
|
+
data-orientation={orientation}
|
|
134
|
+
/>
|
|
135
|
+
)}
|
|
136
|
+
</div>
|
|
137
|
+
|
|
138
|
+
<div
|
|
139
|
+
data-slot="wrapper"
|
|
140
|
+
class={cx(classes.wrapper, item.ui?.wrapper)}
|
|
141
|
+
>
|
|
142
|
+
{hasCustomWrapper ? (
|
|
143
|
+
<slot name={itemWrapperSlot} item={item}>
|
|
144
|
+
<slot name="wrapper" item={item} />
|
|
145
|
+
</slot>
|
|
146
|
+
) : (
|
|
147
|
+
<>
|
|
148
|
+
{(item.date || hasCustomDate) && (
|
|
149
|
+
<div
|
|
150
|
+
data-slot="date"
|
|
151
|
+
class={cx(classes.date, item.ui?.date)}
|
|
152
|
+
>
|
|
153
|
+
<slot name={itemDateSlot} item={item}>
|
|
154
|
+
<slot name="date" item={item}>
|
|
155
|
+
{item.date}
|
|
156
|
+
</slot>
|
|
157
|
+
</slot>
|
|
158
|
+
</div>
|
|
159
|
+
)}
|
|
160
|
+
|
|
161
|
+
{(item.title || hasCustomTitle) && (
|
|
162
|
+
<div
|
|
163
|
+
data-slot="title"
|
|
164
|
+
class={cx(classes.title, item.ui?.title)}
|
|
165
|
+
>
|
|
166
|
+
<slot name={itemTitleSlot} item={item}>
|
|
167
|
+
<slot name="title" item={item}>
|
|
168
|
+
{item.title}
|
|
169
|
+
</slot>
|
|
170
|
+
</slot>
|
|
171
|
+
</div>
|
|
172
|
+
)}
|
|
173
|
+
|
|
174
|
+
{(item.description || hasCustomDescription) && (
|
|
175
|
+
<div
|
|
176
|
+
data-slot="description"
|
|
177
|
+
class={cx(classes.description, item.ui?.description)}
|
|
178
|
+
>
|
|
179
|
+
<slot name={itemDescriptionSlot} item={item}>
|
|
180
|
+
<slot name="description" item={item}>
|
|
181
|
+
{item.description}
|
|
182
|
+
</slot>
|
|
183
|
+
</slot>
|
|
184
|
+
</div>
|
|
185
|
+
)}
|
|
186
|
+
</>
|
|
187
|
+
)}
|
|
188
|
+
</div>
|
|
189
|
+
</div>
|
|
190
|
+
)
|
|
191
|
+
})
|
|
192
|
+
) : (
|
|
193
|
+
<slot />
|
|
194
|
+
)}
|
|
195
|
+
</Component>
|
|
@@ -2,17 +2,315 @@ import { defineTheme } from "../../utils/defineTheme"
|
|
|
2
2
|
|
|
3
3
|
export const createTimelineTheme = () =>
|
|
4
4
|
defineTheme({
|
|
5
|
-
slots: [
|
|
5
|
+
slots: [
|
|
6
|
+
"root",
|
|
7
|
+
"item",
|
|
8
|
+
"container",
|
|
9
|
+
"indicator",
|
|
10
|
+
"separator",
|
|
11
|
+
"wrapper",
|
|
12
|
+
"date",
|
|
13
|
+
"title",
|
|
14
|
+
"description"
|
|
15
|
+
],
|
|
6
16
|
base: {
|
|
7
|
-
root: "
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
17
|
+
root: "flex gap-1.5",
|
|
18
|
+
item: "group relative flex flex-1 gap-3",
|
|
19
|
+
container: "relative flex items-center gap-1.5",
|
|
20
|
+
indicator:
|
|
21
|
+
"group-data-[state=completed]:text-inverted group-data-[state=active]:text-inverted text-highlighted",
|
|
22
|
+
separator: "flex-1 rounded-full bg-elevated",
|
|
23
|
+
wrapper: "w-full",
|
|
24
|
+
date: "text-dimmed text-xs/5",
|
|
25
|
+
title: "font-medium text-highlighted text-sm",
|
|
26
|
+
description: "text-muted text-wrap text-sm"
|
|
13
27
|
},
|
|
14
|
-
variants: {
|
|
15
|
-
|
|
28
|
+
variants: {
|
|
29
|
+
orientation: {
|
|
30
|
+
horizontal: {
|
|
31
|
+
root: "flex-row w-full",
|
|
32
|
+
item: "flex-col",
|
|
33
|
+
separator: "h-0.5"
|
|
34
|
+
},
|
|
35
|
+
vertical: {
|
|
36
|
+
root: "flex-col",
|
|
37
|
+
container: "flex-col",
|
|
38
|
+
separator: "w-0.5"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
color: {
|
|
42
|
+
primary: {
|
|
43
|
+
indicator: "group-data-[state=completed]:bg-primary group-data-[state=active]:bg-primary"
|
|
44
|
+
},
|
|
45
|
+
secondary: {
|
|
46
|
+
indicator:
|
|
47
|
+
"group-data-[state=completed]:bg-secondary group-data-[state=active]:bg-secondary"
|
|
48
|
+
},
|
|
49
|
+
success: {
|
|
50
|
+
indicator: "group-data-[state=completed]:bg-success group-data-[state=active]:bg-success"
|
|
51
|
+
},
|
|
52
|
+
info: {
|
|
53
|
+
indicator: "group-data-[state=completed]:bg-info group-data-[state=active]:bg-info"
|
|
54
|
+
},
|
|
55
|
+
warning: {
|
|
56
|
+
indicator: "group-data-[state=completed]:bg-warning group-data-[state=active]:bg-warning"
|
|
57
|
+
},
|
|
58
|
+
error: {
|
|
59
|
+
indicator: "group-data-[state=completed]:bg-error group-data-[state=active]:bg-error"
|
|
60
|
+
},
|
|
61
|
+
neutral: {
|
|
62
|
+
indicator:
|
|
63
|
+
"group-data-[state=completed]:bg-inverted group-data-[state=active]:bg-inverted"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
size: {
|
|
67
|
+
"3xs": {},
|
|
68
|
+
"2xs": {},
|
|
69
|
+
"xs": {},
|
|
70
|
+
"sm": {},
|
|
71
|
+
"md": {},
|
|
72
|
+
"lg": {},
|
|
73
|
+
"xl": {},
|
|
74
|
+
"2xl": {},
|
|
75
|
+
"3xl": {}
|
|
76
|
+
},
|
|
77
|
+
reverse: {
|
|
78
|
+
true: {},
|
|
79
|
+
false: {}
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
compoundVariants: [
|
|
83
|
+
{
|
|
84
|
+
color: "primary",
|
|
85
|
+
reverse: false,
|
|
86
|
+
class: {
|
|
87
|
+
separator: "group-data-[state=completed]:bg-primary"
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
color: "secondary",
|
|
92
|
+
reverse: false,
|
|
93
|
+
class: {
|
|
94
|
+
separator: "group-data-[state=completed]:bg-secondary"
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
color: "success",
|
|
99
|
+
reverse: false,
|
|
100
|
+
class: {
|
|
101
|
+
separator: "group-data-[state=completed]:bg-success"
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
color: "info",
|
|
106
|
+
reverse: false,
|
|
107
|
+
class: {
|
|
108
|
+
separator: "group-data-[state=completed]:bg-info"
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
color: "warning",
|
|
113
|
+
reverse: false,
|
|
114
|
+
class: {
|
|
115
|
+
separator: "group-data-[state=completed]:bg-warning"
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
color: "error",
|
|
120
|
+
reverse: false,
|
|
121
|
+
class: {
|
|
122
|
+
separator: "group-data-[state=completed]:bg-error"
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
color: "primary",
|
|
127
|
+
reverse: true,
|
|
128
|
+
class: {
|
|
129
|
+
separator: "group-data-[state=active]:bg-primary group-data-[state=completed]:bg-primary"
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
color: "secondary",
|
|
134
|
+
reverse: true,
|
|
135
|
+
class: {
|
|
136
|
+
separator:
|
|
137
|
+
"group-data-[state=active]:bg-secondary group-data-[state=completed]:bg-secondary"
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
color: "success",
|
|
142
|
+
reverse: true,
|
|
143
|
+
class: {
|
|
144
|
+
separator: "group-data-[state=active]:bg-success group-data-[state=completed]:bg-success"
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
color: "info",
|
|
149
|
+
reverse: true,
|
|
150
|
+
class: {
|
|
151
|
+
separator: "group-data-[state=active]:bg-info group-data-[state=completed]:bg-info"
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
color: "warning",
|
|
156
|
+
reverse: true,
|
|
157
|
+
class: {
|
|
158
|
+
separator: "group-data-[state=active]:bg-warning group-data-[state=completed]:bg-warning"
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
color: "error",
|
|
163
|
+
reverse: true,
|
|
164
|
+
class: {
|
|
165
|
+
separator: "group-data-[state=active]:bg-error group-data-[state=completed]:bg-error"
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
color: "neutral",
|
|
170
|
+
reverse: false,
|
|
171
|
+
class: {
|
|
172
|
+
separator: "group-data-[state=completed]:bg-inverted"
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
color: "neutral",
|
|
177
|
+
reverse: true,
|
|
178
|
+
class: {
|
|
179
|
+
separator:
|
|
180
|
+
"group-data-[state=active]:bg-inverted group-data-[state=completed]:bg-inverted"
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
orientation: "horizontal",
|
|
185
|
+
size: "3xs",
|
|
186
|
+
class: {
|
|
187
|
+
wrapper: "pe-4.5"
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
orientation: "horizontal",
|
|
192
|
+
size: "2xs",
|
|
193
|
+
class: {
|
|
194
|
+
wrapper: "pe-5"
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
orientation: "horizontal",
|
|
199
|
+
size: "xs",
|
|
200
|
+
class: {
|
|
201
|
+
wrapper: "pe-5.5"
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
orientation: "horizontal",
|
|
206
|
+
size: "sm",
|
|
207
|
+
class: {
|
|
208
|
+
wrapper: "pe-6"
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
orientation: "horizontal",
|
|
213
|
+
size: "md",
|
|
214
|
+
class: {
|
|
215
|
+
wrapper: "pe-6.5"
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
orientation: "horizontal",
|
|
220
|
+
size: "lg",
|
|
221
|
+
class: {
|
|
222
|
+
wrapper: "pe-7"
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
orientation: "horizontal",
|
|
227
|
+
size: "xl",
|
|
228
|
+
class: {
|
|
229
|
+
wrapper: "pe-7.5"
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
orientation: "horizontal",
|
|
234
|
+
size: "2xl",
|
|
235
|
+
class: {
|
|
236
|
+
wrapper: "pe-8"
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
orientation: "horizontal",
|
|
241
|
+
size: "3xl",
|
|
242
|
+
class: {
|
|
243
|
+
wrapper: "pe-8.5"
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
orientation: "vertical",
|
|
248
|
+
size: "3xs",
|
|
249
|
+
class: {
|
|
250
|
+
wrapper: "-mt-0.5 pb-4.5"
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
orientation: "vertical",
|
|
255
|
+
size: "2xs",
|
|
256
|
+
class: {
|
|
257
|
+
wrapper: "pb-5"
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
orientation: "vertical",
|
|
262
|
+
size: "xs",
|
|
263
|
+
class: {
|
|
264
|
+
wrapper: "mt-0.5 pb-5.5"
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
orientation: "vertical",
|
|
269
|
+
size: "sm",
|
|
270
|
+
class: {
|
|
271
|
+
wrapper: "mt-1 pb-6"
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
orientation: "vertical",
|
|
276
|
+
size: "md",
|
|
277
|
+
class: {
|
|
278
|
+
wrapper: "mt-1.5 pb-6.5"
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
orientation: "vertical",
|
|
283
|
+
size: "lg",
|
|
284
|
+
class: {
|
|
285
|
+
wrapper: "mt-2 pb-7"
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
orientation: "vertical",
|
|
290
|
+
size: "xl",
|
|
291
|
+
class: {
|
|
292
|
+
wrapper: "mt-2.5 pb-7.5"
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
orientation: "vertical",
|
|
297
|
+
size: "2xl",
|
|
298
|
+
class: {
|
|
299
|
+
wrapper: "mt-3 pb-8"
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
orientation: "vertical",
|
|
304
|
+
size: "3xl",
|
|
305
|
+
class: {
|
|
306
|
+
wrapper: "mt-3.5 pb-8.5"
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
],
|
|
310
|
+
defaultVariants: {
|
|
311
|
+
size: "md",
|
|
312
|
+
color: "primary"
|
|
313
|
+
}
|
|
16
314
|
})
|
|
17
315
|
|
|
18
316
|
export default createTimelineTheme()
|
|
@@ -1,11 +1,61 @@
|
|
|
1
|
-
export interface
|
|
1
|
+
export interface TimelineItem {
|
|
2
|
+
date?: string
|
|
3
|
+
title?: string
|
|
4
|
+
description?: string
|
|
5
|
+
icon?: string
|
|
6
|
+
avatar?: any
|
|
7
|
+
value?: string | number
|
|
8
|
+
slot?: string
|
|
9
|
+
class?: any
|
|
10
|
+
ui?: {
|
|
11
|
+
item?: any
|
|
12
|
+
container?: any
|
|
13
|
+
indicator?: any
|
|
14
|
+
separator?: any
|
|
15
|
+
wrapper?: any
|
|
16
|
+
date?: any
|
|
17
|
+
title?: any
|
|
18
|
+
description?: any
|
|
19
|
+
[key: string]: any
|
|
20
|
+
}
|
|
21
|
+
[key: string]: any
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface TimelineProps<T extends TimelineItem = TimelineItem> {
|
|
25
|
+
/**
|
|
26
|
+
* The element or component this component should render as.
|
|
27
|
+
*/
|
|
28
|
+
as?: any
|
|
29
|
+
items?: T[]
|
|
30
|
+
size?: "3xs" | "2xs" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl"
|
|
31
|
+
color?: "primary" | "secondary" | "success" | "info" | "warning" | "error" | "neutral"
|
|
2
32
|
/**
|
|
3
|
-
*
|
|
33
|
+
* The orientation of the Timeline.
|
|
34
|
+
*
|
|
35
|
+
* @default "vertical"
|
|
4
36
|
*/
|
|
5
|
-
|
|
37
|
+
orientation?: "horizontal" | "vertical"
|
|
6
38
|
/**
|
|
7
|
-
*
|
|
39
|
+
* The key used to get the value from the item.
|
|
40
|
+
*
|
|
41
|
+
* @default "value"
|
|
8
42
|
*/
|
|
43
|
+
valueKey?: string
|
|
44
|
+
defaultValue?: string | number
|
|
45
|
+
modelValue?: string | number
|
|
46
|
+
reverse?: boolean
|
|
47
|
+
ui?: {
|
|
48
|
+
root?: any
|
|
49
|
+
item?: any
|
|
50
|
+
container?: any
|
|
51
|
+
indicator?: any
|
|
52
|
+
separator?: any
|
|
53
|
+
wrapper?: any
|
|
54
|
+
date?: any
|
|
55
|
+
title?: any
|
|
56
|
+
description?: any
|
|
57
|
+
[key: string]: any
|
|
58
|
+
}
|
|
9
59
|
class?: any
|
|
10
60
|
[key: string]: unknown
|
|
11
61
|
}
|
|
@@ -4,7 +4,7 @@ import { useUi } from "../../utils/useUi"
|
|
|
4
4
|
import { resolveClasses } from "../../utils/resolveClasses"
|
|
5
5
|
import type { VideoProps } from "./video"
|
|
6
6
|
import videoTheme from "./video.theme"
|
|
7
|
-
import Image from "astro
|
|
7
|
+
import { Image } from "astro:assets"
|
|
8
8
|
import RLAIcon from "../icon/RLAIcon.astro"
|
|
9
9
|
|
|
10
10
|
const PLACEHOLDER_THUMBNAIL = "/assets/placeholder.webp";
|