trix-ui 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/README.md +110 -19
  2. package/dist/commands/add/__tests__/add.test.js +16 -4
  3. package/dist/commands/add/__tests__/add.test.js.map +1 -1
  4. package/dist/commands/add/analysis.js +6 -1
  5. package/dist/commands/add/analysis.js.map +1 -1
  6. package/dist/commands/add/command.js +6 -0
  7. package/dist/commands/add/command.js.map +1 -1
  8. package/dist/commands/add/types.d.ts +1 -0
  9. package/dist/commands/add/ui.js +4 -0
  10. package/dist/commands/add/ui.js.map +1 -1
  11. package/dist/commands/add-composite.d.ts +2 -0
  12. package/dist/commands/add-composite.js +202 -0
  13. package/dist/commands/add-composite.js.map +1 -0
  14. package/dist/commands/add-section.js +6 -0
  15. package/dist/commands/add-section.js.map +1 -1
  16. package/dist/commands/add-wrapper.js +6 -0
  17. package/dist/commands/add-wrapper.js.map +1 -1
  18. package/dist/commands/doctor.js +7 -2
  19. package/dist/commands/doctor.js.map +1 -1
  20. package/dist/commands/init/config.js +1 -0
  21. package/dist/commands/init/config.js.map +1 -1
  22. package/dist/commands/list.js +12 -4
  23. package/dist/commands/list.js.map +1 -1
  24. package/dist/commands/remove.js +24 -10
  25. package/dist/commands/remove.js.map +1 -1
  26. package/dist/commands/shared/add-collection.d.ts +2 -1
  27. package/dist/commands/shared/add-collection.js +8 -2
  28. package/dist/commands/shared/add-collection.js.map +1 -1
  29. package/dist/index.js +2 -0
  30. package/dist/index.js.map +1 -1
  31. package/dist/lib/config.d.ts +1 -0
  32. package/dist/lib/config.js +1 -0
  33. package/dist/lib/config.js.map +1 -1
  34. package/dist/lib/lockfile.d.ts +6 -5
  35. package/dist/lib/lockfile.js +3 -0
  36. package/dist/lib/lockfile.js.map +1 -1
  37. package/dist/lib/paths.d.ts +1 -0
  38. package/dist/lib/paths.js +1 -0
  39. package/dist/lib/paths.js.map +1 -1
  40. package/dist/lib/registry.d.ts +2 -0
  41. package/dist/lib/registry.js +11 -0
  42. package/dist/lib/registry.js.map +1 -1
  43. package/package.json +12 -11
  44. package/registry/index.json +67 -128
  45. package/templates/components/ui/avatar.tsx +109 -0
  46. package/templates/components/ui/button.tsx +48 -44
  47. package/templates/components/ui/label.tsx +24 -0
  48. package/templates/composites/feature-collection-card.tsx +113 -0
  49. package/templates/composites/music-player-card.tsx +221 -0
  50. package/templates/composites/user-profile-card.tsx +145 -0
  51. package/templates/sections/modern-hero.tsx +1226 -0
  52. package/templates/wrappers/Interative-wrapper.tsx +555 -0
  53. package/LICENSE.md +0 -21
  54. package/templates/components/ui/checkbox.tsx +0 -33
  55. package/templates/components/ui/dialog.tsx +0 -92
  56. package/templates/components/ui/dropdown.tsx +0 -75
  57. package/templates/components/ui/select.tsx +0 -24
  58. package/templates/components/ui/switch.tsx +0 -27
  59. package/templates/components/ui/toast.tsx +0 -100
  60. package/templates/sections/cta.tsx +0 -22
  61. package/templates/sections/feature-grid.tsx +0 -62
  62. package/templates/sections/hero.tsx +0 -63
  63. package/templates/wrappers/border-wrapper.tsx +0 -34
  64. package/templates/wrappers/glow-wrapper.tsx +0 -31
  65. package/templates/wrappers/lift-wrapper.tsx +0 -27
