frontend-hamroun 1.2.80 → 1.2.82

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 (104) hide show
  1. package/bin/cli.js +1 -1
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +1 -0
  4. package/dist/index.js.map +1 -1
  5. package/package.json +1 -1
  6. package/templates/basic-app/src/App.jsx +16 -0
  7. package/templates/basic-app/src/client.jsx +5 -0
  8. package/templates/basic-app/src/components/Counter.jsx +13 -0
  9. package/templates/basic-app/src/jsx-shim.js +3 -0
  10. package/templates/basic-app/src/jsx-shim.ts +7 -0
  11. package/templates/basic-app/src/main.jsx +98 -0
  12. package/templates/basic-app/src/server.js +47 -0
  13. package/templates/complete-app/api/hello.js +0 -0
  14. package/templates/complete-app/lib/frontend-hamroun.js +182 -0
  15. package/templates/complete-app/package.json +18 -0
  16. package/templates/complete-app/pages/about.js +119 -0
  17. package/templates/complete-app/pages/about.jsx +0 -0
  18. package/templates/complete-app/pages/index.js +157 -0
  19. package/templates/complete-app/pages/index.jsx +0 -0
  20. package/templates/complete-app/pages/wasm-demo.js +290 -0
  21. package/templates/complete-app/pages/wasm-demo.jsx +0 -0
  22. package/templates/complete-app/public/client.js +89 -0
  23. package/templates/complete-app/public/index.html +118 -0
  24. package/templates/complete-app/public/styles.css +76 -0
  25. package/templates/complete-app/server.js +226 -0
  26. package/templates/complete-app/src/App.tsx +59 -0
  27. package/templates/complete-app/src/client.tsx +18 -0
  28. package/templates/complete-app/src/server.ts +218 -0
  29. package/templates/complete-app/tsconfig.json +22 -0
  30. package/templates/complete-app/tsconfig.server.json +19 -0
  31. package/templates/{ssr-template → complete-app}/vite.config.js +16 -5
  32. package/templates/complete-app/vite.config.ts +30 -0
  33. package/templates/complete-app/wasm/build.bat +0 -0
  34. package/templates/complete-app/wasm/build.sh +0 -0
  35. package/templates/complete-app/wasm/example.go +0 -0
  36. package/templates/fullstack-app/build/main.css +874 -874
  37. package/templates/fullstack-app/build/main.css.map +7 -7
  38. package/templates/fullstack-app/build/main.js +996 -967
  39. package/templates/fullstack-app/build/main.js.map +7 -7
  40. package/templates/fullstack-app/package-lock.json +6301 -0
  41. package/templates/fullstack-app/public/styles.css +768 -768
  42. package/templates/go/example.go +154 -99
  43. package/templates/ssr-template/esbuild.config.js +33 -0
  44. package/templates/ssr-template/jsx-shim.js +1 -0
  45. package/templates/ssr-template/package.json +22 -16
  46. package/templates/ssr-template/src/App.tsx +12 -52
  47. package/templates/ssr-template/src/client.tsx +3 -17
  48. package/templates/ssr-template/src/server.ts +21 -204
  49. package/templates/ssr-template/tsconfig.json +10 -13
  50. package/templates/ssr-template/tsconfig.server.json +6 -14
  51. package/templates/wasm/build-wasm.js +228 -0
  52. package/templates/wasm/esbuild.config.js +63 -0
  53. package/templates/wasm/go/main.go +256 -0
  54. package/templates/wasm/go/wasm_exec.js +0 -0
  55. package/templates/wasm/index.html +97 -0
  56. package/templates/wasm/jsx-shim.js +9 -0
  57. package/templates/wasm/package-lock.json +5307 -0
  58. package/templates/wasm/package.json +42 -0
  59. package/templates/wasm/public/example.wasm +0 -0
  60. package/templates/{go-wasm-app/public/wasm → wasm/public}/wasm_exec.js +561 -561
  61. package/templates/wasm/src/App.tsx +564 -0
  62. package/templates/wasm/src/client.tsx +220 -0
  63. package/templates/wasm/src/index.tsx +21 -0
  64. package/templates/wasm/src/server.ts +145 -0
  65. package/templates/wasm/tsconfig.json +21 -0
  66. package/templates/wasm/tsconfig.node.json +13 -0
  67. package/templates/wasm/tsconfig.server.json +23 -0
  68. package/templates/wasm/vite.config.ts +56 -0
  69. package/templates/wasm/wasm-loader.js +103 -0
  70. package/templates/basic-app/bun.lock +0 -196
  71. package/templates/basic-app/docs/rapport_pfe.aux +0 -27
  72. package/templates/basic-app/docs/rapport_pfe.out +0 -10
  73. package/templates/basic-app/docs/rapport_pfe.pdf +0 -0
  74. package/templates/basic-app/docs/rapport_pfe.tex +0 -68
  75. package/templates/basic-app/docs/rapport_pfe.toc +0 -14
  76. package/templates/basic-app/package-lock.json +0 -4185
  77. package/templates/go-wasm-app/README.md +0 -38
  78. package/templates/go-wasm-app/babel.config.js +0 -15
  79. package/templates/go-wasm-app/build-client.js +0 -49
  80. package/templates/go-wasm-app/build-wasm.js +0 -237
  81. package/templates/go-wasm-app/package.json +0 -23
  82. package/templates/go-wasm-app/public/index.html +0 -128
  83. package/templates/go-wasm-app/public/styles.css +0 -197
  84. package/templates/go-wasm-app/public/wasm/example.wasm +0 -0
  85. package/templates/go-wasm-app/public/wasm/wasm_exec_node.js +0 -39
  86. package/templates/go-wasm-app/server.js +0 -521
  87. package/templates/go-wasm-app/src/App.jsx +0 -38
  88. package/templates/go-wasm-app/src/app.js +0 -153
  89. package/templates/go-wasm-app/src/client.js +0 -57
  90. package/templates/go-wasm-app/src/components/Footer.jsx +0 -13
  91. package/templates/go-wasm-app/src/components/Header.jsx +0 -19
  92. package/templates/go-wasm-app/src/components/WasmDemo.jsx +0 -120
  93. package/templates/go-wasm-app/src/main.jsx +0 -12
  94. package/templates/go-wasm-app/src/wasm/example.go +0 -75
  95. package/templates/go-wasm-app/tsconfig.server.json +0 -18
  96. package/templates/go-wasm-app/vite.config.js +0 -34
  97. package/templates/ssr-template/package-lock.json +0 -2478
  98. package/templates/ssr-template/public/index.html +0 -47
  99. package/templates/ssr-template/server.js +0 -369
  100. /package/templates/{ssr-template → complete-app}/client.js +0 -0
  101. /package/templates/{ssr-template → complete-app}/readme.md +0 -0
  102. /package/templates/{ssr-template → complete-app}/server.ts +0 -0
  103. /package/templates/{ssr-template → complete-app}/src/client.ts +0 -0
  104. /package/templates/{ssr-template → complete-app}/src/pages/index.tsx +0 -0
