@alexandretav/aleui 1.0.0 → 1.1.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/cli.js ADDED
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { execSync } = require('child_process');
6
+
7
+ const COMPONENTS_DIR = path.join(__dirname, 'src', 'components');
8
+ const TARGET_DIR = path.join(process.cwd(), 'src', 'components', 'ui');
9
+
10
+ const args = process.argv.slice(2);
11
+ const command = args[0];
12
+ const componentName = args[1];
13
+
14
+ const availableComponents = [
15
+ 'button',
16
+ 'card',
17
+ 'input',
18
+ 'modal',
19
+ 'accordion',
20
+ 'aero-bubble',
21
+ 'aero-button',
22
+ 'aero-card',
23
+ 'aero-input'
24
+ ];
25
+
26
+ function copyComponent(name) {
27
+ const sourcePath = path.join(COMPONENTS_DIR, name);
28
+ const targetPath = path.join(TARGET_DIR, name);
29
+
30
+ if (!fs.existsSync(sourcePath)) {
31
+ console.error(`❌ Componente "${name}" não encontrado!`);
32
+ return;
33
+ }
34
+
35
+ // Criar diretório de destino
36
+ if (!fs.existsSync(targetPath)) {
37
+ fs.mkdirSync(targetPath, { recursive: true });
38
+ }
39
+
40
+ // Copiar arquivos
41
+ const files = fs.readdirSync(sourcePath);
42
+ files.forEach(file => {
43
+ const sourceFile = path.join(sourcePath, file);
44
+ const targetFile = path.join(targetPath, file);
45
+ fs.copyFileSync(sourceFile, targetFile);
46
+ });
47
+
48
+ console.log(`✅ Componente "${name}" copiado para ${targetPath}`);
49
+ }
50
+
51
+ function copyTheme() {
52
+ const themePath = path.join(__dirname, 'src', 'theme');
53
+ const targetThemePath = path.join(process.cwd(), 'src', 'theme');
54
+
55
+ if (!fs.existsSync(targetThemePath)) {
56
+ fs.mkdirSync(targetThemePath, { recursive: true });
57
+ }
58
+
59
+ const files = fs.readdirSync(themePath);
60
+ files.forEach(file => {
61
+ const sourceFile = path.join(themePath, file);
62
+ const targetFile = path.join(targetThemePath, file);
63
+ fs.copyFileSync(sourceFile, targetFile);
64
+ });
65
+
66
+ console.log(`✅ Tema copiado para ${targetThemePath}`);
67
+ }
68
+
69
+ function showHelp() {
70
+ console.log(`
71
+ 🎨 AleUI - Glassmorphism Components
72
+
73
+ Uso:
74
+ npx @alexandretav/aleui add <componente>
75
+ npx @alexandretav/aleui add-all
76
+ npx @alexandretav/aleui list
77
+
78
+ Comandos:
79
+ add <componente> Adiciona um componente específico
80
+ add-all Adiciona todos os componentes
81
+ list Lista componentes disponíveis
82
+
83
+ Componentes disponíveis:
84
+ ${availableComponents.map(c => ` - ${c}`).join('\n')}
85
+
86
+ Exemplos:
87
+ npx @alexandretav/aleui add button
88
+ npx @alexandretav/aleui add card
89
+ npx @alexandretav/aleui add-all
90
+ `);
91
+ }
92
+
93
+ function listComponents() {
94
+ console.log('\n📦 Componentes disponíveis:\n');
95
+ availableComponents.forEach(c => {
96
+ console.log(` ✨ ${c}`);
97
+ });
98
+ console.log('');
99
+ }
100
+
101
+ // Main
102
+ switch (command) {
103
+ case 'add':
104
+ if (!componentName) {
105
+ console.error('❌ Especifique o nome do componente!');
106
+ console.log('Uso: npx @alexandretav/aleui add <componente>');
107
+ process.exit(1);
108
+ }
109
+ copyTheme();
110
+ copyComponent(componentName);
111
+ break;
112
+
113
+ case 'add-all':
114
+ copyTheme();
115
+ availableComponents.forEach(comp => copyComponent(comp));
116
+ console.log('\n✅ Todos os componentes foram copiados!');
117
+ break;
118
+
119
+ case 'list':
120
+ listComponents();
121
+ break;
122
+
123
+ default:
124
+ showHelp();
125
+ }
package/package.json CHANGED
@@ -1,12 +1,16 @@
1
1
  {
2
2
  "name": "@alexandretav/aleui",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Glass UI components for React",
5
- "main": "dist/index.js",
6
- "module": "dist/index.esm.js",
7
- "types": "dist/index.d.ts",
5
+ "main": "src/components/index.ts",
6
+ "types": "src/components/index.ts",
7
+ "bin": {
8
+ "aleui": "./cli.js"
9
+ },
8
10
  "files": [
9
- "dist",
11
+ "src/components",
12
+ "src/theme",
13
+ "src/utils",
10
14
  "README.md",
11
15
  "LICENSE"
12
16
  ],
@@ -33,10 +37,8 @@
33
37
  "scripts": {
34
38
  "dev": "next dev",
35
39
  "build": "next build",
36
- "build:lib": "tsup src/components/index.ts --format cjs,esm --dts --external react --external react-dom --external framer-motion",
37
40
  "start": "next start",
38
- "lint": "next lint",
39
- "prepublishOnly": "npm run build:lib"
41
+ "lint": "next lint"
40
42
  },
41
43
  "peerDependencies": {
42
44
  "framer-motion": "^11.0.0",
@@ -0,0 +1,103 @@
1
+ 'use client';
2
+
3
+ import React, { useState } from 'react';
4
+ import { getGlassClasses, GlassVariantType } from '@/theme/glass';
5
+
6
+ export interface AccordionItemProps {
7
+ id: string;
8
+ title: string;
9
+ content: React.ReactNode;
10
+ icon?: React.ReactNode;
11
+ }
12
+
13
+ export interface AccordionProps {
14
+ items: AccordionItemProps[];
15
+ variant?: GlassVariantType;
16
+ allowMultiple?: boolean;
17
+ defaultOpen?: string[];
18
+ className?: string;
19
+ }
20
+
21
+ export const Accordion: React.FC<AccordionProps> = ({
22
+ items,
23
+ variant = 'light',
24
+ allowMultiple = false,
25
+ defaultOpen = [],
26
+ className = '',
27
+ }) => {
28
+ const [openItems, setOpenItems] = useState<string[]>(defaultOpen);
29
+
30
+ const toggleItem = (id: string) => {
31
+ if (allowMultiple) {
32
+ setOpenItems((prev) =>
33
+ prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id]
34
+ );
35
+ } else {
36
+ setOpenItems((prev) => (prev.includes(id) ? [] : [id]));
37
+ }
38
+ };
39
+
40
+ const isOpen = (id: string) => openItems.includes(id);
41
+
42
+ return (
43
+ <div className={className}>
44
+ {items.map((item, index) => {
45
+ const open = isOpen(item.id);
46
+ const glassClasses = getGlassClasses(variant, 'rounded-none', false);
47
+ const isFirst = index === 0;
48
+ const isLast = index === items.length - 1;
49
+
50
+ return (
51
+ <div
52
+ key={item.id}
53
+ className={`${glassClasses} ${
54
+ isFirst ? 'rounded-t-lg' : ''
55
+ } ${
56
+ isLast ? 'rounded-b-lg' : ''
57
+ } ${
58
+ !isLast ? 'border-b border-white/10' : ''
59
+ }`}
60
+ >
61
+ <button
62
+ onClick={() => toggleItem(item.id)}
63
+ className="w-full px-4 py-4 flex items-center justify-between text-left text-white font-medium hover:underline transition-all duration-200"
64
+ >
65
+ <div className="flex items-center gap-2">
66
+ {item.icon && <span className="flex items-center text-base">{item.icon}</span>}
67
+ <span className="text-sm font-medium">{item.title}</span>
68
+ </div>
69
+ <svg
70
+ className={`w-4 h-4 shrink-0 transition-transform duration-200 text-white/70 ${
71
+ open ? 'rotate-180' : ''
72
+ }`}
73
+ fill="none"
74
+ stroke="currentColor"
75
+ strokeWidth="2"
76
+ viewBox="0 0 24 24"
77
+ >
78
+ <path
79
+ strokeLinecap="round"
80
+ strokeLinejoin="round"
81
+ d="M19 9l-7 7-7-7"
82
+ />
83
+ </svg>
84
+ </button>
85
+ <div
86
+ className={`grid transition-all duration-200 ease-in-out ${
87
+ open ? 'grid-rows-[1fr] opacity-100' : 'grid-rows-[0fr] opacity-0'
88
+ }`}
89
+ >
90
+ <div className="overflow-hidden">
91
+ <div className="px-4 pb-4 pt-0 text-sm text-white/80 leading-relaxed">
92
+ {item.content}
93
+ </div>
94
+ </div>
95
+ </div>
96
+ </div>
97
+ );
98
+ })}
99
+ </div>
100
+ );
101
+ };
102
+
103
+ export default Accordion;
@@ -0,0 +1,2 @@
1
+ export { Accordion } from './accordion';
2
+ export type { AccordionProps, AccordionItemProps } from './accordion';
@@ -0,0 +1,51 @@
1
+ import React from 'react';
2
+
3
+ export interface AeroBubbleProps {
4
+ size?: 'sm' | 'md' | 'lg' | 'xl';
5
+ color?: 'cyan' | 'blue' | 'lime' | 'sky';
6
+ className?: string;
7
+ }
8
+
9
+ const sizeClasses = {
10
+ sm: 'w-12 h-12',
11
+ md: 'w-20 h-20',
12
+ lg: 'w-32 h-32',
13
+ xl: 'w-48 h-48',
14
+ };
15
+
16
+ const colorClasses = {
17
+ cyan: 'bg-gradient-to-br from-cyan-300/40 to-cyan-500/20',
18
+ blue: 'bg-gradient-to-br from-blue-300/40 to-blue-500/20',
19
+ lime: 'bg-gradient-to-br from-lime-300/40 to-lime-500/20',
20
+ sky: 'bg-gradient-to-br from-sky-300/40 to-sky-500/20',
21
+ };
22
+
23
+ export const AeroBubble: React.FC<AeroBubbleProps> = ({
24
+ size = 'md',
25
+ color = 'cyan',
26
+ className = '',
27
+ }) => {
28
+ return (
29
+ <div
30
+ className={`
31
+ ${sizeClasses[size]}
32
+ ${colorClasses[color]}
33
+ rounded-full
34
+ backdrop-blur-sm
35
+ border border-white/30
36
+ shadow-[0_8px_32px_0_rgba(31,38,135,0.37)]
37
+ relative
38
+ overflow-hidden
39
+ ${className}
40
+ `}
41
+ >
42
+ {/* Shine effect */}
43
+ <div className="absolute inset-0 bg-gradient-to-br from-white/40 via-transparent to-transparent rounded-full"></div>
44
+
45
+ {/* Inner glow */}
46
+ <div className="absolute bottom-2 right-2 w-1/3 h-1/3 bg-white/30 rounded-full blur-md"></div>
47
+ </div>
48
+ );
49
+ };
50
+
51
+ export default AeroBubble;
@@ -0,0 +1,2 @@
1
+ export { AeroBubble } from './aero-bubble';
2
+ export type { AeroBubbleProps } from './aero-bubble';
@@ -0,0 +1,49 @@
1
+ import React from 'react';
2
+ import { getAeroClasses, AeroVariantType } from '@/theme/glass';
3
+
4
+ export interface AeroButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
5
+ variant?: AeroVariantType;
6
+ size?: 'sm' | 'md' | 'lg';
7
+ fullWidth?: boolean;
8
+ children: React.ReactNode;
9
+ }
10
+
11
+ const sizeClasses = {
12
+ sm: 'px-4 py-2 text-sm',
13
+ md: 'px-6 py-3 text-base',
14
+ lg: 'px-8 py-4 text-lg',
15
+ };
16
+
17
+ export const AeroButton: React.FC<AeroButtonProps> = ({
18
+ variant = 'light',
19
+ size = 'md',
20
+ fullWidth = false,
21
+ children,
22
+ className = '',
23
+ disabled = false,
24
+ ...props
25
+ }) => {
26
+ const aeroClasses = getAeroClasses(variant, 'rounded-lg');
27
+ const sizeClass = sizeClasses[size];
28
+ const widthClass = fullWidth ? 'w-full' : '';
29
+ const disabledClass = disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer';
30
+
31
+ return (
32
+ <button
33
+ className={`
34
+ ${aeroClasses}
35
+ ${sizeClass}
36
+ ${widthClass}
37
+ ${disabledClass}
38
+ font-medium text-white
39
+ ${className}
40
+ `}
41
+ disabled={disabled}
42
+ {...props}
43
+ >
44
+ {children}
45
+ </button>
46
+ );
47
+ };
48
+
49
+ export default AeroButton;
@@ -0,0 +1,2 @@
1
+ export { AeroButton } from './aero-button';
2
+ export type { AeroButtonProps } from './aero-button';
@@ -0,0 +1,83 @@
1
+ "use client"
2
+
3
+ import React from 'react'
4
+ import { motion } from 'framer-motion';
5
+ import { cn } from '@/utils';
6
+
7
+ const animation = {
8
+ initial: { "--x": "-100%", scale: 1 },
9
+ animate: { "--x": "-100%", scale: 1 },
10
+ whileHover: { scale: 1.05 },
11
+ whileTap: { scale: 0.95 },
12
+ }
13
+
14
+ const sizeClasses = {
15
+ sm: 'px-4 py-2 text-sm',
16
+ md: 'px-6 py-3 text-base',
17
+ lg: 'px-8 py-4 text-lg',
18
+ };
19
+
20
+ interface ShinyButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
21
+ size?: 'sm' | 'md' | 'lg';
22
+ fullWidth?: boolean;
23
+ children: React.ReactNode;
24
+ onClick?: () => void;
25
+ }
26
+
27
+ export const ShinyButton: React.FC<ShinyButtonProps> = ({
28
+ onClick,
29
+ size = 'md',
30
+ fullWidth = false,
31
+ className = '',
32
+ children,
33
+ disabled = false,
34
+ }) => {
35
+ const sizeClass = sizeClasses[size];
36
+ const widthClass = fullWidth ? 'w-full' : '';
37
+
38
+ return (
39
+ <motion.button
40
+ {...animation}
41
+ onClick={onClick}
42
+ disabled={disabled}
43
+ className={cn(
44
+ "relative rounded-xl overflow-hidden font-medium",
45
+ sizeClass,
46
+ widthClass,
47
+ "bg-gradient-to-br from-cyan-400/30 via-blue-400/25 to-cyan-500/30",
48
+ "backdrop-blur-lg border-2 border-cyan-300/40",
49
+ "shadow-[0_0_30px_rgba(0,206,209,0.4),inset_0_0_20px_rgba(255,255,255,0.1)]",
50
+ "hover:shadow-[0_0_50px_rgba(0,206,209,0.6),inset_0_0_30px_rgba(255,255,255,0.2)]",
51
+ "hover:border-cyan-300/60",
52
+ "transition-all duration-300",
53
+ disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer",
54
+ className,
55
+ )}
56
+ >
57
+ {/* Shine effect */}
58
+ <motion.span
59
+ className="absolute inset-0 z-0"
60
+ animate={{
61
+ x: ["0%", "200%"],
62
+ }}
63
+ transition={{
64
+ duration: 3,
65
+ repeat: Infinity,
66
+ ease: "linear",
67
+ }}
68
+ style={{
69
+ background: "linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.4) 50%, transparent 100%)",
70
+ width: "50%",
71
+ }}
72
+ />
73
+
74
+ {/* Inner glow */}
75
+ <span className="absolute inset-0 bg-gradient-to-t from-transparent via-white/5 to-white/10 z-0" />
76
+
77
+ {/* Text */}
78
+ <span className="relative z-10 text-white font-semibold drop-shadow-[0_2px_8px_rgba(0,0,0,0.5)]">
79
+ {children}
80
+ </span>
81
+ </motion.button>
82
+ );
83
+ };
@@ -0,0 +1,43 @@
1
+ import React from 'react';
2
+ import { getAeroClasses, AeroVariantType } from '@/theme/glass';
3
+
4
+ export interface AeroCardProps extends React.HTMLAttributes<HTMLDivElement> {
5
+ variant?: AeroVariantType;
6
+ padding?: 'none' | 'sm' | 'md' | 'lg';
7
+ enableInteractions?: boolean;
8
+ children: React.ReactNode;
9
+ }
10
+
11
+ const paddingClasses = {
12
+ none: '',
13
+ sm: 'p-4',
14
+ md: 'p-6',
15
+ lg: 'p-8',
16
+ };
17
+
18
+ export const AeroCard: React.FC<AeroCardProps> = ({
19
+ variant = 'light',
20
+ padding = 'md',
21
+ enableInteractions = false,
22
+ children,
23
+ className = '',
24
+ ...props
25
+ }) => {
26
+ const aeroClasses = getAeroClasses(variant, 'rounded-xl', enableInteractions);
27
+ const paddingClass = paddingClasses[padding];
28
+
29
+ return (
30
+ <div
31
+ className={`
32
+ ${aeroClasses}
33
+ ${paddingClass}
34
+ ${className}
35
+ `}
36
+ {...props}
37
+ >
38
+ {children}
39
+ </div>
40
+ );
41
+ };
42
+
43
+ export default AeroCard;
@@ -0,0 +1,2 @@
1
+ export { AeroCard } from './aero-card';
2
+ export type { AeroCardProps } from './aero-card';
@@ -0,0 +1,41 @@
1
+ import React from 'react';
2
+ import { getAeroClasses, AeroVariantType } from '@/theme/glass';
3
+
4
+ export interface AeroInputProps extends React.InputHTMLAttributes<HTMLInputElement> {
5
+ variant?: AeroVariantType;
6
+ label?: string;
7
+ fullWidth?: boolean;
8
+ }
9
+
10
+ export const AeroInput: React.FC<AeroInputProps> = ({
11
+ variant = 'light',
12
+ label,
13
+ fullWidth = false,
14
+ className = '',
15
+ ...props
16
+ }) => {
17
+ const aeroClasses = getAeroClasses(variant, 'rounded-lg');
18
+ const widthClass = fullWidth ? 'w-full' : '';
19
+
20
+ return (
21
+ <div className={`flex flex-col gap-2 ${widthClass}`}>
22
+ {label && (
23
+ <label className="text-white/90 text-sm font-medium">
24
+ {label}
25
+ </label>
26
+ )}
27
+ <input
28
+ className={`
29
+ ${aeroClasses}
30
+ px-4 py-3
31
+ ${widthClass}
32
+ text-white placeholder-white/50
33
+ ${className}
34
+ `}
35
+ {...props}
36
+ />
37
+ </div>
38
+ );
39
+ };
40
+
41
+ export default AeroInput;
@@ -0,0 +1,2 @@
1
+ export { AeroInput } from './aero-input';
2
+ export type { AeroInputProps } from './aero-input';
@@ -0,0 +1,50 @@
1
+ import React from 'react';
2
+ import { getGlassClasses, GlassVariantType } from '@/theme/glass';
3
+
4
+ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
5
+ variant?: GlassVariantType;
6
+ size?: 'sm' | 'md' | 'lg';
7
+ fullWidth?: boolean;
8
+ children: React.ReactNode;
9
+ }
10
+
11
+ const sizeClasses = {
12
+ sm: 'px-4 py-2 text-sm',
13
+ md: 'px-6 py-3 text-base',
14
+ lg: 'px-8 py-4 text-lg',
15
+ };
16
+
17
+
18
+ export const Button: React.FC<ButtonProps> = ({
19
+ variant = 'light',
20
+ size = 'md',
21
+ fullWidth = false,
22
+ children,
23
+ className = '',
24
+ disabled = false,
25
+ ...props
26
+ }) => {
27
+ const glassClasses = getGlassClasses(variant);
28
+ const sizeClass = sizeClasses[size];
29
+ const widthClass = fullWidth ? 'w-full' : '';
30
+ const disabledClass = disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer';
31
+
32
+ return (
33
+ <button
34
+ className={`
35
+ ${glassClasses}
36
+ ${sizeClass}
37
+ ${widthClass}
38
+ ${disabledClass}
39
+ font-medium text-white
40
+ ${className}
41
+ `}
42
+ disabled={disabled}
43
+ {...props}
44
+ >
45
+ {children}
46
+ </button>
47
+ );
48
+ };
49
+
50
+ export default Button;
@@ -0,0 +1,2 @@
1
+ export { Button } from './button';
2
+ export type { ButtonProps } from './button';
@@ -0,0 +1,43 @@
1
+ import React from 'react';
2
+ import { getGlassClasses, GlassVariantType } from '@/theme/glass';
3
+
4
+ export interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
5
+ variant?: GlassVariantType;
6
+ padding?: 'none' | 'sm' | 'md' | 'lg';
7
+ enableInteractions?: boolean;
8
+ children: React.ReactNode;
9
+ }
10
+
11
+ const paddingClasses = {
12
+ none: '',
13
+ sm: 'p-4',
14
+ md: 'p-6',
15
+ lg: 'p-8',
16
+ };
17
+
18
+ export const Card: React.FC<CardProps> = ({
19
+ variant = 'light',
20
+ padding = 'md',
21
+ enableInteractions = false,
22
+ children,
23
+ className = '',
24
+ ...props
25
+ }) => {
26
+ const glassClasses = getGlassClasses(variant, undefined, enableInteractions);
27
+ const paddingClass = paddingClasses[padding];
28
+
29
+ return (
30
+ <div
31
+ className={`
32
+ ${glassClasses}
33
+ ${paddingClass}
34
+ ${className}
35
+ `}
36
+ {...props}
37
+ >
38
+ {children}
39
+ </div>
40
+ );
41
+ };
42
+
43
+ export default Card;
@@ -0,0 +1,2 @@
1
+ export { Card } from './card';
2
+ export type { CardProps } from './card';
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Glassmorphism UI Component Library
3
+ * Export all components from a single entry point
4
+ */
5
+
6
+ export { Button } from './button';
7
+ export type { ButtonProps } from './button';
8
+
9
+ export { Card } from './card';
10
+ export type { CardProps } from './card';
11
+
12
+ export { Input } from './input';
13
+ export type { InputProps } from './input';
14
+
15
+ export { Modal } from './modal';
16
+ export type { ModalProps } from './modal';
17
+
18
+ export { AeroBubble } from './aero-bubble';
19
+ export type { AeroBubbleProps } from './aero-bubble';
20
+
21
+ export { Accordion } from './accordion';
22
+ export type { AccordionProps, AccordionItemProps } from './accordion';
23
+
24
+ export {
25
+ getGlassClasses,
26
+ getAeroClasses,
27
+ glassVariants,
28
+ aeroVariants,
29
+ } from '@/theme/glass';
30
+ export type { GlassVariantType, AeroVariantType } from '@/theme/glass';
@@ -0,0 +1,2 @@
1
+ export { Input } from './input';
2
+ export type { InputProps } from './input';