create-aziz-app 2.0.14 โ†’ 2.0.15

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.
@@ -1,155 +1,59 @@
1
1
  // API Route: /api/users
2
- // Next.js-style API route handler
2
+ // Next.js App Router style
3
+
4
+ const { NextResponse } = require('../modules/next-response');
3
5
 
4
- // Mock database (in production, use a real database)
5
6
  let users = [
6
7
  { id: 1, name: 'Aziz Ahmed', email: 'aziz@example.com', createdAt: new Date().toISOString() },
7
8
  { id: 2, name: 'John Doe', email: 'john@example.com', createdAt: new Date().toISOString() },
8
9
  { id: 3, name: 'Jane Smith', email: 'jane@example.com', createdAt: new Date().toISOString() }
9
10
  ];
10
11
 
11
- // Next.js-style default export
12
- export default async function handler(req, res) {
13
- const { method, query, body } = req;
14
-
15
- switch (method) {
16
- case 'GET':
17
- // GET /api/users - Get all users
18
- // GET /api/users?id=1 - Get specific user
19
- if (query.id) {
20
- const user = users.find(u => u.id === parseInt(query.id));
21
- if (!user) {
22
- return res.status(404).json({
23
- error: 'User not found',
24
- message: `No user found with id ${query.id}`
25
- });
26
- }
27
- return res.status(200).json(user);
28
- }
29
-
30
- // Return all users
31
- return res.status(200).json({
32
- users,
33
- total: users.length,
34
- timestamp: new Date().toISOString()
35
- });
36
-
37
- case 'POST':
38
- // POST /api/users - Create new user
39
- const { name, email } = body;
40
-
41
- // Validation
42
- if (!name || !email) {
43
- return res.status(400).json({
44
- error: 'Validation error',
45
- message: 'Name and email are required',
46
- fields: {
47
- name: !name ? 'Name is required' : null,
48
- email: !email ? 'Email is required' : null
49
- }
50
- });
51
- }
12
+ async function GET(request) {
13
+ const { searchParams } = new URL(request.url);
14
+ const id = searchParams.get('id');
52
15
 
53
- if (!email.includes('@')) {
54
- return res.status(400).json({
55
- error: 'Validation error',
56
- message: 'Invalid email format'
57
- });
58
- }
59
-
60
- // Check if email already exists
61
- if (users.find(u => u.email === email)) {
62
- return res.status(409).json({
63
- error: 'Conflict',
64
- message: 'User with this email already exists'
65
- });
66
- }
16
+ if (id) {
17
+ const user = users.find(u => u.id === parseInt(id));
18
+ if (!user) return NextResponse.json({ error: 'User not found' }, { status: 404 });
19
+ return NextResponse.json(user);
20
+ }
67
21
 
68
- // Create new user
69
- const newUser = {
70
- id: users.length > 0 ? Math.max(...users.map(u => u.id)) + 1 : 1,
71
- name,
72
- email,
73
- createdAt: new Date().toISOString()
74
- };
75
-
76
- users.push(newUser);
77
-
78
- return res.status(201).json({
79
- message: 'User created successfully',
80
- user: newUser
81
- });
22
+ return NextResponse.json({ users, total: users.length });
23
+ }
82
24
 
83
- case 'PUT':
84
- // PUT /api/users?id=1 - Update user
85
- const userId = query.id || body.id;
86
-
87
- if (!userId) {
88
- return res.status(400).json({
89
- error: 'Bad request',
90
- message: 'User ID is required'
91
- });
92
- }
25
+ async function POST(request) {
26
+ const { name, email } = await request.json();
93
27
 
94
- const userIndex = users.findIndex(u => u.id === parseInt(userId));
95
-
96
- if (userIndex === -1) {
97
- return res.status(404).json({
98
- error: 'User not found',
99
- message: `No user found with id ${userId}`
100
- });
101
- }
28
+ if (!name || !email) {
29
+ return NextResponse.json({ error: 'Name and email are required' }, { status: 400 });
30
+ }
102
31
 
103
- // Update user
104
- users[userIndex] = {
105
- ...users[userIndex],
106
- ...body,
107
- id: users[userIndex].id, // Prevent ID change
108
- updatedAt: new Date().toISOString()
109
- };
32
+ if (users.find(u => u.email === email)) {
33
+ return NextResponse.json({ error: 'Email already exists' }, { status: 409 });
34
+ }
110
35
 
111
- return res.status(200).json({
112
- message: 'User updated successfully',
113
- user: users[userIndex]
114
- });
36
+ const newUser = {
37
+ id: Math.max(...users.map(u => u.id)) + 1,
38
+ name, email,
39
+ createdAt: new Date().toISOString()
40
+ };
41
+ users.push(newUser);
115
42
 
116
- case 'DELETE':
117
- // DELETE /api/users?id=1 - Delete user
118
- const deleteId = query.id;
119
-
120
- if (!deleteId) {
121
- return res.status(400).json({
122
- error: 'Bad request',
123
- message: 'User ID is required'
124
- });
125
- }
43
+ return NextResponse.json({ message: 'User created', user: newUser }, { status: 201 });
44
+ }
126
45
 
127
- const deleteIndex = users.findIndex(u => u.id === parseInt(deleteId));
128
-
129
- if (deleteIndex === -1) {
130
- return res.status(404).json({
131
- error: 'User not found',
132
- message: `No user found with id ${deleteId}`
133
- });
134
- }
46
+ async function DELETE(request) {
47
+ const { searchParams } = new URL(request.url);
48
+ const id = searchParams.get('id');
135
49
 
136
- const deletedUser = users.splice(deleteIndex, 1)[0];
50
+ if (!id) return NextResponse.json({ error: 'ID required' }, { status: 400 });
137
51
 
138
- return res.status(200).json({
139
- message: 'User deleted successfully',
140
- user: deletedUser
141
- });
52
+ const idx = users.findIndex(u => u.id === parseInt(id));
53
+ if (idx === -1) return NextResponse.json({ error: 'User not found' }, { status: 404 });
142
54
 
143
- default:
144
- // Method not allowed
145
- res.setHeader('Allow', ['GET', 'POST', 'PUT', 'DELETE']);
146
- return res.status(405).json({
147
- error: 'Method not allowed',
148
- message: `Method ${method} is not allowed for this endpoint`,
149
- allowedMethods: ['GET', 'POST', 'PUT', 'DELETE']
150
- });
151
- }
55
+ const deleted = users.splice(idx, 1)[0];
56
+ return NextResponse.json({ message: 'User deleted', user: deleted });
152
57
  }
153
58
 
154
- // CommonJS export for Node.js compatibility
155
- module.exports = handler;
59
+ module.exports = { GET, POST, DELETE };
@@ -0,0 +1,45 @@
1
+ /** @jsx h */
2
+ import { h } from '/_framework/runtime.js';
3
+ import { navigate } from '/_framework/router.js';
4
+
5
+ // About page โ€” route: /about
6
+ export default function Page() {
7
+ return (
8
+ <div style={{ padding: '40px 32px', maxWidth: '900px', margin: '0 auto' }}>
9
+ <h1>About ๐Ÿ“–</h1>
10
+
11
+ <div class="card">
12
+ <h2>What is AzizApp?</h2>
13
+ <p>
14
+ A lightweight Next.js clone โ€” file-based routing, React hooks,
15
+ server-side API routes, and ES module imports. Zero dependencies.
16
+ </p>
17
+ </div>
18
+
19
+ <div class="card">
20
+ <h2>File Structure</h2>
21
+ <pre style={{ background: '#282c34', color: '#61dafb', padding: '16px', borderRadius: '8px', fontSize: '13px' }}>
22
+ {`app/
23
+ layout.js โ† root layout
24
+ page.js โ† /
25
+ about/
26
+ page.js โ† /about
27
+ blog/
28
+ [slug]/
29
+ page.js โ† /blog/:slug
30
+
31
+ api/
32
+ users.js โ† /api/users
33
+
34
+ components/
35
+ Navbar.js
36
+ Footer.js`}
37
+ </pre>
38
+ </div>
39
+
40
+ <button class="btn btn-primary" onClick={() => navigate('/')}>
41
+ โ† Back Home
42
+ </button>
43
+ </div>
44
+ );
45
+ }
@@ -0,0 +1,23 @@
1
+ /** @jsx h */
2
+ import { h } from '/_framework/runtime.js';
3
+ import Navbar from '/components/Navbar.js';
4
+ import Footer from '/components/Footer.js';
5
+
6
+ // Root layout โ€” wraps every page (like Next.js app/layout.js)
7
+ export default function Layout({ children }) {
8
+ return (
9
+ <div style={{ display: 'flex', flexDirection: 'column', minHeight: '100vh' }}>
10
+ <Navbar />
11
+ <main style={{ flex: 1 }}>
12
+ {children}
13
+ </main>
14
+ <Footer />
15
+ </div>
16
+ );
17
+ }
18
+
19
+ // Optional: export metadata
20
+ export const metadata = {
21
+ title: 'My App',
22
+ description: 'Built with AzizApp'
23
+ };
@@ -0,0 +1,54 @@
1
+ /** @jsx h */
2
+ import { h } from '/_framework/runtime.js';
3
+ import { navigate } from '/_framework/router.js';
4
+
5
+ // Home page โ€” route: /
6
+ export default function Page() {
7
+ const [count, setCount] = useState(0);
8
+
9
+ return (
10
+ <div style={{ padding: '40px 32px', maxWidth: '900px', margin: '0 auto' }}>
11
+ <h1>Welcome Home ๐Ÿ‘‹</h1>
12
+
13
+ <div class="card">
14
+ <h2>Counter</h2>
15
+ <p>useState works exactly like React!</p>
16
+ <div class="count-display">{count}</div>
17
+ <div class="counter-actions">
18
+ <button class="btn btn-danger" onClick={() => setCount(c => c - 1)}>โˆ’</button>
19
+ <button class="btn btn-primary" onClick={() => setCount(c => c + 1)}>+</button>
20
+ <button class="btn btn-grey" onClick={() => setCount(0)}>Reset</button>
21
+ </div>
22
+ </div>
23
+
24
+ <div class="card">
25
+ <h2>File-based Routing</h2>
26
+ <p>
27
+ Each <code>page.js</code> inside <code>app/</code> is a route โ€” just like Next.js.
28
+ Create <code>app/about/page.js</code> and it becomes <code>/about</code>.
29
+ </p>
30
+ <div style={{ display: 'flex', gap: '12px' }}>
31
+ <button class="btn btn-primary" onClick={() => navigate('/about')}>
32
+ Go to About โ†’
33
+ </button>
34
+ <button class="btn btn-primary" onClick={() => navigate('/test')}>
35
+ Go to Test โ†’
36
+ </button>
37
+ </div>
38
+ </div>
39
+
40
+ <div class="card">
41
+ <h2>Import Anything</h2>
42
+ <p>
43
+ Use <code>import</code> statements just like Next.js.
44
+ The dev server resolves bare imports from <code>node_modules</code>.
45
+ </p>
46
+ <pre style={{ background: '#282c34', color: '#61dafb', padding: '16px', borderRadius: '8px', overflow: 'auto', fontSize: '13px' }}>
47
+ {`import mongoose from 'mongoose';
48
+ import connectDB from '@/lib/db';
49
+ import User from '@/models/User';`}
50
+ </pre>
51
+ </div>
52
+ </div>
53
+ );
54
+ }
@@ -0,0 +1,55 @@
1
+ /** @jsx h */
2
+ import { h } from '/_framework/runtime.js';
3
+
4
+ // Test page โ€” route: /test
5
+ export default function Page() {
6
+ const [count, setCount] = useState(0);
7
+ const [name, setName] = useState('');
8
+ const [email, setEmail] = useState('');
9
+
10
+ const handleSubmit = (e) => {
11
+ e.preventDefault();
12
+ alert(`Name: ${name}\nEmail: ${email}\nCount: ${count}`);
13
+ };
14
+
15
+ return (
16
+ <div style={{ padding: '40px 32px', maxWidth: '900px', margin: '0 auto' }}>
17
+ <h1>Test Page ๐Ÿงช</h1>
18
+
19
+ <div class="card">
20
+ <h2>useState</h2>
21
+ <div class="count-display">{count}</div>
22
+ <div class="counter-actions">
23
+ <button class="btn btn-primary" onClick={() => setCount(c => c + 1)}>+</button>
24
+ <button class="btn btn-danger" onClick={() => setCount(0)}>Reset</button>
25
+ </div>
26
+ </div>
27
+
28
+ <div class="card">
29
+ <h2>Form</h2>
30
+ <form onSubmit={handleSubmit}>
31
+ <input
32
+ type="text"
33
+ value={name}
34
+ onInput={(e) => setName(e.target.value)}
35
+ placeholder="Your name"
36
+ />
37
+ <input
38
+ type="email"
39
+ value={email}
40
+ onInput={(e) => setEmail(e.target.value)}
41
+ placeholder="Your email"
42
+ />
43
+ <button type="submit" class="btn btn-primary">Submit</button>
44
+ </form>
45
+ </div>
46
+
47
+ <div class="card">
48
+ <h2>State</h2>
49
+ <p>Name: <strong>{name || 'โ€”'}</strong></p>
50
+ <p>Email: <strong>{email || 'โ€”'}</strong></p>
51
+ <p>Count: <strong>{count}</strong></p>
52
+ </div>
53
+ </div>
54
+ );
55
+ }
@@ -0,0 +1,10 @@
1
+ /** @jsx h */
2
+ import { h } from '/_framework/runtime.js';
3
+
4
+ export default function Footer() {
5
+ return (
6
+ <footer>
7
+ <p>Made with โšก AzizApp</p>
8
+ </footer>
9
+ );
10
+ }
@@ -0,0 +1,30 @@
1
+ /** @jsx h */
2
+ import { h } from '/_framework/runtime.js';
3
+ import { navigate, useRouter } from '/_framework/router.js';
4
+
5
+ export default function Navbar() {
6
+ const { pathname } = useRouter();
7
+
8
+ const links = [
9
+ { href: '/', label: 'Home' },
10
+ { href: '/about', label: 'About' },
11
+ { href: '/test', label: 'Test' },
12
+ { href: '/api-demo', label: 'API Demo' },
13
+ { href: '/contact', label: 'Contact' },
14
+ ];
15
+
16
+ return (
17
+ <nav>
18
+ <span class="brand" onClick={() => navigate('/')}>โšก AzizApp</span>
19
+ {links.map(({ href, label }) =>
20
+ <a
21
+ href={href}
22
+ class={pathname === href ? 'active' : ''}
23
+ onClick={(e) => { e.preventDefault(); navigate(href); }}
24
+ >
25
+ {label}
26
+ </a>
27
+ )}
28
+ </nav>
29
+ );
30
+ }
@@ -0,0 +1,24 @@
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
+ <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
7
+ <title>My App</title>
8
+
9
+ <!-- Global Styles -->
10
+ <link rel="stylesheet" href="/styles/globals.css">
11
+
12
+ <!-- Babel for JSX (loaded before modules) -->
13
+ <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
14
+ </head>
15
+ <body>
16
+ <div id="root"></div>
17
+
18
+ <!-- Boot the framework -->
19
+ <script type="module" src="/_framework/boot.js"></script>
20
+
21
+ <!-- Live Reload (dev only) -->
22
+ <script src="/scripts/live-reload-client.js"></script>
23
+ </body>
24
+ </html>
@@ -1,18 +1,12 @@
1
1
  {
2
2
  "name": "aziz-app",
3
3
  "version": "1.0.2",
4
- "description": "A simple, clean React-like framework with state management, routing, and API routes",
5
- "main": "app.html",
4
+ "description": "Lightweight Next.js clone โ€” file-based routing, React hooks, ES module imports",
5
+ "main": "index.html",
6
6
  "scripts": {
7
- "dev": "node scripts/dev-server.js",
8
- "build": "node scripts/generate-imports.js"
7
+ "dev": "node scripts/dev-server.js"
9
8
  },
10
- "keywords": [
11
- "react",
12
- "framework",
13
- "routing",
14
- "state-management"
15
- ],
9
+ "keywords": ["nextjs", "react", "framework", "routing", "lightweight"],
16
10
  "author": "",
17
11
  "license": "ISC"
18
12
  }