purvex-ui 0.1.2 → 0.1.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "purvex-ui",
3
- "version": "0.1.2",
4
- "description": "React component generator with Tailwind CSS v4 & Purple Elegant theme - Built by Al Zaki Ibra Ramadani",
3
+ "version": "0.1.6",
4
+ "description": "React component generator with Tailwind CSS v4 & Purple Elegant theme",
5
5
  "main": "src/index.js",
6
6
  "bin": {
7
7
  "purvex-ui": "src/index.js"
@@ -9,7 +9,8 @@
9
9
  "files": [
10
10
  "src/",
11
11
  "templates/",
12
- "registry/"
12
+ "registry/",
13
+ "README.md"
13
14
  ],
14
15
  "scripts": {
15
16
  "test": "echo \"No tests yet\"",
@@ -0,0 +1,30 @@
1
+ {
2
+ "version": "0.1.0",
3
+ "lastUpdated": "2025-12-28",
4
+ "components": [
5
+ {
6
+ "name": "button",
7
+ "displayName": "Button",
8
+ "description": "Tombol dengan berbagai variant dan ukuran",
9
+ "category": "basic",
10
+ "files": ["button.jsx"],
11
+ "dependencies": []
12
+ },
13
+ {
14
+ "name": "card",
15
+ "displayName": "Card",
16
+ "description": "Komponen card untuk konten",
17
+ "category": "layout",
18
+ "files": ["card.jsx"],
19
+ "dependencies": []
20
+ },
21
+ {
22
+ "name": "avatar",
23
+ "displayName": "Avatar",
24
+ "description": "Komponen avatar untuk menampilkan gambar profil",
25
+ "category": "layout",
26
+ "files": ["avatar.jsx"],
27
+ "dependencies": []
28
+ }
29
+ ]
30
+ }
@@ -0,0 +1,70 @@
1
+ import React from 'react';
2
+ import { cn } from '@/lib/utils';
3
+
4
+ const Avatar = React.forwardRef(function Avatar({
5
+ src,
6
+ alt = "avatar",
7
+ size = 72,
8
+ border = true,
9
+ variant = "circle", // circle, square, star, heart, triangle, abstract
10
+ className,
11
+ ...props
12
+ }, ref) {
13
+ // Variants shapes dengan clip-path yang benar
14
+ const shapeStyles = {
15
+ star: {
16
+ clipPath: 'polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%)'
17
+ },
18
+ heart: {
19
+ clipPath: 'polygon(50% 93%, 5% 40%, 25% 10%, 50% 30%, 75% 10%, 95% 40%)'
20
+ },
21
+ triangle: {
22
+ clipPath: 'polygon(50% 0%, 0% 100%, 100% 100%)'
23
+ },
24
+ abstract: {
25
+ clipPath: 'polygon(20% 0%, 80% 0%, 100% 50%, 80% 100%, 20% 100%, 0% 50%)'
26
+ },
27
+ };
28
+
29
+ // Kelas Tailwind untuk shape biasa
30
+ const shapeClasses = {
31
+ circle: "rounded-full",
32
+ square: "rounded-md",
33
+ star: "",
34
+ heart: "",
35
+ triangle: "",
36
+ abstract: "",
37
+ };
38
+
39
+ // Apakah perlu inline style untuk clip-path?
40
+ const needsClipPath = ['star', 'heart', 'triangle', 'abstract'].includes(variant);
41
+ const inlineStyle = needsClipPath ? shapeStyles[variant] : {};
42
+
43
+ return (
44
+ <div
45
+ ref={ref}
46
+ className={cn(
47
+ "relative overflow-hidden shrink-0",
48
+ border && "before:absolute before:inset-0 before:border-2 before:border-border/20",
49
+ shapeClasses[variant],
50
+ className
51
+ )}
52
+ style={{
53
+ ...inlineStyle,
54
+ width: `${size}px`,
55
+ height: `${size}px`,
56
+ }}
57
+ {...props}
58
+ >
59
+ <img
60
+ src={src}
61
+ alt={alt}
62
+ className="w-full h-full object-cover"
63
+ />
64
+ </div>
65
+ );
66
+ });
67
+
68
+ Avatar.displayName = "Avatar";
69
+
70
+ export { Avatar };
@@ -0,0 +1,83 @@
1
+ import React from "react";
2
+ import { cn } from "@/lib/utils";
3
+
4
+ const Button = React.forwardRef(function Button(
5
+ { className, variant = "default", size = "default", children, ...props },
6
+ ref
7
+ ) {
8
+ const baseClasses = cn(
9
+ // Base styles
10
+ "inline-flex items-center justify-center break-words rounded-md text-sm font-bold",
11
+ "ring-offset-background transition-colors",
12
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
13
+ "disabled:pointer-events-none disabled:opacity-50 hover:cursor-pointer hover:scale-102 transition-all",
14
+
15
+ // Variants flat
16
+ variant === "default" &&
17
+ "bg-primary text-primary-foreground hover:bg-primary/90",
18
+ variant === "primary-outline" &&
19
+ "bg-blue-100 text-blue-600 hover:bg-blue-200",
20
+ variant === "destructive" &&
21
+ "bg-destructive text-destructive-foreground hover:bg-destructive/90",
22
+ variant === "outline" &&
23
+ "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
24
+ variant === "secondary" &&
25
+ "bg-secondary text-secondary-foreground hover:bg-secondary/80",
26
+ variant === "ghost" && "hover:bg-accent hover:text-accent-foreground",
27
+ variant === "link" && "text-primary underline-offset-4 hover:underline",
28
+ variant === "success" && "bg-green-600 text-white hover:bg-green-700",
29
+ variant === "warning" && "bg-yellow-500 text-black hover:bg-yellow-600",
30
+ variant === "info" && "bg-blue-500 text-white hover:bg-blue-600",
31
+ variant === "dark" && "bg-gray-800 text-white hover:bg-gray-900",
32
+
33
+ // Gradient variants
34
+ variant === "primary-gradient" &&
35
+ "bg-linear-to-bl from-purple-500 via-purple-600 to-purple-700 text-white hover:from-purple-600 hover:via-purple-700 hover:to-purple-800",
36
+ variant === "destructive-gradient" &&
37
+ "bg-linear-to-bl from-red-500 via-red-600 to-red-700 text-white hover:from-red-600 hover:via-red-700 hover:to-red-800",
38
+ variant === "success-gradient" &&
39
+ "bg-linear-to-br from-green-500 via-green-600 to-green-700 text-white hover:from-green-600 hover:via-green-700 hover:to-green-800",
40
+ variant === "warning-gradient" &&
41
+ "bg-linear-to-br from-yellow-400 via-yellow-500 to-yellow-600 text-black hover:from-yellow-500 hover:via-yellow-600 hover:to-yellow-700",
42
+ variant === "info-gradient" &&
43
+ "bg-linear-to-bl from-blue-400 via-blue-500 to-blue-600 text-white hover:from-blue-500 hover:via-blue-600 hover:to-blue-700",
44
+ variant === "secondary-gradient" &&
45
+ "bg-linear-to-bl from-gray-200 via-gray-300 to-gray-400 text-gray-800 hover:from-gray-300 hover:via-gray-400 hover:to-gray-500",
46
+ variant === "dark-gradient" &&
47
+ "bg-linear-to-bl from-gray-700 via-gray-800 to-gray-900 text-white hover:from-gray-800 hover:via-gray-900 hover:to-black",
48
+
49
+ // Pasangan / light / outline
50
+ variant === "primary-light" &&
51
+ "bg-primary/20 text-primary hover:bg-primary/30",
52
+ variant === "destructive-light" &&
53
+ "bg-destructive/20 text-destructive hover:bg-destructive/30",
54
+ variant === "success-light" &&
55
+ "bg-green-100 text-green-600 hover:bg-green-200",
56
+ variant === "warning-light" &&
57
+ "bg-yellow-100 text-yellow-600 hover:bg-yellow-200",
58
+ variant === "info-light" && "bg-blue-100 text-blue-600 hover:bg-blue-200",
59
+ variant === "secondary-light" &&
60
+ "bg-secondary/20 text-secondary hover:bg-secondary/30",
61
+ variant === "dark-light" &&
62
+ "bg-gray-700/30 text-gray-800 hover:bg-gray-700/50",
63
+
64
+ // Sizes
65
+ size === "default" && "min-h-10 rounded-lg px-5 py-2",
66
+ size === "sm" && "min-h-9 rounded-md px-3",
67
+ size === "lg" && "min-h-11 rounded-md px-8",
68
+ size === "icon" && "h-10 w-10",
69
+
70
+ // Custom classes dari user
71
+ className
72
+ );
73
+
74
+ return (
75
+ <button className={baseClasses} ref={ref} {...props}>
76
+ {children}
77
+ </button>
78
+ );
79
+ });
80
+
81
+ Button.displayName = "Button";
82
+
83
+ export { Button };
@@ -0,0 +1,67 @@
1
+ import React from 'react';
2
+ import { cn } from '@/lib/utils';
3
+
4
+ const Card = React.forwardRef(function Card({ className, hover = false, ...props }, ref) {
5
+ return (
6
+ <div
7
+ ref={ref}
8
+ className={cn(
9
+ "rounded-2xl border bg-card text-card-foreground transition-all",
10
+ hover && "hover:shadow-md hover:scale-[1.02]",
11
+ className
12
+ )}
13
+ {...props}
14
+ />
15
+ );
16
+ });
17
+
18
+ Card.displayName = "Card";
19
+
20
+ const CardHeader = React.forwardRef(function CardHeader({ className, ...props }, ref) {
21
+ return (
22
+ <div ref={ref} className={cn("flex flex-col space-y-1.5 p-6", className)} {...props} />
23
+ );
24
+ });
25
+
26
+ CardHeader.displayName = "CardHeader";
27
+
28
+ const CardTitle = React.forwardRef(function CardTitle({ className, ...props }, ref) {
29
+ return (
30
+ <h3
31
+ ref={ref}
32
+ className={cn("text-2xl font-semibold leading-none tracking-tight", className)}
33
+ {...props}
34
+ />
35
+ );
36
+ });
37
+
38
+ CardTitle.displayName = "CardTitle";
39
+
40
+ const CardDescription = React.forwardRef(function CardDescription({ className, ...props }, ref) {
41
+ return (
42
+ <p ref={ref} className={cn("text-sm text-muted-foreground", className)} {...props} />
43
+ );
44
+ });
45
+
46
+ CardDescription.displayName = "CardDescription";
47
+
48
+ const CardContent = React.forwardRef(function CardContent({ className, ...props }, ref) {
49
+ return <div ref={ref} className={cn("p-6 pt-0", className)} {...props} />;
50
+ });
51
+
52
+ CardContent.displayName = "CardContent";
53
+
54
+ const CardFooter = React.forwardRef(function CardFooter({ className, ...props }, ref) {
55
+ return <div ref={ref} className={cn("flex items-center p-6 pt-0", className)} {...props} />;
56
+ });
57
+
58
+ CardFooter.displayName = "CardFooter";
59
+
60
+ export {
61
+ Card,
62
+ CardHeader,
63
+ CardFooter,
64
+ CardTitle,
65
+ CardDescription,
66
+ CardContent,
67
+ };
@@ -0,0 +1,6 @@
1
+ import { clsx } from 'clsx';
2
+ import { twMerge } from 'tailwind-merge';
3
+
4
+ export function cn(...inputs) {
5
+ return twMerge(clsx(inputs));
6
+ }