create-aziz-app 1.0.3 → 2.0.2

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.
@@ -0,0 +1,209 @@
1
+ /** @jsx h */
2
+
3
+ // Register this page at route "api-demo" → "#/api-demo"
4
+ registerPage("api-demo", ApiDemoPage);
5
+
6
+ function ApiDemoPage() {
7
+ const [users, setUsers] = useState([]);
8
+ const [loading, setLoading] = useState(false);
9
+ const [message, setMessage] = useState('');
10
+ const [newUserName, setNewUserName] = useState('');
11
+ const [newUserEmail, setNewUserEmail] = useState('');
12
+
13
+ // Fetch users from API
14
+ const fetchUsers = async () => {
15
+ setLoading(true);
16
+ try {
17
+ const response = await fetchApi('/api/users');
18
+ const data = await response.json();
19
+ setUsers(data);
20
+ setMessage('Users loaded successfully!');
21
+ } catch (error) {
22
+ setMessage('Error loading users: ' + error.message);
23
+ }
24
+ setLoading(false);
25
+ };
26
+
27
+ // Test hello API
28
+ const testHelloApi = async () => {
29
+ try {
30
+ const response = await fetchApi('/api/hello?name=Aziz');
31
+ const data = await response.json();
32
+ setMessage(data.message);
33
+ } catch (error) {
34
+ setMessage('Error: ' + error.message);
35
+ }
36
+ };
37
+
38
+ // Add new user
39
+ const addUser = async (e) => {
40
+ e.preventDefault();
41
+ if (!newUserName || !newUserEmail) {
42
+ setMessage('Please fill in all fields');
43
+ return;
44
+ }
45
+
46
+ setLoading(true);
47
+ try {
48
+ const response = await fetchApi('/api/users', {
49
+ method: 'POST',
50
+ body: JSON.stringify({
51
+ name: newUserName,
52
+ email: newUserEmail
53
+ })
54
+ });
55
+ const data = await response.json();
56
+ setMessage(`User added: ${data.name}`);
57
+ setNewUserName('');
58
+ setNewUserEmail('');
59
+ // Refresh users list
60
+ fetchUsers();
61
+ } catch (error) {
62
+ setMessage('Error adding user: ' + error.message);
63
+ }
64
+ setLoading(false);
65
+ };
66
+
67
+ // Delete user
68
+ const deleteUser = async (userId) => {
69
+ setLoading(true);
70
+ try {
71
+ const response = await fetchApi(`/api/users?id=${userId}`, {
72
+ method: 'DELETE'
73
+ });
74
+ const data = await response.json();
75
+ setMessage(data.message);
76
+ // Refresh users list
77
+ fetchUsers();
78
+ } catch (error) {
79
+ setMessage('Error deleting user: ' + error.message);
80
+ }
81
+ setLoading(false);
82
+ };
83
+
84
+ return (
85
+ <div>
86
+ <h1>API Routes Demo šŸš€</h1>
87
+
88
+ <div class="card">
89
+ <h2>Test API Endpoints</h2>
90
+ <p>This demonstrates the Next.js-like API route system.</p>
91
+
92
+ <div style={{ display: 'flex', gap: '12px', marginBottom: '16px' }}>
93
+ <button class="btn btn-primary" onClick={testHelloApi}>
94
+ Test /api/hello
95
+ </button>
96
+ <button class="btn btn-primary" onClick={fetchUsers}>
97
+ Fetch Users
98
+ </button>
99
+ </div>
100
+
101
+ {message && (
102
+ <div style={{
103
+ padding: '12px',
104
+ background: '#e3f2fd',
105
+ borderRadius: '8px',
106
+ marginTop: '12px',
107
+ color: '#1976d2'
108
+ }}>
109
+ {message}
110
+ </div>
111
+ )}
112
+ </div>
113
+
114
+ <div class="card">
115
+ <h2>Add New User</h2>
116
+ <form onSubmit={addUser}>
117
+ <div>
118
+ <label>Name:</label>
119
+ <input
120
+ type="text"
121
+ value={newUserName}
122
+ onInput={(e) => setNewUserName(e.target.value)}
123
+ placeholder="Enter name"
124
+ />
125
+ </div>
126
+
127
+ <div>
128
+ <label>Email:</label>
129
+ <input
130
+ type="email"
131
+ value={newUserEmail}
132
+ onInput={(e) => setNewUserEmail(e.target.value)}
133
+ placeholder="Enter email"
134
+ />
135
+ </div>
136
+
137
+ <button type="submit" class="btn btn-primary" disabled={loading}>
138
+ {loading ? 'Adding...' : 'Add User'}
139
+ </button>
140
+ </form>
141
+ </div>
142
+
143
+ <div class="card">
144
+ <h2>Users List</h2>
145
+ {loading && <p>Loading...</p>}
146
+
147
+ {users.length === 0 && !loading && (
148
+ <p>No users loaded. Click "Fetch Users" to load data.</p>
149
+ )}
150
+
151
+ {users.length > 0 && (
152
+ <div>
153
+ {users.map(user => (
154
+ <div style={{
155
+ padding: '12px',
156
+ background: '#f5f5f5',
157
+ borderRadius: '8px',
158
+ marginBottom: '8px',
159
+ display: 'flex',
160
+ justifyContent: 'space-between',
161
+ alignItems: 'center'
162
+ }}>
163
+ <div>
164
+ <strong>{user.name}</strong>
165
+ <br />
166
+ <span style={{ fontSize: '14px', color: '#666' }}>
167
+ {user.email}
168
+ </span>
169
+ </div>
170
+ <button
171
+ class="btn btn-danger"
172
+ onClick={() => deleteUser(user.id)}
173
+ disabled={loading}
174
+ >
175
+ Delete
176
+ </button>
177
+ </div>
178
+ ))}
179
+ </div>
180
+ )}
181
+ </div>
182
+
183
+ <div class="card">
184
+ <h2>How to Use API Routes</h2>
185
+ <p>Create API routes in the <code>api/</code> folder:</p>
186
+ <pre style={{
187
+ background: '#282c34',
188
+ color: '#61dafb',
189
+ padding: '16px',
190
+ borderRadius: '8px',
191
+ overflow: 'auto'
192
+ }}>
193
+ {`// api/myroute.js
194
+ registerApiRoute('myroute', async (req, res) => {
195
+ if (req.method === 'GET') {
196
+ return res.status(200).json({
197
+ message: 'Hello!'
198
+ });
199
+ }
200
+ });
201
+
202
+ // Use in components
203
+ const response = await fetchApi('/api/myroute');
204
+ const data = await response.json();`}
205
+ </pre>
206
+ </div>
207
+ </div>
208
+ );
209
+ }
@@ -0,0 +1,27 @@
1
+ /** @jsx h */
2
+
3
+ // Register this page at route "contact" → "#/contact"
4
+ registerPage("contact", ContactPage);
5
+
6
+ function ContactPage() {
7
+ return (
8
+ <div>
9
+ <h1>Contact šŸ“¬</h1>
10
+
11
+ <div class="card">
12
+ <h2>Get in touch</h2>
13
+ <p>Fill out the form below and we'll get back to you.</p>
14
+
15
+ <form onSubmit={(e) => {
16
+ e.preventDefault();
17
+ alert("Message sent! (wire this up to a backend)");
18
+ }}>
19
+ <input type="text" placeholder="Your name" required />
20
+ <input type="email" placeholder="Your email" required />
21
+ <textarea placeholder="Your message" required></textarea>
22
+ <button type="submit" class="btn btn-primary">Send Message</button>
23
+ </form>
24
+ </div>
25
+ </div>
26
+ );
27
+ }
@@ -0,0 +1,39 @@
1
+ /** @jsx h */
2
+
3
+ // Register this page at route "home" → "#/"
4
+ registerPage("home", HomePage);
5
+
6
+ function HomePage() {
7
+ return (
8
+ <div>
9
+ <h1>Welcome Home šŸ‘‹</h1>
10
+
11
+ <div class="card">
12
+ <h2>Global State Counter</h2>
13
+ <p>This uses the global state. Click the buttons to update it.</p>
14
+
15
+ <div class="count-display">{state.count}</div>
16
+
17
+ <div class="counter-actions">
18
+ <button class="btn btn-danger" onClick={() => setState({ count: state.count - 1 })}>āˆ’</button>
19
+ <button class="btn btn-primary" onClick={() => setState({ count: state.count + 1 })}>+</button>
20
+ <button class="btn btn-grey" onClick={() => setState({ count: 0 })}>Reset</button>
21
+ </div>
22
+ </div>
23
+
24
+ <div class="card">
25
+ <h2>File-based Routing</h2>
26
+ <p>
27
+ Each file in <strong>pages/</strong> is a route — just like Next.js.
28
+ Add a new file, register it in app.js, and it's a new page.
29
+ </p>
30
+ <button class="btn btn-primary" onClick={() => navigate("test")}>
31
+ Go to Test Page →
32
+ </button>
33
+ <button class="btn btn-primary" onClick={() => navigate("about")}>
34
+ Go to About →
35
+ </button>
36
+ </div>
37
+ </div>
38
+ );
39
+ }
@@ -0,0 +1,39 @@
1
+ /** @jsx h */
2
+
3
+ // Register this page at route "home" → "#/"
4
+ registerPage("NewPage", NewPage);
5
+
6
+ function NewPage() {
7
+ return (
8
+ <div>
9
+ <h1>Welcome Home šŸ‘‹</h1>
10
+
11
+ <div class="card">
12
+ <h2>Global State Counter</h2>
13
+ <p>This uses the global state. Click the buttons to update it.</p>
14
+
15
+ <div class="count-display">{state.count}</div>
16
+
17
+ <div class="counter-actions">
18
+ <button class="btn btn-danger" onClick={() => setState({ count: state.count - 1 })}>āˆ’</button>
19
+ <button class="btn btn-primary" onClick={() => setState({ count: state.count + 1 })}>+</button>
20
+ <button class="btn btn-grey" onClick={() => setState({ count: 0 })}>Reset</button>
21
+ </div>
22
+ </div>
23
+
24
+ <div class="card">
25
+ <h2>File-based Routing</h2>
26
+ <p>
27
+ Each file in <strong>pages/</strong> is a route — just like Next.js.
28
+ Add a new file, register it in app.js, and it's a new page.
29
+ </p>
30
+ <button class="btn btn-primary" onClick={() => navigate("test")}>
31
+ Go to Test Page →
32
+ </button>
33
+ <button class="btn btn-primary" onClick={() => navigate("about")}>
34
+ Go to About →
35
+ </button>
36
+ </div>
37
+ </div>
38
+ );
39
+ }
@@ -0,0 +1,74 @@
1
+ /** @jsx h */
2
+
3
+ // Register this page at route "test" → "#/test"
4
+ registerPage("test", TestPage);
5
+
6
+ function TestPage() {
7
+ const [count, setCount] = useState(0);
8
+ const [name, setName] = useState('');
9
+ const [email, setEmail] = useState('');
10
+
11
+ const handleSubmit = (e) => {
12
+ e.preventDefault();
13
+ alert(`Form submitted!\nName: ${name}\nEmail: ${email}\nCount: ${count}`);
14
+ };
15
+
16
+ return (
17
+ <div>
18
+ <h1>Test Page 🧪</h1>
19
+
20
+ <div class="card">
21
+ <h2>Counter Example</h2>
22
+ <p>This demonstrates the new state management system.</p>
23
+
24
+ <div class="count-display">{count}</div>
25
+ <div class="counter-actions">
26
+ <button class="btn btn-primary" onClick={() => setCount(count + 1)}>
27
+ Increment
28
+ </button>
29
+ <button class="btn btn-danger" onClick={() => setCount(0)}>
30
+ Reset
31
+ </button>
32
+ </div>
33
+ </div>
34
+
35
+ <div class="card">
36
+ <h2>Form Example</h2>
37
+ <p>Try the form with state management.</p>
38
+
39
+ <form onSubmit={handleSubmit}>
40
+ <div>
41
+ <label>Email:</label>
42
+ <input
43
+ type="email"
44
+ value={email}
45
+ onInput={(e) => setEmail(e.target.value)}
46
+ placeholder="Enter your email"
47
+ />
48
+ </div>
49
+ <div>
50
+ <label>Name:</label>
51
+ <input
52
+ type="text"
53
+ value={name}
54
+ onInput={(e) => setName(e.target.value)}
55
+ placeholder="Enter your name"
56
+ />
57
+ </div>
58
+
59
+
60
+ <button type="submit" class="btn btn-primary">
61
+ Submit Form
62
+ </button>
63
+ </form>
64
+ </div>
65
+
66
+ <div class="card">
67
+ <h2>State Information</h2>
68
+ <p>Current count: <strong>{count}</strong></p>
69
+ <p>Current name: <strong>{name || 'Not set'}</strong></p>
70
+ <p>Current email: <strong>{email || 'Not set'}</strong></p>
71
+ </div>
72
+ </div>
73
+ );
74
+ }
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ console.log('šŸ” Scanning for pages, components, and API routes...\n');
7
+
8
+ // Scan a directory for files
9
+ function scanDirectory(dir, extensions = []) {
10
+ const files = [];
11
+
12
+ if (!fs.existsSync(dir)) {
13
+ return files;
14
+ }
15
+
16
+ const items = fs.readdirSync(dir);
17
+
18
+ for (const item of items) {
19
+ const fullPath = path.join(dir, item);
20
+ const stat = fs.statSync(fullPath);
21
+
22
+ if (stat.isFile()) {
23
+ const ext = path.extname(item);
24
+ if (extensions.length === 0 || extensions.includes(ext)) {
25
+ files.push(path.relative('.', fullPath).replace(/\\/g, '/'));
26
+ }
27
+ }
28
+ }
29
+
30
+ return files;
31
+ }
32
+
33
+ // Scan for files
34
+ const apiRoutes = scanDirectory('api', ['.js']);
35
+ const components = scanDirectory('components', ['.jsx', '.js']);
36
+ const pages = scanDirectory('pages', ['.jsx', '.js']);
37
+
38
+ console.log(`šŸ“” Found ${apiRoutes.length} API routes`);
39
+ console.log(`🧩 Found ${components.length} components`);
40
+ console.log(`šŸ“„ Found ${pages.length} pages\n`);
41
+
42
+ // Generate app.config.js
43
+ const configContent = `// ============================================================
44
+ // APP CONFIGURATION (AUTO-GENERATED)
45
+ // This file is automatically generated by build.js
46
+ // Run: node build.js to regenerate
47
+ // ============================================================
48
+
49
+ window.APP_CONFIG = {
50
+ apiRoutes: ${JSON.stringify(apiRoutes, null, 8).replace(/\n/g, '\n ')},
51
+
52
+ components: ${JSON.stringify(components, null, 8).replace(/\n/g, '\n ')},
53
+
54
+ pages: ${JSON.stringify(pages, null, 8).replace(/\n/g, '\n ')}
55
+ };
56
+ `;
57
+
58
+ fs.writeFileSync('app.config.js', configContent);
59
+ console.log('āœ… Generated app.config.js\n');
60
+
61
+ // Generate script tags for app.html
62
+ const scriptTags = [];
63
+
64
+ // Add API routes
65
+ apiRoutes.forEach(route => {
66
+ scriptTags.push(` <script type="text/babel" src="${route}"></script>`);
67
+ });
68
+
69
+ // Add components
70
+ components.forEach(component => {
71
+ scriptTags.push(` <script type="text/babel" src="${component}"></script>`);
72
+ });
73
+
74
+ // Add pages
75
+ pages.forEach(page => {
76
+ scriptTags.push(` <script type="text/babel" src="${page}"></script>`);
77
+ });
78
+
79
+ console.log('šŸ“‹ Copy these script tags to app.html:\n');
80
+ console.log(scriptTags.join('\n'));
81
+ console.log('\n✨ Done! Refresh your browser to see changes.');
@@ -0,0 +1,172 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const http = require('http');
6
+ const { exec } = require('child_process');
7
+
8
+ const PORT = process.env.PORT || 3000;
9
+ const clients = []; // Store SSE clients for live reload
10
+
11
+ console.log('šŸš€ Dev server starting...\n');
12
+
13
+ // Function to generate imports
14
+ function generateImports() {
15
+ console.log('šŸ”„ Regenerating imports...');
16
+ exec('node scripts/generate-imports.js', (error, stdout, stderr) => {
17
+ if (error) {
18
+ console.error('āŒ Error:', error);
19
+ return;
20
+ }
21
+ console.log(stdout);
22
+ // Notify all connected clients to reload
23
+ notifyClients();
24
+ });
25
+ }
26
+
27
+ // Notify all clients to reload
28
+ function notifyClients() {
29
+ console.log('šŸ”„ Notifying browser to reload...');
30
+ clients.forEach(client => {
31
+ client.write('data: reload\n\n');
32
+ });
33
+ }
34
+
35
+ // Live reload script to inject
36
+ const liveReloadScript = `
37
+ <script>
38
+ // Live reload client
39
+ const evtSource = new EventSource('/live-reload');
40
+ evtSource.onmessage = (event) => {
41
+ if (event.data === 'reload') {
42
+ console.log('šŸ”„ Changes detected, reloading...');
43
+ location.reload();
44
+ }
45
+ };
46
+ evtSource.onerror = () => {
47
+ console.log('āš ļø Live reload disconnected');
48
+ };
49
+ console.log('āœ… Live reload connected');
50
+ </script>
51
+ `;
52
+
53
+ // Create HTTP server
54
+ function createServer(port) {
55
+ return http.createServer((req, res) => {
56
+ // Handle live reload SSE endpoint
57
+ if (req.url === '/live-reload') {
58
+ res.writeHead(200, {
59
+ 'Content-Type': 'text/event-stream',
60
+ 'Cache-Control': 'no-cache',
61
+ 'Connection': 'keep-alive',
62
+ 'Access-Control-Allow-Origin': '*'
63
+ });
64
+
65
+ clients.push(res);
66
+ console.log('šŸ”Œ Browser connected for live reload');
67
+
68
+ req.on('close', () => {
69
+ const index = clients.indexOf(res);
70
+ if (index !== -1) {
71
+ clients.splice(index, 1);
72
+ }
73
+ console.log('šŸ”Œ Browser disconnected from live reload');
74
+ });
75
+
76
+ return;
77
+ }
78
+
79
+ let filePath = '.' + req.url;
80
+ if (filePath === './') {
81
+ filePath = './app.html';
82
+ }
83
+
84
+ const extname = String(path.extname(filePath)).toLowerCase();
85
+ const mimeTypes = {
86
+ '.html': 'text/html',
87
+ '.js': 'text/javascript',
88
+ '.jsx': 'text/javascript',
89
+ '.css': 'text/css',
90
+ '.json': 'application/json',
91
+ '.png': 'image/png',
92
+ '.jpg': 'image/jpg',
93
+ '.gif': 'image/gif',
94
+ '.svg': 'image/svg+xml',
95
+ '.wav': 'audio/wav',
96
+ '.mp4': 'video/mp4',
97
+ '.woff': 'application/font-woff',
98
+ '.ttf': 'application/font-ttf',
99
+ '.eot': 'application/vnd.ms-fontobject',
100
+ '.otf': 'application/font-otf',
101
+ '.wasm': 'application/wasm'
102
+ };
103
+
104
+ const contentType = mimeTypes[extname] || 'application/octet-stream';
105
+
106
+ fs.readFile(filePath, (error, content) => {
107
+ if (error) {
108
+ if (error.code === 'ENOENT') {
109
+ res.writeHead(404, { 'Content-Type': 'text/html' });
110
+ res.end('<h1>404 - File Not Found</h1>', 'utf-8');
111
+ } else {
112
+ res.writeHead(500);
113
+ res.end('Server Error: ' + error.code, 'utf-8');
114
+ }
115
+ } else {
116
+ // Inject live reload script into HTML files
117
+ if (extname === '.html') {
118
+ content = content.toString().replace('</body>', liveReloadScript + '</body>');
119
+ }
120
+
121
+ res.writeHead(200, { 'Content-Type': contentType });
122
+ res.end(content, 'utf-8');
123
+ }
124
+ });
125
+ });
126
+ }
127
+
128
+ // Function to start server on available port
129
+ function startServer(port) {
130
+ const server = createServer(port);
131
+
132
+ server.listen(port, () => {
133
+ console.log(`🌐 Server running at http://localhost:${port}/`);
134
+ console.log(`šŸ“± Open http://localhost:${port}/ in your browser\n`);
135
+ }).on('error', (err) => {
136
+ if (err.code === 'EADDRINUSE') {
137
+ console.log(`āš ļø Port ${port} is busy, trying ${port + 1}...`);
138
+ startServer(port + 1);
139
+ } else {
140
+ console.error('āŒ Server error:', err);
141
+ }
142
+ });
143
+ }
144
+
145
+ // Watch directories
146
+ const watchDirs = ['api', 'components', 'pages', 'modules'];
147
+
148
+ console.log('šŸ‘€ Watching for changes in:');
149
+ watchDirs.forEach(dir => {
150
+ if (fs.existsSync(dir)) {
151
+ console.log(` - ${dir}/`);
152
+ fs.watch(dir, { recursive: false }, (eventType, filename) => {
153
+ if (filename && (filename.endsWith('.js') || filename.endsWith('.jsx'))) {
154
+ console.log(`\nšŸ“ Detected change: ${dir}/${filename}`);
155
+ generateImports();
156
+ }
157
+ });
158
+ }
159
+ });
160
+
161
+ console.log('\nāœ… Dev server running with live reload!');
162
+ console.log('šŸ’” Create/modify files and browser will auto-refresh');
163
+ console.log('ā¹ļø Press Ctrl+C to stop\n');
164
+
165
+ // Start server
166
+ startServer(PORT);
167
+
168
+ // Generate imports on startup
169
+ generateImports();
170
+
171
+ // Keep the process running
172
+ process.stdin.resume();