create-aziz-app 2.0.15 → 3.0.0

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.
Files changed (56) hide show
  1. package/README.md +3 -3
  2. package/bin/create-aziz-app.js +9 -9
  3. package/package.json +10 -11
  4. package/template/README.md +5 -5
  5. package/template/_framework/boot.js +3 -3
  6. package/template/_framework/hooks.js +1 -1
  7. package/template/{modules → _framework}/next-response.js +5 -13
  8. package/template/_framework/router.js +1 -1
  9. package/template/_framework/runtime.js +1 -1
  10. package/template/api/createUser.js +1 -1
  11. package/template/api/hello.js +1 -1
  12. package/template/api/loginUser.js +1 -1
  13. package/template/api/users.js +1 -1
  14. package/template/app/about/page.js +1 -1
  15. package/template/app/layout.js +1 -1
  16. package/template/components/Footer.js +1 -1
  17. package/template/components/Navbar.js +1 -1
  18. package/template/package.json +4 -7
  19. package/template/scripts/dev-server.js +1 -1
  20. package/template/.vscode/settings.json +0 -15
  21. package/template/api/getUser.js +0 -60
  22. package/template/api/getUserWithDB.js +0 -65
  23. package/template/app.config.js +0 -41
  24. package/template/app.html +0 -55
  25. package/template/components/Counter.jsx +0 -36
  26. package/template/components/Footer.jsx +0 -9
  27. package/template/components/Navbar.jsx +0 -17
  28. package/template/docs/API-GUIDE.md +0 -196
  29. package/template/docs/API-ROUTES.md +0 -538
  30. package/template/docs/AUTO-IMPORT.md +0 -99
  31. package/template/docs/AUTO-REGISTRATION.md +0 -248
  32. package/template/docs/CSS-FRAMEWORKS.md +0 -221
  33. package/template/docs/DEV-SERVER.md +0 -184
  34. package/template/docs/GETTING-STARTED.md +0 -205
  35. package/template/docs/HOW-IT-WORKS.md +0 -362
  36. package/template/docs/NEXTJS-APP-ROUTER.md +0 -536
  37. package/template/docs/NEXTJS-COMPARISON.md +0 -473
  38. package/template/docs/QUICK-START.md +0 -111
  39. package/template/docs/STYLING.md +0 -269
  40. package/template/docs/TROUBLESHOOTING.md +0 -282
  41. package/template/modules/README.md +0 -129
  42. package/template/modules/api.js +0 -44
  43. package/template/modules/auto-import.js +0 -130
  44. package/template/modules/router.js +0 -218
  45. package/template/modules/state.js +0 -248
  46. package/template/package-lock.json +0 -13
  47. package/template/pages/About.jsx +0 -48
  48. package/template/pages/ApiDemo.jsx +0 -209
  49. package/template/pages/Contact.jsx +0 -25
  50. package/template/pages/Example.jsx +0 -59
  51. package/template/pages/Home.jsx +0 -39
  52. package/template/pages/HooksDemo.jsx +0 -194
  53. package/template/pages/test.jsx +0 -72
  54. package/template/scripts/build.js +0 -81
  55. package/template/scripts/generate-imports.js +0 -88
  56. package/template/tailwind.config.js +0 -17
