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
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "ssr-app",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "scripts": {
6
+ "dev": "node server.js",
7
+ "start": "node server.js",
8
+ "build": "echo 'No build step required for this template'"
9
+ },
10
+ "dependencies": {
11
+ "compression": "^1.8.0",
12
+ "cors": "^2.8.5",
13
+ "dotenv": "^16.0.3",
14
+ "express": "^4.18.2",
15
+ "frontend-hamroun": "^1.2.79",
16
+ "node-fetch": "^3.3.1"
17
+ }
18
+ }
@@ -0,0 +1,119 @@
1
+ import { jsx, useState, useEffect } from 'frontend-hamroun';
2
+
3
+ // Simple animation component to demonstrate useEffect
4
+ function FadeIn({ children, delay = 0 }) {
5
+ const [opacity, setOpacity] = useState(0);
6
+
7
+ useEffect(() => {
8
+ const timer = setTimeout(() => {
9
+ setOpacity(1);
10
+ }, delay);
11
+
12
+ return () => clearTimeout(timer);
13
+ }, [delay]);
14
+
15
+ return jsx('div', {
16
+ style: `opacity: ${opacity}; transition: opacity 0.5s ease-in-out;`
17
+ }, children);
18
+ }
19
+
20
+ // Main about page component
21
+ export default function AboutPage(props) {
22
+ const [activeSection, setActiveSection] = useState('overview');
23
+
24
+ return jsx('div', { className: 'container' }, [
25
+ jsx('header', { className: 'header' }, [
26
+ jsx('h1', {}, 'About Frontend Hamroun'),
27
+ jsx('a', { href: '/', className: 'back-link' }, '← Back to Home')
28
+ ]),
29
+
30
+ jsx('main', {}, [
31
+ jsx('div', { className: 'about-nav' }, [
32
+ jsx('button', {
33
+ className: activeSection === 'overview' ? 'active' : '',
34
+ onClick: () => setActiveSection('overview')
35
+ }, 'Overview'),
36
+ jsx('button', {
37
+ className: activeSection === 'features' ? 'active' : '',
38
+ onClick: () => setActiveSection('features')
39
+ }, 'Features'),
40
+ jsx('button', {
41
+ className: activeSection === 'team' ? 'active' : '',
42
+ onClick: () => setActiveSection('team')
43
+ }, 'Team')
44
+ ]),
45
+
46
+ // Overview section
47
+ activeSection === 'overview' && jsx(FadeIn, {}, [
48
+ jsx('section', { className: 'about-section' }, [
49
+ jsx('h2', {}, 'Framework Overview'),
50
+ jsx('p', {}, 'Frontend Hamroun is a lightweight JavaScript framework for building modern web applications with server-side rendering and client-side hydration.'),
51
+ jsx('p', {}, 'Inspired by React and other modern frameworks, it provides a simple yet powerful component model with hooks for state management and side effects.'),
52
+ jsx('p', {}, `This page was rendered on the server at ${props.api?.serverTime} and then hydrated on the client to provide interactivity.`)
53
+ ])
54
+ ]),
55
+
56
+ // Features section
57
+ activeSection === 'features' && jsx(FadeIn, {}, [
58
+ jsx('section', { className: 'about-section' }, [
59
+ jsx('h2', {}, 'Key Features'),
60
+ jsx('ul', { className: 'feature-list expanded' }, [
61
+ jsx('li', {}, [
62
+ jsx('strong', {}, 'Server-Side Rendering (SSR):'),
63
+ jsx('p', {}, 'Render pages on the server for faster initial load and improved SEO.')
64
+ ]),
65
+ jsx('li', {}, [
66
+ jsx('strong', {}, 'Client-Side Hydration:'),
67
+ jsx('p', {}, 'Add interactivity to server-rendered HTML without rebuilding the DOM.')
68
+ ]),
69
+ jsx('li', {}, [
70
+ jsx('strong', {}, 'React-like Hooks:'),
71
+ jsx('p', {}, 'Use useState, useEffect, useMemo, and useRef for managing component state and lifecycle.')
72
+ ]),
73
+ jsx('li', {}, [
74
+ jsx('strong', {}, 'Context API:'),
75
+ jsx('p', {}, 'Share state between components without prop drilling using createContext and useContext.')
76
+ ]),
77
+ jsx('li', {}, [
78
+ jsx('strong', {}, 'WebAssembly Integration:'),
79
+ jsx('p', {}, 'Leverage high-performance Go code compiled to WebAssembly for computationally intensive tasks.')
80
+ ]),
81
+ jsx('li', {}, [
82
+ jsx('strong', {}, 'Automatic Route Handling:'),
83
+ jsx('p', {}, 'File-based routing system similar to Next.js for intuitive page organization.')
84
+ ])
85
+ ])
86
+ ])
87
+ ]),
88
+
89
+ // Team section
90
+ activeSection === 'team' && jsx(FadeIn, {}, [
91
+ jsx('section', { className: 'about-section' }, [
92
+ jsx('h2', {}, 'The Team'),
93
+ jsx('div', { className: 'team-grid' }, [
94
+ jsx('div', { className: 'team-member' }, [
95
+ jsx('div', { className: 'avatar' }, 'MH'),
96
+ jsx('h3', {}, 'Mohamed Hamroun'),
97
+ jsx('p', { className: 'title' }, 'Lead Framework Developer'),
98
+ jsx('p', { className: 'bio' }, 'Creator of Frontend Hamroun and full-stack JavaScript enthusiast.')
99
+ ]),
100
+ jsx('div', { className: 'team-member' }, [
101
+ jsx('div', { className: 'avatar' }, 'AI'),
102
+ jsx('h3', {}, 'AI Assistant'),
103
+ jsx('p', { className: 'title' }, 'Documentation & Support'),
104
+ jsx('p', { className: 'bio' }, 'Helps with documentation, examples, and framework support.')
105
+ ])
106
+ ])
107
+ ])
108
+ ])
109
+ ]),
110
+
111
+ jsx('footer', {}, [
112
+ jsx('p', {}, '© 2025 Frontend Hamroun Framework')
113
+ ])
114
+ ]);
115
+ }
116
+
117
+ // Static metadata for SEO
118
+ AboutPage.getTitle = () => 'About - Frontend Hamroun Framework';
119
+ AboutPage.getDescription = () => 'Learn about the Frontend Hamroun framework, its features, and the team behind it.';
File without changes
@@ -0,0 +1,157 @@
1
+ import { jsx, useState, useEffect, useMemo, useRef, useContext, createContext } from 'frontend-hamroun';
2
+
3
+ // Create a context for theme
4
+ const ThemeContext = createContext({ theme: 'light', toggleTheme: () => {} });
5
+
6
+ // Demo counter component using hooks
7
+ function Counter({ initialCount = 0 }) {
8
+ const [count, setCount] = useState(initialCount);
9
+ const countRef = useRef(count);
10
+ const { theme } = useContext(ThemeContext);
11
+
12
+ // Update ref when count changes
13
+ useEffect(() => {
14
+ countRef.current = count;
15
+ console.log('Count updated to:', count);
16
+ }, [count]);
17
+
18
+ // Use memoization for expensive calculation
19
+ const isEven = useMemo(() => {
20
+ console.log('Computing isEven...');
21
+ return count % 2 === 0;
22
+ }, [count]);
23
+
24
+ const themeClass = theme === 'dark' ? 'dark-theme' : 'light-theme';
25
+
26
+ return jsx('div', { className: `counter ${themeClass}` }, [
27
+ jsx('h3', {}, 'Interactive Counter'),
28
+ jsx('p', {}, [
29
+ jsx('span', {}, `Current count: ${count} `),
30
+ jsx('span', { className: 'badge' }, isEven ? 'even' : 'odd')
31
+ ]),
32
+ jsx('div', { className: 'button-group' }, [
33
+ jsx('button', {
34
+ onClick: () => setCount(c => c - 1),
35
+ className: 'btn'
36
+ }, 'Decrease'),
37
+ jsx('button', {
38
+ onClick: () => setCount(c => c + 1),
39
+ className: 'btn primary'
40
+ }, 'Increase'),
41
+ jsx('button', {
42
+ onClick: () => setCount(initialCount),
43
+ className: 'btn secondary'
44
+ }, 'Reset')
45
+ ])
46
+ ]);
47
+ }
48
+
49
+ // ServerInfo component to show server time
50
+ function ServerInfo({ serverTime }) {
51
+ const [clientTime, setClientTime] = useState(new Date().toISOString());
52
+ const [timeVisible, setTimeVisible] = useState(true);
53
+
54
+ // Update client time every second
55
+ useEffect(() => {
56
+ if (!timeVisible) return;
57
+
58
+ const interval = setInterval(() => {
59
+ setClientTime(new Date().toISOString());
60
+ }, 1000);
61
+
62
+ return () => clearInterval(interval);
63
+ }, [timeVisible]);
64
+
65
+ return jsx('div', { className: 'server-info card' }, [
66
+ jsx('h3', {}, 'Server/Client Time'),
67
+ jsx('button', {
68
+ onClick: () => setTimeVisible(!timeVisible),
69
+ className: 'btn small'
70
+ }, timeVisible ? 'Hide Times' : 'Show Times'),
71
+ timeVisible && jsx('div', { className: 'time-container' }, [
72
+ jsx('p', {}, [
73
+ jsx('strong', {}, 'Server Time: '),
74
+ jsx('span', {}, serverTime)
75
+ ]),
76
+ jsx('p', {}, [
77
+ jsx('strong', {}, 'Client Time: '),
78
+ jsx('span', {}, clientTime)
79
+ ]),
80
+ jsx('p', { className: 'note' }, 'The client time updates every second to demonstrate client-side effects.')
81
+ ])
82
+ ]);
83
+ }
84
+
85
+ // Main page component
86
+ export default function HomePage(props) {
87
+ const [theme, setTheme] = useState('light');
88
+ const toggleTheme = () => setTheme(theme === 'light' ? 'dark' : 'light');
89
+
90
+ const themeValue = useMemo(() => ({ theme, toggleTheme }), [theme]);
91
+
92
+ return jsx(ThemeContext.Provider, { value: themeValue }, [
93
+ jsx('div', { className: `container ${theme}-theme` }, [
94
+ jsx('header', { className: 'header' }, [
95
+ jsx('div', { className: 'logo' }, [
96
+ jsx('h1', {}, 'Frontend Hamroun'),
97
+ jsx('span', { className: 'version' }, 'v1.2')
98
+ ]),
99
+ jsx('button', {
100
+ onClick: toggleTheme,
101
+ className: 'theme-toggle'
102
+ }, theme === 'light' ? '🌙 Dark Mode' : '☀️ Light Mode')
103
+ ]),
104
+
105
+ jsx('main', {}, [
106
+ jsx('section', { className: 'hero' }, [
107
+ jsx('h2', {}, 'Welcome to the Complete Server-Side Rendered App'),
108
+ jsx('p', {}, 'This demo showcases the power of Frontend Hamroun framework with server-side rendering and hydration.')
109
+ ]),
110
+
111
+ jsx('div', { className: 'grid' }, [
112
+ jsx('div', { className: 'card' }, [
113
+ jsx('h3', {}, 'Framework Features'),
114
+ jsx('ul', { className: 'feature-list' }, [
115
+ jsx('li', {}, 'Server-Side Rendering'),
116
+ jsx('li', {}, 'Client-Side Hydration'),
117
+ jsx('li', {}, 'React-like Hooks (useState, useEffect, useMemo, useRef)'),
118
+ jsx('li', {}, 'Context API for State Management'),
119
+ jsx('li', {}, 'WebAssembly Integration'),
120
+ jsx('li', {}, 'SEO Optimization')
121
+ ])
122
+ ]),
123
+
124
+ jsx('div', { className: 'card' }, [
125
+ jsx(Counter, { initialCount: props.params.count ? parseInt(props.params.count) : 0 })
126
+ ]),
127
+
128
+ jsx('div', { className: 'card' }, [
129
+ jsx(ServerInfo, { serverTime: props.api?.serverTime || 'Not available' })
130
+ ]),
131
+
132
+ jsx('div', { className: 'card' }, [
133
+ jsx('h3', {}, 'Navigation'),
134
+ jsx('nav', { className: 'nav-links' }, [
135
+ jsx('a', { href: '/', className: 'active' }, 'Home'),
136
+ jsx('a', { href: '/about', className: '' }, 'About'),
137
+ jsx('a', { href: '/users', className: '' }, 'Users'),
138
+ jsx('a', { href: '/wasm-demo', className: '' }, 'WebAssembly Demo')
139
+ ])
140
+ ])
141
+ ])
142
+ ]),
143
+
144
+ jsx('footer', {}, [
145
+ jsx('p', {}, [
146
+ '© ',
147
+ jsx('span', {}, new Date().getFullYear()),
148
+ ' Frontend Hamroun Framework. Built with 💙 using SSR and hydration.'
149
+ ])
150
+ ])
151
+ ])
152
+ ]);
153
+ }
154
+
155
+ // Static metadata for SEO
156
+ HomePage.getTitle = (props) => 'Frontend Hamroun - Modern JavaScript Framework';
157
+ HomePage.getDescription = (props) => 'A server-side rendered demo of the Frontend Hamroun framework with React-like hooks and component architecture.';
File without changes
@@ -0,0 +1,290 @@
1
+ import { jsx, useState, useEffect } from 'frontend-hamroun';
2
+ import { loadGoWasm } from 'frontend-hamroun/wasm';
3
+
4
+ export default function WasmDemo(props) {
5
+ // State for WASM loading
6
+ const [wasm, setWasm] = useState(null);
7
+ const [loading, setLoading] = useState(true);
8
+ const [error, setError] = useState(null);
9
+
10
+ // State for math demo
11
+ const [num1, setNum1] = useState(5);
12
+ const [num2, setNum2] = useState(3);
13
+ const [operation, setOperation] = useState('add');
14
+ const [result, setResult] = useState(null);
15
+
16
+ // State for string operations
17
+ const [inputText, setInputText] = useState('Hello WebAssembly!');
18
+ const [processedText, setProcessedText] = useState('');
19
+
20
+ // State for array processing
21
+ const [arrayInput, setArrayInput] = useState('apple, banana, orange');
22
+ const [arrayResult, setArrayResult] = useState('');
23
+
24
+ // Load WASM module on client-side only
25
+ useEffect(() => {
26
+ async function loadWasmModule() {
27
+ setLoading(true);
28
+ try {
29
+ const wasmModule = await loadGoWasm('/wasm/example.wasm', {
30
+ debug: true
31
+ });
32
+ setWasm(wasmModule);
33
+ setError(null);
34
+ console.log('WASM module loaded:', wasmModule);
35
+ } catch (err) {
36
+ console.error('Failed to load WASM:', err);
37
+ setError(`Error loading WASM: ${err.message}`);
38
+ } finally {
39
+ setLoading(false);
40
+ }
41
+ }
42
+
43
+ loadWasmModule();
44
+ }, []);
45
+
46
+ // Update result when inputs or operation change
47
+ useEffect(() => {
48
+ if (!wasm || !wasm.functions) return;
49
+
50
+ try {
51
+ let calculatedResult;
52
+ switch (operation) {
53
+ case 'add':
54
+ calculatedResult = wasm.functions.goAdd(num1.toString(), num2.toString());
55
+ break;
56
+ case 'subtract':
57
+ calculatedResult = wasm.functions.goSubtract(num1.toString(), num2.toString());
58
+ break;
59
+ case 'multiply':
60
+ calculatedResult = wasm.functions.goMultiply(num1.toString(), num2.toString());
61
+ break;
62
+ case 'divide':
63
+ calculatedResult = wasm.functions.goDivide(num1.toString(), num2.toString());
64
+ break;
65
+ default:
66
+ calculatedResult = 'Unknown operation';
67
+ }
68
+
69
+ setResult(calculatedResult);
70
+ } catch (err) {
71
+ setResult(`Error: ${err.message}`);
72
+ }
73
+ }, [wasm, num1, num2, operation]);
74
+
75
+ // Handle text processing
76
+ const handleProcessText = () => {
77
+ if (!wasm || !wasm.functions) return;
78
+
79
+ try {
80
+ // Process the text with the WASM module's goReverseString function
81
+ const reversed = wasm.functions.goReverseString(inputText);
82
+ setProcessedText(reversed);
83
+ } catch (err) {
84
+ setProcessedText(`Error: ${err.message}`);
85
+ }
86
+ };
87
+
88
+ // Handle array processing
89
+ const handleProcessArray = () => {
90
+ if (!wasm || !wasm.functions) return;
91
+
92
+ try {
93
+ // Process the array with the WASM module's goProcessArray function
94
+ const processed = wasm.functions.goProcessArray(arrayInput);
95
+ setArrayResult(processed);
96
+ } catch (err) {
97
+ setArrayResult(`Error: ${err.message}`);
98
+ }
99
+ };
100
+
101
+ // Handle factorial calculation
102
+ const [factorialInput, setFactorialInput] = useState(5);
103
+ const [factorialResult, setFactorialResult] = useState(null);
104
+
105
+ const calculateFactorial = () => {
106
+ if (!wasm || !wasm.functions) return;
107
+
108
+ try {
109
+ const result = wasm.functions.goCalculateFactorial(factorialInput.toString());
110
+ setFactorialResult(result);
111
+ } catch (err) {
112
+ setFactorialResult(`Error: ${err.message}`);
113
+ }
114
+ };
115
+
116
+ if (loading) {
117
+ return jsx('div', { className: 'container loading-container' }, [
118
+ jsx('h1', {}, 'WebAssembly Demo'),
119
+ jsx('div', { className: 'loading' }, [
120
+ jsx('div', { className: 'spinner' }),
121
+ jsx('p', {}, 'Loading WebAssembly module...')
122
+ ])
123
+ ]);
124
+ }
125
+
126
+ if (error) {
127
+ return jsx('div', { className: 'container error-container' }, [
128
+ jsx('h1', {}, 'WebAssembly Demo'),
129
+ jsx('div', { className: 'error-box' }, [
130
+ jsx('h3', {}, 'Error Loading WebAssembly'),
131
+ jsx('p', {}, error),
132
+ jsx('p', {}, 'Make sure your browser supports WebAssembly and that the WASM file is correctly built and accessible.')
133
+ ]),
134
+ jsx('a', { href: '/', className: 'button' }, 'Back to Home')
135
+ ]);
136
+ }
137
+
138
+ return jsx('div', { className: 'container' }, [
139
+ jsx('header', { className: 'header' }, [
140
+ jsx('h1', {}, 'WebAssembly Integration Demo'),
141
+ jsx('a', { href: '/', className: 'back-link' }, '← Back to Home')
142
+ ]),
143
+
144
+ jsx('main', { className: 'wasm-demo' }, [
145
+ jsx('section', { className: 'intro-section' }, [
146
+ jsx('h2', {}, 'Go + WebAssembly Integration'),
147
+ jsx('p', {}, 'This page demonstrates how Frontend Hamroun integrates with WebAssembly modules compiled from Go. The following examples show different operations performed by Go code running in your browser.')
148
+ ]),
149
+
150
+ jsx('div', { className: 'demo-grid' }, [
151
+ // Math Operations Demo
152
+ jsx('section', { className: 'card' }, [
153
+ jsx('h3', {}, 'Math Operations'),
154
+
155
+ jsx('div', { className: 'form-grid' }, [
156
+ jsx('div', { className: 'form-group' }, [
157
+ jsx('label', { htmlFor: 'num1' }, 'First Number'),
158
+ jsx('input', {
159
+ id: 'num1',
160
+ type: 'number',
161
+ value: num1,
162
+ onChange: (e) => setNum1(parseInt(e.target.value))
163
+ })
164
+ ]),
165
+
166
+ jsx('div', { className: 'form-group' }, [
167
+ jsx('label', { htmlFor: 'num2' }, 'Second Number'),
168
+ jsx('input', {
169
+ id: 'num2',
170
+ type: 'number',
171
+ value: num2,
172
+ onChange: (e) => setNum2(parseInt(e.target.value))
173
+ })
174
+ ]),
175
+
176
+ jsx('div', { className: 'form-group' }, [
177
+ jsx('label', { htmlFor: 'operation' }, 'Operation'),
178
+ jsx('select', {
179
+ id: 'operation',
180
+ value: operation,
181
+ onChange: (e) => setOperation(e.target.value)
182
+ }, [
183
+ jsx('option', { value: 'add' }, 'Addition'),
184
+ jsx('option', { value: 'subtract' }, 'Subtraction'),
185
+ jsx('option', { value: 'multiply' }, 'Multiplication'),
186
+ jsx('option', { value: 'divide' }, 'Division')
187
+ ])
188
+ ])
189
+ ]),
190
+
191
+ jsx('div', { className: 'result-box' }, [
192
+ jsx('div', { className: 'result-label' }, 'Result:'),
193
+ jsx('div', { className: 'result-value' }, result !== null ? result : 'Calculating...')
194
+ ])
195
+ ]),
196
+
197
+ // String Operations Demo
198
+ jsx('section', { className: 'card' }, [
199
+ jsx('h3', {}, 'String Reversal'),
200
+
201
+ jsx('div', { className: 'form-group' }, [
202
+ jsx('label', { htmlFor: 'inputText' }, 'Input Text'),
203
+ jsx('input', {
204
+ id: 'inputText',
205
+ type: 'text',
206
+ value: inputText,
207
+ onChange: (e) => setInputText(e.target.value)
208
+ })
209
+ ]),
210
+
211
+ jsx('button', {
212
+ onClick: handleProcessText,
213
+ className: 'btn primary'
214
+ }, 'Reverse Text'),
215
+
216
+ jsx('div', { className: 'result-box' }, [
217
+ jsx('div', { className: 'result-label' }, 'Reversed Text:'),
218
+ jsx('div', { className: 'result-value' }, processedText || 'Click button to process')
219
+ ])
220
+ ]),
221
+
222
+ // Factorial Calculation Demo
223
+ jsx('section', { className: 'card' }, [
224
+ jsx('h3', {}, 'Factorial Calculation'),
225
+
226
+ jsx('div', { className: 'form-group' }, [
227
+ jsx('label', { htmlFor: 'factorialInput' }, 'Number (0-20)'),
228
+ jsx('input', {
229
+ id: 'factorialInput',
230
+ type: 'number',
231
+ min: '0',
232
+ max: '20',
233
+ value: factorialInput,
234
+ onChange: (e) => setFactorialInput(parseInt(e.target.value))
235
+ })
236
+ ]),
237
+
238
+ jsx('button', {
239
+ onClick: calculateFactorial,
240
+ className: 'btn primary'
241
+ }, 'Calculate Factorial'),
242
+
243
+ jsx('div', { className: 'result-box' }, [
244
+ jsx('div', { className: 'result-label' }, `Factorial of ${factorialInput}:`),
245
+ jsx('div', { className: 'result-value' }, factorialResult || 'Click button to calculate')
246
+ ])
247
+ ]),
248
+
249
+ // Array Processing Demo
250
+ jsx('section', { className: 'card' }, [
251
+ jsx('h3', {}, 'Array Processing'),
252
+
253
+ jsx('div', { className: 'form-group' }, [
254
+ jsx('label', { htmlFor: 'arrayInput' }, 'Comma-separated values'),
255
+ jsx('input', {
256
+ id: 'arrayInput',
257
+ type: 'text',
258
+ value: arrayInput,
259
+ onChange: (e) => setArrayInput(e.target.value)
260
+ })
261
+ ]),
262
+
263
+ jsx('button', {
264
+ onClick: handleProcessArray,
265
+ className: 'btn primary'
266
+ }, 'Process Array'),
267
+
268
+ jsx('div', { className: 'result-box' }, [
269
+ jsx('div', { className: 'result-label' }, 'Processed Array (uppercase):'),
270
+ jsx('div', { className: 'result-value array-result' }, arrayResult || 'Click button to process')
271
+ ])
272
+ ])
273
+ ]),
274
+
275
+ jsx('section', { className: 'info-section' }, [
276
+ jsx('h3', {}, 'How It Works'),
277
+ jsx('p', {}, 'The computations on this page are performed by Go code compiled to WebAssembly. The WebAssembly binary is loaded by Frontend Hamroun\'s WASM utility and executed in your browser.'),
278
+ jsx('p', {}, 'This demonstrates how you can leverage the performance and type safety of Go while maintaining the interactivity of a JavaScript application.')
279
+ ])
280
+ ]),
281
+
282
+ jsx('footer', {}, [
283
+ jsx('p', {}, '© 2025 Frontend Hamroun Framework - WebAssembly Demo')
284
+ ])
285
+ ]);
286
+ }
287
+
288
+ // Static metadata for SEO
289
+ WasmDemo.getTitle = () => 'WebAssembly Demo - Frontend Hamroun';
290
+ WasmDemo.getDescription = () => 'Interactive demonstration of WebAssembly integration with Go in the Frontend Hamroun framework.';
File without changes
@@ -0,0 +1,89 @@
1
+ // Simple client-side hydration script
2
+
3
+ // Helper to create a jsx element
4
+ function jsx(type, props, ...children) {
5
+ props = props || {};
6
+ if (children.length) {
7
+ props.children = children.length === 1 ? children[0] : children;
8
+ }
9
+ return { type, props };
10
+ }
11
+
12
+ // Global Fragment symbol
13
+ const Fragment = Symbol.for('react.fragment');
14
+
15
+ // Basic hydration logic for interactivity
16
+ function hydrate(element, container) {
17
+ console.log('Hydrating app...');
18
+
19
+ // Simple event delegation for the entire app container
20
+ container.addEventListener('click', (event) => {
21
+ const target = event.target;
22
+
23
+ // Handle button clicks
24
+ if (target.tagName === 'BUTTON') {
25
+ console.log('Button clicked:', target.textContent);
26
+
27
+ // Add some visual feedback
28
+ const originalColor = target.style.backgroundColor;
29
+ target.style.backgroundColor = '#ccc';
30
+
31
+ setTimeout(() => {
32
+ target.style.backgroundColor = originalColor;
33
+ }, 200);
34
+ }
35
+
36
+ // Handle links
37
+ if (target.tagName === 'A' && target.getAttribute('href') && !target.getAttribute('href').startsWith('http')) {
38
+ event.preventDefault();
39
+ const href = target.getAttribute('href');
40
+ console.log('Link clicked:', href);
41
+
42
+ // Simple client-side navigation simulation
43
+ history.pushState(null, '', href);
44
+
45
+ // Show a loading message - in a real app, you would fetch the new page
46
+ container.innerHTML = '<div class="container"><h3>Loading...</h3></div>';
47
+
48
+ // Reload the page after a short delay to demonstrate
49
+ setTimeout(() => {
50
+ window.location.reload();
51
+ }, 300);
52
+ }
53
+ });
54
+ }
55
+
56
+ // Immediately invoked function to handle hydration
57
+ (async function() {
58
+ try {
59
+ // Get the app container
60
+ const appRoot = document.getElementById('app');
61
+ if (!appRoot) {
62
+ console.error('App root element not found');
63
+ return;
64
+ }
65
+
66
+ // Get initial data from the server
67
+ let initialData = {};
68
+ try {
69
+ const dataElement = document.getElementById('__APP_DATA__');
70
+ if (dataElement && dataElement.textContent) {
71
+ initialData = JSON.parse(dataElement.textContent);
72
+ console.log('Initial data loaded:', initialData);
73
+ }
74
+ } catch (err) {
75
+ console.error('Error parsing initial data:', err);
76
+ }
77
+
78
+ // Make the app interactive
79
+ hydrate({ type: 'div', props: { initialData } }, appRoot);
80
+
81
+ console.log('App hydrated successfully');
82
+ } catch (err) {
83
+ console.error('Hydration failed:', err);
84
+ }
85
+ })();
86
+
87
+ // Make jsx globally available
88
+ window.jsx = jsx;
89
+ window.Fragment = Fragment;