modula-ui 1.0.0 → 1.0.3
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/README.md +98 -36
- package/bin/run.js +74 -10
- package/package.json +4 -4
- package/registry.json +27 -2
- package/src/app/layout.js +2 -2
- package/src/components/Header.jsx +1 -1
- package/src/components/Logo.jsx +6 -19
- package/src/library/pages/GroupChat/index.jsx +1 -1
- package/src/library/pages/VideoConference/index.jsx +1 -1
package/README.md
CHANGED
|
@@ -1,36 +1,98 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
1
|
+
# Modula UI
|
|
2
|
+
|
|
3
|
+
A library of modern UI patterns and complete interfaces built with [Shadcn](https://ui.shadcn.com/) and [Tailwind CSS](https://tailwindcss.com/). Get beautiful, functional UIs without building from scratch.
|
|
4
|
+
|
|
5
|
+
## ✨ Features
|
|
6
|
+
|
|
7
|
+
- 🎨 **Complete UI Patterns** - Full-featured interfaces, not just individual components
|
|
8
|
+
- 🚀 **Easy Integration** - Simple CLI to add entire UI blocks to your project
|
|
9
|
+
- 📦 **Copy & Paste** - Browse interfaces in your browser and copy code directly
|
|
10
|
+
- 🎯 **Modern Stack** - Built with Next.js, React 19, and Tailwind CSS 4
|
|
11
|
+
- 🔧 **Customizable** - Full control over styling and behavior
|
|
12
|
+
- 📱 **Responsive** - Mobile-first design approach
|
|
13
|
+
|
|
14
|
+
## 🚀 Quick Start
|
|
15
|
+
|
|
16
|
+
### Browse UI Patterns
|
|
17
|
+
|
|
18
|
+
Run the library locally to browse all available UI patterns and interfaces:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx modula-ui
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
This will start a local server at `http://localhost:3177` where you can:
|
|
25
|
+
- Preview all UI patterns
|
|
26
|
+
- Copy interface code
|
|
27
|
+
- See live examples
|
|
28
|
+
|
|
29
|
+
### Add UI Patterns to Your Project
|
|
30
|
+
|
|
31
|
+
Use the CLI to add complete interfaces directly to your project:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx modula-ui add <component-name>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The CLI will automatically:
|
|
38
|
+
1. Install required dependencies
|
|
39
|
+
2. Install necessary Shadcn UI components
|
|
40
|
+
3. Copy the complete interface files to your project
|
|
41
|
+
|
|
42
|
+
## 📦 Available UI Patterns
|
|
43
|
+
|
|
44
|
+
- **video-conference** - Full-featured video conferencing interface with participant grid, controls, and animations
|
|
45
|
+
- **group-chat** - Modern group chat interface with sidebar, message threads, and real-time feel
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
## 🛠️ Installation
|
|
49
|
+
|
|
50
|
+
### Prerequisites
|
|
51
|
+
|
|
52
|
+
- Node.js >= 18.17.0
|
|
53
|
+
- A Next.js or React project with Tailwind CSS configured
|
|
54
|
+
|
|
55
|
+
### Example: Adding a UI Block
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# Add the video conference page
|
|
59
|
+
npx modula-ui add video-conference
|
|
60
|
+
|
|
61
|
+
# Add the group chat interface
|
|
62
|
+
npx modula-ui add group-chat
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The interface will be added to `src/library/<type>/` (or `library/<type>/` if no `src` folder exists).
|
|
66
|
+
|
|
67
|
+
## 🎯 Usage
|
|
68
|
+
|
|
69
|
+
After adding a UI pattern, import and use it in your project:
|
|
70
|
+
|
|
71
|
+
```jsx
|
|
72
|
+
import VideoConferencePage from '@/library/pages/VideoConferencePage';
|
|
73
|
+
|
|
74
|
+
export default function MyPage() {
|
|
75
|
+
return <VideoConferencePage />;
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## 🏗️ Tech Stack
|
|
80
|
+
|
|
81
|
+
- **Framework:** Next.js 16
|
|
82
|
+
- **UI Library:** React 19
|
|
83
|
+
- **Styling:** Tailwind CSS 4
|
|
84
|
+
- **Components:** Radix UI primitives
|
|
85
|
+
- **Animations:** Framer Motion
|
|
86
|
+
- **Icons:** Lucide React
|
|
87
|
+
- **Charts:** Recharts
|
|
88
|
+
|
|
89
|
+
## 📄 License
|
|
90
|
+
|
|
91
|
+
MIT © Mary Ojo
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
## 🔗 Links
|
|
95
|
+
|
|
96
|
+
- [npm Package](https://www.npmjs.com/package/modula-ui)
|
|
97
|
+
- [Shadcn UI](https://ui.shadcn.com/)
|
|
98
|
+
- [Tailwind CSS](https://tailwindcss.com/)
|
package/bin/run.js
CHANGED
|
@@ -6,6 +6,7 @@ import { parse } from 'url';
|
|
|
6
6
|
import fs from 'fs/promises';
|
|
7
7
|
import path from 'path';
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
|
+
import { execSync } from 'child_process';
|
|
9
10
|
|
|
10
11
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
11
12
|
const packageRoot = path.join(__dirname, '..');
|
|
@@ -13,11 +14,60 @@ const packageRoot = path.join(__dirname, '..');
|
|
|
13
14
|
const args = process.argv.slice(2);
|
|
14
15
|
const command = args[0];
|
|
15
16
|
|
|
17
|
+
const getPackageManager = async () => {
|
|
18
|
+
const userRoot = process.cwd();
|
|
19
|
+
try {
|
|
20
|
+
await fs.access(path.join(userRoot, 'pnpm-lock.yaml'));
|
|
21
|
+
return 'pnpm';
|
|
22
|
+
} catch {}
|
|
23
|
+
try {
|
|
24
|
+
await fs.access(path.join(userRoot, 'yarn.lock'));
|
|
25
|
+
return 'yarn';
|
|
26
|
+
} catch {}
|
|
27
|
+
try {
|
|
28
|
+
await fs.access(path.join(userRoot, 'bun.lockb'));
|
|
29
|
+
return 'bun';
|
|
30
|
+
} catch {}
|
|
31
|
+
return 'npm';
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const installDependencies = async (dependencies) => {
|
|
35
|
+
if (!dependencies || dependencies.length === 0) return;
|
|
36
|
+
|
|
37
|
+
const pm = await getPackageManager();
|
|
38
|
+
const installCmd = pm === 'npm' ? 'install' : 'add';
|
|
39
|
+
const cmd = `${pm} ${installCmd} ${dependencies.join(' ')}`;
|
|
40
|
+
|
|
41
|
+
console.log(`\n📦 Installing dependencies: ${dependencies.join(', ')}...`);
|
|
42
|
+
try {
|
|
43
|
+
execSync(cmd, { stdio: 'inherit', cwd: process.cwd() });
|
|
44
|
+
console.log('✅ Dependencies installed.');
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.error('❌ Failed to install dependencies.');
|
|
47
|
+
// Don't exit, just warn
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const installRegistryDependencies = (dependencies) => {
|
|
52
|
+
if (!dependencies || dependencies.length === 0) return;
|
|
53
|
+
|
|
54
|
+
console.log(`\n🎨 Installing UI components: ${dependencies.join(', ')}...`);
|
|
55
|
+
try {
|
|
56
|
+
// Attempt to use shadcn CLI
|
|
57
|
+
// We add -y to accept defaults if possible, but shadcn might still prompt
|
|
58
|
+
execSync(`npx shadcn@latest add ${dependencies.join(' ')} -y`, { stdio: 'inherit', cwd: process.cwd() });
|
|
59
|
+
console.log('✅ UI components installed.');
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.warn('⚠️ Failed to install UI components via shadcn. You might need to install them manually.');
|
|
62
|
+
console.warn(` Run: npx shadcn@latest add ${dependencies.join(' ')}`);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
16
66
|
if (command === 'add') {
|
|
17
67
|
const componentName = args[1];
|
|
18
68
|
|
|
19
69
|
if (!componentName) {
|
|
20
|
-
console.error('Please specify a component name: npx
|
|
70
|
+
console.error('Please specify a component name: npx modula-ui add <component-name>');
|
|
21
71
|
process.exit(1);
|
|
22
72
|
}
|
|
23
73
|
|
|
@@ -34,10 +84,20 @@ if (command === 'add') {
|
|
|
34
84
|
process.exit(1);
|
|
35
85
|
}
|
|
36
86
|
|
|
37
|
-
|
|
87
|
+
// 1. Install External Dependencies
|
|
88
|
+
if (component.dependencies) {
|
|
89
|
+
await installDependencies(component.dependencies);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 2. Install Registry Dependencies (Shadcn components)
|
|
93
|
+
if (component.registryDependencies) {
|
|
94
|
+
installRegistryDependencies(component.registryDependencies);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// 3. Copy Files
|
|
98
|
+
const filesToCopy = component.files || [component.path];
|
|
38
99
|
|
|
39
|
-
// Determine destination
|
|
40
|
-
// Check if src directory exists in the user's project
|
|
100
|
+
// Determine destination directory
|
|
41
101
|
const userProjectRoot = process.cwd();
|
|
42
102
|
const hasSrc = await fs.access(path.join(userProjectRoot, 'src')).then(() => true).catch(() => false);
|
|
43
103
|
|
|
@@ -45,16 +105,20 @@ if (command === 'add') {
|
|
|
45
105
|
? path.join(userProjectRoot, 'src', 'library', component.type)
|
|
46
106
|
: path.join(userProjectRoot, 'library', component.type);
|
|
47
107
|
|
|
48
|
-
const destPath = path.join(destDir, path.basename(sourcePath));
|
|
49
|
-
|
|
50
108
|
// Ensure destination directory exists
|
|
51
109
|
await fs.mkdir(destDir, { recursive: true });
|
|
52
110
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
111
|
+
for (const filePath of filesToCopy) {
|
|
112
|
+
const sourcePath = path.join(packageRoot, filePath);
|
|
113
|
+
const fileName = path.basename(sourcePath);
|
|
114
|
+
const destPath = path.join(destDir, fileName);
|
|
56
115
|
|
|
57
|
-
|
|
116
|
+
// Read and write file
|
|
117
|
+
const content = await fs.readFile(sourcePath, 'utf-8');
|
|
118
|
+
await fs.writeFile(destPath, content);
|
|
119
|
+
|
|
120
|
+
console.log(`\n✨ Component file ${fileName} added to ${path.relative(userProjectRoot, destPath)}`);
|
|
121
|
+
}
|
|
58
122
|
|
|
59
123
|
} catch (error) {
|
|
60
124
|
console.error('Error adding component:', error);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "modula-ui",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "A library of modern interfaces with great UX built with Shadcn",
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"description": "A library of modern interfaces and UI patterns with great UX built with Shadcn",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tailwind",
|
|
7
7
|
"components",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"type": "module",
|
|
16
16
|
"bin": {
|
|
17
17
|
"maryojo": "./bin/run.js",
|
|
18
|
-
"
|
|
18
|
+
"modula-ui": "./bin/run.js"
|
|
19
19
|
},
|
|
20
20
|
"files": [
|
|
21
21
|
"src",
|
|
@@ -68,4 +68,4 @@
|
|
|
68
68
|
"engines": {
|
|
69
69
|
"node": ">=18.17.0"
|
|
70
70
|
}
|
|
71
|
-
}
|
|
71
|
+
}
|
package/registry.json
CHANGED
|
@@ -2,11 +2,36 @@
|
|
|
2
2
|
"video-conference": {
|
|
3
3
|
"name": "VideoConference",
|
|
4
4
|
"type": "pages",
|
|
5
|
-
"path": "src/library/pages/VideoConference/VideoConferencePage.jsx"
|
|
5
|
+
"path": "src/library/pages/VideoConference/VideoConferencePage.jsx",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"lucide-react",
|
|
8
|
+
"framer-motion",
|
|
9
|
+
"clsx",
|
|
10
|
+
"tailwind-merge"
|
|
11
|
+
],
|
|
12
|
+
"registryDependencies": [
|
|
13
|
+
"avatar"
|
|
14
|
+
]
|
|
6
15
|
},
|
|
7
16
|
"group-chat": {
|
|
8
17
|
"name": "GroupChat",
|
|
9
18
|
"type": "pages",
|
|
10
|
-
"path": "src/library/pages/GroupChat/
|
|
19
|
+
"path": "src/library/pages/GroupChat/GroupChat.jsx",
|
|
20
|
+
"files": [
|
|
21
|
+
"src/library/pages/GroupChat/GroupChat.jsx",
|
|
22
|
+
"src/library/pages/GroupChat/data.js"
|
|
23
|
+
],
|
|
24
|
+
"dependencies": [
|
|
25
|
+
"lucide-react"
|
|
26
|
+
],
|
|
27
|
+
"registryDependencies": [
|
|
28
|
+
"sidebar",
|
|
29
|
+
"avatar",
|
|
30
|
+
"badge",
|
|
31
|
+
"scroll-area",
|
|
32
|
+
"navigation-menu",
|
|
33
|
+
"input",
|
|
34
|
+
"button"
|
|
35
|
+
]
|
|
11
36
|
}
|
|
12
37
|
}
|
package/src/app/layout.js
CHANGED
|
@@ -12,8 +12,8 @@ const geistMono = Geist_Mono({
|
|
|
12
12
|
});
|
|
13
13
|
|
|
14
14
|
export const metadata = {
|
|
15
|
-
title: "
|
|
16
|
-
description: "A library of modern interfaces with great UX built with Shadcn",
|
|
15
|
+
title: "Modula UI",
|
|
16
|
+
description: "A library of modern interfaces and UI patterns with great UX built with Shadcn",
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
export default function RootLayout({ children }) {
|
|
@@ -9,7 +9,7 @@ export default function Header({ sidebarOpen, toggleSidebar }) {
|
|
|
9
9
|
<div className="mb-8 flex items-center justify-between">
|
|
10
10
|
<div>
|
|
11
11
|
<Logo />
|
|
12
|
-
<p className="text-gray-600">A library of modern interfaces with great UX built with Shadcn</p>
|
|
12
|
+
<p className="text-gray-600">A library of modern interfaces and UI patterns with great UX built with Shadcn</p>
|
|
13
13
|
</div>
|
|
14
14
|
|
|
15
15
|
<button
|
package/src/components/Logo.jsx
CHANGED
|
@@ -3,24 +3,24 @@ import React from 'react';
|
|
|
3
3
|
const Logo = ({ className = '' }) => {
|
|
4
4
|
return (
|
|
5
5
|
<svg
|
|
6
|
-
width="
|
|
6
|
+
width="215"
|
|
7
7
|
height="50"
|
|
8
|
-
viewBox="0 0
|
|
8
|
+
viewBox="0 0 215 50"
|
|
9
9
|
fill="none"
|
|
10
10
|
xmlns="http://www.w3.org/2000/svg"
|
|
11
11
|
className={className}
|
|
12
12
|
>
|
|
13
|
-
{/* Icon Element - Abstract '
|
|
13
|
+
{/* Icon Element - Abstract 'M' */}
|
|
14
14
|
<circle cx="25" cy="25" r="20" fill="url(#grad1)" opacity="0.2" />
|
|
15
15
|
<path
|
|
16
|
-
d="M15
|
|
16
|
+
d="M15 35V15L25 25L35 15V35"
|
|
17
17
|
stroke="url(#grad2)"
|
|
18
18
|
strokeWidth="4"
|
|
19
19
|
strokeLinecap="round"
|
|
20
20
|
strokeLinejoin="round"
|
|
21
21
|
/>
|
|
22
22
|
|
|
23
|
-
{/* Text '
|
|
23
|
+
{/* Text 'modula ui' */}
|
|
24
24
|
<text
|
|
25
25
|
x="55"
|
|
26
26
|
y="32"
|
|
@@ -30,20 +30,7 @@ const Logo = ({ className = '' }) => {
|
|
|
30
30
|
fill="#111827"
|
|
31
31
|
letterSpacing="-1"
|
|
32
32
|
>
|
|
33
|
-
|
|
34
|
-
</text>
|
|
35
|
-
|
|
36
|
-
{/* Text '-ui' with different style */}
|
|
37
|
-
<text
|
|
38
|
-
x="115"
|
|
39
|
-
y="32"
|
|
40
|
-
fontFamily="system-ui, -apple-system, sans-serif"
|
|
41
|
-
fontWeight="800"
|
|
42
|
-
fontSize="28"
|
|
43
|
-
fill="#111827"
|
|
44
|
-
letterSpacing="-1"
|
|
45
|
-
>
|
|
46
|
-
ui
|
|
33
|
+
modula ui
|
|
47
34
|
</text>
|
|
48
35
|
|
|
49
36
|
{/* Gradients */}
|