@@ -1,130 +0,0 @@
1
- /** @jsx h */
2
-
3
- // ============================================================
4
- // AUTO-IMPORT SYSTEM
5
- // Automatically discovers and loads all components, pages, and API routes
6
- // ============================================================
7
-
8
- // Track loaded scripts
9
- const loadedScripts = new Set();
10
- let scriptsToLoad = 0;
11
- let scriptsLoaded = 0;
12
-
13
- // Get configuration from app.config.js
14
- function getConfig() {
15
- return window.APP_CONFIG || {
16
- apiRoutes: [],
17
- components: [],
18
- pages: []
19
- };
20
- }
21
-
22
- // Load a script dynamically
23
- function loadScript(src) {
24
- return new Promise((resolve, reject) => {
25
- if (loadedScripts.has(src)) {
26
- resolve();
27
- return;
28
- }
29
-
30
- const script = document.createElement('script');
31
- script.type = 'text/babel';
32
- script.src = src;
33
-
34
- script.onload = () => {
35
- loadedScripts.add(src);
36
- scriptsLoaded++;
37
- console.log(`✓ Loaded: ${src} (${scriptsLoaded}/${scriptsToLoad})`);
38
- resolve();
39
- };
40
-
41
- script.onerror = () => {
42
- console.error(`✗ Failed to load: ${src}`);
43
- scriptsLoaded++;
44
- reject(new Error(`Failed to load ${src}`));
45
- };
46
-
47
- document.body.appendChild(script);
48
- });
49
- }
50
-
51
- // Load all scripts in order
52
- async function autoLoadScripts() {
53
- console.log('🚀 Auto-import starting...');
54
-
55
- const config = getConfig();
56
-
57
- // Calculate total scripts to load
58
- scriptsToLoad =
59
- config.apiRoutes.length +
60
- config.components.length +
61
- config.pages.length;
62
-
63
- if (scriptsToLoad === 0) {
64
- console.warn('⚠️ No files configured in app.config.js');
65
- if (typeof startApp === 'function') {
66
- startApp();
67
- }
68
- return;
69
- }
70
-
71
- try {
72
- // Load API routes first
73
- if (config.apiRoutes.length > 0) {
74
- console.log('📡 Loading API routes...');
75
- for (const route of config.apiRoutes) {
76
- await loadScript(route);
77
- }
78
- }
79
-
80
- // Load components
81
- if (config.components.length > 0) {
82
- console.log('🧩 Loading components...');
83
- for (const component of config.components) {
84
- await loadScript(component);
85
- }
86
- }
87
-
88
- // Load pages
89
- if (config.pages.length > 0) {
90
- console.log('📄 Loading pages...');
91
- for (const page of config.pages) {
92
- await loadScript(page);
93
- }
94
- }
95
-
96
- console.log('✅ Auto-import complete!');
97
-
98
- // Start the app after everything is loaded
99
- if (typeof startApp === 'function') {
100
- console.log('🎉 Starting app...');
101
- startApp();
102
- } else {
103
- console.error('❌ startApp function not found!');
104
- }
105
-
106
- } catch (error) {
107
- console.error('❌ Auto-import failed:', error);
108
- }
109
- }
110
-
111
- // Export to global scope
112
- window.autoLoadScripts = autoLoadScripts;
113
-
114
- // Start auto-loading when this script loads
115
- function startAutoImport() {
116
- // Small delay to ensure config is loaded
117
- if (!window.APP_CONFIG) {
118
- console.warn('⚠️ APP_CONFIG not found, retrying...');
119
- setTimeout(startAutoImport, 50);
120
- return;
121
- }
122
-
123
- if (document.readyState === 'loading') {
124
- document.addEventListener('DOMContentLoaded', autoLoadScripts);
125
- } else {
126
- autoLoadScripts();
127
- }
128
- }
129
-
130
- startAutoImport();
@@ -1,218 +0,0 @@
1
- /** @jsx h */
2
-
3
- // ============================================================
4
- // h() — our createElement
5
- // Babel compiles <div class="x"> → h("div", { class: "x" })
6
- // This builds a real DOM element from that
7
- // ============================================================
8
- function h(tag, props, ...children) {
9
- // If it's a component function, call it with its props
10
- if (typeof tag === "function") {
11
- return tag({ ...props, children });
12
- }
13
-
14
- const el = document.createElement(tag);
15
-
16
- if (props) {
17
- for (let key in props) {
18
- if (key === "children") continue;
19
-
20
- if (key.startsWith("on")) {
21
- // onClick → "click" event listener
22
- el.addEventListener(key.slice(2).toLowerCase(), props[key]);
23
- } else if (key === "className") {
24
- el.className = props[key];
25
- } else if (key === "style" && typeof props[key] === "object") {
26
- Object.assign(el.style, props[key]);
27
- } else if (key === "value" && (tag === "input" || tag === "textarea")) {
28
- // Set value property directly for inputs/textareas
29
- el.value = props[key];
30
- } else {
31
- el.setAttribute(key, props[key]);
32
- }
33
- }
34
- }
35
-
36
- // Flatten and append children
37
- const flat = children.flat(Infinity);
38
- for (let child of flat) {
39
- if (child === null || child === undefined || child === false) continue;
40
- if (typeof child === "string" || typeof child === "number") {
41
- el.appendChild(document.createTextNode(child));
42
- } else if (child instanceof Node) {
43
- el.appendChild(child);
44
- }
45
- }
46
-
47
- return el;
48
- }
49
-
50
-
51
- // ============================================================
52
- // ROUTER
53
- // File-based routing using the URL hash
54
- // "#/" → Home page
55
- // "#/about" → About page
56
- // "#/contact" → Contact page
57
- //
58
- // To add a new page:
59
- // 1. Create pages/YourPage.jsx with a function like AboutPage()
60
- // 2. The page will automatically be registered!
61
- // 3. Optional: Call registerPage("about", AboutPage) for custom route names
62
- // ============================================================
63
- const routes = {};
64
-
65
- // registerPage("about", AboutPage) — called by each page file
66
- // Now optional! Pages auto-register based on function name
67
- function registerPage(path, component) {
68
- routes[path] = component;
69
- }
70
-
71
- // Auto-register pages from global scope
72
- // Looks for functions ending with "Page" (e.g., AboutPage, HomePage)
73
- function autoRegisterPages() {
74
- for (let key in window) {
75
- if (key.endsWith('Page') && typeof window[key] === 'function') {
76
- // Convert "AboutPage" → "about", "HomePage" → "home"
77
- const routeName = key.replace('Page', '').toLowerCase();
78
-
79
- // Only register if not already registered
80
- if (!routes[routeName]) {
81
- routes[routeName] = window[key];
82
- console.log(`📄 Auto-registered: ${routeName} → ${key}()`);
83
- }
84
- }
85
- }
86
- }
87
-
88
- function getCurrentPath() {
89
- // Remove the "#/" prefix → "about", "contact", or "" for home
90
- return window.location.hash.replace("#/", "") || "home";
91
- }
92
-
93
- function navigate(path) {
94
- window.location.hash = "/" + path;
95
- }
96
-
97
-
98
- // ============================================================
99
- // STATE MANAGEMENT
100
- // Simple global state — update it and the page re-renders
101
- // ============================================================
102
- let state = {
103
- count: 0
104
- };
105
-
106
- function setState(newState) {
107
- // Merge new values into state
108
- state = { ...state, ...newState };
109
- renderPage(); // re-render when state changes
110
- }
111
-
112
-
113
- // ============================================================
114
- // RENDER ENGINE
115
- // ============================================================
116
- function renderPage() {
117
- // Reset hooks before rendering
118
- if (typeof resetHooks === 'function') {
119
- resetHooks();
120
- }
121
-
122
- const path = getCurrentPath();
123
- const root = document.getElementById("root");
124
-
125
- // Save focus state before re-render
126
- const activeElement = document.activeElement;
127
- const shouldRestoreFocus = activeElement && (activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA');
128
- const focusInfo = shouldRestoreFocus ? {
129
- type: activeElement.type,
130
- placeholder: activeElement.placeholder,
131
- value: activeElement.value,
132
- selectionStart: activeElement.selectionStart,
133
- selectionEnd: activeElement.selectionEnd
134
- } : null;
135
-
136
- root.innerHTML = "";
137
-
138
- const PageComponent = routes[path] || NotFoundPage;
139
- root.appendChild(PageComponent());
140
-
141
- // Restore focus after re-render (use setTimeout to ensure DOM is ready)
142
- if (focusInfo) {
143
- setTimeout(() => {
144
- const inputs = root.querySelectorAll('input, textarea');
145
- for (let input of inputs) {
146
- // Match by type and placeholder for unique identification
147
- if (input.type === focusInfo.type &&
148
- input.placeholder === focusInfo.placeholder) {
149
- input.focus();
150
- // Restore cursor position
151
- if (focusInfo.selectionStart !== null && focusInfo.selectionEnd !== null) {
152
- input.setSelectionRange(focusInfo.selectionStart, focusInfo.selectionEnd);
153
- }
154
- break;
155
- }
156
- }
157
- }, 0);
158
- }
159
- }
160
-
161
- function renderShell() {
162
- // Render navbar and footer (they don't change between pages)
163
- const navbar = document.getElementById("navbar");
164
- const footer = document.getElementById("footer");
165
- navbar.innerHTML = "";
166
- footer.innerHTML = "";
167
- navbar.appendChild(Navbar());
168
- footer.appendChild(Footer());
169
- }
170
-
171
- // Re-render shell when route changes (for navbar active state)
172
- function updateShell() {
173
- const navbar = document.getElementById("navbar");
174
- navbar.innerHTML = "";
175
- navbar.appendChild(Navbar());
176
- }
177
-
178
- // 404 page — shown when no route matches
179
- function NotFoundPage() {
180
- return (
181
- <div class="not-found">
182
- <h1>404</h1>
183
- <p>Oops! The page you're looking for doesn't exist.</p>
184
- <button class="btn btn-primary" onClick={() => navigate("home")}>
185
- Go Home
186
- </button>
187
- </div>
188
- );
189
- }
190
-
191
-
192
- // ============================================================
193
- // START
194
- // Called once after all scripts are loaded
195
- // ============================================================
196
- function startApp() {
197
- // Auto-register any pages that weren't manually registered
198
- autoRegisterPages();
199
-
200
- renderShell();
201
- renderPage();
202
-
203
- // Re-render the page and navbar whenever the hash changes (back/forward navigation)
204
- window.addEventListener("hashchange", () => {
205
- updateShell(); // Update navbar active state
206
- renderPage();
207
- });
208
- }
209
-
210
- // Export to global scope
211
- window.h = h;
212
- window.registerPage = registerPage;
213
- window.getCurrentPath = getCurrentPath;
214
- window.navigate = navigate;
215
- window.state = state;
216
- window.setState = setState;
217
- window.renderPage = renderPage;
218
- window.startApp = startApp;
@@ -1,248 +0,0 @@
1
- /** @jsx h */
2
-
3
- // ============================================================
4
- // STATE MANAGEMENT
5
- // React-like hooks system (useState, useEffect, etc.)
6
- // Exactly like React/Next.js!
7
- // ============================================================
8
-
9
- let currentComponent = null;
10
- let currentHookIndex = 0;
11
- const componentStates = new Map();
12
-
13
- // Get or create state for current component
14
- function getComponentState() {
15
- if (!currentComponent) {
16
- currentComponent = { hooks: [] };
17
- }
18
- return currentComponent;
19
- }
20
-
21
- // useState - Exactly like React!
22
- function useState(initialValue) {
23
- const component = getComponentState();
24
- const hookIndex = currentHookIndex++;
25
-
26
- // Initialize state if first render
27
- if (component.hooks[hookIndex] === undefined) {
28
- component.hooks[hookIndex] = {
29
- value: typeof initialValue === 'function' ? initialValue() : initialValue
30
- };
31
- }
32
-
33
- const hook = component.hooks[hookIndex];
34
-
35
- const setState = (newValue) => {
36
- const nextValue = typeof newValue === 'function'
37
- ? newValue(hook.value)
38
- : newValue;
39
-
40
- if (hook.value !== nextValue) {
41
- hook.value = nextValue;
42
- // Trigger re-render
43
- if (typeof renderPage === 'function') {
44
- renderPage();
45
- }
46
- }
47
- };
48
-
49
- return [hook.value, setState];
50
- }
51
-
52
- // useEffect - Exactly like React!
53
- function useEffect(callback, dependencies) {
54
- const component = getComponentState();
55
- const hookIndex = currentHookIndex++;
56
-
57
- const oldDeps = component.hooks[hookIndex]?.deps;
58
-
59
- let hasChanged = true;
60
- if (oldDeps) {
61
- hasChanged = dependencies.some((dep, i) => dep !== oldDeps[i]);
62
- }
63
-
64
- if (hasChanged) {
65
- // Clean up previous effect
66
- if (component.hooks[hookIndex]?.cleanup) {
67
- component.hooks[hookIndex].cleanup();
68
- }
69
-
70
- // Run effect after render
71
- setTimeout(() => {
72
- const cleanup = callback();
73
- if (component.hooks[hookIndex]) {
74
- component.hooks[hookIndex].cleanup = cleanup;
75
- }
76
- }, 0);
77
- }
78
-
79
- component.hooks[hookIndex] = {
80
- deps: dependencies,
81
- cleanup: component.hooks[hookIndex]?.cleanup
82
- };
83
- }
84
-
85
- // useMemo - Exactly like React!
86
- function useMemo(factory, dependencies) {
87
- const component = getComponentState();
88
- const hookIndex = currentHookIndex++;
89
-
90
- const oldDeps = component.hooks[hookIndex]?.deps;
91
-
92
- let hasChanged = true;
93
- if (oldDeps) {
94
- hasChanged = dependencies.some((dep, i) => dep !== oldDeps[i]);
95
- }
96
-
97
- if (hasChanged || !component.hooks[hookIndex]) {
98
- const value = factory();
99
- component.hooks[hookIndex] = {
100
- value,
101
- deps: dependencies
102
- };
103
- }
104
-
105
- return component.hooks[hookIndex].value;
106
- }
107
-
108
- // useCallback - Exactly like React!
109
- function useCallback(callback, dependencies) {
110
- return useMemo(() => callback, dependencies);
111
- }
112
-
113
- // useRef - Exactly like React!
114
- function useRef(initialValue) {
115
- const component = getComponentState();
116
- const hookIndex = currentHookIndex++;
117
-
118
- if (!component.hooks[hookIndex]) {
119
- component.hooks[hookIndex] = {
120
- current: initialValue
121
- };
122
- }
123
-
124
- return component.hooks[hookIndex];
125
- }
126
-
127
- // useReducer - Exactly like React!
128
- function useReducer(reducer, initialState, init) {
129
- const [state, setState] = useState(
130
- init ? init(initialState) : initialState
131
- );
132
-
133
- const dispatch = (action) => {
134
- setState(prevState => reducer(prevState, action));
135
- };
136
-
137
- return [state, dispatch];
138
- }
139
-
140
- // Custom hook: useLocalStorage
141
- function useLocalStorage(key, initialValue) {
142
- const [storedValue, setStoredValue] = useState(() => {
143
- try {
144
- const item = window.localStorage.getItem(key);
145
- return item ? JSON.parse(item) : initialValue;
146
- } catch (error) {
147
- console.error(error);
148
- return initialValue;
149
- }
150
- });
151
-
152
- const setValue = (value) => {
153
- try {
154
- const valueToStore = value instanceof Function ? value(storedValue) : value;
155
- setStoredValue(valueToStore);
156
- window.localStorage.setItem(key, JSON.stringify(valueToStore));
157
- } catch (error) {
158
- console.error(error);
159
- }
160
- };
161
-
162
- return [storedValue, setValue];
163
- }
164
-
165
- // Custom hook: useFetch
166
- function useFetch(url, options = {}) {
167
- const [data, setData] = useState(null);
168
- const [loading, setLoading] = useState(true);
169
- const [error, setError] = useState(null);
170
-
171
- useEffect(() => {
172
- let cancelled = false;
173
-
174
- const fetchData = async () => {
175
- try {
176
- setLoading(true);
177
- const response = await fetch(url, options);
178
-
179
- if (!response.ok) {
180
- throw new Error(`HTTP error! status: ${response.status}`);
181
- }
182
-
183
- const json = await response.json();
184
-
185
- if (!cancelled) {
186
- setData(json);
187
- setError(null);
188
- }
189
- } catch (e) {
190
- if (!cancelled) {
191
- setError(e.message);
192
- setData(null);
193
- }
194
- } finally {
195
- if (!cancelled) {
196
- setLoading(false);
197
- }
198
- }
199
- };
200
-
201
- fetchData();
202
-
203
- return () => {
204
- cancelled = true;
205
- };
206
- }, [url, JSON.stringify(options)]);
207
-
208
- return { data, loading, error };
209
- }
210
-
211
- // Reset hooks before each render
212
- function resetHooks() {
213
- currentHookIndex = 0;
214
- }
215
-
216
- // Initialize component state
217
- function initComponent() {
218
- currentComponent = { hooks: [] };
219
- currentHookIndex = 0;
220
- }
221
-
222
- // Export to global scope (like React)
223
- window.useState = useState;
224
- window.useEffect = useEffect;
225
- window.useMemo = useMemo;
226
- window.useCallback = useCallback;
227
- window.useRef = useRef;
228
- window.useReducer = useReducer;
229
- window.useLocalStorage = useLocalStorage;
230
- window.useFetch = useFetch;
231
- window.resetHooks = resetHooks;
232
- window.initComponent = initComponent;
233
-
234
- // Also make available without window prefix
235
- if (typeof globalThis !== 'undefined') {
236
- globalThis.useState = useState;
237
- globalThis.useEffect = useEffect;
238
- globalThis.useMemo = useMemo;
239
- globalThis.useCallback = useCallback;
240
- globalThis.useRef = useRef;
241
- globalThis.useReducer = useReducer;
242
- globalThis.useLocalStorage = useLocalStorage;
243
- globalThis.useFetch = useFetch;
244
- globalThis.resetHooks = resetHooks;
245
- globalThis.initComponent = initComponent;
246
- }
247
-
248
- console.log('✅ React-like hooks loaded: useState, useEffect, useMemo, useCallback, useRef, useReducer');
@@ -1,13 +0,0 @@
1
- {
2
- "name": "aziz-app",
3
- "version": "1.0.2",
4
- "lockfileVersion": 3,
5
- "requires": true,
6
- "packages": {
7
- "": {
8
- "name": "aziz-app",
9
- "version": "1.0.2",
10
- "license": "ISC"
11
- }
12
- }
13
- }
@@ -1,48 +0,0 @@
1
- /** @jsx h */
2
-
3
- // Optional: You can still manually register if you want a custom route name
4
- // registerPage("about", AboutPage);
5
-
6
- // Or just define the function and it auto-registers as "about"
7
- function AboutPage() {
8
- return (
9
- <div>
10
- <h1>About 📖</h1>
11
-
12
- <div class="card">
13
- <h2>What is this?</h2>
14
- <p>
15
- This app is built with <strong>create-aziz-app</strong> — a lightweight
16
- vanilla JS framework with JSX support and file-based routing.
17
- No React, no Vite, no dependencies. Just plain JavaScript + Babel.
18
- </p>
19
- </div>
20
-
21
- <div class="card">
22
- <h2>How routing works</h2>
23
- <p>
24
- The URL hash controls which page is shown.
25
- Changing <strong>#/about</strong> to <strong>#/contact</strong>
26
- loads the Contact page — no page refresh needed.
27
- </p>
28
- <button class="btn btn-primary" onClick={() => navigate("contact")}>
29
- Go to Contact →
30
- </button>
31
- </div>
32
-
33
- <div class="card">
34
- <h2>✨ Auto-Registration</h2>
35
- <p>
36
- This page works without calling <code>registerPage()</code>!
37
- Just name your function <code>YourNamePage()</code> and it automatically
38
- becomes a route.
39
- </p>
40
- <ul style={{ lineHeight: '1.8', marginLeft: '20px' }}>
41
- <li><code>HomePage()</code> → <code>#/home</code></li>
42
- <li><code>AboutPage()</code> → <code>#/about</code></li>
43
- <li><code>ContactPage()</code> → <code>#/contact</code></li>
44
- </ul>
45
- </div>
46
- </div>
47
- );
48
- }