create-aziz-app 1.0.3 → 2.0.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/bin/create-aziz-app.js +39 -20
- package/package.json +3 -1
- package/template/README.md +189 -0
- package/template/api/hello.js +14 -0
- package/template/api/users.js +62 -0
- package/template/app.config.js +41 -0
- package/template/app.html +127 -24
- package/template/components/Counter.jsx +30 -12
- package/template/components/Footer.jsx +3 -3
- package/template/components/Navbar.jsx +16 -0
- package/template/docs/API-GUIDE.md +196 -0
- package/template/docs/AUTO-IMPORT.md +99 -0
- package/template/docs/GETTING-STARTED.md +205 -0
- package/template/docs/QUICK-START.md +111 -0
- package/template/modules/README.md +129 -0
- package/template/modules/api.js +148 -0
- package/template/modules/auto-import.js +130 -0
- package/template/modules/router.js +185 -0
- package/template/modules/state.js +54 -0
- package/template/pages/About.jsx +33 -0
- package/template/pages/ApiDemo.jsx +209 -0
- package/template/pages/Contact.jsx +27 -0
- package/template/pages/Home.jsx +39 -0
- package/template/pages/NewPage.jsx +39 -0
- package/template/pages/Test.jsx +74 -0
- package/template/scripts/build.js +81 -0
- package/template/scripts/dev-server.js +172 -0
- package/template/scripts/generate-imports.js +98 -0
- package/template/app.js +0 -83
- package/template/components/Header.jsx +0 -10
package/bin/create-aziz-app.js
CHANGED
|
@@ -1,41 +1,60 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const fs
|
|
3
|
+
const fs = require("fs");
|
|
4
4
|
const path = require("path");
|
|
5
5
|
|
|
6
|
-
// The folder name comes from the command line argument
|
|
7
|
-
// e.g. npm create aziz-app my-app → projectName = "my-app"
|
|
8
6
|
const projectName = process.argv[2] || "my-aziz-app";
|
|
9
|
-
const targetDir
|
|
7
|
+
const targetDir = path.join(process.cwd(), projectName);
|
|
10
8
|
const templateDir = path.join(__dirname, "../template");
|
|
11
9
|
|
|
12
|
-
|
|
10
|
+
console.log(`\n⚡ Creating "${projectName}"...\n`);
|
|
11
|
+
|
|
13
12
|
if (fs.existsSync(targetDir)) {
|
|
14
|
-
console.
|
|
13
|
+
console.error(`❌ Folder "${projectName}" already exists. Choose a different name.`);
|
|
15
14
|
process.exit(1);
|
|
16
15
|
}
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
// Copy all template files into the new project folder
|
|
17
|
+
// Copy the entire template folder into the new project
|
|
21
18
|
copyDir(templateDir, targetDir);
|
|
22
19
|
|
|
23
|
-
console.log(`
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
cd ${projectName}
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
console.log(`✅ Done! Your project is ready.\n`);
|
|
21
|
+
console.log(`🎉 Welcome to Aziz App - A React-like Framework\n`);
|
|
22
|
+
console.log(`📁 Created project: ${projectName}\n`);
|
|
23
|
+
console.log(`👉 Get started:\n`);
|
|
24
|
+
console.log(` cd ${projectName}`);
|
|
25
|
+
console.log(` npm run dev\n`);
|
|
26
|
+
console.log(`🌐 This will:`);
|
|
27
|
+
console.log(` • Start dev server on http://localhost:3000/`);
|
|
28
|
+
console.log(` • Watch for file changes`);
|
|
29
|
+
console.log(` • Auto-import new files`);
|
|
30
|
+
console.log(` • Live reload browser\n`);
|
|
31
|
+
console.log(`� Project structure:\n`);
|
|
32
|
+
console.log(` app.html ← Main HTML file`);
|
|
33
|
+
console.log(` modules/ ← Core system (router, state, API)`);
|
|
34
|
+
console.log(` pages/ ← Your pages (auto-imported)`);
|
|
35
|
+
console.log(` components/ ← Your components (auto-imported)`);
|
|
36
|
+
console.log(` api/ ← Your API routes (auto-imported)`);
|
|
37
|
+
console.log(` scripts/ ← Build tools`);
|
|
38
|
+
console.log(` docs/ ← Documentation\n`);
|
|
39
|
+
console.log(`✨ Features:\n`);
|
|
40
|
+
console.log(` • State Management - useState() like React`);
|
|
41
|
+
console.log(` • File-based Routing - pages/About.jsx → #/about`);
|
|
42
|
+
console.log(` • API Routes - Next.js-like API system`);
|
|
43
|
+
console.log(` • Auto-Import - No manual script tags!`);
|
|
44
|
+
console.log(` • Live Reload - Instant browser refresh\n`);
|
|
45
|
+
console.log(`💡 Quick tips:\n`);
|
|
46
|
+
console.log(` • Create pages/MyPage.jsx → Auto-imported!`);
|
|
47
|
+
console.log(` • Create api/todos.js → Auto-imported!`);
|
|
48
|
+
console.log(` • Just save and browser refreshes automatically`);
|
|
49
|
+
console.log(` • Read docs/ folder for detailed guides\n`);
|
|
50
|
+
console.log(`🚀 Ready to build something awesome!\n`);
|
|
30
51
|
|
|
31
|
-
// Helper
|
|
52
|
+
// ---- Helper ----
|
|
32
53
|
function copyDir(src, dest) {
|
|
33
54
|
fs.mkdirSync(dest, { recursive: true });
|
|
34
|
-
|
|
35
55
|
for (let file of fs.readdirSync(src)) {
|
|
36
|
-
const srcPath
|
|
56
|
+
const srcPath = path.join(src, file);
|
|
37
57
|
const destPath = path.join(dest, file);
|
|
38
|
-
|
|
39
58
|
if (fs.statSync(srcPath).isDirectory()) {
|
|
40
59
|
copyDir(srcPath, destPath);
|
|
41
60
|
} else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-aziz-app",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "so close to react ~~ just joking",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"html",
|
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
},
|
|
21
21
|
"main": "app.js",
|
|
22
22
|
"scripts": {
|
|
23
|
+
"dev": "cd template && node scripts/dev-server.js",
|
|
24
|
+
"build": "cd template && node scripts/generate-imports.js",
|
|
23
25
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
24
26
|
}
|
|
25
27
|
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# Aziz App - React-like Framework
|
|
2
|
+
|
|
3
|
+
A simple, clean React-like framework with state management, routing, and API routes.
|
|
4
|
+
|
|
5
|
+
## 📁 Project Structure
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
template/
|
|
9
|
+
├── app.html # Main HTML file
|
|
10
|
+
├── app.config.js # Auto-generated config (don't edit manually)
|
|
11
|
+
│
|
|
12
|
+
├── modules/ # Core system modules
|
|
13
|
+
│ ├── router.js # Routing & rendering engine
|
|
14
|
+
│ ├── state.js # State management (useState)
|
|
15
|
+
│ ├── api.js # API route system
|
|
16
|
+
│ └── README.md # Module documentation
|
|
17
|
+
│
|
|
18
|
+
├── scripts/ # Build & dev tools
|
|
19
|
+
│ ├── dev-server.js # Development server with auto-import
|
|
20
|
+
│ ├── generate-imports.js # Import generator
|
|
21
|
+
│ └── build.js # Build script
|
|
22
|
+
│
|
|
23
|
+
├── docs/ # Documentation
|
|
24
|
+
│ ├── API-GUIDE.md # API routes guide
|
|
25
|
+
│ ├── AUTO-IMPORT.md # Auto-import system docs
|
|
26
|
+
│ ├── GETTING-STARTED.md # Getting started guide
|
|
27
|
+
│ └── QUICK-START.md # Quick start guide
|
|
28
|
+
│
|
|
29
|
+
├── api/ # API route handlers
|
|
30
|
+
│ ├── hello.js # Example: /api/hello
|
|
31
|
+
│ └── users.js # Example: /api/users
|
|
32
|
+
│
|
|
33
|
+
├── components/ # Reusable UI components
|
|
34
|
+
│ ├── Navbar.jsx
|
|
35
|
+
│ ├── Footer.jsx
|
|
36
|
+
│ └── Counter.jsx
|
|
37
|
+
│
|
|
38
|
+
└── pages/ # Page components (routes)
|
|
39
|
+
├── Home.jsx # Route: #/home
|
|
40
|
+
├── About.jsx # Route: #/about
|
|
41
|
+
├── Contact.jsx # Route: #/contact
|
|
42
|
+
├── test.jsx # Route: #/test
|
|
43
|
+
└── ApiDemo.jsx # Route: #/api-demo
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## 🚀 Quick Start
|
|
47
|
+
|
|
48
|
+
### 1. Start the Dev Server
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm run dev
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
This will:
|
|
55
|
+
- Start HTTP server on `http://localhost:3000/`
|
|
56
|
+
- Watch for file changes in `api/`, `components/`, and `pages/`
|
|
57
|
+
- Auto-generate imports when you create new files
|
|
58
|
+
- Auto-reload on changes
|
|
59
|
+
|
|
60
|
+
### 2. Open Your Browser
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
http://localhost:3000/
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 3. Create New Files
|
|
67
|
+
|
|
68
|
+
Just create files in the appropriate folders - they're automatically imported!
|
|
69
|
+
|
|
70
|
+
**Create a new page:**
|
|
71
|
+
```javascript
|
|
72
|
+
// pages/Profile.jsx
|
|
73
|
+
/** @jsx h */
|
|
74
|
+
|
|
75
|
+
registerPage("profile", ProfilePage);
|
|
76
|
+
|
|
77
|
+
function ProfilePage() {
|
|
78
|
+
const [name, setName] = useState('');
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<div>
|
|
82
|
+
<h1>Profile</h1>
|
|
83
|
+
<input
|
|
84
|
+
value={name}
|
|
85
|
+
onInput={(e) => setName(e.target.value)}
|
|
86
|
+
placeholder="Your name"
|
|
87
|
+
/>
|
|
88
|
+
<p>Hello, {name}!</p>
|
|
89
|
+
</div>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**Navigate to:** `http://localhost:3000/#/profile`
|
|
95
|
+
|
|
96
|
+
## ✨ Features
|
|
97
|
+
|
|
98
|
+
### State Management
|
|
99
|
+
```javascript
|
|
100
|
+
const [count, setCount] = useState(0);
|
|
101
|
+
const [name, setName] = useState('');
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Routing
|
|
105
|
+
```javascript
|
|
106
|
+
// Register a page
|
|
107
|
+
registerPage("about", AboutPage);
|
|
108
|
+
|
|
109
|
+
// Navigate
|
|
110
|
+
navigate("about");
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### API Routes
|
|
114
|
+
```javascript
|
|
115
|
+
// api/todos.js
|
|
116
|
+
registerApiRoute('todos', async (req, res) => {
|
|
117
|
+
return res.status(200).json({ todos: [] });
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Use in components
|
|
121
|
+
const response = await fetchApi('/api/todos');
|
|
122
|
+
const data = await response.json();
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Auto-Import
|
|
126
|
+
- Create files in `pages/`, `components/`, or `api/`
|
|
127
|
+
- Dev server automatically detects them
|
|
128
|
+
- Refresh browser to see changes
|
|
129
|
+
|
|
130
|
+
## 📚 Documentation
|
|
131
|
+
|
|
132
|
+
- **[Getting Started](docs/GETTING-STARTED.md)** - Complete setup guide
|
|
133
|
+
- **[API Guide](docs/API-GUIDE.md)** - How to create API routes
|
|
134
|
+
- **[Auto-Import](docs/AUTO-IMPORT.md)** - Auto-import system details
|
|
135
|
+
- **[Quick Start](docs/QUICK-START.md)** - Quick examples
|
|
136
|
+
|
|
137
|
+
## 🛠️ Commands
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
npm run dev # Start dev server with auto-import
|
|
141
|
+
npm run build # Generate imports manually
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## 🎯 Key Concepts
|
|
145
|
+
|
|
146
|
+
### Pages
|
|
147
|
+
- Files in `pages/` become routes
|
|
148
|
+
- Use `registerPage("route", Component)`
|
|
149
|
+
- Access via `#/route`
|
|
150
|
+
|
|
151
|
+
### Components
|
|
152
|
+
- Reusable UI components
|
|
153
|
+
- Use JSX syntax with `/** @jsx h */`
|
|
154
|
+
- Import automatically
|
|
155
|
+
|
|
156
|
+
### API Routes
|
|
157
|
+
- Files in `api/` become API endpoints
|
|
158
|
+
- Use `registerApiRoute("path", handler)`
|
|
159
|
+
- Access via `fetchApi('/api/path')`
|
|
160
|
+
|
|
161
|
+
### State
|
|
162
|
+
- Use `useState(initialValue)` like React
|
|
163
|
+
- Returns `[value, setValue]`
|
|
164
|
+
- Triggers re-render on change
|
|
165
|
+
|
|
166
|
+
## 🔥 Hot Tips
|
|
167
|
+
|
|
168
|
+
1. **Dev server must be running** for auto-import to work
|
|
169
|
+
2. **Refresh browser** after creating new files
|
|
170
|
+
3. **Use `/** @jsx h */`** at the top of JSX files
|
|
171
|
+
4. **Route names are case-sensitive** - `#/home` not `#/Home`
|
|
172
|
+
|
|
173
|
+
## 📦 What's in Each Folder
|
|
174
|
+
|
|
175
|
+
- **`modules/`** - Core framework code (don't modify unless extending)
|
|
176
|
+
- **`scripts/`** - Build tools (don't modify)
|
|
177
|
+
- **`docs/`** - Documentation (read these!)
|
|
178
|
+
- **`api/`** - Your API routes (add your endpoints here)
|
|
179
|
+
- **`components/`** - Your components (add reusable UI here)
|
|
180
|
+
- **`pages/`** - Your pages (add new pages here)
|
|
181
|
+
|
|
182
|
+
## 🎉 You're Ready!
|
|
183
|
+
|
|
184
|
+
Start the dev server and start building:
|
|
185
|
+
```bash
|
|
186
|
+
npm run dev
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Then open `http://localhost:3000/` and start creating!
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** @jsx h */
|
|
2
|
+
|
|
3
|
+
// Example API route: /api/hello
|
|
4
|
+
// Simple hello world API endpoint
|
|
5
|
+
|
|
6
|
+
registerApiRoute('hello', async (req, res) => {
|
|
7
|
+
const name = req.query.name || 'World';
|
|
8
|
+
|
|
9
|
+
return res.status(200).json({
|
|
10
|
+
message: `Hello, ${name}!`,
|
|
11
|
+
timestamp: new Date().toISOString(),
|
|
12
|
+
method: req.method
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/** @jsx h */
|
|
2
|
+
|
|
3
|
+
// Example API route: /api/users
|
|
4
|
+
// This simulates a backend API endpoint
|
|
5
|
+
|
|
6
|
+
// Mock database
|
|
7
|
+
const users = [
|
|
8
|
+
{ id: 1, name: 'Aziz Ahmed', email: 'aziz@example.com' },
|
|
9
|
+
{ id: 2, name: 'John Doe', email: 'john@example.com' },
|
|
10
|
+
{ id: 3, name: 'Jane Smith', email: 'jane@example.com' }
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
// Register the API route
|
|
14
|
+
registerApiRoute('users', async (req, res) => {
|
|
15
|
+
// Handle different HTTP methods
|
|
16
|
+
switch (req.method) {
|
|
17
|
+
case 'GET':
|
|
18
|
+
// Get all users or a specific user
|
|
19
|
+
if (req.query.id) {
|
|
20
|
+
const user = users.find(u => u.id === parseInt(req.query.id));
|
|
21
|
+
if (user) {
|
|
22
|
+
return res.status(200).json(user);
|
|
23
|
+
} else {
|
|
24
|
+
return res.status(404).json({ error: 'User not found' });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return res.status(200).json(users);
|
|
28
|
+
|
|
29
|
+
case 'POST':
|
|
30
|
+
// Create a new user
|
|
31
|
+
const newUser = {
|
|
32
|
+
id: users.length + 1,
|
|
33
|
+
name: req.body.name,
|
|
34
|
+
email: req.body.email
|
|
35
|
+
};
|
|
36
|
+
users.push(newUser);
|
|
37
|
+
return res.status(201).json(newUser);
|
|
38
|
+
|
|
39
|
+
case 'PUT':
|
|
40
|
+
// Update a user
|
|
41
|
+
const userId = req.query.id || req.body.id;
|
|
42
|
+
const userIndex = users.findIndex(u => u.id === parseInt(userId));
|
|
43
|
+
if (userIndex !== -1) {
|
|
44
|
+
users[userIndex] = { ...users[userIndex], ...req.body };
|
|
45
|
+
return res.status(200).json(users[userIndex]);
|
|
46
|
+
}
|
|
47
|
+
return res.status(404).json({ error: 'User not found' });
|
|
48
|
+
|
|
49
|
+
case 'DELETE':
|
|
50
|
+
// Delete a user
|
|
51
|
+
const deleteId = req.query.id;
|
|
52
|
+
const deleteIndex = users.findIndex(u => u.id === parseInt(deleteId));
|
|
53
|
+
if (deleteIndex !== -1) {
|
|
54
|
+
const deleted = users.splice(deleteIndex, 1);
|
|
55
|
+
return res.status(200).json({ message: 'User deleted', user: deleted[0] });
|
|
56
|
+
}
|
|
57
|
+
return res.status(404).json({ error: 'User not found' });
|
|
58
|
+
|
|
59
|
+
default:
|
|
60
|
+
return res.status(405).json({ error: 'Method not allowed' });
|
|
61
|
+
}
|
|
62
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// APP CONFIGURATION
|
|
3
|
+
// Configure what files to auto-import
|
|
4
|
+
// ============================================================
|
|
5
|
+
|
|
6
|
+
// Define all files to be automatically loaded
|
|
7
|
+
window.APP_CONFIG = {
|
|
8
|
+
// API routes to load
|
|
9
|
+
apiRoutes: [
|
|
10
|
+
'api/hello.js',
|
|
11
|
+
'api/users.js'
|
|
12
|
+
],
|
|
13
|
+
|
|
14
|
+
// Components to load
|
|
15
|
+
components: [
|
|
16
|
+
'components/Navbar.jsx',
|
|
17
|
+
'components/Footer.jsx',
|
|
18
|
+
'components/Counter.jsx'
|
|
19
|
+
],
|
|
20
|
+
|
|
21
|
+
// Pages to load
|
|
22
|
+
pages: [
|
|
23
|
+
'pages/Home.jsx',
|
|
24
|
+
'pages/About.jsx',
|
|
25
|
+
'pages/Contact.jsx',
|
|
26
|
+
'pages/test.jsx',
|
|
27
|
+
'pages/ApiDemo.jsx',
|
|
28
|
+
'pages/NewPage.jsx'
|
|
29
|
+
]
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// HOW TO ADD NEW FILES:
|
|
33
|
+
//
|
|
34
|
+
// 1. Create your new file in the appropriate folder
|
|
35
|
+
// 2. Add the path to the array above
|
|
36
|
+
// 3. Refresh the page - it will auto-load!
|
|
37
|
+
//
|
|
38
|
+
// Example:
|
|
39
|
+
// - New page: Add 'pages/MyNewPage.jsx' to pages array
|
|
40
|
+
// - New component: Add 'components/MyComponent.jsx' to components array
|
|
41
|
+
// - New API route: Add 'api/myroute.js' to apiRoutes array
|
package/template/app.html
CHANGED
|
@@ -3,53 +3,156 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>My Aziz
|
|
6
|
+
<title>My Aziz App</title>
|
|
7
7
|
|
|
8
8
|
<!-- Babel compiles JSX in the browser -->
|
|
9
9
|
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
|
|
10
10
|
|
|
11
11
|
<style>
|
|
12
|
+
/* ---- Reset ---- */
|
|
12
13
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
14
|
+
|
|
13
15
|
body {
|
|
14
16
|
font-family: Arial, sans-serif;
|
|
15
|
-
background-color: #
|
|
17
|
+
background-color: #f5f5f5;
|
|
18
|
+
color: #333;
|
|
19
|
+
min-height: 100vh;
|
|
16
20
|
display: flex;
|
|
17
21
|
flex-direction: column;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* ---- Navbar ---- */
|
|
25
|
+
nav {
|
|
26
|
+
background-color: #282c34;
|
|
27
|
+
padding: 16px 32px;
|
|
28
|
+
display: flex;
|
|
18
29
|
align-items: center;
|
|
19
|
-
|
|
30
|
+
gap: 24px;
|
|
20
31
|
}
|
|
21
|
-
.
|
|
32
|
+
nav .brand {
|
|
33
|
+
color: #61dafb;
|
|
34
|
+
font-size: 20px;
|
|
35
|
+
font-weight: bold;
|
|
36
|
+
cursor: pointer;
|
|
37
|
+
}
|
|
38
|
+
nav a {
|
|
39
|
+
color: #ffffffcc;
|
|
40
|
+
text-decoration: none;
|
|
41
|
+
font-size: 15px;
|
|
42
|
+
transition: color 0.2s;
|
|
43
|
+
}
|
|
44
|
+
nav a:hover, nav a.active { color: #61dafb; }
|
|
45
|
+
|
|
46
|
+
/* ---- Page wrapper ---- */
|
|
47
|
+
#root {
|
|
48
|
+
flex: 1;
|
|
49
|
+
padding: 40px 32px;
|
|
50
|
+
max-width: 900px;
|
|
22
51
|
width: 100%;
|
|
52
|
+
margin: 0 auto;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* ---- Footer ---- */
|
|
56
|
+
footer {
|
|
23
57
|
background-color: #282c34;
|
|
24
|
-
color:
|
|
25
|
-
padding: 20px;
|
|
58
|
+
color: #888;
|
|
26
59
|
text-align: center;
|
|
60
|
+
padding: 16px;
|
|
61
|
+
font-size: 13px;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* ---- Utility styles ---- */
|
|
65
|
+
h1 { margin-bottom: 16px; color: #282c34; }
|
|
66
|
+
h2 { margin-bottom: 12px; }
|
|
67
|
+
p { line-height: 1.6; margin-bottom: 12px; color: #555; }
|
|
68
|
+
|
|
69
|
+
.card {
|
|
70
|
+
background: white;
|
|
71
|
+
border-radius: 10px;
|
|
72
|
+
padding: 24px;
|
|
73
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
|
74
|
+
margin-bottom: 20px;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.btn {
|
|
78
|
+
display: inline-block;
|
|
79
|
+
padding: 10px 22px;
|
|
80
|
+
border: none;
|
|
81
|
+
border-radius: 8px;
|
|
82
|
+
cursor: pointer;
|
|
83
|
+
font-size: 15px;
|
|
84
|
+
transition: opacity 0.2s;
|
|
27
85
|
}
|
|
28
|
-
.main { margin-top: 60px; text-align: center; }
|
|
29
|
-
.counter-box {
|
|
30
|
-
background-color: white;
|
|
31
|
-
padding: 40px 60px;
|
|
32
|
-
border-radius: 12px;
|
|
33
|
-
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
|
34
|
-
}
|
|
35
|
-
.counter-box h2 { margin-bottom: 20px; color: #333; }
|
|
36
|
-
.count-display { font-size: 64px; font-weight: bold; color: #282c34; margin: 20px 0; }
|
|
37
|
-
.btn { padding: 12px 28px; margin: 0 8px; font-size: 24px; border: none; border-radius: 8px; cursor: pointer; transition: background-color 0.2s; }
|
|
38
|
-
.btn-plus { background-color: #61dafb; color: #282c34; }
|
|
39
|
-
.btn-minus { background-color: #ff6b6b; color: white; }
|
|
40
|
-
.btn-reset { background-color: #ccc; color: #333; font-size: 16px; padding: 12px 24px; margin-top: 20px; display: block; width: 100%; border-radius: 8px; border: none; cursor: pointer; }
|
|
41
86
|
.btn:hover { opacity: 0.85; }
|
|
42
|
-
.
|
|
87
|
+
.btn-primary { background-color: #61dafb; color: #282c34; font-weight: bold; }
|
|
88
|
+
.btn-danger { background-color: #ff6b6b; color: white; }
|
|
89
|
+
.btn-grey { background-color: #ccc; color: #333; }
|
|
90
|
+
|
|
91
|
+
/* ---- Counter (on home page) ---- */
|
|
92
|
+
.count-display {
|
|
93
|
+
font-size: 64px;
|
|
94
|
+
font-weight: bold;
|
|
95
|
+
color: #282c34;
|
|
96
|
+
margin: 16px 0;
|
|
97
|
+
text-align: center;
|
|
98
|
+
}
|
|
99
|
+
.counter-actions { display: flex; gap: 12px; justify-content: center; margin-top: 8px; }
|
|
100
|
+
|
|
101
|
+
/* ---- Form ---- */
|
|
102
|
+
form { display: flex; flex-direction: column; gap: 12px; }
|
|
103
|
+
input, textarea {
|
|
104
|
+
padding: 10px 14px;
|
|
105
|
+
border: 1px solid #ddd;
|
|
106
|
+
border-radius: 8px;
|
|
107
|
+
font-size: 15px;
|
|
108
|
+
outline: none;
|
|
109
|
+
transition: border-color 0.2s;
|
|
110
|
+
}
|
|
111
|
+
input:focus, textarea:focus { border-color: #61dafb; }
|
|
112
|
+
textarea { resize: vertical; min-height: 100px; }
|
|
113
|
+
|
|
114
|
+
/* ---- 404 ---- */
|
|
115
|
+
.not-found { text-align: center; padding: 60px 0; }
|
|
116
|
+
.not-found h1 { font-size: 80px; color: #61dafb; }
|
|
43
117
|
</style>
|
|
44
118
|
</head>
|
|
45
119
|
<body>
|
|
46
120
|
|
|
121
|
+
<!-- Navbar is always visible -->
|
|
122
|
+
<div id="navbar"></div>
|
|
123
|
+
|
|
124
|
+
<!-- Page content goes here -->
|
|
47
125
|
<div id="root"></div>
|
|
48
126
|
|
|
49
|
-
|
|
50
|
-
<
|
|
51
|
-
|
|
52
|
-
|
|
127
|
+
<!-- Footer is always visible -->
|
|
128
|
+
<div id="footer"></div>
|
|
129
|
+
|
|
130
|
+
<!-- Load core modules -->
|
|
131
|
+
<script type="text/babel" src="modules/router.js"></script>
|
|
132
|
+
<script type="text/babel" src="modules/state.js"></script>
|
|
133
|
+
<script type="text/babel" src="modules/api.js"></script>
|
|
134
|
+
|
|
135
|
+
<!-- Load API routes -->
|
|
136
|
+
<script type="text/babel" src="api/hello.js"></script>
|
|
137
|
+
<script type="text/babel" src="api/users.js"></script>
|
|
138
|
+
|
|
139
|
+
<!-- Load shared components -->
|
|
140
|
+
<script type="text/babel" src="components/Counter.jsx"></script>
|
|
141
|
+
<script type="text/babel" src="components/Footer.jsx"></script>
|
|
142
|
+
<script type="text/babel" src="components/Navbar.jsx"></script>
|
|
143
|
+
|
|
144
|
+
<!-- Load pages -->
|
|
145
|
+
<script type="text/babel" src="pages/About.jsx"></script>
|
|
146
|
+
<script type="text/babel" src="pages/ApiDemo.jsx"></script>
|
|
147
|
+
<script type="text/babel" src="pages/Contact.jsx"></script>
|
|
148
|
+
<script type="text/babel" src="pages/Home.jsx"></script>
|
|
149
|
+
<script type="text/babel" src="pages/NewPage.jsx"></script>
|
|
150
|
+
<script type="text/babel" src="pages/Test.jsx"></script>
|
|
151
|
+
|
|
152
|
+
<!-- Start the app -->
|
|
153
|
+
<script type="text/babel">
|
|
154
|
+
startApp();
|
|
155
|
+
</script>
|
|
53
156
|
|
|
54
157
|
</body>
|
|
55
158
|
</html>
|
|
@@ -1,18 +1,36 @@
|
|
|
1
1
|
/** @jsx h */
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
<h2>Counter App</h2>
|
|
8
|
-
|
|
9
|
-
<div class="count-display">{state.count}</div>
|
|
10
|
-
|
|
11
|
-
<button class="btn btn-minus" onClick={() => decrement()}>−</button>
|
|
12
|
-
<button class="btn btn-plus" onClick={() => increment()}>+</button>
|
|
3
|
+
// Register this component
|
|
4
|
+
if (window.AutoImport && window.AutoImport.registerComponent) {
|
|
5
|
+
window.AutoImport.registerComponent('Counter', Counter);
|
|
6
|
+
}
|
|
13
7
|
|
|
14
|
-
|
|
8
|
+
function Counter({ initialValue = 0 }) {
|
|
9
|
+
// Use the state management system
|
|
10
|
+
const [count, setCount] = window.StateManager ?
|
|
11
|
+
window.StateManager.useState(initialValue) : [initialValue, () => {}];
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<div class="card">
|
|
15
|
+
<h3>Counter Component</h3>
|
|
16
|
+
<p>This is a reusable counter component using the new state system.</p>
|
|
17
|
+
|
|
18
|
+
<div class="count-display">{count}</div>
|
|
19
|
+
<div class="counter-actions">
|
|
20
|
+
<button class="btn btn-primary" onClick={() => setCount(count + 1)}>
|
|
21
|
+
+
|
|
22
|
+
</button>
|
|
23
|
+
<button class="btn btn-danger" onClick={() => setCount(count - 1)}>
|
|
24
|
+
-
|
|
25
|
+
</button>
|
|
26
|
+
<button class="btn btn-grey" onClick={() => setCount(initialValue)}>
|
|
27
|
+
Reset
|
|
28
|
+
</button>
|
|
15
29
|
</div>
|
|
30
|
+
|
|
31
|
+
<p style={{ marginTop: '16px', fontSize: '14px', color: '#666' }}>
|
|
32
|
+
Component state is isolated and reactive.
|
|
33
|
+
</p>
|
|
16
34
|
</div>
|
|
17
35
|
);
|
|
18
|
-
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** @jsx h */
|
|
2
|
+
|
|
3
|
+
function Navbar() {
|
|
4
|
+
const path = getCurrentPath();
|
|
5
|
+
|
|
6
|
+
return (
|
|
7
|
+
<nav>
|
|
8
|
+
<span class="brand" onClick={() => navigate("home")}>⚡ AzizJS</span>
|
|
9
|
+
<a href="#/home" class={path === "home" ? "active" : ""}>Home</a>
|
|
10
|
+
<a href="#/about" class={path === "about" ? "active" : ""}>About</a>
|
|
11
|
+
<a href="#/contact" class={path === "contact" ? "active" : ""}>Contact</a>
|
|
12
|
+
<a href="#/test" class={path === "test" ? "active" : ""}>Test</a>
|
|
13
|
+
<a href="#/api-demo" class={path === "api-demo" ? "active" : ""}>API Demo</a>
|
|
14
|
+
</nav>
|
|
15
|
+
);
|
|
16
|
+
}
|