@@ -1,967 +1,996 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropNames = Object.getOwnPropertyNames;
3
- var __glob = (map) => (path) => {
4
- var fn = map[path];
5
- if (fn)
6
- return fn();
7
- throw new Error("Module not found in bundle: " + path);
8
- };
9
- var __esm = (fn, res) => function __init() {
10
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
- };
12
- var __export = (target, all) => {
13
- for (var name in all)
14
- __defProp(target, name, { get: all[name], enumerable: true });
15
- };
16
-
17
- // node_modules/frontend-hamroun/dist/index.mjs
18
- function batchUpdates(fn) {
19
- if (isBatching) {
20
- queue.push(fn);
21
- return;
22
- }
23
- isBatching = true;
24
- try {
25
- fn();
26
- while (queue.length > 0) {
27
- const nextFn = queue.shift();
28
- nextFn == null ? void 0 : nextFn();
29
- }
30
- } finally {
31
- isBatching = false;
32
- }
33
- }
34
- function setRenderCallback(callback, element, container) {
35
- globalRenderCallback = callback;
36
- globalContainer = container;
37
- currentElement = element;
38
- }
39
- function prepareRender() {
40
- currentRender++;
41
- stateIndices.set(currentRender, 0);
42
- return currentRender;
43
- }
44
- function finishRender() {
45
- if (isServer) {
46
- serverStates.delete(currentRender);
47
- }
48
- currentRender = 0;
49
- }
50
- function useState(initial) {
51
- if (!currentRender) {
52
- throw new Error("useState must be called within a render");
53
- }
54
- if (isServer) {
55
- if (!serverStates.has(currentRender)) {
56
- serverStates.set(currentRender, /* @__PURE__ */ new Map());
57
- }
58
- const componentState = serverStates.get(currentRender);
59
- const index2 = stateIndices.get(currentRender) || 0;
60
- if (!componentState.has(index2)) {
61
- componentState.set(index2, initial);
62
- }
63
- const state2 = componentState.get(index2);
64
- const setState2 = (newValue) => {
65
- };
66
- stateIndices.set(currentRender, index2 + 1);
67
- return [state2, setState2];
68
- }
69
- if (!states.has(currentRender)) {
70
- states.set(currentRender, []);
71
- }
72
- const componentStates = states.get(currentRender);
73
- const index = stateIndices.get(currentRender);
74
- if (index >= componentStates.length) {
75
- componentStates.push(initial);
76
- }
77
- const state = componentStates[index];
78
- const setState = (newValue) => {
79
- const nextValue = typeof newValue === "function" ? newValue(componentStates[index]) : newValue;
80
- if (componentStates[index] === nextValue)
81
- return;
82
- componentStates[index] = nextValue;
83
- if (isBatching) {
84
- batchUpdates(() => rerender(currentRender));
85
- } else {
86
- rerender(currentRender);
87
- }
88
- };
89
- stateIndices.set(currentRender, index + 1);
90
- return [state, setState];
91
- }
92
- function useEffect(callback, deps) {
93
- if (!currentRender)
94
- throw new Error("useEffect must be called within a render");
95
- const effectIndex = stateIndices.get(currentRender);
96
- if (!effects.has(currentRender)) {
97
- effects.set(currentRender, []);
98
- }
99
- const componentEffects = effects.get(currentRender);
100
- const prevEffect = componentEffects[effectIndex];
101
- if (!prevEffect || !deps || !prevEffect.deps || deps.some((dep, i) => dep !== prevEffect.deps[i])) {
102
- if (prevEffect == null ? void 0 : prevEffect.cleanup) {
103
- prevEffect.cleanup();
104
- }
105
- queueMicrotask(() => {
106
- const cleanup = callback() || void 0;
107
- componentEffects[effectIndex] = { cleanup, deps };
108
- });
109
- }
110
- stateIndices.set(currentRender, effectIndex + 1);
111
- }
112
- function useMemo(factory, deps) {
113
- if (!currentRender)
114
- throw new Error("useMemo must be called within a render");
115
- const memoIndex = stateIndices.get(currentRender);
116
- if (!memos.has(currentRender)) {
117
- memos.set(currentRender, []);
118
- }
119
- const componentMemos = memos.get(currentRender);
120
- const prevMemo = componentMemos[memoIndex];
121
- if (!prevMemo || deps && deps.some((dep, i) => !Object.is(dep, prevMemo.deps[i]))) {
122
- const value = factory();
123
- componentMemos[memoIndex] = { value, deps };
124
- stateIndices.set(currentRender, memoIndex + 1);
125
- return value;
126
- }
127
- stateIndices.set(currentRender, memoIndex + 1);
128
- return prevMemo.value;
129
- }
130
- async function rerender(rendererId) {
131
- try {
132
- const componentEffects = effects.get(rendererId);
133
- if (componentEffects) {
134
- componentEffects.forEach((effect) => {
135
- if (effect.cleanup)
136
- effect.cleanup();
137
- });
138
- effects.set(rendererId, []);
139
- }
140
- if (globalRenderCallback && globalContainer && currentElement) {
141
- await globalRenderCallback(currentElement, globalContainer);
142
- }
143
- } catch (error) {
144
- console.error("Error during rerender:", error);
145
- }
146
- }
147
- function useErrorBoundary() {
148
- const [error, setError] = useState(null);
149
- return [error, () => setError(null)];
150
- }
151
- function jsx(type, props) {
152
- console.log("JSX Transform:", { type, props });
153
- const processedProps = { ...props };
154
- if (arguments.length > 2) {
155
- processedProps.children = Array.prototype.slice.call(arguments, 2);
156
- }
157
- return { type, props: processedProps };
158
- }
159
- async function createElement(vnode) {
160
- var _a;
161
- console.log("Creating element from:", vnode);
162
- if (vnode == null) {
163
- return document.createTextNode("");
164
- }
165
- if (typeof vnode === "boolean") {
166
- return document.createTextNode("");
167
- }
168
- if (typeof vnode === "number" || typeof vnode === "string") {
169
- return document.createTextNode(String(vnode));
170
- }
171
- if (Array.isArray(vnode)) {
172
- const fragment = document.createDocumentFragment();
173
- for (const child of vnode) {
174
- const node = await createElement(child);
175
- fragment.appendChild(node);
176
- }
177
- return fragment;
178
- }
179
- if ("type" in vnode && vnode.props !== void 0) {
180
- const { type, props } = vnode;
181
- if (typeof type === "function") {
182
- try {
183
- const result = await type(props || {});
184
- const node = await createElement(result);
185
- if (node instanceof Element) {
186
- node.setAttribute("data-component-id", type.name || type.toString());
187
- }
188
- return node;
189
- } catch (error) {
190
- console.error("Error rendering component:", error);
191
- return document.createTextNode("");
192
- }
193
- }
194
- const element = document.createElement(type);
195
- for (const [key, value] of Object.entries(props || {})) {
196
- if (key === "children")
197
- continue;
198
- if (key.startsWith("on") && typeof value === "function") {
199
- const eventName = key.toLowerCase().slice(2);
200
- const existingHandler = (_a = element.__events) == null ? void 0 : _a[eventName];
201
- if (existingHandler) {
202
- element.removeEventListener(eventName, existingHandler);
203
- }
204
- element.addEventListener(eventName, value);
205
- if (!element.__events) {
206
- element.__events = {};
207
- }
208
- element.__events[eventName] = value;
209
- } else if (key === "style" && typeof value === "object") {
210
- Object.assign(element.style, value);
211
- } else if (key === "className") {
212
- element.setAttribute("class", String(value));
213
- } else if (key !== "key" && key !== "ref") {
214
- element.setAttribute(key, String(value));
215
- }
216
- }
217
- const children = props == null ? void 0 : props.children;
218
- if (children != null) {
219
- const childArray = Array.isArray(children) ? children.flat() : [children];
220
- for (const child of childArray) {
221
- const childNode = await createElement(child);
222
- element.appendChild(childNode);
223
- }
224
- }
225
- return element;
226
- }
227
- return document.createTextNode(String(vnode));
228
- }
229
- async function hydrate(element, container) {
230
- isHydrating = true;
231
- try {
232
- await render(element, container);
233
- } finally {
234
- isHydrating = false;
235
- }
236
- }
237
- async function render(element, container) {
238
- console.log("Rendering to:", container.id);
239
- batchUpdates(async () => {
240
- const rendererId = prepareRender();
241
- try {
242
- setRenderCallback(render, element, container);
243
- const domNode = await createElement(element);
244
- if (!isHydrating) {
245
- container.innerHTML = "";
246
- }
247
- container.appendChild(domNode);
248
- } finally {
249
- finishRender();
250
- }
251
- });
252
- }
253
- var isBatching, queue, currentRender, states, stateIndices, effects, memos, globalRenderCallback, globalContainer, currentElement, isServer, serverStates, isHydrating;
254
- var init_dist = __esm({
255
- "node_modules/frontend-hamroun/dist/index.mjs"() {
256
- isBatching = false;
257
- queue = [];
258
- currentRender = 0;
259
- states = /* @__PURE__ */ new Map();
260
- stateIndices = /* @__PURE__ */ new Map();
261
- effects = /* @__PURE__ */ new Map();
262
- memos = /* @__PURE__ */ new Map();
263
- globalRenderCallback = null;
264
- globalContainer = null;
265
- currentElement = null;
266
- isServer = typeof window === "undefined";
267
- serverStates = /* @__PURE__ */ new Map();
268
- isHydrating = false;
269
- }
270
- });
271
-
272
- // src/pages/404.tsx
273
- var __exports = {};
274
- __export(__exports, {
275
- default: () => NotFound
276
- });
277
- function NotFound({ initialState: initialState2 }) {
278
- return /* @__PURE__ */ jsx("div", { className: "not-found-container max-w-4xl mx-auto p-6" }, /* @__PURE__ */ jsx("div", { className: "bg-gray-50 border border-gray-200 rounded-lg p-8 shadow-sm" }, /* @__PURE__ */ jsx("h1", { className: "text-3xl font-bold text-gray-700 mb-4" }, "Page Not Found"), /* @__PURE__ */ jsx("p", { className: "text-lg text-gray-600 mb-4" }, "The page you are looking for does not exist or has been moved."), /* @__PURE__ */ jsx("p", { className: "text-gray-600 mb-6" }, "Path: ", /* @__PURE__ */ jsx("code", { className: "bg-gray-100 px-2 py-1 rounded" }, initialState2?.route || "unknown")), /* @__PURE__ */ jsx("div", { className: "mt-6" }, /* @__PURE__ */ jsx(
279
- "a",
280
- {
281
- href: "/",
282
- className: "inline-block px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700"
283
- },
284
- "Back to Home"
285
- ))));
286
- }
287
- var init__ = __esm({
288
- "src/pages/404.tsx"() {
289
- "use strict";
290
- init_dist();
291
- }
292
- });
293
-
294
- // src/pages/[id].tsx
295
- var id_exports = {};
296
- var init_id = __esm({
297
- "src/pages/[id].tsx"() {
298
- "use strict";
299
- }
300
- });
301
-
302
- // src/components/Layout.tsx
303
- function Layout({ children, title = "Frontend Hamroun App" }) {
304
- return /* @__PURE__ */ jsx("div", { className: "min-h-screen flex flex-col bg-gray-50" }, /* @__PURE__ */ jsx("header", { className: "bg-blue-600 text-white" }, /* @__PURE__ */ jsx("div", { className: "container mx-auto px-4 py-4 flex justify-between items-center" }, /* @__PURE__ */ jsx("h1", { className: "text-xl font-bold" }, /* @__PURE__ */ jsx("a", { href: "/", className: "hover:text-blue-100" }, title)), /* @__PURE__ */ jsx("nav", null, /* @__PURE__ */ jsx("ul", { className: "flex space-x-6" }, /* @__PURE__ */ jsx("li", null, /* @__PURE__ */ jsx("a", { href: "/", className: "hover:text-blue-100" }, "Home")), /* @__PURE__ */ jsx("li", null, /* @__PURE__ */ jsx("a", { href: "/about", className: "hover:text-blue-100" }, "About")))))), /* @__PURE__ */ jsx("main", { className: "flex-grow container mx-auto px-4 py-8" }, children), /* @__PURE__ */ jsx("footer", { className: "bg-gray-800 text-white" }, /* @__PURE__ */ jsx("div", { className: "container mx-auto px-4 py-6" }, /* @__PURE__ */ jsx("p", { className: "text-center text-gray-400" }, "\xA9 ", (/* @__PURE__ */ new Date()).getFullYear(), " Frontend Hamroun App. All rights reserved."))));
305
- }
306
- var init_Layout = __esm({
307
- "src/components/Layout.tsx"() {
308
- "use strict";
309
- init_dist();
310
- }
311
- });
312
-
313
- // src/pages/_app.tsx
314
- var app_exports = {};
315
- __export(app_exports, {
316
- default: () => App
317
- });
318
- function App({ Component, pageProps, initialState: initialState2 }) {
319
- return /* @__PURE__ */ jsx(Layout, null, /* @__PURE__ */ jsx(Component, { ...pageProps, initialState: initialState2 }));
320
- }
321
- var init_app = __esm({
322
- "src/pages/_app.tsx"() {
323
- "use strict";
324
- init_dist();
325
- init_Layout();
326
- }
327
- });
328
-
329
- // src/pages/_document.tsx
330
- var document_exports = {};
331
- __export(document_exports, {
332
- default: () => Document
333
- });
334
- function Document({
335
- title = "Frontend Hamroun App",
336
- headContent,
337
- bodyContent,
338
- scripts
339
- }) {
340
- return /* @__PURE__ */ jsx("html", { lang: "en" }, /* @__PURE__ */ jsx("head", null, /* @__PURE__ */ jsx("meta", { charSet: "UTF-8" }), /* @__PURE__ */ jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1.0" }), /* @__PURE__ */ jsx("title", null, title), /* @__PURE__ */ jsx("link", { rel: "stylesheet", href: "/styles.css" }), headContent), /* @__PURE__ */ jsx("body", null, /* @__PURE__ */ jsx("div", { id: "root" }, bodyContent), /* @__PURE__ */ jsx("script", { src: "/build/main.js", type: "module" }), scripts));
341
- }
342
- var init_document = __esm({
343
- "src/pages/_document.tsx"() {
344
- "use strict";
345
- init_dist();
346
- }
347
- });
348
-
349
- // src/pages/_error.tsx
350
- var error_exports = {};
351
- __export(error_exports, {
352
- default: () => ErrorPage
353
- });
354
- function ErrorPage({ initialState: initialState2 }) {
355
- const { error } = initialState2 || {};
356
- const [showDetails, setShowDetails] = useState(false);
357
- const isDev = true;
358
- return /* @__PURE__ */ jsx("div", { className: "error-page-container max-w-4xl mx-auto p-6" }, /* @__PURE__ */ jsx("div", { className: "bg-red-50 border border-red-200 rounded-lg p-8 shadow-sm" }, /* @__PURE__ */ jsx("h1", { className: "text-3xl font-bold text-red-700 mb-4" }, "Something went wrong"), /* @__PURE__ */ jsx("p", { className: "text-lg text-red-600 mb-4" }, error?.message || "An unexpected error occurred"), isDev && error?.stack && /* @__PURE__ */ jsx("div", { className: "mt-6" }, /* @__PURE__ */ jsx(
359
- "button",
360
- {
361
- className: "text-blue-600 underline mb-2",
362
- onClick: () => setShowDetails(!showDetails)
363
- },
364
- showDetails ? "Hide" : "Show",
365
- " technical details"
366
- ), showDetails && /* @__PURE__ */ jsx("pre", { className: "bg-gray-100 p-4 rounded-md text-sm overflow-auto max-h-96 text-gray-800" }, error.stack)), /* @__PURE__ */ jsx("div", { className: "mt-6" }, /* @__PURE__ */ jsx(
367
- "a",
368
- {
369
- href: "/",
370
- className: "inline-block px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700"
371
- },
372
- "Back to Home"
373
- ))));
374
- }
375
- var init_error = __esm({
376
- "src/pages/_error.tsx"() {
377
- "use strict";
378
- init_dist();
379
- }
380
- });
381
-
382
- // src/pages/about.tsx
383
- var about_exports = {};
384
- __export(about_exports, {
385
- default: () => AboutPage,
386
- getServerSideProps: () => getServerSideProps
387
- });
388
- function AboutPage({ initialState: initialState2 }) {
389
- return /* @__PURE__ */ jsx(Layout, { title: "About - Frontend Hamroun" }, /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto" }, /* @__PURE__ */ jsx("h1", { className: "text-3xl font-bold text-blue-600 mb-6" }, "About Frontend Hamroun"), /* @__PURE__ */ jsx("div", { className: "bg-white shadow-lg rounded-lg p-8 mb-8" }, /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-gray-800 mb-4" }, "What is Frontend Hamroun?"), /* @__PURE__ */ jsx("p", { className: "text-gray-600 mb-4" }, "Frontend Hamroun is a lightweight JavaScript framework for building modern web applications. It provides a familiar component-based architecture with hooks, JSX support, and server-side rendering capabilities."), /* @__PURE__ */ jsx("p", { className: "text-gray-600 mb-4" }, "This framework is designed to be simple yet powerful, offering the essential features needed for web application development without the complexity of larger frameworks."), /* @__PURE__ */ jsx("h3", { className: "text-lg font-medium text-gray-700 mt-6 mb-2" }, "Key Features:"), /* @__PURE__ */ jsx("ul", { className: "list-disc pl-6 text-gray-600 space-y-2" }, /* @__PURE__ */ jsx("li", null, "Component-based architecture"), /* @__PURE__ */ jsx("li", null, "JSX support"), /* @__PURE__ */ jsx("li", null, "Hooks for state and effects"), /* @__PURE__ */ jsx("li", null, "Server-side rendering"), /* @__PURE__ */ jsx("li", null, "Minimal API surface"), /* @__PURE__ */ jsx("li", null, "File-based routing"), /* @__PURE__ */ jsx("li", null, "Built-in API routes"))), /* @__PURE__ */ jsx("div", { className: "bg-white shadow-lg rounded-lg p-8" }, /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-gray-800 mb-4" }, "Getting Started"), /* @__PURE__ */ jsx("p", { className: "text-gray-600 mb-4" }, "This application was created using the Frontend Hamroun fullstack template, which provides a complete setup for building applications with server-side rendering, API routes, and client-side navigation."), /* @__PURE__ */ jsx("div", { className: "bg-gray-50 p-4 rounded-md mt-4" }, /* @__PURE__ */ jsx("h3", { className: "text-md font-medium text-gray-700 mb-2" }, "Quick Start:"), /* @__PURE__ */ jsx("pre", { className: "bg-gray-800 text-gray-100 p-4 rounded overflow-x-auto" }, /* @__PURE__ */ jsx("code", null, `# Create a new application
390
- npx frontend-hamroun create my-app
391
-
392
- # Change directory
393
- cd my-app
394
-
395
- # Start the development server
396
- npm run dev`))))));
397
- }
398
- async function getServerSideProps() {
399
- return {
400
- props: {
401
- pageTitle: "About Frontend Hamroun",
402
- description: "Learn more about the Frontend Hamroun framework"
403
- }
404
- };
405
- }
406
- var init_about = __esm({
407
- "src/pages/about.tsx"() {
408
- "use strict";
409
- init_dist();
410
- init_Layout();
411
- }
412
- });
413
-
414
- // src/pages/about/index.tsx
415
- var about_exports2 = {};
416
- __export(about_exports2, {
417
- default: () => about_default
418
- });
419
- var AboutPage2, about_default;
420
- var init_about2 = __esm({
421
- "src/pages/about/index.tsx"() {
422
- "use strict";
423
- init_dist();
424
- init_Layout();
425
- AboutPage2 = ({ initialState: initialState2 }) => {
426
- return /* @__PURE__ */ jsx(Layout, { title: "About This App" }, /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto bg-white shadow-lg rounded-lg overflow-hidden" }, /* @__PURE__ */ jsx("div", { className: "p-8" }, /* @__PURE__ */ jsx("p", { className: "text-lg text-gray-700 mb-6" }, "This is a frontend application built with Frontend Hamroun framework and styled with Tailwind CSS."), /* @__PURE__ */ jsx("p", { className: "text-gray-600 mb-8" }, "It features server-side rendering, client-side navigation, and websocket-based live reloading during development."), /* @__PURE__ */ jsx("div", { className: "bg-gray-50 p-6 rounded-lg border border-gray-200 mb-8" }, /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-gray-800 mb-4" }, "Key Features"), /* @__PURE__ */ jsx("ul", { className: "space-y-2 text-gray-700" }, /* @__PURE__ */ jsx("li", { className: "flex items-center" }, /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-green-500 mr-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M5 13l4 4L19 7" })), "Server-side rendering"), /* @__PURE__ */ jsx("li", { className: "flex items-center" }, /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-green-500 mr-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M5 13l4 4L19 7" })), "Client-side navigation"), /* @__PURE__ */ jsx("li", { className: "flex items-center" }, /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-green-500 mr-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M5 13l4 4L19 7" })), "Component-based architecture"), /* @__PURE__ */ jsx("li", { className: "flex items-center" }, /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-green-500 mr-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M5 13l4 4L19 7" })), "Integrated API backend"), /* @__PURE__ */ jsx("li", { className: "flex items-center" }, /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-green-500 mr-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M5 13l4 4L19 7" })), "Live reload during development"), /* @__PURE__ */ jsx("li", { className: "flex items-center" }, /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-green-500 mr-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M5 13l4 4L19 7" })), "Tailwind CSS for styling"))), /* @__PURE__ */ jsx("a", { href: "/", className: "inline-block px-6 py-3 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 transition-colors" }, "Back to Home"))));
427
- };
428
- about_default = AboutPage2;
429
- }
430
- });
431
-
432
- // src/components/UserList.tsx
433
- function UserList({ users }) {
434
- if (!users || users.length === 0) {
435
- return /* @__PURE__ */ jsx("div", { className: "empty-state p-4 text-center bg-gray-50 rounded" }, /* @__PURE__ */ jsx("p", { className: "text-gray-500" }, "No users available"));
436
- }
437
- return /* @__PURE__ */ jsx("div", { className: "user-list" }, /* @__PURE__ */ jsx("ul", { className: "divide-y divide-gray-100" }, users.map((user) => /* @__PURE__ */ jsx("li", { key: user.id, className: "py-3" }, /* @__PURE__ */ jsx("div", { className: "flex justify-between" }, /* @__PURE__ */ jsx("div", null, /* @__PURE__ */ jsx("p", { className: "font-medium text-gray-900" }, user.name), /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500" }, user.email)), /* @__PURE__ */ jsx(
438
- "a",
439
- {
440
- href: `/users/${user.id}`,
441
- className: "text-blue-600 hover:underline text-sm self-center"
442
- },
443
- "View Profile"
444
- ))))));
445
- }
446
- var init_UserList = __esm({
447
- "src/components/UserList.tsx"() {
448
- "use strict";
449
- init_dist();
450
- }
451
- });
452
-
453
- // src/components/StateDemo.tsx
454
- function StateDemo() {
455
- const [state, setState] = useState({
456
- count: 0,
457
- lastUpdated: null,
458
- history: []
459
- });
460
- const [isLoading, setIsLoading] = useState(false);
461
- const [showHistory, setShowHistory] = useState(false);
462
- const isSSR = typeof window === "undefined";
463
- const stats = useMemo(() => {
464
- if (isSSR || !state || !state.history || state.history.length === 0) {
465
- return { avg: 0, max: 0, min: 0 };
466
- }
467
- try {
468
- const sum = state.history.reduce((a, b) => a + b, 0);
469
- return {
470
- avg: parseFloat((sum / state.history.length).toFixed(1)),
471
- max: Math.max(...state.history),
472
- min: Math.min(...state.history)
473
- };
474
- } catch (error) {
475
- console.error("Error calculating stats:", error);
476
- return { avg: 0, max: 0, min: 0 };
477
- }
478
- }, [state?.history]);
479
- const increment = () => {
480
- if (isSSR)
481
- return;
482
- setIsLoading(true);
483
- setTimeout(() => {
484
- setState((prevState) => ({
485
- count: prevState.count + 1,
486
- lastUpdated: (/* @__PURE__ */ new Date()).toLocaleTimeString(),
487
- history: [...prevState.history || [], prevState.count + 1]
488
- }));
489
- setIsLoading(false);
490
- }, 300);
491
- };
492
- const decrement = () => {
493
- if (isSSR)
494
- return;
495
- setIsLoading(true);
496
- setTimeout(() => {
497
- setState((prevState) => ({
498
- count: Math.max(0, prevState.count - 1),
499
- lastUpdated: (/* @__PURE__ */ new Date()).toLocaleTimeString(),
500
- history: prevState.count > 0 ? [...prevState.history || [], prevState.count - 1] : prevState.history || []
501
- }));
502
- setIsLoading(false);
503
- }, 300);
504
- };
505
- const reset = () => {
506
- if (isSSR)
507
- return;
508
- setState({
509
- count: 0,
510
- lastUpdated: (/* @__PURE__ */ new Date()).toLocaleTimeString(),
511
- history: []
512
- });
513
- };
514
- const toggleHistory = () => {
515
- if (isSSR)
516
- return;
517
- setShowHistory((prev) => !prev);
518
- };
519
- if (isSSR) {
520
- return /* @__PURE__ */ jsx("div", { className: "bg-white shadow-lg rounded-lg p-6 mb-8" }, /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-gray-800 mb-4" }, "State Management Demo"), /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between mb-4" }, /* @__PURE__ */ jsx("button", { className: "px-4 py-2 bg-gray-200 text-gray-800 rounded-lg" }, "-"), /* @__PURE__ */ jsx("span", { className: "text-2xl font-bold mx-4" }, "0"), /* @__PURE__ */ jsx("button", { className: "px-4 py-2 bg-blue-600 text-white rounded-lg" }, "+")), /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500" }, "Interactive counter (client-side only)"));
521
- }
522
- return /* @__PURE__ */ jsx("div", { className: "bg-white shadow-lg rounded-lg p-6 mb-8" }, /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-gray-800 mb-4" }, "State Management Demo"), /* @__PURE__ */ jsx("div", { className: "mb-6" }, /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between mb-4" }, /* @__PURE__ */ jsx(
523
- "button",
524
- {
525
- onClick: decrement,
526
- className: "px-4 py-2 bg-gray-200 text-gray-800 rounded-lg hover:bg-gray-300 disabled:opacity-50",
527
- disabled: state.count === 0 || isLoading
528
- },
529
- isLoading ? "..." : "-"
530
- ), /* @__PURE__ */ jsx("span", { className: "text-2xl font-bold mx-4" }, state.count), /* @__PURE__ */ jsx(
531
- "button",
532
- {
533
- onClick: increment,
534
- className: "px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-50",
535
- disabled: isLoading
536
- },
537
- isLoading ? "..." : "+"
538
- )), /* @__PURE__ */ jsx(
539
- "button",
540
- {
541
- onClick: reset,
542
- className: "text-sm text-gray-600 hover:text-red-600",
543
- disabled: state.count === 0 && (!state.history || state.history.length === 0)
544
- },
545
- "Reset Counter"
546
- )), state.lastUpdated && /* @__PURE__ */ jsx("div", { className: "mb-4" }, /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500" }, "Last updated: ", state.lastUpdated)), state.history && state.history.length > 0 && /* @__PURE__ */ jsx("div", { className: "border-t pt-4 mt-4" }, /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ jsx("h3", { className: "text-md font-medium text-gray-700" }, "Statistics"), /* @__PURE__ */ jsx(
547
- "button",
548
- {
549
- onClick: toggleHistory,
550
- className: "text-sm text-blue-600 hover:underline"
551
- },
552
- showHistory ? "Hide History" : "Show History"
553
- )), /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-2 mb-3" }, /* @__PURE__ */ jsx("div", { className: "bg-blue-50 p-2 rounded text-center" }, /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500" }, "Average"), /* @__PURE__ */ jsx("div", { className: "font-bold" }, stats.avg)), /* @__PURE__ */ jsx("div", { className: "bg-green-50 p-2 rounded text-center" }, /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500" }, "Maximum"), /* @__PURE__ */ jsx("div", { className: "font-bold" }, stats.max)), /* @__PURE__ */ jsx("div", { className: "bg-red-50 p-2 rounded text-center" }, /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500" }, "Minimum"), /* @__PURE__ */ jsx("div", { className: "font-bold" }, stats.min))), showHistory && /* @__PURE__ */ jsx("div", { className: "mt-3" }, /* @__PURE__ */ jsx("h4", { className: "text-sm font-medium text-gray-600 mb-1" }, "History (", state.history.length, " events)"), /* @__PURE__ */ jsx("div", { className: "bg-gray-50 p-2 rounded max-h-24 overflow-y-auto text-xs" }, state.history.map((value, index) => /* @__PURE__ */ jsx(
554
- "span",
555
- {
556
- key: index,
557
- className: "inline-block bg-gray-200 rounded px-2 py-1 m-1"
558
- },
559
- value
560
- ))))));
561
- }
562
- var init_StateDemo = __esm({
563
- "src/components/StateDemo.tsx"() {
564
- "use strict";
565
- init_dist();
566
- }
567
- });
568
-
569
- // src/components/ErrorBoundary.tsx
570
- function ErrorBoundary({ children, fallback }) {
571
- const [error, resetError] = useErrorBoundary();
572
- if (error) {
573
- if (fallback) {
574
- return fallback(error, resetError);
575
- }
576
- return /* @__PURE__ */ jsx("div", { className: "error-boundary p-4 border border-red-500 rounded bg-red-50" }, /* @__PURE__ */ jsx("h3", { className: "text-lg font-medium text-red-800 mb-2" }, "Something went wrong"), /* @__PURE__ */ jsx("p", { className: "text-red-600 mb-2" }, error.message), /* @__PURE__ */ jsx(
577
- "button",
578
- {
579
- onClick: resetError,
580
- className: "px-3 py-1 bg-red-600 text-white rounded hover:bg-red-700"
581
- },
582
- "Try again"
583
- ), /* @__PURE__ */ jsx("pre", { className: "mt-3 text-xs overflow-auto p-2 bg-gray-100" }, error.stack));
584
- }
585
- return children;
586
- }
587
- var init_ErrorBoundary = __esm({
588
- "src/components/ErrorBoundary.tsx"() {
589
- "use strict";
590
- init_dist();
591
- }
592
- });
593
-
594
- // src/data/api.ts
595
- var sampleUsers, samplePosts, delay, UserApi;
596
- var init_api = __esm({
597
- "src/data/api.ts"() {
598
- "use strict";
599
- init_dist();
600
- sampleUsers = [
601
- { id: 1, name: "User 1", email: "user1@example.com" },
602
- { id: 2, name: "User 2", email: "user2@example.com" },
603
- { id: 3, name: "User 3", email: "user3@example.com" }
604
- ];
605
- samplePosts = [
606
- { id: 1, title: "Post 1", content: "Content for post 1", authorId: 1 },
607
- { id: 2, title: "Post 2", content: "Content for post 2", authorId: 2 },
608
- { id: 3, title: "Post 3", content: "Content for post 3", authorId: 1 }
609
- ];
610
- delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
611
- UserApi = {
612
- // Get all users
613
- async getAll() {
614
- try {
615
- await delay(300);
616
- return [...sampleUsers];
617
- } catch (error) {
618
- console.error("Error fetching users:", error);
619
- return [];
620
- }
621
- },
622
- // Get user by ID
623
- async getById(id) {
624
- try {
625
- const userId = typeof id === "string" ? parseInt(id, 10) : id;
626
- await delay(200);
627
- const user = sampleUsers.find((u) => u.id === userId);
628
- if (!user)
629
- throw new Error("User not found");
630
- return { ...user };
631
- } catch (error) {
632
- console.error(`Error fetching user ${id}:`, error);
633
- return null;
634
- }
635
- },
636
- // Get posts (all or by author)
637
- async getPosts(authorId) {
638
- try {
639
- const userId = authorId ? typeof authorId === "string" ? parseInt(authorId, 10) : authorId : void 0;
640
- await delay(400);
641
- const posts = userId ? samplePosts.filter((p) => p.authorId === userId) : samplePosts;
642
- return [...posts];
643
- } catch (error) {
644
- console.error("Error fetching posts:", error);
645
- return [];
646
- }
647
- }
648
- };
649
- }
650
- });
651
-
652
- // src/pages/index.tsx
653
- var pages_exports = {};
654
- __export(pages_exports, {
655
- default: () => HomePage,
656
- getServerSideProps: () => getServerSideProps2
657
- });
658
- function HomePage({ users, posts, initialState: initialState2 }) {
659
- const [state, setState] = useState(initialState2 || {});
660
- const [refreshTrigger, setRefreshTrigger] = useState(0);
661
- useEffect(() => {
662
- if (refreshTrigger === 0)
663
- return;
664
- async function fetchData() {
665
- try {
666
- const [users2, posts2] = await Promise.all([
667
- UserApi.getAll(),
668
- UserApi.getPosts()
669
- ]);
670
- batchUpdates(() => {
671
- setState((prev) => ({
672
- ...prev,
673
- data: {
674
- ...prev.data,
675
- users: users2,
676
- posts: posts2
677
- },
678
- lastUpdate: (/* @__PURE__ */ new Date()).toISOString()
679
- }));
680
- });
681
- } catch (error) {
682
- console.error("Error fetching data:", error);
683
- }
684
- }
685
- fetchData();
686
- }, [refreshTrigger]);
687
- const handleRefresh = () => {
688
- setRefreshTrigger((t) => t + 1);
689
- };
690
- return /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto py-8" }, /* @__PURE__ */ jsx("h1", { className: "text-3xl font-bold text-blue-600 mb-6" }, "Welcome to your Next-style Frontend Hamroun application!"), /* @__PURE__ */ jsx("div", { className: "mb-8" }, /* @__PURE__ */ jsx(
691
- "button",
692
- {
693
- className: "mb-4 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700",
694
- onClick: handleRefresh
695
- },
696
- "Refresh Data"
697
- ), /* @__PURE__ */ jsx("div", { className: "bg-blue-50 p-4 rounded-lg border border-blue-100 mb-6" }, /* @__PURE__ */ jsx("p", { className: "text-blue-700" }, "Last updated: ", state.lastUpdate || "Never"))), /* @__PURE__ */ jsx(ErrorBoundary, null, /* @__PURE__ */ jsx("div", { className: "bg-white shadow-lg rounded-lg p-6 mb-8" }, /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-gray-800 mb-4" }, "User List"), /* @__PURE__ */ jsx(UserList, { users: users || state.data?.users || [] }))), /* @__PURE__ */ jsx(ErrorBoundary, null, /* @__PURE__ */ jsx(StateDemo, null)), /* @__PURE__ */ jsx("div", { className: "bg-gray-50 rounded-lg p-6 border border-gray-200 mt-8" }, /* @__PURE__ */ jsx("h3", { className: "text-lg font-medium text-gray-700 mb-3" }, "Application State"), /* @__PURE__ */ jsx("pre", { className: "overflow-auto p-4 bg-gray-100 rounded-md text-sm text-gray-800" }, JSON.stringify({ users, posts, ...state }, null, 2))));
698
- }
699
- async function getServerSideProps2() {
700
- try {
701
- const users = await UserApi.getAll();
702
- const posts = await UserApi.getPosts();
703
- return {
704
- props: {
705
- users,
706
- posts
707
- }
708
- };
709
- } catch (error) {
710
- console.error("Error fetching initial data:", error);
711
- return {
712
- props: {
713
- users: [],
714
- posts: []
715
- }
716
- };
717
- }
718
- }
719
- var init_pages = __esm({
720
- "src/pages/index.tsx"() {
721
- "use strict";
722
- init_dist();
723
- init_UserList();
724
- init_StateDemo();
725
- init_ErrorBoundary();
726
- init_api();
727
- }
728
- });
729
-
730
- // src/pages/users.tsx
731
- var users_exports = {};
732
- __export(users_exports, {
733
- default: () => users_default
734
- });
735
- var UsersPage, users_default;
736
- var init_users = __esm({
737
- "src/pages/users.tsx"() {
738
- "use strict";
739
- init_dist();
740
- init_Layout();
741
- init_api();
742
- UsersPage = ({ initialState: initialState2 }) => {
743
- const users = initialState2.data?.users || [];
744
- return /* @__PURE__ */ jsx(Layout, { title: "User Management" }, /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto" }, /* @__PURE__ */ jsx("div", { className: "bg-blue-50 p-6 rounded-lg mb-8 border border-blue-100" }, /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-blue-800 mb-2" }, "Data Fetching Demo"), /* @__PURE__ */ jsx("p", { className: "text-blue-700" }, "This page demonstrates dynamic data fetching with the Users API.")), /* @__PURE__ */ jsx("div", { className: "bg-white shadow-md rounded-lg overflow-hidden" }, /* @__PURE__ */ jsx("div", { className: "px-6 py-4 border-b border-gray-200" }, /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-gray-800" }, "User List")), users.length === 0 ? /* @__PURE__ */ jsx("div", { className: "p-6 text-center text-gray-500" }, /* @__PURE__ */ jsx("p", null, "No users found.")) : /* @__PURE__ */ jsx("div", { className: "overflow-x-auto" }, /* @__PURE__ */ jsx("table", { className: "w-full" }, /* @__PURE__ */ jsx("thead", null, /* @__PURE__ */ jsx("tr", { className: "bg-gray-50" }, /* @__PURE__ */ jsx("th", { className: "text-left py-3 px-6 font-medium text-gray-600 text-sm uppercase tracking-wider border-b" }, "ID"), /* @__PURE__ */ jsx("th", { className: "text-left py-3 px-6 font-medium text-gray-600 text-sm uppercase tracking-wider border-b" }, "Name"), /* @__PURE__ */ jsx("th", { className: "text-left py-3 px-6 font-medium text-gray-600 text-sm uppercase tracking-wider border-b" }, "Email"))), /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-gray-200" }, users.map((user) => /* @__PURE__ */ jsx("tr", { key: user.id, className: "hover:bg-gray-50" }, /* @__PURE__ */ jsx("td", { className: "py-4 px-6 text-sm text-gray-900" }, user.id), /* @__PURE__ */ jsx("td", { className: "py-4 px-6 text-sm font-medium text-gray-900" }, user.name), /* @__PURE__ */ jsx("td", { className: "py-4 px-6 text-sm text-gray-500" }, user.email)))))))));
745
- };
746
- UsersPage.getInitialData = async () => {
747
- return {
748
- users: await UserApi.getAll()
749
- };
750
- };
751
- users_default = UsersPage;
752
- }
753
- });
754
-
755
- // src/pages/users/[id].tsx
756
- var id_exports2 = {};
757
- __export(id_exports2, {
758
- default: () => UserDetail,
759
- getServerSideProps: () => getServerSideProps3
760
- });
761
- function UserDetail({ user, posts, initialState: initialState2 }) {
762
- const [userData, setUserData] = useState(user);
763
- const [userPosts, setUserPosts] = useState(posts || []);
764
- const [loading, setLoading] = useState(false);
765
- const [error, setError] = useState(null);
766
- const { id } = initialState2?.params || {};
767
- useEffect(() => {
768
- if (!userData && id) {
769
- setLoading(true);
770
- Promise.all([
771
- UserApi.getById(id),
772
- UserApi.getPosts(id)
773
- ]).then(([userData2, postsData]) => {
774
- setUserData(userData2);
775
- setUserPosts(postsData);
776
- setLoading(false);
777
- }).catch((err) => {
778
- console.error("Error fetching user data:", err);
779
- setError(err.message || "Failed to load user data");
780
- setLoading(false);
781
- });
782
- }
783
- }, [userData, id]);
784
- if (loading) {
785
- return /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto p-4" }, /* @__PURE__ */ jsx("div", { className: "animate-pulse rounded-md bg-gray-100 p-8" }, /* @__PURE__ */ jsx("div", { className: "h-8 bg-gray-200 rounded w-1/4 mb-4" }), /* @__PURE__ */ jsx("div", { className: "h-4 bg-gray-200 rounded w-1/2 mb-2" }), /* @__PURE__ */ jsx("div", { className: "h-4 bg-gray-200 rounded w-3/4 mb-4" }), /* @__PURE__ */ jsx("div", { className: "h-40 bg-gray-200 rounded mb-4" })));
786
- }
787
- if (error) {
788
- return /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto p-4" }, /* @__PURE__ */ jsx("div", { className: "rounded-md bg-red-50 p-4 border border-red-200" }, /* @__PURE__ */ jsx("h2", { className: "text-lg font-bold text-red-700" }, "Error Loading User"), /* @__PURE__ */ jsx("p", { className: "text-red-600" }, error)));
789
- }
790
- if (!userData) {
791
- return /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto p-4" }, /* @__PURE__ */ jsx("div", { className: "rounded-md bg-yellow-50 p-4 border border-yellow-200" }, /* @__PURE__ */ jsx("h2", { className: "text-lg font-bold text-yellow-700" }, "User Not Found"), /* @__PURE__ */ jsx("p", { className: "text-yellow-600" }, "Could not find user with ID: ", id), /* @__PURE__ */ jsx("a", { href: "/users", className: "text-blue-600 hover:underline mt-2 block" }, "Back to Users List")));
792
- }
793
- return /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto p-4" }, /* @__PURE__ */ jsx("div", { className: "bg-white shadow-lg rounded-lg p-6 mb-6" }, /* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold text-gray-800 mb-4" }, userData.name), /* @__PURE__ */ jsx("div", { className: "user-info mb-6" }, /* @__PURE__ */ jsx("p", { className: "text-gray-600" }, /* @__PURE__ */ jsx("span", { className: "font-bold" }, "ID:"), " ", userData.id), /* @__PURE__ */ jsx("p", { className: "text-gray-600" }, /* @__PURE__ */ jsx("span", { className: "font-bold" }, "Email:"), " ", userData.email)), /* @__PURE__ */ jsx("a", { href: "/users", className: "text-blue-600 hover:underline" }, "Back to Users List")), userPosts && userPosts.length > 0 ? /* @__PURE__ */ jsx("div", { className: "bg-white shadow-lg rounded-lg p-6" }, /* @__PURE__ */ jsx("h2", { className: "text-xl font-bold text-gray-800 mb-4" }, "Posts by ", userData.name), /* @__PURE__ */ jsx("div", { className: "space-y-4" }, userPosts.map((post) => /* @__PURE__ */ jsx("div", { key: post.id, className: "border-b pb-4" }, /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold" }, post.title), /* @__PURE__ */ jsx("p", { className: "text-gray-600" }, post.content))))) : /* @__PURE__ */ jsx("div", { className: "bg-white shadow-lg rounded-lg p-6" }, /* @__PURE__ */ jsx("h2", { className: "text-xl font-bold text-gray-800 mb-4" }, "Posts by ", userData.name), /* @__PURE__ */ jsx("p", { className: "text-gray-500 italic" }, "No posts found for this user.")));
794
- }
795
- async function getServerSideProps3({ params }) {
796
- try {
797
- const userId = params.id;
798
- const [user, posts] = await Promise.all([
799
- UserApi.getById(parseInt(userId)),
800
- UserApi.getPosts(parseInt(userId))
801
- ]);
802
- if (!user) {
803
- return {
804
- notFound: true
805
- };
806
- }
807
- return {
808
- props: {
809
- user,
810
- posts
811
- }
812
- };
813
- } catch (error) {
814
- console.error(`Error fetching user ${params.id}:`, error);
815
- return {
816
- props: {
817
- error: {
818
- message: error.message,
819
- status: error.status || 500
820
- },
821
- user: null,
822
- posts: []
823
- }
824
- };
825
- }
826
- }
827
- var init_id2 = __esm({
828
- "src/pages/users/[id].tsx"() {
829
- "use strict";
830
- init_dist();
831
- init_api();
832
- }
833
- });
834
-
835
- // src/pages/wasm-demo.tsx
836
- var wasm_demo_exports = {};
837
- var init_wasm_demo = __esm({
838
- "src/pages/wasm-demo.tsx"() {
839
- "use strict";
840
- }
841
- });
842
-
843
- // src/main.tsx
844
- init_dist();
845
-
846
- // import("./pages/**/*.tsx") in src/main.tsx
847
- var globImport_pages_tsx = __glob({
848
- "./pages/404.tsx": () => Promise.resolve().then(() => (init__(), __exports)),
849
- "./pages/[id].tsx": () => Promise.resolve().then(() => (init_id(), id_exports)),
850
- "./pages/_app.tsx": () => Promise.resolve().then(() => (init_app(), app_exports)),
851
- "./pages/_document.tsx": () => Promise.resolve().then(() => (init_document(), document_exports)),
852
- "./pages/_error.tsx": () => Promise.resolve().then(() => (init_error(), error_exports)),
853
- "./pages/about.tsx": () => Promise.resolve().then(() => (init_about(), about_exports)),
854
- "./pages/about/index.tsx": () => Promise.resolve().then(() => (init_about2(), about_exports2)),
855
- "./pages/index.tsx": () => Promise.resolve().then(() => (init_pages(), pages_exports)),
856
- "./pages/users.tsx": () => Promise.resolve().then(() => (init_users(), users_exports)),
857
- "./pages/users/[id].tsx": () => Promise.resolve().then(() => (init_id2(), id_exports2)),
858
- "./pages/wasm-demo.tsx": () => Promise.resolve().then(() => (init_wasm_demo(), wasm_demo_exports))
859
- });
860
-
861
- // import("./pages/**/*/index.tsx") in src/main.tsx
862
- var globImport_pages_index_tsx = __glob({
863
- "./pages/about/index.tsx": () => Promise.resolve().then(() => (init_about2(), about_exports2))
864
- });
865
-
866
- // src/main.tsx
867
- var initialState = window.__INITIAL_STATE__ || {
868
- route: window.location.pathname,
869
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
870
- serverRendered: false,
871
- data: {
872
- users: null,
873
- posts: null
874
- }
875
- };
876
- console.log("[Client] Initial state:", initialState);
877
- var isHydrating2 = document.getElementById("root")?.innerHTML.trim() !== "";
878
- async function handleRouteChange(path, isPushState = true) {
879
- try {
880
- console.log(`[Router] Navigating to: ${path}`);
881
- if (isPushState) {
882
- window.history.pushState(null, "", path);
883
- }
884
- const normalizedPath = path === "/" ? "index" : path.replace(/^\//, "");
885
- let Page;
886
- try {
887
- const module = await globImport_pages_tsx(`./pages/${normalizedPath}.tsx`);
888
- Page = module.default;
889
- } catch (error) {
890
- console.warn(`[Router] Could not load page for ${path}, trying index file`);
891
- try {
892
- const module = await globImport_pages_index_tsx(`./pages/${normalizedPath}/index.tsx`);
893
- Page = module.default;
894
- } catch (innerError) {
895
- console.error(`[Router] Failed to load page component for ${path}`);
896
- try {
897
- const notFoundModule = await Promise.resolve().then(() => (init__(), __exports));
898
- Page = notFoundModule.default;
899
- } catch (notFoundError) {
900
- const rootElement2 = document.getElementById("root");
901
- if (rootElement2) {
902
- render(
903
- /* @__PURE__ */ jsx("div", { style: { padding: "20px", maxWidth: "800px", margin: "0 auto" } }, /* @__PURE__ */ jsx("h1", null, "Page Not Found"), /* @__PURE__ */ jsx("p", null, "The page you requested could not be found."), /* @__PURE__ */ jsx("a", { href: "/", style: { color: "#0066cc" } }, "Go to Home")),
904
- rootElement2
905
- );
906
- }
907
- return;
908
- }
909
- }
910
- }
911
- let pageProps = initialState.pageProps || {};
912
- if (Page.getServerSideProps) {
913
- try {
914
- const response = await fetch(`/api/__props${path}`);
915
- if (response.ok) {
916
- const data = await response.json();
917
- pageProps = data.props || {};
918
- }
919
- } catch (error) {
920
- console.error("[Router] Error fetching page props:", error);
921
- }
922
- }
923
- const updatedState = {
924
- ...initialState,
925
- route: path,
926
- pageProps
927
- };
928
- const rootElement = document.getElementById("root");
929
- if (!rootElement)
930
- return;
931
- if (isHydrating2 && path === initialState.route) {
932
- console.log("[Client] Hydrating server-rendered content");
933
- hydrate(/* @__PURE__ */ jsx(Page, { ...pageProps, initialState: updatedState }), rootElement);
934
- isHydrating2 = false;
935
- } else {
936
- console.log("[Client] Rendering client-side");
937
- render(/* @__PURE__ */ jsx(Page, { ...pageProps, initialState: updatedState }), rootElement);
938
- }
939
- } catch (error) {
940
- console.error("[Router] Navigation error:", error);
941
- }
942
- }
943
- handleRouteChange(window.location.pathname, false);
944
- document.addEventListener("click", (e) => {
945
- let target = e.target;
946
- while (target && target.tagName !== "A") {
947
- target = target.parentElement;
948
- if (!target)
949
- break;
950
- }
951
- if (target && target.tagName === "A" && target.getAttribute("href") && target.getAttribute("href")?.startsWith("/") && !target.getAttribute("href")?.startsWith("//") && !target.getAttribute("target")) {
952
- e.preventDefault();
953
- const href = target.getAttribute("href") || "/";
954
- handleRouteChange(href);
955
- }
956
- });
957
- window.addEventListener("popstate", () => {
958
- handleRouteChange(window.location.pathname, false);
959
- });
960
- if (typeof io !== "undefined") {
961
- const socket = io();
962
- socket.on("reload", () => {
963
- console.log("[Dev] Reloading page due to file changes");
964
- window.location.reload();
965
- });
966
- }
967
- //# sourceMappingURL=main.js.map
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __glob = (map) => (path) => {
4
+ var fn = map[path];
5
+ if (fn)
6
+ return fn();
7
+ throw new Error("Module not found in bundle: " + path);
8
+ };
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, { get: all[name], enumerable: true });
15
+ };
16
+
17
+ // node_modules/frontend-hamroun/dist/jsx-runtime.js
18
+ function jsx(type, props) {
19
+ console.log("JSX Transform:", { type, props });
20
+ const processedProps = { ...props };
21
+ if (arguments.length > 2) {
22
+ processedProps.children = Array.prototype.slice.call(arguments, 2);
23
+ }
24
+ return { type, props: processedProps };
25
+ }
26
+ async function createElement(vnode) {
27
+ console.log("Creating element from:", vnode);
28
+ if (vnode == null) {
29
+ return document.createTextNode("");
30
+ }
31
+ if (typeof vnode === "boolean") {
32
+ return document.createTextNode("");
33
+ }
34
+ if (typeof vnode === "number" || typeof vnode === "string") {
35
+ return document.createTextNode(String(vnode));
36
+ }
37
+ if (Array.isArray(vnode)) {
38
+ const fragment = document.createDocumentFragment();
39
+ for (const child of vnode) {
40
+ const node = await createElement(child);
41
+ fragment.appendChild(node);
42
+ }
43
+ return fragment;
44
+ }
45
+ if ("type" in vnode && vnode.props !== void 0) {
46
+ const { type, props } = vnode;
47
+ if (typeof type === "function") {
48
+ try {
49
+ const result = await type(props || {});
50
+ const node = await createElement(result);
51
+ if (node instanceof Element) {
52
+ node.setAttribute("data-component-id", type.name || type.toString());
53
+ }
54
+ return node;
55
+ } catch (error) {
56
+ console.error("Error rendering component:", error);
57
+ return document.createTextNode("");
58
+ }
59
+ }
60
+ const element = document.createElement(type);
61
+ for (const [key, value] of Object.entries(props || {})) {
62
+ if (key === "children")
63
+ continue;
64
+ if (key.startsWith("on") && typeof value === "function") {
65
+ const eventName = key.toLowerCase().slice(2);
66
+ const existingHandler = element.__events?.[eventName];
67
+ if (existingHandler) {
68
+ element.removeEventListener(eventName, existingHandler);
69
+ }
70
+ element.addEventListener(eventName, value);
71
+ if (!element.__events) {
72
+ element.__events = {};
73
+ }
74
+ element.__events[eventName] = value;
75
+ } else if (key === "style" && typeof value === "object") {
76
+ Object.assign(element.style, value);
77
+ } else if (key === "className") {
78
+ element.setAttribute("class", String(value));
79
+ } else if (key !== "key" && key !== "ref") {
80
+ element.setAttribute(key, String(value));
81
+ }
82
+ }
83
+ const children = props?.children;
84
+ if (children != null) {
85
+ const childArray = Array.isArray(children) ? children.flat() : [children];
86
+ for (const child of childArray) {
87
+ const childNode = await createElement(child);
88
+ element.appendChild(childNode);
89
+ }
90
+ }
91
+ return element;
92
+ }
93
+ return document.createTextNode(String(vnode));
94
+ }
95
+ var init_jsx_runtime = __esm({
96
+ "node_modules/frontend-hamroun/dist/jsx-runtime.js"() {
97
+ }
98
+ });
99
+
100
+ // node_modules/frontend-hamroun/dist/server-renderer-QHt45Ip2.js
101
+ function batchUpdates(fn) {
102
+ if (isBatching) {
103
+ queue.push(fn);
104
+ return;
105
+ }
106
+ isBatching = true;
107
+ try {
108
+ fn();
109
+ while (queue.length > 0) {
110
+ const nextFn = queue.shift();
111
+ nextFn?.();
112
+ }
113
+ } finally {
114
+ isBatching = false;
115
+ }
116
+ }
117
+ function setRenderCallback(callback, element, container) {
118
+ globalRenderCallback = callback;
119
+ globalContainer = container;
120
+ currentElement = element;
121
+ }
122
+ function prepareRender() {
123
+ currentRender++;
124
+ stateIndices.set(currentRender, 0);
125
+ return currentRender;
126
+ }
127
+ function finishRender() {
128
+ if (isServer) {
129
+ serverStates.delete(currentRender);
130
+ }
131
+ currentRender = 0;
132
+ }
133
+ function useState(initial) {
134
+ if (!currentRender) {
135
+ throw new Error("useState must be called within a render");
136
+ }
137
+ if (isServer) {
138
+ if (!serverStates.has(currentRender)) {
139
+ serverStates.set(currentRender, /* @__PURE__ */ new Map());
140
+ }
141
+ const componentState = serverStates.get(currentRender);
142
+ const index2 = stateIndices.get(currentRender) || 0;
143
+ if (!componentState.has(index2)) {
144
+ componentState.set(index2, initial);
145
+ }
146
+ const state2 = componentState.get(index2);
147
+ const setState2 = (_newValue) => {
148
+ };
149
+ stateIndices.set(currentRender, index2 + 1);
150
+ return [state2, setState2];
151
+ }
152
+ if (!states.has(currentRender)) {
153
+ states.set(currentRender, []);
154
+ }
155
+ const componentStates = states.get(currentRender);
156
+ const index = stateIndices.get(currentRender) || 0;
157
+ if (index >= componentStates.length) {
158
+ componentStates.push(initial);
159
+ }
160
+ const state = componentStates[index];
161
+ const setState = (newValue) => {
162
+ const nextValue = typeof newValue === "function" ? newValue(componentStates[index]) : newValue;
163
+ if (componentStates[index] === nextValue)
164
+ return;
165
+ componentStates[index] = nextValue;
166
+ if (isBatching) {
167
+ batchUpdates(() => rerender(currentRender));
168
+ } else {
169
+ rerender(currentRender);
170
+ }
171
+ };
172
+ stateIndices.set(currentRender, index + 1);
173
+ return [state, setState];
174
+ }
175
+ function useEffect(callback, deps) {
176
+ if (!currentRender)
177
+ throw new Error("useEffect must be called within a render");
178
+ if (isServer) {
179
+ const effectIndex2 = stateIndices.get(currentRender) || 0;
180
+ stateIndices.set(currentRender, effectIndex2 + 1);
181
+ return;
182
+ }
183
+ const effectIndex = stateIndices.get(currentRender) || 0;
184
+ if (!effects.has(currentRender)) {
185
+ effects.set(currentRender, []);
186
+ }
187
+ const componentEffects = effects.get(currentRender);
188
+ const prevEffect = componentEffects[effectIndex];
189
+ if (!prevEffect || !deps || !prevEffect.deps || deps.some((dep, i) => dep !== prevEffect.deps[i])) {
190
+ if (prevEffect?.cleanup) {
191
+ prevEffect.cleanup();
192
+ }
193
+ queueMicrotask(() => {
194
+ const cleanup = callback() || void 0;
195
+ componentEffects[effectIndex] = { cleanup, deps: deps || [] };
196
+ });
197
+ }
198
+ stateIndices.set(currentRender, effectIndex + 1);
199
+ }
200
+ function useMemo(factory, deps) {
201
+ if (!currentRender)
202
+ throw new Error("useMemo must be called within a render");
203
+ const memoIndex = stateIndices.get(currentRender) || 0;
204
+ if (!memos.has(currentRender)) {
205
+ memos.set(currentRender, []);
206
+ }
207
+ const componentMemos = memos.get(currentRender);
208
+ const prevMemo = componentMemos[memoIndex];
209
+ if (!prevMemo || deps && deps.some((dep, i) => !Object.is(dep, prevMemo.deps[i]))) {
210
+ const value = factory();
211
+ componentMemos[memoIndex] = { value, deps: deps || [] };
212
+ stateIndices.set(currentRender, memoIndex + 1);
213
+ return value;
214
+ }
215
+ stateIndices.set(currentRender, memoIndex + 1);
216
+ return prevMemo.value;
217
+ }
218
+ async function rerender(rendererId) {
219
+ try {
220
+ const componentEffects = effects.get(rendererId);
221
+ if (componentEffects) {
222
+ componentEffects.forEach((effect) => {
223
+ if (effect.cleanup)
224
+ effect.cleanup();
225
+ });
226
+ effects.set(rendererId, []);
227
+ }
228
+ if (globalRenderCallback && globalContainer && currentElement) {
229
+ await globalRenderCallback(currentElement, globalContainer);
230
+ }
231
+ } catch (error) {
232
+ console.error("Error during rerender:", error);
233
+ }
234
+ }
235
+ function useErrorBoundary() {
236
+ const [error, setError] = useState(null);
237
+ return [error, () => setError(null)];
238
+ }
239
+ var isBatching, queue, currentRender, states, stateIndices, effects, memos, isServer, serverStates, globalRenderCallback, globalContainer, currentElement;
240
+ var init_server_renderer_QHt45Ip2 = __esm({
241
+ "node_modules/frontend-hamroun/dist/server-renderer-QHt45Ip2.js"() {
242
+ isBatching = false;
243
+ queue = [];
244
+ currentRender = 0;
245
+ states = /* @__PURE__ */ new Map();
246
+ stateIndices = /* @__PURE__ */ new Map();
247
+ effects = /* @__PURE__ */ new Map();
248
+ memos = /* @__PURE__ */ new Map();
249
+ isServer = typeof window === "undefined";
250
+ serverStates = /* @__PURE__ */ new Map();
251
+ globalRenderCallback = null;
252
+ globalContainer = null;
253
+ currentElement = null;
254
+ }
255
+ });
256
+
257
+ // node_modules/frontend-hamroun/dist/renderer-Bo9zkUZ_.js
258
+ async function hydrate(element, container) {
259
+ isHydrating = true;
260
+ try {
261
+ await render(element, container);
262
+ } finally {
263
+ isHydrating = false;
264
+ }
265
+ }
266
+ async function render(element, container) {
267
+ console.log("Rendering to:", container.id);
268
+ batchUpdates(async () => {
269
+ const rendererId = prepareRender();
270
+ try {
271
+ setRenderCallback(render, element, container);
272
+ const domNode = await createElement(element);
273
+ if (!isHydrating) {
274
+ container.innerHTML = "";
275
+ }
276
+ container.appendChild(domNode);
277
+ } finally {
278
+ finishRender();
279
+ }
280
+ });
281
+ }
282
+ var isHydrating;
283
+ var init_renderer_Bo9zkUZ = __esm({
284
+ "node_modules/frontend-hamroun/dist/renderer-Bo9zkUZ_.js"() {
285
+ init_jsx_runtime();
286
+ init_server_renderer_QHt45Ip2();
287
+ isHydrating = false;
288
+ }
289
+ });
290
+
291
+ // node_modules/frontend-hamroun/dist/index.js
292
+ var init_dist = __esm({
293
+ "node_modules/frontend-hamroun/dist/index.js"() {
294
+ init_jsx_runtime();
295
+ init_renderer_Bo9zkUZ();
296
+ init_server_renderer_QHt45Ip2();
297
+ init_server_renderer_QHt45Ip2();
298
+ }
299
+ });
300
+
301
+ // src/pages/404.tsx
302
+ var __exports = {};
303
+ __export(__exports, {
304
+ default: () => NotFound
305
+ });
306
+ function NotFound({ initialState: initialState2 }) {
307
+ return /* @__PURE__ */ jsx("div", { className: "not-found-container max-w-4xl mx-auto p-6" }, /* @__PURE__ */ jsx("div", { className: "bg-gray-50 border border-gray-200 rounded-lg p-8 shadow-sm" }, /* @__PURE__ */ jsx("h1", { className: "text-3xl font-bold text-gray-700 mb-4" }, "Page Not Found"), /* @__PURE__ */ jsx("p", { className: "text-lg text-gray-600 mb-4" }, "The page you are looking for does not exist or has been moved."), /* @__PURE__ */ jsx("p", { className: "text-gray-600 mb-6" }, "Path: ", /* @__PURE__ */ jsx("code", { className: "bg-gray-100 px-2 py-1 rounded" }, initialState2?.route || "unknown")), /* @__PURE__ */ jsx("div", { className: "mt-6" }, /* @__PURE__ */ jsx(
308
+ "a",
309
+ {
310
+ href: "/",
311
+ className: "inline-block px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700"
312
+ },
313
+ "Back to Home"
314
+ ))));
315
+ }
316
+ var init__ = __esm({
317
+ "src/pages/404.tsx"() {
318
+ "use strict";
319
+ init_dist();
320
+ }
321
+ });
322
+
323
+ // src/pages/[id].tsx
324
+ var id_exports = {};
325
+ var init_id = __esm({
326
+ "src/pages/[id].tsx"() {
327
+ "use strict";
328
+ }
329
+ });
330
+
331
+ // src/components/Layout.tsx
332
+ function Layout({ children, title = "Frontend Hamroun App" }) {
333
+ return /* @__PURE__ */ jsx("div", { className: "min-h-screen flex flex-col bg-gray-50" }, /* @__PURE__ */ jsx("header", { className: "bg-blue-600 text-white" }, /* @__PURE__ */ jsx("div", { className: "container mx-auto px-4 py-4 flex justify-between items-center" }, /* @__PURE__ */ jsx("h1", { className: "text-xl font-bold" }, /* @__PURE__ */ jsx("a", { href: "/", className: "hover:text-blue-100" }, title)), /* @__PURE__ */ jsx("nav", null, /* @__PURE__ */ jsx("ul", { className: "flex space-x-6" }, /* @__PURE__ */ jsx("li", null, /* @__PURE__ */ jsx("a", { href: "/", className: "hover:text-blue-100" }, "Home")), /* @__PURE__ */ jsx("li", null, /* @__PURE__ */ jsx("a", { href: "/about", className: "hover:text-blue-100" }, "About")))))), /* @__PURE__ */ jsx("main", { className: "flex-grow container mx-auto px-4 py-8" }, children), /* @__PURE__ */ jsx("footer", { className: "bg-gray-800 text-white" }, /* @__PURE__ */ jsx("div", { className: "container mx-auto px-4 py-6" }, /* @__PURE__ */ jsx("p", { className: "text-center text-gray-400" }, "\xA9 ", (/* @__PURE__ */ new Date()).getFullYear(), " Frontend Hamroun App. All rights reserved."))));
334
+ }
335
+ var init_Layout = __esm({
336
+ "src/components/Layout.tsx"() {
337
+ "use strict";
338
+ init_dist();
339
+ }
340
+ });
341
+
342
+ // src/pages/_app.tsx
343
+ var app_exports = {};
344
+ __export(app_exports, {
345
+ default: () => App
346
+ });
347
+ function App({ Component, pageProps, initialState: initialState2 }) {
348
+ return /* @__PURE__ */ jsx(Layout, null, /* @__PURE__ */ jsx(Component, { ...pageProps, initialState: initialState2 }));
349
+ }
350
+ var init_app = __esm({
351
+ "src/pages/_app.tsx"() {
352
+ "use strict";
353
+ init_dist();
354
+ init_Layout();
355
+ }
356
+ });
357
+
358
+ // src/pages/_document.tsx
359
+ var document_exports = {};
360
+ __export(document_exports, {
361
+ default: () => Document
362
+ });
363
+ function Document({
364
+ title = "Frontend Hamroun App",
365
+ headContent,
366
+ bodyContent,
367
+ scripts
368
+ }) {
369
+ return /* @__PURE__ */ jsx("html", { lang: "en" }, /* @__PURE__ */ jsx("head", null, /* @__PURE__ */ jsx("meta", { charSet: "UTF-8" }), /* @__PURE__ */ jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1.0" }), /* @__PURE__ */ jsx("title", null, title), /* @__PURE__ */ jsx("link", { rel: "stylesheet", href: "/styles.css" }), headContent), /* @__PURE__ */ jsx("body", null, /* @__PURE__ */ jsx("div", { id: "root" }, bodyContent), /* @__PURE__ */ jsx("script", { src: "/build/main.js", type: "module" }), scripts));
370
+ }
371
+ var init_document = __esm({
372
+ "src/pages/_document.tsx"() {
373
+ "use strict";
374
+ init_dist();
375
+ }
376
+ });
377
+
378
+ // src/pages/_error.tsx
379
+ var error_exports = {};
380
+ __export(error_exports, {
381
+ default: () => ErrorPage
382
+ });
383
+ function ErrorPage({ initialState: initialState2 }) {
384
+ const { error } = initialState2 || {};
385
+ const [showDetails, setShowDetails] = useState(false);
386
+ const isDev = true;
387
+ return /* @__PURE__ */ jsx("div", { className: "error-page-container max-w-4xl mx-auto p-6" }, /* @__PURE__ */ jsx("div", { className: "bg-red-50 border border-red-200 rounded-lg p-8 shadow-sm" }, /* @__PURE__ */ jsx("h1", { className: "text-3xl font-bold text-red-700 mb-4" }, "Something went wrong"), /* @__PURE__ */ jsx("p", { className: "text-lg text-red-600 mb-4" }, error?.message || "An unexpected error occurred"), isDev && error?.stack && /* @__PURE__ */ jsx("div", { className: "mt-6" }, /* @__PURE__ */ jsx(
388
+ "button",
389
+ {
390
+ className: "text-blue-600 underline mb-2",
391
+ onClick: () => setShowDetails(!showDetails)
392
+ },
393
+ showDetails ? "Hide" : "Show",
394
+ " technical details"
395
+ ), showDetails && /* @__PURE__ */ jsx("pre", { className: "bg-gray-100 p-4 rounded-md text-sm overflow-auto max-h-96 text-gray-800" }, error.stack)), /* @__PURE__ */ jsx("div", { className: "mt-6" }, /* @__PURE__ */ jsx(
396
+ "a",
397
+ {
398
+ href: "/",
399
+ className: "inline-block px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700"
400
+ },
401
+ "Back to Home"
402
+ ))));
403
+ }
404
+ var init_error = __esm({
405
+ "src/pages/_error.tsx"() {
406
+ "use strict";
407
+ init_dist();
408
+ }
409
+ });
410
+
411
+ // src/pages/about.tsx
412
+ var about_exports = {};
413
+ __export(about_exports, {
414
+ default: () => AboutPage,
415
+ getServerSideProps: () => getServerSideProps
416
+ });
417
+ function AboutPage({ initialState: initialState2 }) {
418
+ return /* @__PURE__ */ jsx(Layout, { title: "About - Frontend Hamroun" }, /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto" }, /* @__PURE__ */ jsx("h1", { className: "text-3xl font-bold text-blue-600 mb-6" }, "About Frontend Hamroun"), /* @__PURE__ */ jsx("div", { className: "bg-white shadow-lg rounded-lg p-8 mb-8" }, /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-gray-800 mb-4" }, "What is Frontend Hamroun?"), /* @__PURE__ */ jsx("p", { className: "text-gray-600 mb-4" }, "Frontend Hamroun is a lightweight JavaScript framework for building modern web applications. It provides a familiar component-based architecture with hooks, JSX support, and server-side rendering capabilities."), /* @__PURE__ */ jsx("p", { className: "text-gray-600 mb-4" }, "This framework is designed to be simple yet powerful, offering the essential features needed for web application development without the complexity of larger frameworks."), /* @__PURE__ */ jsx("h3", { className: "text-lg font-medium text-gray-700 mt-6 mb-2" }, "Key Features:"), /* @__PURE__ */ jsx("ul", { className: "list-disc pl-6 text-gray-600 space-y-2" }, /* @__PURE__ */ jsx("li", null, "Component-based architecture"), /* @__PURE__ */ jsx("li", null, "JSX support"), /* @__PURE__ */ jsx("li", null, "Hooks for state and effects"), /* @__PURE__ */ jsx("li", null, "Server-side rendering"), /* @__PURE__ */ jsx("li", null, "Minimal API surface"), /* @__PURE__ */ jsx("li", null, "File-based routing"), /* @__PURE__ */ jsx("li", null, "Built-in API routes"))), /* @__PURE__ */ jsx("div", { className: "bg-white shadow-lg rounded-lg p-8" }, /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-gray-800 mb-4" }, "Getting Started"), /* @__PURE__ */ jsx("p", { className: "text-gray-600 mb-4" }, "This application was created using the Frontend Hamroun fullstack template, which provides a complete setup for building applications with server-side rendering, API routes, and client-side navigation."), /* @__PURE__ */ jsx("div", { className: "bg-gray-50 p-4 rounded-md mt-4" }, /* @__PURE__ */ jsx("h3", { className: "text-md font-medium text-gray-700 mb-2" }, "Quick Start:"), /* @__PURE__ */ jsx("pre", { className: "bg-gray-800 text-gray-100 p-4 rounded overflow-x-auto" }, /* @__PURE__ */ jsx("code", null, `# Create a new application
419
+ npx frontend-hamroun create my-app
420
+
421
+ # Change directory
422
+ cd my-app
423
+
424
+ # Start the development server
425
+ npm run dev`))))));
426
+ }
427
+ async function getServerSideProps() {
428
+ return {
429
+ props: {
430
+ pageTitle: "About Frontend Hamroun",
431
+ description: "Learn more about the Frontend Hamroun framework"
432
+ }
433
+ };
434
+ }
435
+ var init_about = __esm({
436
+ "src/pages/about.tsx"() {
437
+ "use strict";
438
+ init_dist();
439
+ init_Layout();
440
+ }
441
+ });
442
+
443
+ // src/pages/about/index.tsx
444
+ var about_exports2 = {};
445
+ __export(about_exports2, {
446
+ default: () => about_default
447
+ });
448
+ var AboutPage2, about_default;
449
+ var init_about2 = __esm({
450
+ "src/pages/about/index.tsx"() {
451
+ "use strict";
452
+ init_dist();
453
+ init_Layout();
454
+ AboutPage2 = ({ initialState: initialState2 }) => {
455
+ return /* @__PURE__ */ jsx(Layout, { title: "About This App" }, /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto bg-white shadow-lg rounded-lg overflow-hidden" }, /* @__PURE__ */ jsx("div", { className: "p-8" }, /* @__PURE__ */ jsx("p", { className: "text-lg text-gray-700 mb-6" }, "This is a frontend application built with Frontend Hamroun framework and styled with Tailwind CSS."), /* @__PURE__ */ jsx("p", { className: "text-gray-600 mb-8" }, "It features server-side rendering, client-side navigation, and websocket-based live reloading during development."), /* @__PURE__ */ jsx("div", { className: "bg-gray-50 p-6 rounded-lg border border-gray-200 mb-8" }, /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-gray-800 mb-4" }, "Key Features"), /* @__PURE__ */ jsx("ul", { className: "space-y-2 text-gray-700" }, /* @__PURE__ */ jsx("li", { className: "flex items-center" }, /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-green-500 mr-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M5 13l4 4L19 7" })), "Server-side rendering"), /* @__PURE__ */ jsx("li", { className: "flex items-center" }, /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-green-500 mr-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M5 13l4 4L19 7" })), "Client-side navigation"), /* @__PURE__ */ jsx("li", { className: "flex items-center" }, /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-green-500 mr-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M5 13l4 4L19 7" })), "Component-based architecture"), /* @__PURE__ */ jsx("li", { className: "flex items-center" }, /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-green-500 mr-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M5 13l4 4L19 7" })), "Integrated API backend"), /* @__PURE__ */ jsx("li", { className: "flex items-center" }, /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-green-500 mr-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M5 13l4 4L19 7" })), "Live reload during development"), /* @__PURE__ */ jsx("li", { className: "flex items-center" }, /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-green-500 mr-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M5 13l4 4L19 7" })), "Tailwind CSS for styling"))), /* @__PURE__ */ jsx("a", { href: "/", className: "inline-block px-6 py-3 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 transition-colors" }, "Back to Home"))));
456
+ };
457
+ about_default = AboutPage2;
458
+ }
459
+ });
460
+
461
+ // src/components/UserList.tsx
462
+ function UserList({ users }) {
463
+ if (!users || users.length === 0) {
464
+ return /* @__PURE__ */ jsx("div", { className: "empty-state p-4 text-center bg-gray-50 rounded" }, /* @__PURE__ */ jsx("p", { className: "text-gray-500" }, "No users available"));
465
+ }
466
+ return /* @__PURE__ */ jsx("div", { className: "user-list" }, /* @__PURE__ */ jsx("ul", { className: "divide-y divide-gray-100" }, users.map((user) => /* @__PURE__ */ jsx("li", { key: user.id, className: "py-3" }, /* @__PURE__ */ jsx("div", { className: "flex justify-between" }, /* @__PURE__ */ jsx("div", null, /* @__PURE__ */ jsx("p", { className: "font-medium text-gray-900" }, user.name), /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500" }, user.email)), /* @__PURE__ */ jsx(
467
+ "a",
468
+ {
469
+ href: `/users/${user.id}`,
470
+ className: "text-blue-600 hover:underline text-sm self-center"
471
+ },
472
+ "View Profile"
473
+ ))))));
474
+ }
475
+ var init_UserList = __esm({
476
+ "src/components/UserList.tsx"() {
477
+ "use strict";
478
+ init_dist();
479
+ }
480
+ });
481
+
482
+ // src/components/StateDemo.tsx
483
+ function StateDemo() {
484
+ const [state, setState] = useState({
485
+ count: 0,
486
+ lastUpdated: null,
487
+ history: []
488
+ });
489
+ const [isLoading, setIsLoading] = useState(false);
490
+ const [showHistory, setShowHistory] = useState(false);
491
+ const isSSR = typeof window === "undefined";
492
+ const stats = useMemo(() => {
493
+ if (isSSR || !state || !state.history || state.history.length === 0) {
494
+ return { avg: 0, max: 0, min: 0 };
495
+ }
496
+ try {
497
+ const sum = state.history.reduce((a, b) => a + b, 0);
498
+ return {
499
+ avg: parseFloat((sum / state.history.length).toFixed(1)),
500
+ max: Math.max(...state.history),
501
+ min: Math.min(...state.history)
502
+ };
503
+ } catch (error) {
504
+ console.error("Error calculating stats:", error);
505
+ return { avg: 0, max: 0, min: 0 };
506
+ }
507
+ }, [state?.history]);
508
+ const increment = () => {
509
+ if (isSSR)
510
+ return;
511
+ setIsLoading(true);
512
+ setTimeout(() => {
513
+ setState((prevState) => ({
514
+ count: prevState.count + 1,
515
+ lastUpdated: (/* @__PURE__ */ new Date()).toLocaleTimeString(),
516
+ history: [...prevState.history || [], prevState.count + 1]
517
+ }));
518
+ setIsLoading(false);
519
+ }, 300);
520
+ };
521
+ const decrement = () => {
522
+ if (isSSR)
523
+ return;
524
+ setIsLoading(true);
525
+ setTimeout(() => {
526
+ setState((prevState) => ({
527
+ count: Math.max(0, prevState.count - 1),
528
+ lastUpdated: (/* @__PURE__ */ new Date()).toLocaleTimeString(),
529
+ history: prevState.count > 0 ? [...prevState.history || [], prevState.count - 1] : prevState.history || []
530
+ }));
531
+ setIsLoading(false);
532
+ }, 300);
533
+ };
534
+ const reset = () => {
535
+ if (isSSR)
536
+ return;
537
+ setState({
538
+ count: 0,
539
+ lastUpdated: (/* @__PURE__ */ new Date()).toLocaleTimeString(),
540
+ history: []
541
+ });
542
+ };
543
+ const toggleHistory = () => {
544
+ if (isSSR)
545
+ return;
546
+ setShowHistory((prev) => !prev);
547
+ };
548
+ if (isSSR) {
549
+ return /* @__PURE__ */ jsx("div", { className: "bg-white shadow-lg rounded-lg p-6 mb-8" }, /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-gray-800 mb-4" }, "State Management Demo"), /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between mb-4" }, /* @__PURE__ */ jsx("button", { className: "px-4 py-2 bg-gray-200 text-gray-800 rounded-lg" }, "-"), /* @__PURE__ */ jsx("span", { className: "text-2xl font-bold mx-4" }, "0"), /* @__PURE__ */ jsx("button", { className: "px-4 py-2 bg-blue-600 text-white rounded-lg" }, "+")), /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500" }, "Interactive counter (client-side only)"));
550
+ }
551
+ return /* @__PURE__ */ jsx("div", { className: "bg-white shadow-lg rounded-lg p-6 mb-8" }, /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-gray-800 mb-4" }, "State Management Demo"), /* @__PURE__ */ jsx("div", { className: "mb-6" }, /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between mb-4" }, /* @__PURE__ */ jsx(
552
+ "button",
553
+ {
554
+ onClick: decrement,
555
+ className: "px-4 py-2 bg-gray-200 text-gray-800 rounded-lg hover:bg-gray-300 disabled:opacity-50",
556
+ disabled: state.count === 0 || isLoading
557
+ },
558
+ isLoading ? "..." : "-"
559
+ ), /* @__PURE__ */ jsx("span", { className: "text-2xl font-bold mx-4" }, state.count), /* @__PURE__ */ jsx(
560
+ "button",
561
+ {
562
+ onClick: increment,
563
+ className: "px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-50",
564
+ disabled: isLoading
565
+ },
566
+ isLoading ? "..." : "+"
567
+ )), /* @__PURE__ */ jsx(
568
+ "button",
569
+ {
570
+ onClick: reset,
571
+ className: "text-sm text-gray-600 hover:text-red-600",
572
+ disabled: state.count === 0 && (!state.history || state.history.length === 0)
573
+ },
574
+ "Reset Counter"
575
+ )), state.lastUpdated && /* @__PURE__ */ jsx("div", { className: "mb-4" }, /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500" }, "Last updated: ", state.lastUpdated)), state.history && state.history.length > 0 && /* @__PURE__ */ jsx("div", { className: "border-t pt-4 mt-4" }, /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ jsx("h3", { className: "text-md font-medium text-gray-700" }, "Statistics"), /* @__PURE__ */ jsx(
576
+ "button",
577
+ {
578
+ onClick: toggleHistory,
579
+ className: "text-sm text-blue-600 hover:underline"
580
+ },
581
+ showHistory ? "Hide History" : "Show History"
582
+ )), /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-2 mb-3" }, /* @__PURE__ */ jsx("div", { className: "bg-blue-50 p-2 rounded text-center" }, /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500" }, "Average"), /* @__PURE__ */ jsx("div", { className: "font-bold" }, stats.avg)), /* @__PURE__ */ jsx("div", { className: "bg-green-50 p-2 rounded text-center" }, /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500" }, "Maximum"), /* @__PURE__ */ jsx("div", { className: "font-bold" }, stats.max)), /* @__PURE__ */ jsx("div", { className: "bg-red-50 p-2 rounded text-center" }, /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500" }, "Minimum"), /* @__PURE__ */ jsx("div", { className: "font-bold" }, stats.min))), showHistory && /* @__PURE__ */ jsx("div", { className: "mt-3" }, /* @__PURE__ */ jsx("h4", { className: "text-sm font-medium text-gray-600 mb-1" }, "History (", state.history.length, " events)"), /* @__PURE__ */ jsx("div", { className: "bg-gray-50 p-2 rounded max-h-24 overflow-y-auto text-xs" }, state.history.map((value, index) => /* @__PURE__ */ jsx(
583
+ "span",
584
+ {
585
+ key: index,
586
+ className: "inline-block bg-gray-200 rounded px-2 py-1 m-1"
587
+ },
588
+ value
589
+ ))))));
590
+ }
591
+ var init_StateDemo = __esm({
592
+ "src/components/StateDemo.tsx"() {
593
+ "use strict";
594
+ init_dist();
595
+ }
596
+ });
597
+
598
+ // src/components/ErrorBoundary.tsx
599
+ function ErrorBoundary({ children, fallback }) {
600
+ const [error, resetError] = useErrorBoundary();
601
+ if (error) {
602
+ if (fallback) {
603
+ return fallback(error, resetError);
604
+ }
605
+ return /* @__PURE__ */ jsx("div", { className: "error-boundary p-4 border border-red-500 rounded bg-red-50" }, /* @__PURE__ */ jsx("h3", { className: "text-lg font-medium text-red-800 mb-2" }, "Something went wrong"), /* @__PURE__ */ jsx("p", { className: "text-red-600 mb-2" }, error.message), /* @__PURE__ */ jsx(
606
+ "button",
607
+ {
608
+ onClick: resetError,
609
+ className: "px-3 py-1 bg-red-600 text-white rounded hover:bg-red-700"
610
+ },
611
+ "Try again"
612
+ ), /* @__PURE__ */ jsx("pre", { className: "mt-3 text-xs overflow-auto p-2 bg-gray-100" }, error.stack));
613
+ }
614
+ return children;
615
+ }
616
+ var init_ErrorBoundary = __esm({
617
+ "src/components/ErrorBoundary.tsx"() {
618
+ "use strict";
619
+ init_dist();
620
+ }
621
+ });
622
+
623
+ // src/data/api.ts
624
+ var sampleUsers, samplePosts, delay, UserApi;
625
+ var init_api = __esm({
626
+ "src/data/api.ts"() {
627
+ "use strict";
628
+ init_dist();
629
+ sampleUsers = [
630
+ { id: 1, name: "User 1", email: "user1@example.com" },
631
+ { id: 2, name: "User 2", email: "user2@example.com" },
632
+ { id: 3, name: "User 3", email: "user3@example.com" }
633
+ ];
634
+ samplePosts = [
635
+ { id: 1, title: "Post 1", content: "Content for post 1", authorId: 1 },
636
+ { id: 2, title: "Post 2", content: "Content for post 2", authorId: 2 },
637
+ { id: 3, title: "Post 3", content: "Content for post 3", authorId: 1 }
638
+ ];
639
+ delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
640
+ UserApi = {
641
+ // Get all users
642
+ async getAll() {
643
+ try {
644
+ await delay(300);
645
+ return [...sampleUsers];
646
+ } catch (error) {
647
+ console.error("Error fetching users:", error);
648
+ return [];
649
+ }
650
+ },
651
+ // Get user by ID
652
+ async getById(id) {
653
+ try {
654
+ const userId = typeof id === "string" ? parseInt(id, 10) : id;
655
+ await delay(200);
656
+ const user = sampleUsers.find((u) => u.id === userId);
657
+ if (!user)
658
+ throw new Error("User not found");
659
+ return { ...user };
660
+ } catch (error) {
661
+ console.error(`Error fetching user ${id}:`, error);
662
+ return null;
663
+ }
664
+ },
665
+ // Get posts (all or by author)
666
+ async getPosts(authorId) {
667
+ try {
668
+ const userId = authorId ? typeof authorId === "string" ? parseInt(authorId, 10) : authorId : void 0;
669
+ await delay(400);
670
+ const posts = userId ? samplePosts.filter((p) => p.authorId === userId) : samplePosts;
671
+ return [...posts];
672
+ } catch (error) {
673
+ console.error("Error fetching posts:", error);
674
+ return [];
675
+ }
676
+ }
677
+ };
678
+ }
679
+ });
680
+
681
+ // src/pages/index.tsx
682
+ var pages_exports = {};
683
+ __export(pages_exports, {
684
+ default: () => HomePage,
685
+ getServerSideProps: () => getServerSideProps2
686
+ });
687
+ function HomePage({ users, posts, initialState: initialState2 }) {
688
+ const [state, setState] = useState(initialState2 || {});
689
+ const [refreshTrigger, setRefreshTrigger] = useState(0);
690
+ useEffect(() => {
691
+ if (refreshTrigger === 0)
692
+ return;
693
+ async function fetchData() {
694
+ try {
695
+ const [users2, posts2] = await Promise.all([
696
+ UserApi.getAll(),
697
+ UserApi.getPosts()
698
+ ]);
699
+ batchUpdates(() => {
700
+ setState((prev) => ({
701
+ ...prev,
702
+ data: {
703
+ ...prev.data,
704
+ users: users2,
705
+ posts: posts2
706
+ },
707
+ lastUpdate: (/* @__PURE__ */ new Date()).toISOString()
708
+ }));
709
+ });
710
+ } catch (error) {
711
+ console.error("Error fetching data:", error);
712
+ }
713
+ }
714
+ fetchData();
715
+ }, [refreshTrigger]);
716
+ const handleRefresh = () => {
717
+ setRefreshTrigger((t) => t + 1);
718
+ };
719
+ return /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto py-8" }, /* @__PURE__ */ jsx("h1", { className: "text-3xl font-bold text-blue-600 mb-6" }, "Welcome to your Next-style Frontend Hamroun application!"), /* @__PURE__ */ jsx("div", { className: "mb-8" }, /* @__PURE__ */ jsx(
720
+ "button",
721
+ {
722
+ className: "mb-4 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700",
723
+ onClick: handleRefresh
724
+ },
725
+ "Refresh Data"
726
+ ), /* @__PURE__ */ jsx("div", { className: "bg-blue-50 p-4 rounded-lg border border-blue-100 mb-6" }, /* @__PURE__ */ jsx("p", { className: "text-blue-700" }, "Last updated: ", state.lastUpdate || "Never"))), /* @__PURE__ */ jsx(ErrorBoundary, null, /* @__PURE__ */ jsx("div", { className: "bg-white shadow-lg rounded-lg p-6 mb-8" }, /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-gray-800 mb-4" }, "User List"), /* @__PURE__ */ jsx(UserList, { users: users || state.data?.users || [] }))), /* @__PURE__ */ jsx(ErrorBoundary, null, /* @__PURE__ */ jsx(StateDemo, null)), /* @__PURE__ */ jsx("div", { className: "bg-gray-50 rounded-lg p-6 border border-gray-200 mt-8" }, /* @__PURE__ */ jsx("h3", { className: "text-lg font-medium text-gray-700 mb-3" }, "Application State"), /* @__PURE__ */ jsx("pre", { className: "overflow-auto p-4 bg-gray-100 rounded-md text-sm text-gray-800" }, JSON.stringify({ users, posts, ...state }, null, 2))));
727
+ }
728
+ async function getServerSideProps2() {
729
+ try {
730
+ const users = await UserApi.getAll();
731
+ const posts = await UserApi.getPosts();
732
+ return {
733
+ props: {
734
+ users,
735
+ posts
736
+ }
737
+ };
738
+ } catch (error) {
739
+ console.error("Error fetching initial data:", error);
740
+ return {
741
+ props: {
742
+ users: [],
743
+ posts: []
744
+ }
745
+ };
746
+ }
747
+ }
748
+ var init_pages = __esm({
749
+ "src/pages/index.tsx"() {
750
+ "use strict";
751
+ init_dist();
752
+ init_UserList();
753
+ init_StateDemo();
754
+ init_ErrorBoundary();
755
+ init_api();
756
+ }
757
+ });
758
+
759
+ // src/pages/users.tsx
760
+ var users_exports = {};
761
+ __export(users_exports, {
762
+ default: () => users_default
763
+ });
764
+ var UsersPage, users_default;
765
+ var init_users = __esm({
766
+ "src/pages/users.tsx"() {
767
+ "use strict";
768
+ init_dist();
769
+ init_Layout();
770
+ init_api();
771
+ UsersPage = ({ initialState: initialState2 }) => {
772
+ const users = initialState2.data?.users || [];
773
+ return /* @__PURE__ */ jsx(Layout, { title: "User Management" }, /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto" }, /* @__PURE__ */ jsx("div", { className: "bg-blue-50 p-6 rounded-lg mb-8 border border-blue-100" }, /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-blue-800 mb-2" }, "Data Fetching Demo"), /* @__PURE__ */ jsx("p", { className: "text-blue-700" }, "This page demonstrates dynamic data fetching with the Users API.")), /* @__PURE__ */ jsx("div", { className: "bg-white shadow-md rounded-lg overflow-hidden" }, /* @__PURE__ */ jsx("div", { className: "px-6 py-4 border-b border-gray-200" }, /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-gray-800" }, "User List")), users.length === 0 ? /* @__PURE__ */ jsx("div", { className: "p-6 text-center text-gray-500" }, /* @__PURE__ */ jsx("p", null, "No users found.")) : /* @__PURE__ */ jsx("div", { className: "overflow-x-auto" }, /* @__PURE__ */ jsx("table", { className: "w-full" }, /* @__PURE__ */ jsx("thead", null, /* @__PURE__ */ jsx("tr", { className: "bg-gray-50" }, /* @__PURE__ */ jsx("th", { className: "text-left py-3 px-6 font-medium text-gray-600 text-sm uppercase tracking-wider border-b" }, "ID"), /* @__PURE__ */ jsx("th", { className: "text-left py-3 px-6 font-medium text-gray-600 text-sm uppercase tracking-wider border-b" }, "Name"), /* @__PURE__ */ jsx("th", { className: "text-left py-3 px-6 font-medium text-gray-600 text-sm uppercase tracking-wider border-b" }, "Email"))), /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-gray-200" }, users.map((user) => /* @__PURE__ */ jsx("tr", { key: user.id, className: "hover:bg-gray-50" }, /* @__PURE__ */ jsx("td", { className: "py-4 px-6 text-sm text-gray-900" }, user.id), /* @__PURE__ */ jsx("td", { className: "py-4 px-6 text-sm font-medium text-gray-900" }, user.name), /* @__PURE__ */ jsx("td", { className: "py-4 px-6 text-sm text-gray-500" }, user.email)))))))));
774
+ };
775
+ UsersPage.getInitialData = async () => {
776
+ return {
777
+ users: await UserApi.getAll()
778
+ };
779
+ };
780
+ users_default = UsersPage;
781
+ }
782
+ });
783
+
784
+ // src/pages/users/[id].tsx
785
+ var id_exports2 = {};
786
+ __export(id_exports2, {
787
+ default: () => UserDetail,
788
+ getServerSideProps: () => getServerSideProps3
789
+ });
790
+ function UserDetail({ user, posts, initialState: initialState2 }) {
791
+ const [userData, setUserData] = useState(user);
792
+ const [userPosts, setUserPosts] = useState(posts || []);
793
+ const [loading, setLoading] = useState(false);
794
+ const [error, setError] = useState(null);
795
+ const { id } = initialState2?.params || {};
796
+ useEffect(() => {
797
+ if (!userData && id) {
798
+ setLoading(true);
799
+ Promise.all([
800
+ UserApi.getById(id),
801
+ UserApi.getPosts(id)
802
+ ]).then(([userData2, postsData]) => {
803
+ setUserData(userData2);
804
+ setUserPosts(postsData);
805
+ setLoading(false);
806
+ }).catch((err) => {
807
+ console.error("Error fetching user data:", err);
808
+ setError(err.message || "Failed to load user data");
809
+ setLoading(false);
810
+ });
811
+ }
812
+ }, [userData, id]);
813
+ if (loading) {
814
+ return /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto p-4" }, /* @__PURE__ */ jsx("div", { className: "animate-pulse rounded-md bg-gray-100 p-8" }, /* @__PURE__ */ jsx("div", { className: "h-8 bg-gray-200 rounded w-1/4 mb-4" }), /* @__PURE__ */ jsx("div", { className: "h-4 bg-gray-200 rounded w-1/2 mb-2" }), /* @__PURE__ */ jsx("div", { className: "h-4 bg-gray-200 rounded w-3/4 mb-4" }), /* @__PURE__ */ jsx("div", { className: "h-40 bg-gray-200 rounded mb-4" })));
815
+ }
816
+ if (error) {
817
+ return /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto p-4" }, /* @__PURE__ */ jsx("div", { className: "rounded-md bg-red-50 p-4 border border-red-200" }, /* @__PURE__ */ jsx("h2", { className: "text-lg font-bold text-red-700" }, "Error Loading User"), /* @__PURE__ */ jsx("p", { className: "text-red-600" }, error)));
818
+ }
819
+ if (!userData) {
820
+ return /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto p-4" }, /* @__PURE__ */ jsx("div", { className: "rounded-md bg-yellow-50 p-4 border border-yellow-200" }, /* @__PURE__ */ jsx("h2", { className: "text-lg font-bold text-yellow-700" }, "User Not Found"), /* @__PURE__ */ jsx("p", { className: "text-yellow-600" }, "Could not find user with ID: ", id), /* @__PURE__ */ jsx("a", { href: "/users", className: "text-blue-600 hover:underline mt-2 block" }, "Back to Users List")));
821
+ }
822
+ return /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto p-4" }, /* @__PURE__ */ jsx("div", { className: "bg-white shadow-lg rounded-lg p-6 mb-6" }, /* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold text-gray-800 mb-4" }, userData.name), /* @__PURE__ */ jsx("div", { className: "user-info mb-6" }, /* @__PURE__ */ jsx("p", { className: "text-gray-600" }, /* @__PURE__ */ jsx("span", { className: "font-bold" }, "ID:"), " ", userData.id), /* @__PURE__ */ jsx("p", { className: "text-gray-600" }, /* @__PURE__ */ jsx("span", { className: "font-bold" }, "Email:"), " ", userData.email)), /* @__PURE__ */ jsx("a", { href: "/users", className: "text-blue-600 hover:underline" }, "Back to Users List")), userPosts && userPosts.length > 0 ? /* @__PURE__ */ jsx("div", { className: "bg-white shadow-lg rounded-lg p-6" }, /* @__PURE__ */ jsx("h2", { className: "text-xl font-bold text-gray-800 mb-4" }, "Posts by ", userData.name), /* @__PURE__ */ jsx("div", { className: "space-y-4" }, userPosts.map((post) => /* @__PURE__ */ jsx("div", { key: post.id, className: "border-b pb-4" }, /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold" }, post.title), /* @__PURE__ */ jsx("p", { className: "text-gray-600" }, post.content))))) : /* @__PURE__ */ jsx("div", { className: "bg-white shadow-lg rounded-lg p-6" }, /* @__PURE__ */ jsx("h2", { className: "text-xl font-bold text-gray-800 mb-4" }, "Posts by ", userData.name), /* @__PURE__ */ jsx("p", { className: "text-gray-500 italic" }, "No posts found for this user.")));
823
+ }
824
+ async function getServerSideProps3({ params }) {
825
+ try {
826
+ const userId = params.id;
827
+ const [user, posts] = await Promise.all([
828
+ UserApi.getById(parseInt(userId)),
829
+ UserApi.getPosts(parseInt(userId))
830
+ ]);
831
+ if (!user) {
832
+ return {
833
+ notFound: true
834
+ };
835
+ }
836
+ return {
837
+ props: {
838
+ user,
839
+ posts
840
+ }
841
+ };
842
+ } catch (error) {
843
+ console.error(`Error fetching user ${params.id}:`, error);
844
+ return {
845
+ props: {
846
+ error: {
847
+ message: error.message,
848
+ status: error.status || 500
849
+ },
850
+ user: null,
851
+ posts: []
852
+ }
853
+ };
854
+ }
855
+ }
856
+ var init_id2 = __esm({
857
+ "src/pages/users/[id].tsx"() {
858
+ "use strict";
859
+ init_dist();
860
+ init_api();
861
+ }
862
+ });
863
+
864
+ // src/pages/wasm-demo.tsx
865
+ var wasm_demo_exports = {};
866
+ var init_wasm_demo = __esm({
867
+ "src/pages/wasm-demo.tsx"() {
868
+ "use strict";
869
+ }
870
+ });
871
+
872
+ // src/main.tsx
873
+ init_dist();
874
+
875
+ // import("./pages/**/*.tsx") in src/main.tsx
876
+ var globImport_pages_tsx = __glob({
877
+ "./pages/404.tsx": () => Promise.resolve().then(() => (init__(), __exports)),
878
+ "./pages/[id].tsx": () => Promise.resolve().then(() => (init_id(), id_exports)),
879
+ "./pages/_app.tsx": () => Promise.resolve().then(() => (init_app(), app_exports)),
880
+ "./pages/_document.tsx": () => Promise.resolve().then(() => (init_document(), document_exports)),
881
+ "./pages/_error.tsx": () => Promise.resolve().then(() => (init_error(), error_exports)),
882
+ "./pages/about.tsx": () => Promise.resolve().then(() => (init_about(), about_exports)),
883
+ "./pages/about/index.tsx": () => Promise.resolve().then(() => (init_about2(), about_exports2)),
884
+ "./pages/index.tsx": () => Promise.resolve().then(() => (init_pages(), pages_exports)),
885
+ "./pages/users.tsx": () => Promise.resolve().then(() => (init_users(), users_exports)),
886
+ "./pages/users/[id].tsx": () => Promise.resolve().then(() => (init_id2(), id_exports2)),
887
+ "./pages/wasm-demo.tsx": () => Promise.resolve().then(() => (init_wasm_demo(), wasm_demo_exports))
888
+ });
889
+
890
+ // import("./pages/**/*/index.tsx") in src/main.tsx
891
+ var globImport_pages_index_tsx = __glob({
892
+ "./pages/about/index.tsx": () => Promise.resolve().then(() => (init_about2(), about_exports2))
893
+ });
894
+
895
+ // src/main.tsx
896
+ var initialState = window.__INITIAL_STATE__ || {
897
+ route: window.location.pathname,
898
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
899
+ serverRendered: false,
900
+ data: {
901
+ users: null,
902
+ posts: null
903
+ }
904
+ };
905
+ console.log("[Client] Initial state:", initialState);
906
+ var isHydrating2 = document.getElementById("root")?.innerHTML.trim() !== "";
907
+ async function handleRouteChange(path, isPushState = true) {
908
+ try {
909
+ console.log(`[Router] Navigating to: ${path}`);
910
+ if (isPushState) {
911
+ window.history.pushState(null, "", path);
912
+ }
913
+ const normalizedPath = path === "/" ? "index" : path.replace(/^\//, "");
914
+ let Page;
915
+ try {
916
+ const module = await globImport_pages_tsx(`./pages/${normalizedPath}.tsx`);
917
+ Page = module.default;
918
+ } catch (error) {
919
+ console.warn(`[Router] Could not load page for ${path}, trying index file`);
920
+ try {
921
+ const module = await globImport_pages_index_tsx(`./pages/${normalizedPath}/index.tsx`);
922
+ Page = module.default;
923
+ } catch (innerError) {
924
+ console.error(`[Router] Failed to load page component for ${path}`);
925
+ try {
926
+ const notFoundModule = await Promise.resolve().then(() => (init__(), __exports));
927
+ Page = notFoundModule.default;
928
+ } catch (notFoundError) {
929
+ const rootElement2 = document.getElementById("root");
930
+ if (rootElement2) {
931
+ render(
932
+ /* @__PURE__ */ jsx("div", { style: { padding: "20px", maxWidth: "800px", margin: "0 auto" } }, /* @__PURE__ */ jsx("h1", null, "Page Not Found"), /* @__PURE__ */ jsx("p", null, "The page you requested could not be found."), /* @__PURE__ */ jsx("a", { href: "/", style: { color: "#0066cc" } }, "Go to Home")),
933
+ rootElement2
934
+ );
935
+ }
936
+ return;
937
+ }
938
+ }
939
+ }
940
+ let pageProps = initialState.pageProps || {};
941
+ if (Page.getServerSideProps) {
942
+ try {
943
+ const response = await fetch(`/api/__props${path}`);
944
+ if (response.ok) {
945
+ const data = await response.json();
946
+ pageProps = data.props || {};
947
+ }
948
+ } catch (error) {
949
+ console.error("[Router] Error fetching page props:", error);
950
+ }
951
+ }
952
+ const updatedState = {
953
+ ...initialState,
954
+ route: path,
955
+ pageProps
956
+ };
957
+ const rootElement = document.getElementById("root");
958
+ if (!rootElement)
959
+ return;
960
+ if (isHydrating2 && path === initialState.route) {
961
+ console.log("[Client] Hydrating server-rendered content");
962
+ hydrate(/* @__PURE__ */ jsx(Page, { ...pageProps, initialState: updatedState }), rootElement);
963
+ isHydrating2 = false;
964
+ } else {
965
+ console.log("[Client] Rendering client-side");
966
+ render(/* @__PURE__ */ jsx(Page, { ...pageProps, initialState: updatedState }), rootElement);
967
+ }
968
+ } catch (error) {
969
+ console.error("[Router] Navigation error:", error);
970
+ }
971
+ }
972
+ handleRouteChange(window.location.pathname, false);
973
+ document.addEventListener("click", (e) => {
974
+ let target = e.target;
975
+ while (target && target.tagName !== "A") {
976
+ target = target.parentElement;
977
+ if (!target)
978
+ break;
979
+ }
980
+ if (target && target.tagName === "A" && target.getAttribute("href") && target.getAttribute("href")?.startsWith("/") && !target.getAttribute("href")?.startsWith("//") && !target.getAttribute("target")) {
981
+ e.preventDefault();
982
+ const href = target.getAttribute("href") || "/";
983
+ handleRouteChange(href);
984
+ }
985
+ });
986
+ window.addEventListener("popstate", () => {
987
+ handleRouteChange(window.location.pathname, false);
988
+ });
989
+ if (typeof io !== "undefined") {
990
+ const socket = io();
991
+ socket.on("reload", () => {
992
+ console.log("[Dev] Reloading page due to file changes");
993
+ window.location.reload();
994
+ });
995
+ }
996
+ //# sourceMappingURL=main.js.map