@nikala-ui/core 0.10.1-nightly.4e09f2a → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/registry/bubble.json +18 -0
- package/registry/create-chat-scroll.json +13 -0
- package/registry/create-pagination.json +13 -0
- package/registry/footer.json +18 -0
- package/registry/forgot-password-01.json +28 -0
- package/registry/hero-01.json +22 -0
- package/registry/index.json +288 -0
- package/registry/login-01.json +28 -0
- package/registry/marker.json +17 -0
- package/registry/marquee.json +17 -0
- package/registry/message.json +17 -0
- package/registry/navbar.json +19 -0
- package/registry/navigation-menu.json +22 -0
- package/registry/otp-verification-01.json +26 -0
- package/registry/pagination.json +22 -0
- package/registry/rating.json +19 -0
- package/registry/register-01.json +31 -0
- package/registry/review-card.json +23 -0
- package/registry/scroll-area.json +1 -1
- package/registry/sidebar.json +24 -0
- package/registry/spinner.json +1 -1
- package/registry/stat.json +19 -0
- package/registry/timeline.json +18 -0
- package/registry/toggle-group.json +21 -0
- package/src/registry/blocks/forgot-password-01.tsx +141 -0
- package/src/registry/blocks/hero-01.tsx +28 -0
- package/src/registry/blocks/login-01.tsx +231 -0
- package/src/registry/blocks/otp-verification-01.tsx +170 -0
- package/src/registry/blocks/register-01.tsx +318 -0
- package/src/registry/components/ui/bubble.tsx +142 -0
- package/src/registry/components/ui/footer.tsx +247 -0
- package/src/registry/components/ui/marker.tsx +102 -0
- package/src/registry/components/ui/marquee.tsx +118 -0
- package/src/registry/components/ui/message.tsx +168 -0
- package/src/registry/components/ui/navbar.tsx +368 -0
- package/src/registry/components/ui/navigation-menu.tsx +358 -0
- package/src/registry/components/ui/pagination.tsx +258 -0
- package/src/registry/components/ui/rating.tsx +185 -0
- package/src/registry/components/ui/review-card.tsx +195 -0
- package/src/registry/components/ui/scroll-area.tsx +2 -2
- package/src/registry/components/ui/sidebar.tsx +692 -0
- package/src/registry/components/ui/spinner.tsx +1 -1
- package/src/registry/components/ui/stat.tsx +245 -0
- package/src/registry/components/ui/timeline.tsx +350 -0
- package/src/registry/components/ui/toggle-group.tsx +203 -0
- package/src/registry/index.ts +3 -3
- package/src/registry/metadata.ts +120 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import {
|
|
2
|
+
splitProps,
|
|
3
|
+
type JSX,
|
|
4
|
+
type ParentComponent,
|
|
5
|
+
} from "solid-js";
|
|
6
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
7
|
+
import { TrendingUp, TrendingDown, Minus } from "lucide-solid";
|
|
8
|
+
import { cn } from "@/lib/cn";
|
|
9
|
+
|
|
10
|
+
/* --- 1. Stat Group (Container Grid) --- */
|
|
11
|
+
export interface StatGroupProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
12
|
+
class?: string;
|
|
13
|
+
columns?: 1 | 2 | 3 | 4 | 5;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const StatGroup: ParentComponent<StatGroupProps> = (props) => {
|
|
17
|
+
const [local, rest] = splitProps(props, ["class", "columns", "children"]);
|
|
18
|
+
|
|
19
|
+
const columnClass = () => {
|
|
20
|
+
switch (local.columns) {
|
|
21
|
+
case 1:
|
|
22
|
+
return "grid-cols-1";
|
|
23
|
+
case 2:
|
|
24
|
+
return "grid-cols-1 sm:grid-cols-2";
|
|
25
|
+
case 3:
|
|
26
|
+
return "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3";
|
|
27
|
+
case 5:
|
|
28
|
+
return "grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5";
|
|
29
|
+
case 4:
|
|
30
|
+
default:
|
|
31
|
+
return "grid-cols-1 sm:grid-cols-2 lg:grid-cols-4";
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<div
|
|
37
|
+
class={cn("grid gap-4 sm:gap-5 w-full", columnClass(), local.class)}
|
|
38
|
+
{...rest}
|
|
39
|
+
>
|
|
40
|
+
{local.children}
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/* --- 2. Stat Root Card --- */
|
|
46
|
+
export const statVariants = cva(
|
|
47
|
+
"relative flex flex-col justify-between rounded-lg transition-all duration-200",
|
|
48
|
+
{
|
|
49
|
+
variants: {
|
|
50
|
+
variant: {
|
|
51
|
+
default: "border border-border bg-card text-card-foreground p-4 sm:p-5 shadow-2xs space-y-2",
|
|
52
|
+
flat: "bg-muted/40 text-foreground p-4 sm:p-5 space-y-2",
|
|
53
|
+
bordered: "border-2 border-border bg-background text-foreground p-4 sm:p-5 space-y-2",
|
|
54
|
+
ghost: "bg-transparent text-foreground p-2 space-y-1",
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
defaultVariants: {
|
|
58
|
+
variant: "default",
|
|
59
|
+
},
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
export interface StatProps
|
|
64
|
+
extends JSX.HTMLAttributes<HTMLDivElement>,
|
|
65
|
+
VariantProps<typeof statVariants> {
|
|
66
|
+
class?: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export const Stat: ParentComponent<StatProps> = (props) => {
|
|
70
|
+
const [local, rest] = splitProps(props, ["class", "variant", "children"]);
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<div
|
|
74
|
+
class={cn(statVariants({ variant: local.variant }), local.class)}
|
|
75
|
+
{...rest}
|
|
76
|
+
>
|
|
77
|
+
{local.children}
|
|
78
|
+
</div>
|
|
79
|
+
);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/* --- 3. Stat Header (Top Row) --- */
|
|
83
|
+
export interface StatHeaderProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
84
|
+
class?: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export const StatHeader: ParentComponent<StatHeaderProps> = (props) => {
|
|
88
|
+
const [local, rest] = splitProps(props, ["class", "children"]);
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<div
|
|
92
|
+
class={cn("flex items-center justify-between gap-2", local.class)}
|
|
93
|
+
{...rest}
|
|
94
|
+
>
|
|
95
|
+
{local.children}
|
|
96
|
+
</div>
|
|
97
|
+
);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/* --- 4. Stat Label / Title --- */
|
|
101
|
+
export interface StatLabelProps extends JSX.HTMLAttributes<HTMLParagraphElement> {
|
|
102
|
+
class?: string;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export const StatLabel: ParentComponent<StatLabelProps> = (props) => {
|
|
106
|
+
const [local, rest] = splitProps(props, ["class", "children"]);
|
|
107
|
+
|
|
108
|
+
return (
|
|
109
|
+
<p
|
|
110
|
+
class={cn(
|
|
111
|
+
"text-xs sm:text-sm font-medium text-muted-foreground leading-tight tracking-tight",
|
|
112
|
+
local.class
|
|
113
|
+
)}
|
|
114
|
+
{...rest}
|
|
115
|
+
>
|
|
116
|
+
{local.children}
|
|
117
|
+
</p>
|
|
118
|
+
);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
/* --- 5. Stat Icon Wrapper --- */
|
|
122
|
+
export interface StatIconProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
123
|
+
class?: string;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export const StatIcon: ParentComponent<StatIconProps> = (props) => {
|
|
127
|
+
const [local, rest] = splitProps(props, ["class", "children"]);
|
|
128
|
+
|
|
129
|
+
return (
|
|
130
|
+
<div
|
|
131
|
+
class={cn(
|
|
132
|
+
"flex size-4 sm:size-4.5 shrink-0 items-center justify-center text-muted-foreground",
|
|
133
|
+
local.class
|
|
134
|
+
)}
|
|
135
|
+
{...rest}
|
|
136
|
+
>
|
|
137
|
+
{local.children}
|
|
138
|
+
</div>
|
|
139
|
+
);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
/* --- 6. Stat Value (Big Number) --- */
|
|
143
|
+
export interface StatValueProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
144
|
+
class?: string;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export const StatValue: ParentComponent<StatValueProps> = (props) => {
|
|
148
|
+
const [local, rest] = splitProps(props, ["class", "children"]);
|
|
149
|
+
|
|
150
|
+
return (
|
|
151
|
+
<div
|
|
152
|
+
class={cn(
|
|
153
|
+
"text-2xl sm:text-3xl font-bold tracking-tight text-foreground flex items-baseline gap-1 my-0.5",
|
|
154
|
+
local.class
|
|
155
|
+
)}
|
|
156
|
+
{...rest}
|
|
157
|
+
>
|
|
158
|
+
{local.children}
|
|
159
|
+
</div>
|
|
160
|
+
);
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
/* --- 7. Stat Unit / Currency (Prefix or Suffix) --- */
|
|
164
|
+
export interface StatUnitProps extends JSX.HTMLAttributes<HTMLSpanElement> {
|
|
165
|
+
class?: string;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export const StatUnit: ParentComponent<StatUnitProps> = (props) => {
|
|
169
|
+
const [local, rest] = splitProps(props, ["class", "children"]);
|
|
170
|
+
|
|
171
|
+
return (
|
|
172
|
+
<span
|
|
173
|
+
class={cn("text-lg sm:text-xl font-semibold text-muted-foreground self-baseline", local.class)}
|
|
174
|
+
{...rest}
|
|
175
|
+
>
|
|
176
|
+
{local.children}
|
|
177
|
+
</span>
|
|
178
|
+
);
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
/* --- 8. Stat Trend (Growth / Decline Indicator - No Background) --- */
|
|
182
|
+
export const statTrendVariants = cva(
|
|
183
|
+
"inline-flex items-center gap-1 text-xs font-semibold select-none shrink-0 tracking-tight",
|
|
184
|
+
{
|
|
185
|
+
variants: {
|
|
186
|
+
type: {
|
|
187
|
+
up: "text-emerald-600 dark:text-emerald-400",
|
|
188
|
+
down: "text-red-600 dark:text-red-400",
|
|
189
|
+
neutral: "text-muted-foreground",
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
defaultVariants: {
|
|
193
|
+
type: "up",
|
|
194
|
+
},
|
|
195
|
+
}
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
export interface StatTrendProps
|
|
199
|
+
extends JSX.HTMLAttributes<HTMLSpanElement>,
|
|
200
|
+
VariantProps<typeof statTrendVariants> {
|
|
201
|
+
class?: string;
|
|
202
|
+
hideIcon?: boolean;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export const StatTrend: ParentComponent<StatTrendProps> = (props) => {
|
|
206
|
+
const [local, rest] = splitProps(props, ["class", "type", "hideIcon", "children"]);
|
|
207
|
+
|
|
208
|
+
const Icon = () => {
|
|
209
|
+
if (local.hideIcon) return null;
|
|
210
|
+
if (local.type === "down") return <TrendingDown class="size-3.5 stroke-[2.5]" />;
|
|
211
|
+
if (local.type === "neutral") return <Minus class="size-3.5 stroke-[2.5]" />;
|
|
212
|
+
return <TrendingUp class="size-3.5 stroke-[2.5]" />;
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
return (
|
|
216
|
+
<span
|
|
217
|
+
class={cn(statTrendVariants({ type: local.type }), local.class)}
|
|
218
|
+
{...rest}
|
|
219
|
+
>
|
|
220
|
+
<Icon />
|
|
221
|
+
<span>{local.children}</span>
|
|
222
|
+
</span>
|
|
223
|
+
);
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
/* --- 9. Stat Help Text / Bottom Row (Between Alignment) --- */
|
|
227
|
+
export interface StatHelpTextProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
228
|
+
class?: string;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export const StatHelpText: ParentComponent<StatHelpTextProps> = (props) => {
|
|
232
|
+
const [local, rest] = splitProps(props, ["class", "children"]);
|
|
233
|
+
|
|
234
|
+
return (
|
|
235
|
+
<div
|
|
236
|
+
class={cn(
|
|
237
|
+
"flex items-center justify-between gap-2 text-xs text-muted-foreground pt-1",
|
|
238
|
+
local.class
|
|
239
|
+
)}
|
|
240
|
+
{...rest}
|
|
241
|
+
>
|
|
242
|
+
{local.children}
|
|
243
|
+
</div>
|
|
244
|
+
);
|
|
245
|
+
};
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
useContext,
|
|
4
|
+
splitProps,
|
|
5
|
+
type Component,
|
|
6
|
+
type JSX,
|
|
7
|
+
type Accessor,
|
|
8
|
+
} from "solid-js";
|
|
9
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
10
|
+
import { cn } from "@/lib/cn";
|
|
11
|
+
|
|
12
|
+
/* --- Timeline Context --- */
|
|
13
|
+
interface TimelineContextValue {
|
|
14
|
+
orientation: Accessor<"vertical" | "horizontal">;
|
|
15
|
+
align: Accessor<"left" | "right" | "alternate">;
|
|
16
|
+
size: Accessor<"sm" | "default" | "lg">;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const TimelineContext = createContext<TimelineContextValue>();
|
|
20
|
+
|
|
21
|
+
export interface TimelineProps extends JSX.HTMLAttributes<HTMLOListElement> {
|
|
22
|
+
/** Layout orientation of the timeline */
|
|
23
|
+
orientation?: "vertical" | "horizontal";
|
|
24
|
+
/** Alignment of content relative to the timeline line */
|
|
25
|
+
align?: "left" | "right" | "alternate";
|
|
26
|
+
/** Sizing of dots and spacing */
|
|
27
|
+
size?: "sm" | "default" | "lg";
|
|
28
|
+
class?: string;
|
|
29
|
+
children?: JSX.Element;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Root container for chronological timeline event sequences.
|
|
34
|
+
*/
|
|
35
|
+
export const Timeline: Component<TimelineProps> = (props) => {
|
|
36
|
+
const [local, rest] = splitProps(props, [
|
|
37
|
+
"orientation",
|
|
38
|
+
"align",
|
|
39
|
+
"size",
|
|
40
|
+
"class",
|
|
41
|
+
"children",
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
const orientation = () => local.orientation ?? "vertical";
|
|
45
|
+
const align = () => local.align ?? "left";
|
|
46
|
+
const size = () => local.size ?? "default";
|
|
47
|
+
|
|
48
|
+
const contextValue: TimelineContextValue = {
|
|
49
|
+
orientation,
|
|
50
|
+
align,
|
|
51
|
+
size,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<TimelineContext.Provider value={contextValue}>
|
|
56
|
+
<ol
|
|
57
|
+
role="list"
|
|
58
|
+
data-orientation={orientation()}
|
|
59
|
+
data-align={align()}
|
|
60
|
+
class={cn(
|
|
61
|
+
"relative flex",
|
|
62
|
+
orientation() === "vertical"
|
|
63
|
+
? "flex-col w-full"
|
|
64
|
+
: "flex-row w-full items-start",
|
|
65
|
+
local.class
|
|
66
|
+
)}
|
|
67
|
+
{...rest}
|
|
68
|
+
>
|
|
69
|
+
{local.children}
|
|
70
|
+
</ol>
|
|
71
|
+
</TimelineContext.Provider>
|
|
72
|
+
);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/* --- Timeline Item --- */
|
|
76
|
+
export interface TimelineItemProps extends JSX.HTMLAttributes<HTMLLIElement> {
|
|
77
|
+
class?: string;
|
|
78
|
+
children?: JSX.Element;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Individual event row container in the timeline.
|
|
83
|
+
*/
|
|
84
|
+
export const TimelineItem: Component<TimelineItemProps> = (props) => {
|
|
85
|
+
const context = useContext(TimelineContext);
|
|
86
|
+
const [local, rest] = splitProps(props, ["class", "children"]);
|
|
87
|
+
|
|
88
|
+
const isVertical = () => !context || context.orientation() === "vertical";
|
|
89
|
+
const align = () => context?.align() ?? "left";
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<li
|
|
93
|
+
class={cn(
|
|
94
|
+
"group relative flex",
|
|
95
|
+
isVertical()
|
|
96
|
+
? "min-h-[3.5rem] w-full items-start"
|
|
97
|
+
: "flex-1 min-w-0 flex-col items-start",
|
|
98
|
+
isVertical() && align() === "right" && "flex-row-reverse",
|
|
99
|
+
isVertical() && align() === "alternate" && "[&:nth-child(even)]:flex-row-reverse",
|
|
100
|
+
local.class
|
|
101
|
+
)}
|
|
102
|
+
{...rest}
|
|
103
|
+
>
|
|
104
|
+
{local.children}
|
|
105
|
+
</li>
|
|
106
|
+
);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
/* --- Timeline Separator (Dot + Connector wrapper) --- */
|
|
110
|
+
export interface TimelineSeparatorProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
111
|
+
class?: string;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export const TimelineSeparator: Component<TimelineSeparatorProps> = (props) => {
|
|
115
|
+
const context = useContext(TimelineContext);
|
|
116
|
+
const [local, rest] = splitProps(props, ["class", "children"]);
|
|
117
|
+
|
|
118
|
+
const isVertical = () => !context || context.orientation() === "vertical";
|
|
119
|
+
|
|
120
|
+
return (
|
|
121
|
+
<div
|
|
122
|
+
aria-hidden="true"
|
|
123
|
+
class={cn(
|
|
124
|
+
"flex shrink-0 relative",
|
|
125
|
+
isVertical()
|
|
126
|
+
? "flex-col items-center self-stretch"
|
|
127
|
+
: "flex-row items-center w-full",
|
|
128
|
+
local.class
|
|
129
|
+
)}
|
|
130
|
+
{...rest}
|
|
131
|
+
>
|
|
132
|
+
{local.children}
|
|
133
|
+
</div>
|
|
134
|
+
);
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
/* --- Timeline Point / Dot --- */
|
|
138
|
+
export const timelinePointVariants = cva(
|
|
139
|
+
"relative z-10 flex shrink-0 items-center justify-center rounded-lg font-medium transition-all shadow-xs",
|
|
140
|
+
{
|
|
141
|
+
variants: {
|
|
142
|
+
variant: {
|
|
143
|
+
default: "border-2 bg-background",
|
|
144
|
+
solid: "text-primary-foreground",
|
|
145
|
+
subtle: "bg-muted text-muted-foreground",
|
|
146
|
+
outline: "border-2 border-border bg-card text-foreground",
|
|
147
|
+
},
|
|
148
|
+
status: {
|
|
149
|
+
default: "border-border text-foreground bg-card",
|
|
150
|
+
primary: "border-primary bg-primary text-primary-foreground",
|
|
151
|
+
success: "border-emerald-500 bg-emerald-500 text-white dark:border-emerald-400 dark:bg-emerald-400",
|
|
152
|
+
warning: "border-amber-500 bg-amber-500 text-white dark:border-amber-400 dark:bg-amber-400",
|
|
153
|
+
destructive: "border-destructive bg-destructive text-destructive-foreground",
|
|
154
|
+
muted: "border-border/60 bg-muted text-muted-foreground",
|
|
155
|
+
},
|
|
156
|
+
size: {
|
|
157
|
+
sm: "size-5 text-[10px] [&_svg]:size-3",
|
|
158
|
+
default: "size-8 text-xs [&_svg]:size-4",
|
|
159
|
+
lg: "size-10 text-sm [&_svg]:size-5",
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
defaultVariants: {
|
|
163
|
+
variant: "default",
|
|
164
|
+
status: "default",
|
|
165
|
+
size: "default",
|
|
166
|
+
},
|
|
167
|
+
}
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
export interface TimelinePointProps
|
|
171
|
+
extends JSX.HTMLAttributes<HTMLDivElement>,
|
|
172
|
+
VariantProps<typeof timelinePointVariants> {
|
|
173
|
+
class?: string;
|
|
174
|
+
children?: JSX.Element;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Status indicator node or icon container in the timeline separator.
|
|
179
|
+
*/
|
|
180
|
+
export const TimelinePoint: Component<TimelinePointProps> = (props) => {
|
|
181
|
+
const context = useContext(TimelineContext);
|
|
182
|
+
const [local, rest] = splitProps(props, [
|
|
183
|
+
"variant",
|
|
184
|
+
"status",
|
|
185
|
+
"size",
|
|
186
|
+
"class",
|
|
187
|
+
"children",
|
|
188
|
+
]);
|
|
189
|
+
|
|
190
|
+
const size = () => local.size || context?.size() || "default";
|
|
191
|
+
|
|
192
|
+
return (
|
|
193
|
+
<div
|
|
194
|
+
class={cn(
|
|
195
|
+
timelinePointVariants({
|
|
196
|
+
variant: local.variant,
|
|
197
|
+
status: local.status,
|
|
198
|
+
size: size(),
|
|
199
|
+
}),
|
|
200
|
+
local.class
|
|
201
|
+
)}
|
|
202
|
+
{...rest}
|
|
203
|
+
>
|
|
204
|
+
{local.children}
|
|
205
|
+
</div>
|
|
206
|
+
);
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
/* --- Timeline Connector (Line track) --- */
|
|
210
|
+
export interface TimelineConnectorProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
211
|
+
dashed?: boolean;
|
|
212
|
+
class?: string;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Line track connecting sequential timeline items.
|
|
217
|
+
*/
|
|
218
|
+
export const TimelineConnector: Component<TimelineConnectorProps> = (props) => {
|
|
219
|
+
const context = useContext(TimelineContext);
|
|
220
|
+
const [local, rest] = splitProps(props, ["dashed", "class"]);
|
|
221
|
+
|
|
222
|
+
const isVertical = () => !context || context.orientation() === "vertical";
|
|
223
|
+
|
|
224
|
+
return (
|
|
225
|
+
<div
|
|
226
|
+
aria-hidden="true"
|
|
227
|
+
class={cn(
|
|
228
|
+
"transition-colors group-last:hidden",
|
|
229
|
+
isVertical()
|
|
230
|
+
? "w-0.5 flex-1 min-h-6 my-1 bg-border"
|
|
231
|
+
: "h-0.5 flex-1 min-w-4 mx-2 bg-border",
|
|
232
|
+
local.dashed && (
|
|
233
|
+
isVertical()
|
|
234
|
+
? "border-l-2 border-dashed border-border bg-transparent w-0"
|
|
235
|
+
: "border-t-2 border-dashed border-border bg-transparent h-0"
|
|
236
|
+
),
|
|
237
|
+
local.class
|
|
238
|
+
)}
|
|
239
|
+
{...rest}
|
|
240
|
+
/>
|
|
241
|
+
);
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
/* --- Timeline Content (Event Details) --- */
|
|
245
|
+
export interface TimelineContentProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
246
|
+
class?: string;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Primary container holding the description, title, and body for a timeline event.
|
|
251
|
+
*/
|
|
252
|
+
export const TimelineContent: Component<TimelineContentProps> = (props) => {
|
|
253
|
+
const context = useContext(TimelineContext);
|
|
254
|
+
const [local, rest] = splitProps(props, ["class"]);
|
|
255
|
+
|
|
256
|
+
const isVertical = () => !context || context.orientation() === "vertical";
|
|
257
|
+
const align = () => context?.align() ?? "left";
|
|
258
|
+
|
|
259
|
+
return (
|
|
260
|
+
<div
|
|
261
|
+
class={cn(
|
|
262
|
+
"flex flex-col",
|
|
263
|
+
isVertical() ? "flex-1 pb-6 pt-0.5" : "pt-2 pr-2 text-left",
|
|
264
|
+
isVertical() && align() === "left" && "text-left pl-3.5 pr-0",
|
|
265
|
+
isVertical() && align() === "right" && "text-right pr-3.5 pl-0",
|
|
266
|
+
isVertical() && align() === "alternate" && "text-left pl-3.5 group-even:text-right group-even:pr-3.5 group-even:pl-0",
|
|
267
|
+
local.class
|
|
268
|
+
)}
|
|
269
|
+
{...rest}
|
|
270
|
+
/>
|
|
271
|
+
);
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
/* --- Timeline Opposite Content --- */
|
|
275
|
+
export interface TimelineOppositeContentProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
276
|
+
class?: string;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Content placed on the opposite side of the timeline separator (e.g. timestamps in alternate layouts).
|
|
281
|
+
*/
|
|
282
|
+
export const TimelineOppositeContent: Component<TimelineOppositeContentProps> = (props) => {
|
|
283
|
+
const context = useContext(TimelineContext);
|
|
284
|
+
const [local, rest] = splitProps(props, ["class"]);
|
|
285
|
+
|
|
286
|
+
const isVertical = () => !context || context.orientation() === "vertical";
|
|
287
|
+
const align = () => context?.align() ?? "left";
|
|
288
|
+
|
|
289
|
+
return (
|
|
290
|
+
<div
|
|
291
|
+
class={cn(
|
|
292
|
+
"flex flex-col text-xs text-muted-foreground",
|
|
293
|
+
align() !== "alternate" && "hidden",
|
|
294
|
+
isVertical()
|
|
295
|
+
? "flex-1 pb-6 pt-1 text-right pr-3.5 group-even:text-left group-even:pl-3.5 group-even:pr-0"
|
|
296
|
+
: "pb-1 pr-2",
|
|
297
|
+
local.class
|
|
298
|
+
)}
|
|
299
|
+
{...rest}
|
|
300
|
+
/>
|
|
301
|
+
);
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
/* --- Timeline Title --- */
|
|
305
|
+
export interface TimelineTitleProps extends JSX.HTMLAttributes<HTMLHeadingElement> {
|
|
306
|
+
class?: string;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
export const TimelineTitle: Component<TimelineTitleProps> = (props) => {
|
|
310
|
+
const [local, rest] = splitProps(props, ["class"]);
|
|
311
|
+
|
|
312
|
+
return (
|
|
313
|
+
<h4
|
|
314
|
+
class={cn("text-sm font-semibold tracking-tight text-foreground", local.class)}
|
|
315
|
+
{...rest}
|
|
316
|
+
/>
|
|
317
|
+
);
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
/* --- Timeline Description --- */
|
|
321
|
+
export interface TimelineDescriptionProps extends JSX.HTMLAttributes<HTMLParagraphElement> {
|
|
322
|
+
class?: string;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
export const TimelineDescription: Component<TimelineDescriptionProps> = (props) => {
|
|
326
|
+
const [local, rest] = splitProps(props, ["class"]);
|
|
327
|
+
|
|
328
|
+
return (
|
|
329
|
+
<p
|
|
330
|
+
class={cn("mt-1 text-sm text-muted-foreground", local.class)}
|
|
331
|
+
{...rest}
|
|
332
|
+
/>
|
|
333
|
+
);
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
/* --- Timeline Time --- */
|
|
337
|
+
export interface TimelineTimeProps extends JSX.HTMLAttributes<HTMLTimeElement> {
|
|
338
|
+
class?: string;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export const TimelineTime: Component<TimelineTimeProps> = (props) => {
|
|
342
|
+
const [local, rest] = splitProps(props, ["class"]);
|
|
343
|
+
|
|
344
|
+
return (
|
|
345
|
+
<time
|
|
346
|
+
class={cn("text-xs font-medium text-muted-foreground/80", local.class)}
|
|
347
|
+
{...rest}
|
|
348
|
+
/>
|
|
349
|
+
);
|
|
350
|
+
};
|