@@ -0,0 +1,113 @@
1
+ import * as React from "react";
2
+ import { cn } from "@/lib/utils";
3
+
4
+ export type FeaturedCollectionCardProps = {
5
+ imageSrc: string;
6
+ title: string;
7
+
8
+ imageAlt?: string;
9
+ badgeText?: string;
10
+ description?: string;
11
+
12
+ onClick?: React.MouseEventHandler<HTMLDivElement>;
13
+
14
+ className?: string;
15
+ contentClassName?: string;
16
+
17
+ minHeightClassName?: string;
18
+ overlayClassName?: string;
19
+ imageHoverScaleClassName?: string;
20
+
21
+ badgeClassName?: string;
22
+ titleClassName?: string;
23
+ descriptionClassName?: string;
24
+
25
+ disableHoverReveal?: boolean;
26
+ } & Omit<React.HTMLAttributes<HTMLDivElement>, "title" | "onClick">;
27
+
28
+ const FeaturedCollectionCardBase = React.forwardRef<HTMLDivElement, FeaturedCollectionCardProps>(
29
+ (
30
+ {
31
+ imageSrc,
32
+ title,
33
+ imageAlt = "Background",
34
+ badgeText = "Featured Collection",
35
+ description,
36
+ onClick,
37
+
38
+ minHeightClassName = "min-h-[300px]",
39
+ overlayClassName = "bg-gradient-to-t from-black/90 via-black/40 to-transparent",
40
+ imageHoverScaleClassName = "group-hover:scale-110",
41
+
42
+ badgeClassName = "text-cyan-400",
43
+ titleClassName,
44
+ descriptionClassName,
45
+
46
+ className,
47
+ contentClassName,
48
+ disableHoverReveal = false,
49
+
50
+ ...props
51
+ },
52
+ ref
53
+ ) => {
54
+ const motionWrap = disableHoverReveal
55
+ ? "translate-y-0"
56
+ : "translate-y-4 group-hover:translate-y-0 transition-transform duration-300";
57
+
58
+ return (
59
+ <div
60
+ ref={ref}
61
+ onClick={onClick}
62
+ className={cn(
63
+ "group relative h-full rounded-2xl overflow-hidden shadow-lg cursor-pointer",
64
+ minHeightClassName,
65
+ className
66
+ )}
67
+ {...props}
68
+ >
69
+ <img
70
+ src={imageSrc}
71
+ alt={imageAlt}
72
+ loading="lazy"
73
+ decoding="async"
74
+ className={cn(
75
+ "absolute inset-0 h-full w-full object-cover transition-transform duration-700 will-change-transform",
76
+ imageHoverScaleClassName
77
+ )}
78
+ />
79
+
80
+ <div className={cn("absolute inset-0", overlayClassName)} />
81
+
82
+ <div className={cn("absolute bottom-0 left-0 w-full p-6", contentClassName)}>
83
+ <div className={cn("transform", motionWrap)}>
84
+ {badgeText && (
85
+ <span className={cn("mb-2 block text-xs font-bold uppercase tracking-wider", badgeClassName)}>
86
+ {badgeText}
87
+ </span>
88
+ )}
89
+
90
+ <h3 className={cn("mb-2 text-2xl font-bold text-white", titleClassName)}>{title}</h3>
91
+
92
+ {description && (
93
+ <p
94
+ className={cn(
95
+ "text-sm text-stone-400 overflow-hidden transition-all duration-300",
96
+ disableHoverReveal
97
+ ? "max-h-40 opacity-100"
98
+ : "max-h-0 opacity-0 group-hover:max-h-40 group-hover:opacity-100",
99
+ descriptionClassName
100
+ )}
101
+ >
102
+ {description}
103
+ </p>
104
+ )}
105
+ </div>
106
+ </div>
107
+ </div>
108
+ );
109
+ }
110
+ );
111
+
112
+ FeaturedCollectionCardBase.displayName = "FeaturedCollectionCard";
113
+ export const FeaturedCollectionCard = React.memo(FeaturedCollectionCardBase);
@@ -0,0 +1,221 @@
1
+ import * as React from "react";
2
+ import { cn } from "../../lib/utils";
3
+ import {
4
+ Shuffle,
5
+ SkipBack,
6
+ Play,
7
+ Pause,
8
+ SkipForward,
9
+ Repeat,
10
+ } from "lucide-react";
11
+
12
+ export type MusicPlayerCardProps = {
13
+ imageSrc: string;
14
+ title: string;
15
+ subtitle?: string;
16
+
17
+ /** 0 to 100 */
18
+ progress?: number;
19
+ currentTime?: string;
20
+ totalTime?: string;
21
+
22
+ onShuffle?: () => void;
23
+ onPrev?: () => void;
24
+ onPlay?: () => void;
25
+ onNext?: () => void;
26
+ onRepeat?: () => void;
27
+
28
+ /** Toggle states */
29
+ isPlaying?: boolean;
30
+ isShuffleOn?: boolean;
31
+ isRepeatOn?: boolean;
32
+
33
+ /** Styling overrides */
34
+ className?: string;
35
+ imageWrapClassName?: string;
36
+ titleClassName?: string;
37
+ subtitleClassName?: string;
38
+
39
+ progressTrackClassName?: string;
40
+ progressFillClassName?: string;
41
+
42
+ controlsClassName?: string;
43
+ sideButtonClassName?: string;
44
+ midButtonClassName?: string;
45
+
46
+ accentClassName?: string; // default rose
47
+ } & React.HTMLAttributes<HTMLDivElement>;
48
+
49
+ const clamp = (n: number, min: number, max: number) => Math.max(min, Math.min(max, n));
50
+
51
+ const MusicPlayerCardBase = React.forwardRef<HTMLDivElement, MusicPlayerCardProps>(
52
+ (
53
+ {
54
+ imageSrc,
55
+ title,
56
+ subtitle = "Unknown Artist",
57
+
58
+ progress = 0,
59
+ currentTime = "0:00",
60
+ totalTime = "0:00",
61
+
62
+ onShuffle,
63
+ onPrev,
64
+ onPlay,
65
+ onNext,
66
+ onRepeat,
67
+
68
+ isPlaying = false,
69
+ isShuffleOn = false,
70
+ isRepeatOn = false,
71
+
72
+ className,
73
+ imageWrapClassName,
74
+ titleClassName,
75
+ subtitleClassName,
76
+
77
+ progressTrackClassName,
78
+ progressFillClassName,
79
+
80
+ controlsClassName,
81
+ sideButtonClassName,
82
+ midButtonClassName,
83
+
84
+ accentClassName = "bg-rose-500",
85
+
86
+ ...props
87
+ },
88
+ ref
89
+ ) => {
90
+ const pct = clamp(progress, 0, 100);
91
+
92
+ return (
93
+ <div
94
+ ref={ref}
95
+ className={cn(
96
+ "bg-white p-5 rounded-3xl border border-stone-100 flex flex-col h-full",
97
+ "shadow-lg transition-all duration-500 ease-out",
98
+ "hover:-translate-y-1 hover:shadow-2xl",
99
+ className
100
+ )}
101
+ {...props}
102
+ >
103
+ {/* Album Art */}
104
+ <div
105
+ className={cn(
106
+ "relative aspect-square rounded-2xl overflow-hidden mb-5 shadow-inner",
107
+ "ring-1 ring-black/5",
108
+ imageWrapClassName
109
+ )}
110
+ >
111
+ <img
112
+ src={imageSrc}
113
+ alt="Album Art"
114
+ loading="lazy"
115
+ decoding="async"
116
+ className="w-full h-full object-cover"
117
+ />
118
+ <div className="absolute inset-0 bg-black/10" />
119
+
120
+ {/* Premium Glow */}
121
+ <div className="pointer-events-none absolute inset-0 opacity-0 hover:opacity-100 transition-opacity duration-700 bg-[radial-gradient(circle_at_30%_20%,rgba(255,255,255,0.18),transparent_55%)]" />
122
+ </div>
123
+
124
+ {/* Text */}
125
+ <div className="mb-4">
126
+ <h3 className={cn("text-lg font-bold text-stone-800 truncate", titleClassName)}>
127
+ {title}
128
+ </h3>
129
+ <p
130
+ className={cn(
131
+ "text-stone-400 text-xs font-medium uppercase tracking-wide truncate",
132
+ subtitleClassName
133
+ )}
134
+ >
135
+ {subtitle}
136
+ </p>
137
+ </div>
138
+
139
+ {/* Progress Bar */}
140
+ <div
141
+ className={cn(
142
+ "w-full bg-stone-100 h-1.5 rounded-full mb-2 overflow-hidden",
143
+ progressTrackClassName
144
+ )}
145
+ >
146
+ <div
147
+ className={cn(
148
+ "h-full rounded-full transition-all duration-500 ease-out",
149
+ accentClassName,
150
+ progressFillClassName
151
+ )}
152
+ style={{ width: `${pct}%` }}
153
+ />
154
+ </div>
155
+
156
+ <div className="flex justify-between text-[10px] text-stone-400 font-mono mb-4">
157
+ <span>{currentTime}</span>
158
+ <span>{totalTime}</span>
159
+ </div>
160
+
161
+ {/* Controls */}
162
+ <div className={cn("flex justify-between items-center mt-auto px-2", controlsClassName)}>
163
+ <button
164
+ type="button"
165
+ onClick={onShuffle}
166
+ className={cn(
167
+ "text-stone-400 transition-colors hover:text-stone-800",
168
+ isShuffleOn && "text-stone-800",
169
+ sideButtonClassName
170
+ )}
171
+ >
172
+ <Shuffle className="h-5 w-5" />
173
+ </button>
174
+
175
+ <button
176
+ type="button"
177
+ onClick={onPrev}
178
+ className={cn("text-stone-800 transition-colors hover:text-rose-500", midButtonClassName)}
179
+ >
180
+ <SkipBack className="h-8 w-8" />
181
+ </button>
182
+
183
+ <button
184
+ type="button"
185
+ onClick={onPlay}
186
+ className={cn(
187
+ "w-12 h-12 text-white rounded-full flex items-center justify-center shadow-lg",
188
+ "transition-all duration-300 ease-out hover:scale-105 active:scale-95",
189
+ accentClassName
190
+ )}
191
+ >
192
+ {isPlaying ? <Pause className="h-6 w-6" /> : <Play className="h-6 w-6" />}
193
+ </button>
194
+
195
+ <button
196
+ type="button"
197
+ onClick={onNext}
198
+ className={cn("text-stone-800 transition-colors hover:text-rose-500", midButtonClassName)}
199
+ >
200
+ <SkipForward className="h-8 w-8" />
201
+ </button>
202
+
203
+ <button
204
+ type="button"
205
+ onClick={onRepeat}
206
+ className={cn(
207
+ "text-stone-400 transition-colors hover:text-stone-800",
208
+ isRepeatOn && "text-stone-800",
209
+ sideButtonClassName
210
+ )}
211
+ >
212
+ <Repeat className="h-5 w-5" />
213
+ </button>
214
+ </div>
215
+ </div>
216
+ );
217
+ }
218
+ );
219
+
220
+ MusicPlayerCardBase.displayName = "MusicPlayerCard";
221
+ export const MusicPlayerCard = React.memo(MusicPlayerCardBase);
@@ -0,0 +1,145 @@
1
+ import * as React from "react";
2
+ import { cn } from "@/lib/utils";
3
+ import { Card } from "@/components/ui/card";
4
+ import { Badge } from "@/components/ui/badge";
5
+ import { Button } from "@/components/ui/button";
6
+ import { ArrowRight } from "lucide-react";
7
+
8
+ type UserProfileCardTag = {
9
+ label: string;
10
+ };
11
+
12
+ export type UserProfileCardProps = {
13
+ name: string;
14
+ role: string;
15
+ avatarSrc: string;
16
+ avatarAlt?: string;
17
+
18
+ /** Example: [{ label: "Figma" }, { label: "Design Ops" }] */
19
+ tags?: UserProfileCardTag[];
20
+
21
+ /** You can pass "1.2k" directly OR number like 1200 */
22
+ followers?: string | number;
23
+
24
+ /** Online green dot */
25
+ online?: boolean;
26
+
27
+ /** Right action (arrow button) */
28
+ onActionClick?: () => void;
29
+ actionAriaLabel?: string;
30
+
31
+ className?: string;
32
+ };
33
+
34
+ function formatFollowers(value: string | number | undefined) {
35
+ if (value === undefined || value === null) return "";
36
+ if (typeof value === "string") return value;
37
+
38
+ // number formatting like 1200 -> 1.2k
39
+ const n = value;
40
+ if (n < 1000) return `${n}`;
41
+ if (n < 1_000_000) return `${(n / 1000).toFixed(n % 1000 === 0 ? 0 : 1)}k`;
42
+ return `${(n / 1_000_000).toFixed(n % 1_000_000 === 0 ? 0 : 1)}M`;
43
+ }
44
+
45
+ export function UserProfileCard({
46
+ name,
47
+ role,
48
+ avatarSrc,
49
+ avatarAlt = name,
50
+ tags = [],
51
+ followers = "1.2k",
52
+ online = true,
53
+ onActionClick,
54
+ actionAriaLabel = "Open profile",
55
+ className,
56
+ }: UserProfileCardProps) {
57
+ return (
58
+ <Card
59
+ className={cn(
60
+ "w-[280px] rounded-[28px] bg-white shadow-[0_18px_60px_-35px_rgba(15,23,42,0.35)]",
61
+ "border border-neutral-100",
62
+ className
63
+ )}
64
+ >
65
+ <div className="px-6 pt-6 pb-5">
66
+ {/* Avatar */}
67
+ <div className="flex justify-center">
68
+ <div className="relative">
69
+ {/* Gradient ring */}
70
+ <div className="grid place-items-center rounded-full p-[3px] bg-gradient-to-br from-violet-500 to-indigo-500">
71
+ <div className="rounded-full bg-white p-[3px]">
72
+ <img
73
+ src={avatarSrc}
74
+ alt={avatarAlt}
75
+ className="h-[74px] w-[74px] rounded-full object-cover"
76
+ draggable={false}
77
+ />
78
+ </div>
79
+ </div>
80
+
81
+ {/* Online dot */}
82
+ {online && (
83
+ <span className="absolute bottom-[7px] right-[7px] h-3.5 w-3.5 rounded-full bg-emerald-500 ring-4 ring-white" />
84
+ )}
85
+ </div>
86
+ </div>
87
+
88
+ {/* Name + Role */}
89
+ <div className="mt-4 text-center">
90
+ <div className="text-[18px] font-semibold leading-tight text-slate-900">
91
+ {name}
92
+ </div>
93
+ <div className="mt-1 text-[11px] font-semibold tracking-[0.18em] text-indigo-500">
94
+ {role.toUpperCase()}
95
+ </div>
96
+ </div>
97
+
98
+ {/* Tags */}
99
+ {tags.length > 0 && (
100
+ <div className="mt-4 flex justify-center gap-2">
101
+ {tags.map((t, idx) => (
102
+ <Badge
103
+ key={`${t.label}-${idx}`}
104
+ variant="secondary"
105
+ className={cn(
106
+ "rounded-full px-3 py-1 text-[10px] font-semibold tracking-widest",
107
+ "bg-neutral-100 text-neutral-700 shadow-none border border-neutral-200"
108
+ )}
109
+ >
110
+ {t.label.toUpperCase()}
111
+ </Badge>
112
+ ))}
113
+ </div>
114
+ )}
115
+
116
+ {/* Bottom section */}
117
+ <div className="mt-6 flex items-end justify-between">
118
+ <div>
119
+ <div className="text-[10px] font-semibold tracking-[0.18em] text-neutral-300">
120
+ FOLLOWERS
121
+ </div>
122
+ <div className="mt-1 text-[16px] font-semibold text-slate-900">
123
+ {formatFollowers(followers)}
124
+ </div>
125
+ </div>
126
+
127
+ <Button
128
+ type="button"
129
+ variant="ghost"
130
+ size="icon"
131
+ onClick={onActionClick}
132
+ aria-label={actionAriaLabel}
133
+ className={cn(
134
+ "h-10 w-10 rounded-full",
135
+ "text-violet-600 hover:text-violet-700",
136
+ "hover:bg-violet-50 active:bg-violet-100"
137
+ )}
138
+ >
139
+ <ArrowRight className="h-5 w-5" />
140
+ </Button>
141
+ </div>
142
+ </div>
143
+ </Card>
144
+ );
145
+ }