@clubz/cli 0.1.0 → 0.1.1
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 +82 -0
- package/dist/commands/init.js +2 -2
- package/dist/templates/templates/react-vite-ts/clubz.json +21 -0
- package/dist/templates/templates/react-vite-ts/index.html +13 -0
- package/dist/templates/templates/react-vite-ts/package.json +23 -0
- package/dist/templates/templates/react-vite-ts/src/App.tsx +35 -0
- package/dist/templates/templates/react-vite-ts/src/main.tsx +9 -0
- package/dist/templates/templates/react-vite-ts/vite.config.ts +18 -0
- package/package.json +2 -2
- package/src/commands/init.ts +2 -2
package/README.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# @clubz/cli
|
|
2
|
+
|
|
3
|
+
The official Command Line Interface for building widgets and pages for the **Clubz Community Builder**.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @clubz/cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### 1. Create a new Widget
|
|
14
|
+
|
|
15
|
+
Scaffold a new widget project with the official React + Vite + TypeScript template.
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
clubz init my-awesome-widget
|
|
19
|
+
cd my-awesome-widget
|
|
20
|
+
npm install
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### 2. Develop Locally (Simulator)
|
|
24
|
+
|
|
25
|
+
Start the local development server. This launches a **Local Simulator** that mimics the Clubz mobile environment (IFrame, SDK communication, etc.), allowing you to test your widget in isolation.
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm run dev
|
|
29
|
+
# OR
|
|
30
|
+
clubz dev
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The simulator will open at `http://localhost:3000` (or the next available port).
|
|
34
|
+
|
|
35
|
+
### 3. Deploy
|
|
36
|
+
|
|
37
|
+
Package your widget and deploy it to the Clubz platform.
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm run deploy
|
|
41
|
+
# OR
|
|
42
|
+
clubz deploy
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Project Structure
|
|
46
|
+
|
|
47
|
+
A standard Clubz widget project looks like this:
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
my-widget/
|
|
51
|
+
├── src/
|
|
52
|
+
│ ├── App.tsx # Your main widget code
|
|
53
|
+
│ └── main.tsx # Entry point
|
|
54
|
+
├── clubz.json # Widget metadata (name, version, permissions)
|
|
55
|
+
├── package.json
|
|
56
|
+
└── vite.config.ts # Vite configuration
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## SDK Integration
|
|
60
|
+
|
|
61
|
+
The CLI templates come pre-configured with `@clubz/sdk`. Use it to interact with the host application:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { bridge } from '@clubz/sdk';
|
|
65
|
+
|
|
66
|
+
// Get user info
|
|
67
|
+
const user = await bridge.getUser();
|
|
68
|
+
|
|
69
|
+
// Show a native toast
|
|
70
|
+
await bridge.showToast({ message: 'Hello from Widget!', type: 'success' });
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Contributing
|
|
74
|
+
|
|
75
|
+
This CLI is part of the Clubz monorepo.
|
|
76
|
+
|
|
77
|
+
### Local Setup
|
|
78
|
+
|
|
79
|
+
1. Clone the repository.
|
|
80
|
+
2. Install dependencies: `npm install`
|
|
81
|
+
3. Build the CLI: `npm run build`
|
|
82
|
+
4. Link globally for testing: `npm link`
|
package/dist/commands/init.js
CHANGED
|
@@ -31,8 +31,8 @@ async function initCommand(name) {
|
|
|
31
31
|
let templateDir = path_1.default.join(__dirname, '../../templates', templateName); // from dist/commands or src/commands
|
|
32
32
|
// Fallback if structure is different (e.g. src vs dist) - explicit check
|
|
33
33
|
if (!fs_extra_1.default.existsSync(templateDir)) {
|
|
34
|
-
// Try source path if we are running
|
|
35
|
-
templateDir = path_1.default.join(__dirname, '
|
|
34
|
+
// Try source path if we are running from dist but templates are in src (common in local dev)
|
|
35
|
+
templateDir = path_1.default.join(__dirname, '../../src/templates', templateName);
|
|
36
36
|
}
|
|
37
37
|
if (!fs_extra_1.default.existsSync(templateDir)) {
|
|
38
38
|
console.error(chalk_1.default.red(`❌ Template not found at ${templateDir}`));
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "My Amazing Widget",
|
|
3
|
+
"description": "A widget built for Clubz",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"type": "widget",
|
|
6
|
+
"config": {
|
|
7
|
+
"props": [
|
|
8
|
+
{
|
|
9
|
+
"name": "title",
|
|
10
|
+
"type": "string",
|
|
11
|
+
"label": "Titre du widget",
|
|
12
|
+
"default": "Hello World"
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
"permissions": [],
|
|
17
|
+
"tags": [
|
|
18
|
+
"beta",
|
|
19
|
+
"react"
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Clubz Widget</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="root"></div>
|
|
10
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
11
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "my-clubz-widget",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "tsc && vite build",
|
|
9
|
+
"preview": "vite preview"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"react": "^18.2.0",
|
|
13
|
+
"react-dom": "^18.2.0",
|
|
14
|
+
"@clubz/sdk": "latest"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@types/react": "^18.2.66",
|
|
18
|
+
"@types/react-dom": "^18.2.22",
|
|
19
|
+
"@vitejs/plugin-react": "^4.2.1",
|
|
20
|
+
"typescript": "^5.2.2",
|
|
21
|
+
"vite": "^5.2.0"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react'
|
|
2
|
+
import { bridge } from '@clubz/sdk'
|
|
3
|
+
|
|
4
|
+
function App() {
|
|
5
|
+
const [user, setUser] = useState<{ name: string } | null>(null)
|
|
6
|
+
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
// Determine user context via Bridge
|
|
9
|
+
bridge.getUser().then((u: any) => setUser(u)).catch(() => console.log('Guest mode'))
|
|
10
|
+
}, [])
|
|
11
|
+
|
|
12
|
+
const handleVibrate = () => {
|
|
13
|
+
bridge.vibrate();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<div className="w-full h-full min-h-[200px] bg-white rounded-xl p-6 border border-slate-200 flex flex-col items-center justify-center">
|
|
18
|
+
<h1 className="text-xl font-bold text-slate-800 mb-2">
|
|
19
|
+
Hello {user ? user.name : 'Guest'}!
|
|
20
|
+
</h1>
|
|
21
|
+
<p className="text-slate-500 text-center mb-4">
|
|
22
|
+
Welcome to your new Clubz Widget.
|
|
23
|
+
</p>
|
|
24
|
+
|
|
25
|
+
<button
|
|
26
|
+
onClick={handleVibrate}
|
|
27
|
+
className="px-4 py-2 bg-blue-600 text-white rounded-lg active:bg-blue-700 transition"
|
|
28
|
+
>
|
|
29
|
+
Test Vibration
|
|
30
|
+
</button>
|
|
31
|
+
</div>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default App
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { defineConfig } from 'vite'
|
|
2
|
+
import react from '@vitejs/plugin-react'
|
|
3
|
+
|
|
4
|
+
// https://vitejs.dev/config/
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
plugins: [react()],
|
|
7
|
+
build: {
|
|
8
|
+
rollupOptions: {
|
|
9
|
+
output: {
|
|
10
|
+
// Ensure we get a single recognizable entry point if possible,
|
|
11
|
+
// though standard vite build is fine for the platform zipper.
|
|
12
|
+
entryFileNames: 'assets/[name].js',
|
|
13
|
+
chunkFileNames: 'assets/[name].js',
|
|
14
|
+
assetFileNames: 'assets/[name].[ext]'
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
})
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clubz/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"bin": {
|
|
5
5
|
"clubz": "bin/clubz.js"
|
|
6
6
|
},
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"scripts": {
|
|
9
|
-
"build": "tsc",
|
|
9
|
+
"build": "tsc && cp -r src/templates dist/templates",
|
|
10
10
|
"dev": "tsc -w"
|
|
11
11
|
},
|
|
12
12
|
"publishConfig": {
|
package/src/commands/init.ts
CHANGED
|
@@ -33,8 +33,8 @@ export async function initCommand(name: string) {
|
|
|
33
33
|
|
|
34
34
|
// Fallback if structure is different (e.g. src vs dist) - explicit check
|
|
35
35
|
if (!fs.existsSync(templateDir)) {
|
|
36
|
-
// Try source path if we are running
|
|
37
|
-
templateDir = path.join(__dirname, '
|
|
36
|
+
// Try source path if we are running from dist but templates are in src (common in local dev)
|
|
37
|
+
templateDir = path.join(__dirname, '../../src/templates', templateName);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
if (!fs.existsSync(templateDir)) {
|