frontend-hamroun 1.2.80 → 1.2.83
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.
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.client.cjs +1 -1
- package/dist/index.client.js +2 -2
- package/dist/index.js +11 -7
- package/dist/index.js.map +1 -1
- package/dist/{renderer-Din1y3YM.cjs → renderer-BL3gq8cW.cjs} +2 -2
- package/dist/{renderer-Din1y3YM.cjs.map → renderer-BL3gq8cW.cjs.map} +1 -1
- package/dist/{renderer-Bo9zkUZ_.js → renderer-Dyy-o05F.js} +2 -2
- package/dist/{renderer-Bo9zkUZ_.js.map → renderer-Dyy-o05F.js.map} +1 -1
- package/dist/{server-renderer-QHt45Ip2.js → server-renderer-C1WXH-zV.js} +99 -73
- package/dist/server-renderer-C1WXH-zV.js.map +1 -0
- package/dist/server-renderer-Chs-nmJm.cjs +2 -0
- package/dist/server-renderer-Chs-nmJm.cjs.map +1 -0
- package/dist/server-renderer.cjs +1 -1
- package/dist/server-renderer.js +1 -1
- package/package.json +1 -1
- package/templates/basic-app/src/App.jsx +16 -0
- package/templates/basic-app/src/client.jsx +5 -0
- package/templates/basic-app/src/components/Counter.jsx +13 -0
- package/templates/basic-app/src/jsx-shim.js +3 -0
- package/templates/basic-app/src/jsx-shim.ts +7 -0
- package/templates/basic-app/src/main.jsx +98 -0
- package/templates/basic-app/src/server.js +47 -0
- package/templates/complete-app/api/hello.js +0 -0
- package/templates/complete-app/lib/frontend-hamroun.js +182 -0
- package/templates/complete-app/package.json +18 -0
- package/templates/complete-app/pages/about.js +119 -0
- package/templates/complete-app/pages/about.jsx +0 -0
- package/templates/complete-app/pages/index.js +157 -0
- package/templates/complete-app/pages/index.jsx +0 -0
- package/templates/complete-app/pages/wasm-demo.js +290 -0
- package/templates/complete-app/pages/wasm-demo.jsx +0 -0
- package/templates/complete-app/public/client.js +89 -0
- package/templates/complete-app/public/index.html +118 -0
- package/templates/complete-app/public/styles.css +76 -0
- package/templates/complete-app/server.js +226 -0
- package/templates/complete-app/src/App.tsx +59 -0
- package/templates/complete-app/src/client.tsx +18 -0
- package/templates/complete-app/src/server.ts +218 -0
- package/templates/complete-app/tsconfig.json +22 -0
- package/templates/complete-app/tsconfig.server.json +19 -0
- package/templates/{ssr-template → complete-app}/vite.config.js +16 -5
- package/templates/complete-app/vite.config.ts +30 -0
- package/templates/complete-app/wasm/build.bat +0 -0
- package/templates/complete-app/wasm/build.sh +0 -0
- package/templates/complete-app/wasm/example.go +0 -0
- package/templates/fullstack-app/build/main.css +874 -874
- package/templates/fullstack-app/build/main.css.map +7 -7
- package/templates/fullstack-app/build/main.js +996 -967
- package/templates/fullstack-app/build/main.js.map +7 -7
- package/templates/fullstack-app/package-lock.json +6301 -0
- package/templates/fullstack-app/public/styles.css +768 -768
- package/templates/go/example.go +154 -99
- package/templates/ssr-template/dist/client/assets/main-D-VH3xOb.js +1 -0
- package/templates/ssr-template/dist/client/index.html +23 -0
- package/templates/ssr-template/dist/client.js +951 -0
- package/templates/ssr-template/dist/server.js +739 -0
- package/templates/ssr-template/esbuild.config.js +33 -0
- package/templates/ssr-template/jsx-shim.js +1 -0
- package/templates/ssr-template/package.json +14 -8
- package/templates/ssr-template/src/App.tsx +847 -49
- package/templates/ssr-template/src/client.tsx +3 -17
- package/templates/ssr-template/src/server.ts +21 -204
- package/templates/ssr-template/tsconfig.json +9 -8
- package/templates/ssr-template/tsconfig.server.json +6 -14
- package/templates/ssr-template/vite.config.ts +19 -17
- package/templates/wasm/build-wasm.js +228 -0
- package/templates/wasm/dist/assets/index-BNqTDBdE.js +295 -0
- package/templates/wasm/dist/example.wasm +0 -0
- package/templates/wasm/dist/index.html +53 -0
- package/templates/{go-wasm-app/public/wasm → wasm/dist}/wasm_exec.js +572 -561
- package/templates/wasm/esbuild.config.js +63 -0
- package/templates/wasm/go/main.go +256 -0
- package/templates/wasm/go/wasm_exec.js +0 -0
- package/templates/wasm/index.html +97 -0
- package/templates/wasm/jsx-shim.js +9 -0
- package/templates/wasm/package-lock.json +4577 -0
- package/templates/wasm/package.json +25 -0
- package/templates/wasm/public/example.wasm +0 -0
- package/templates/wasm/public/wasm_exec.js +572 -0
- package/templates/wasm/src/App.tsx +550 -0
- package/templates/wasm/src/client.tsx +220 -0
- package/templates/wasm/src/index.tsx +21 -0
- package/templates/wasm/src/server.ts +145 -0
- package/templates/wasm/tsconfig.json +21 -0
- package/templates/wasm/tsconfig.node.json +13 -0
- package/templates/wasm/tsconfig.server.json +23 -0
- package/templates/wasm/vite.config.ts +38 -0
- package/templates/wasm/wasm-loader.js +103 -0
- package/dist/server-renderer-CqIpQ-od.cjs +0 -2
- package/dist/server-renderer-CqIpQ-od.cjs.map +0 -1
- package/dist/server-renderer-QHt45Ip2.js.map +0 -1
- package/templates/basic-app/bun.lock +0 -196
- package/templates/basic-app/docs/rapport_pfe.aux +0 -27
- package/templates/basic-app/docs/rapport_pfe.out +0 -10
- package/templates/basic-app/docs/rapport_pfe.pdf +0 -0
- package/templates/basic-app/docs/rapport_pfe.tex +0 -68
- package/templates/basic-app/docs/rapport_pfe.toc +0 -14
- package/templates/basic-app/package-lock.json +0 -4185
- package/templates/go-wasm-app/README.md +0 -38
- package/templates/go-wasm-app/babel.config.js +0 -15
- package/templates/go-wasm-app/build-client.js +0 -49
- package/templates/go-wasm-app/build-wasm.js +0 -237
- package/templates/go-wasm-app/package.json +0 -23
- package/templates/go-wasm-app/public/index.html +0 -128
- package/templates/go-wasm-app/public/styles.css +0 -197
- package/templates/go-wasm-app/public/wasm/example.wasm +0 -0
- package/templates/go-wasm-app/public/wasm/wasm_exec_node.js +0 -39
- package/templates/go-wasm-app/server.js +0 -521
- package/templates/go-wasm-app/src/App.jsx +0 -38
- package/templates/go-wasm-app/src/app.js +0 -153
- package/templates/go-wasm-app/src/client.js +0 -57
- package/templates/go-wasm-app/src/components/Footer.jsx +0 -13
- package/templates/go-wasm-app/src/components/Header.jsx +0 -19
- package/templates/go-wasm-app/src/components/WasmDemo.jsx +0 -120
- package/templates/go-wasm-app/src/main.jsx +0 -12
- package/templates/go-wasm-app/src/wasm/example.go +0 -75
- package/templates/go-wasm-app/tsconfig.server.json +0 -18
- package/templates/go-wasm-app/vite.config.js +0 -34
- package/templates/ssr-template/package-lock.json +0 -2478
- package/templates/ssr-template/public/index.html +0 -47
- package/templates/ssr-template/server.js +0 -369
- /package/templates/{ssr-template → complete-app}/client.js +0 -0
- /package/templates/{ssr-template → complete-app}/readme.md +0 -0
- /package/templates/{ssr-template → complete-app}/server.ts +0 -0
- /package/templates/{ssr-template → complete-app}/src/client.ts +0 -0
- /package/templates/{ssr-template → complete-app}/src/pages/index.tsx +0 -0
@@ -0,0 +1,550 @@
|
|
1
|
+
import { jsx, useState, useEffect } from 'baraqex';
|
2
|
+
import { loadGoWasm, callWasmFunction } from 'baraqex';
|
3
|
+
|
4
|
+
export default function App() {
|
5
|
+
const [wasmReady, setWasmReady] = useState(false);
|
6
|
+
const [wasmError, setWasmError] = useState<string | null>(null);
|
7
|
+
const [result, setResult] = useState<any>(null);
|
8
|
+
const [inputA, setInputA] = useState(10);
|
9
|
+
const [inputB, setInputB] = useState(20);
|
10
|
+
const [fibInput, setFibInput] = useState(10);
|
11
|
+
const [primeInput, setPrimeInput] = useState(17);
|
12
|
+
const [name, setName] = useState('World');
|
13
|
+
|
14
|
+
useEffect(() => {
|
15
|
+
let mounted = true;
|
16
|
+
|
17
|
+
async function loadWasm() {
|
18
|
+
try {
|
19
|
+
console.log('Loading Go WASM module using baraqex API...');
|
20
|
+
|
21
|
+
// Use baraqex API to load WASM
|
22
|
+
await loadGoWasm('/example.wasm', {
|
23
|
+
debug: true,
|
24
|
+
onLoad: () => {
|
25
|
+
console.log('WASM module loaded successfully via baraqex');
|
26
|
+
}
|
27
|
+
});
|
28
|
+
|
29
|
+
if (mounted) {
|
30
|
+
setWasmReady(true);
|
31
|
+
setWasmError(null);
|
32
|
+
console.log('WASM module ready');
|
33
|
+
}
|
34
|
+
} catch (error) {
|
35
|
+
console.error('WASM loading error:', error);
|
36
|
+
if (mounted) {
|
37
|
+
setWasmError(error instanceof Error ? error.message : 'Unknown WASM loading error');
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
loadWasm();
|
43
|
+
|
44
|
+
return () => {
|
45
|
+
mounted = false;
|
46
|
+
};
|
47
|
+
}, []);
|
48
|
+
|
49
|
+
// Use baraqex callWasmFunction API
|
50
|
+
const callFunction = (funcName: string, ...args: any[]) => {
|
51
|
+
try {
|
52
|
+
// Call using baraqex API
|
53
|
+
return callWasmFunction(funcName, ...args);
|
54
|
+
} catch (error) {
|
55
|
+
const errorMsg = error instanceof Error ? error.message : 'Function call failed';
|
56
|
+
setWasmError(errorMsg);
|
57
|
+
return null;
|
58
|
+
}
|
59
|
+
};
|
60
|
+
|
61
|
+
const handleHello = () => {
|
62
|
+
const greeting = callFunction('goHello', name);
|
63
|
+
if (greeting !== null) {
|
64
|
+
setResult({ type: 'hello', value: greeting, input: name });
|
65
|
+
setWasmError(null);
|
66
|
+
}
|
67
|
+
};
|
68
|
+
|
69
|
+
const handleAddition = () => {
|
70
|
+
const sum = callFunction('goAdd', inputA, inputB);
|
71
|
+
if (sum !== null) {
|
72
|
+
setResult({ type: 'addition', value: sum, inputs: [inputA, inputB] });
|
73
|
+
setWasmError(null);
|
74
|
+
}
|
75
|
+
};
|
76
|
+
|
77
|
+
const handleMultiplication = () => {
|
78
|
+
const product = callFunction('goMultiply', inputA, inputB);
|
79
|
+
if (product !== null) {
|
80
|
+
setResult({ type: 'multiplication', value: product, inputs: [inputA, inputB] });
|
81
|
+
setWasmError(null);
|
82
|
+
}
|
83
|
+
};
|
84
|
+
|
85
|
+
const handleFibonacci = () => {
|
86
|
+
if (fibInput > 40) {
|
87
|
+
setWasmError('Fibonacci input too large (max 40)');
|
88
|
+
return;
|
89
|
+
}
|
90
|
+
const fibResult = callFunction('goFibonacci', fibInput);
|
91
|
+
if (fibResult !== null) {
|
92
|
+
setResult({ type: 'fibonacci', value: fibResult, input: fibInput });
|
93
|
+
setWasmError(null);
|
94
|
+
}
|
95
|
+
};
|
96
|
+
|
97
|
+
const handlePrimeCheck = () => {
|
98
|
+
const isPrime = callFunction('goIsPrime', primeInput);
|
99
|
+
if (isPrime !== null) {
|
100
|
+
setResult({ type: 'prime', value: isPrime, input: primeInput });
|
101
|
+
setWasmError(null);
|
102
|
+
}
|
103
|
+
};
|
104
|
+
|
105
|
+
if (!wasmReady && !wasmError) {
|
106
|
+
return (
|
107
|
+
<div className="app loading">
|
108
|
+
<div className="spinner"></div>
|
109
|
+
<h2>Loading Go WASM Module...</h2>
|
110
|
+
<p>Initializing WebAssembly runtime...</p>
|
111
|
+
</div>
|
112
|
+
);
|
113
|
+
}
|
114
|
+
|
115
|
+
if (wasmError) {
|
116
|
+
return (
|
117
|
+
<div className="app error">
|
118
|
+
<h2>WASM Error</h2>
|
119
|
+
<p>{wasmError}</p>
|
120
|
+
<button onClick={() => window.location.reload()}>Reload Page</button>
|
121
|
+
<details style={{ marginTop: '20px', textAlign: 'left' }}>
|
122
|
+
<summary>Troubleshooting</summary>
|
123
|
+
<ul>
|
124
|
+
<li>Make sure the WASM file is built: <code>npm run build:wasm</code></li>
|
125
|
+
<li>Check if <code>example.wasm</code> exists in the public folder</li>
|
126
|
+
<li>Verify <code>wasm_exec.js</code> is loaded in the HTML</li>
|
127
|
+
<li>Check browser console for additional errors</li>
|
128
|
+
</ul>
|
129
|
+
</details>
|
130
|
+
</div>
|
131
|
+
);
|
132
|
+
}
|
133
|
+
|
134
|
+
return (
|
135
|
+
<div className="app">
|
136
|
+
<header>
|
137
|
+
<h1>Frontend Hamroun + Go WASM (Baraqex)</h1>
|
138
|
+
<p>High-performance computing with WebAssembly via Baraqex API</p>
|
139
|
+
<div className="status">
|
140
|
+
<span className="status-indicator ready"></span>
|
141
|
+
WASM Ready via Baraqex
|
142
|
+
</div>
|
143
|
+
</header>
|
144
|
+
|
145
|
+
<main>
|
146
|
+
<section className="demo-grid">
|
147
|
+
{/* Hello Function */}
|
148
|
+
<div className="demo-card">
|
149
|
+
<h3>🌍 Hello Function</h3>
|
150
|
+
<div className="input-group">
|
151
|
+
<input
|
152
|
+
type="text"
|
153
|
+
value={name}
|
154
|
+
onChange={(e:any) => setName(e.target.value)}
|
155
|
+
placeholder="Enter your name"
|
156
|
+
/>
|
157
|
+
<button onClick={handleHello}>Say Hello</button>
|
158
|
+
</div>
|
159
|
+
<small>callWasmFunction('goHello', '{name}')</small>
|
160
|
+
</div>
|
161
|
+
|
162
|
+
{/* Math Operations */}
|
163
|
+
<div className="demo-card">
|
164
|
+
<h3>🧮 Math Operations</h3>
|
165
|
+
<div className="input-group">
|
166
|
+
<input
|
167
|
+
type="number"
|
168
|
+
value={inputA}
|
169
|
+
onChange={(e: { target: { value: any; }; }) => setInputA(Number(e.target.value))}
|
170
|
+
placeholder="First number"
|
171
|
+
/>
|
172
|
+
<input
|
173
|
+
type="number"
|
174
|
+
value={inputB}
|
175
|
+
onChange={(e: { target: { value: any; }; }) => setInputB(Number(e.target.value))}
|
176
|
+
placeholder="Second number"
|
177
|
+
/>
|
178
|
+
</div>
|
179
|
+
<div className="button-group">
|
180
|
+
<button onClick={handleAddition}>Add</button>
|
181
|
+
<button onClick={handleMultiplication}>Multiply</button>
|
182
|
+
</div>
|
183
|
+
<small>callWasmFunction('goAdd', {inputA}, {inputB})</small>
|
184
|
+
</div>
|
185
|
+
|
186
|
+
{/* Fibonacci */}
|
187
|
+
<div className="demo-card">
|
188
|
+
<h3>🔢 Fibonacci Sequence</h3>
|
189
|
+
<div className="input-group">
|
190
|
+
<input
|
191
|
+
type="number"
|
192
|
+
value={fibInput}
|
193
|
+
onChange={(e: { target: { value: any; }; }) => setFibInput(Number(e.target.value))}
|
194
|
+
placeholder="Fibonacci number"
|
195
|
+
min="0"
|
196
|
+
max="40"
|
197
|
+
/>
|
198
|
+
<button onClick={handleFibonacci}>Calculate</button>
|
199
|
+
</div>
|
200
|
+
<small>Maximum value: 40</small>
|
201
|
+
</div>
|
202
|
+
|
203
|
+
{/* Prime Check */}
|
204
|
+
<div className="demo-card">
|
205
|
+
<h3>🔍 Prime Number Check</h3>
|
206
|
+
<div className="input-group">
|
207
|
+
<input
|
208
|
+
type="number"
|
209
|
+
value={primeInput}
|
210
|
+
onChange={(e: { target: { value: any; }; }) => setPrimeInput(Number(e.target.value))}
|
211
|
+
placeholder="Number to check"
|
212
|
+
min="1"
|
213
|
+
/>
|
214
|
+
<button onClick={handlePrimeCheck}>Check Prime</button>
|
215
|
+
</div>
|
216
|
+
</div>
|
217
|
+
</section>
|
218
|
+
|
219
|
+
{/* Results Display */}
|
220
|
+
{result && (
|
221
|
+
<section className="results">
|
222
|
+
<h2>📊 Baraqex WASM Result</h2>
|
223
|
+
<div className="result-card">
|
224
|
+
{result.type === 'hello' && (
|
225
|
+
<p><strong>Greeting:</strong> <span className="result-value">{result.value}</span></p>
|
226
|
+
)}
|
227
|
+
{result.type === 'addition' && (
|
228
|
+
<p><strong>Addition:</strong> {result.inputs[0]} + {result.inputs[1]} = <span className="result-value">{result.value}</span></p>
|
229
|
+
)}
|
230
|
+
{result.type === 'multiplication' && (
|
231
|
+
<p><strong>Multiplication:</strong> {result.inputs[0]} × {result.inputs[1]} = <span className="result-value">{result.value}</span></p>
|
232
|
+
)}
|
233
|
+
{result.type === 'fibonacci' && (
|
234
|
+
<p><strong>Fibonacci:</strong> F({result.input}) = <span className="result-value">{result.value}</span></p>
|
235
|
+
)}
|
236
|
+
{result.type === 'prime' && (
|
237
|
+
<p><strong>Prime Check:</strong> {result.input} is <span className="result-value">{result.value ? 'prime' : 'not prime'}</span></p>
|
238
|
+
)}
|
239
|
+
</div>
|
240
|
+
</section>
|
241
|
+
)}
|
242
|
+
|
243
|
+
{/* Info Section */}
|
244
|
+
<section className="info-section">
|
245
|
+
<h2>⚡ Baraqex WASM Benefits</h2>
|
246
|
+
<div className="benefits-grid">
|
247
|
+
<div className="benefit">
|
248
|
+
<h4>🚀 Simple API</h4>
|
249
|
+
<p>Easy-to-use loadGoWasm() and callWasmFunction() API</p>
|
250
|
+
</div>
|
251
|
+
<div className="benefit">
|
252
|
+
<h4>🔄 Cross-Platform</h4>
|
253
|
+
<p>Works in browser and Node.js with same API</p>
|
254
|
+
</div>
|
255
|
+
<div className="benefit">
|
256
|
+
<h4>🛠️ Go Integration</h4>
|
257
|
+
<p>Seamless Go + JavaScript interoperability</p>
|
258
|
+
</div>
|
259
|
+
<div className="benefit">
|
260
|
+
<h4>📊 Debug Support</h4>
|
261
|
+
<p>Built-in debugging and function discovery</p>
|
262
|
+
</div>
|
263
|
+
</div>
|
264
|
+
</section>
|
265
|
+
</main>
|
266
|
+
|
267
|
+
<style>{`
|
268
|
+
.app {
|
269
|
+
max-width: 1200px;
|
270
|
+
margin: 0 auto;
|
271
|
+
padding: 20px;
|
272
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
273
|
+
line-height: 1.6;
|
274
|
+
}
|
275
|
+
|
276
|
+
.app.loading, .app.error {
|
277
|
+
text-align: center;
|
278
|
+
padding: 60px 20px;
|
279
|
+
}
|
280
|
+
|
281
|
+
.spinner {
|
282
|
+
width: 50px;
|
283
|
+
height: 50px;
|
284
|
+
border: 4px solid #f3f3f3;
|
285
|
+
border-top: 4px solid #007acc;
|
286
|
+
border-radius: 50%;
|
287
|
+
animation: spin 1s linear infinite;
|
288
|
+
margin: 0 auto 20px;
|
289
|
+
}
|
290
|
+
|
291
|
+
@keyframes spin {
|
292
|
+
0% { transform: rotate(0deg); }
|
293
|
+
100% { transform: rotate(360deg); }
|
294
|
+
}
|
295
|
+
|
296
|
+
header {
|
297
|
+
text-align: center;
|
298
|
+
margin-bottom: 40px;
|
299
|
+
padding: 30px;
|
300
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
301
|
+
color: white;
|
302
|
+
border-radius: 16px;
|
303
|
+
position: relative;
|
304
|
+
}
|
305
|
+
|
306
|
+
header h1 {
|
307
|
+
margin: 0 0 10px 0;
|
308
|
+
font-size: 2.5rem;
|
309
|
+
font-weight: 700;
|
310
|
+
}
|
311
|
+
|
312
|
+
header p {
|
313
|
+
margin: 0 0 20px 0;
|
314
|
+
opacity: 0.9;
|
315
|
+
font-size: 1.1rem;
|
316
|
+
}
|
317
|
+
|
318
|
+
.status {
|
319
|
+
display: inline-flex;
|
320
|
+
align-items: center;
|
321
|
+
gap: 8px;
|
322
|
+
background: rgba(255, 255, 255, 0.2);
|
323
|
+
padding: 8px 16px;
|
324
|
+
border-radius: 20px;
|
325
|
+
font-size: 0.9rem;
|
326
|
+
}
|
327
|
+
|
328
|
+
.status-indicator {
|
329
|
+
width: 8px;
|
330
|
+
height: 8px;
|
331
|
+
border-radius: 50%;
|
332
|
+
background: #4ade80;
|
333
|
+
animation: pulse 2s infinite;
|
334
|
+
}
|
335
|
+
|
336
|
+
@keyframes pulse {
|
337
|
+
0%, 100% { opacity: 1; }
|
338
|
+
50% { opacity: 0.5; }
|
339
|
+
}
|
340
|
+
|
341
|
+
.demo-grid {
|
342
|
+
display: grid;
|
343
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
344
|
+
gap: 20px;
|
345
|
+
margin-bottom: 30px;
|
346
|
+
}
|
347
|
+
|
348
|
+
.demo-card {
|
349
|
+
background: white;
|
350
|
+
padding: 24px;
|
351
|
+
border-radius: 12px;
|
352
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
353
|
+
border: 1px solid #e5e7eb;
|
354
|
+
transition: transform 0.2s, box-shadow 0.2s;
|
355
|
+
}
|
356
|
+
|
357
|
+
.demo-card:hover {
|
358
|
+
transform: translateY(-2px);
|
359
|
+
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
|
360
|
+
}
|
361
|
+
|
362
|
+
.demo-card h3 {
|
363
|
+
margin-top: 0;
|
364
|
+
margin-bottom: 16px;
|
365
|
+
color: #374151;
|
366
|
+
font-size: 1.2rem;
|
367
|
+
}
|
368
|
+
|
369
|
+
.input-group {
|
370
|
+
display: flex;
|
371
|
+
gap: 8px;
|
372
|
+
margin-bottom: 12px;
|
373
|
+
flex-wrap: wrap;
|
374
|
+
}
|
375
|
+
|
376
|
+
.button-group {
|
377
|
+
display: flex;
|
378
|
+
gap: 8px;
|
379
|
+
flex-wrap: wrap;
|
380
|
+
}
|
381
|
+
|
382
|
+
input {
|
383
|
+
flex: 1;
|
384
|
+
min-width: 120px;
|
385
|
+
padding: 10px 12px;
|
386
|
+
border: 2px solid #e5e7eb;
|
387
|
+
border-radius: 8px;
|
388
|
+
font-size: 14px;
|
389
|
+
transition: border-color 0.2s;
|
390
|
+
}
|
391
|
+
|
392
|
+
input:focus {
|
393
|
+
outline: none;
|
394
|
+
border-color: #007acc;
|
395
|
+
}
|
396
|
+
|
397
|
+
button {
|
398
|
+
background: #007acc;
|
399
|
+
color: white;
|
400
|
+
border: none;
|
401
|
+
padding: 10px 16px;
|
402
|
+
border-radius: 8px;
|
403
|
+
cursor: pointer;
|
404
|
+
font-size: 14px;
|
405
|
+
font-weight: 600;
|
406
|
+
transition: all 0.2s;
|
407
|
+
white-space: nowrap;
|
408
|
+
}
|
409
|
+
|
410
|
+
button:hover {
|
411
|
+
background: #0056a3;
|
412
|
+
transform: translateY(-1px);
|
413
|
+
}
|
414
|
+
|
415
|
+
button:active {
|
416
|
+
transform: translateY(0);
|
417
|
+
}
|
418
|
+
|
419
|
+
small {
|
420
|
+
color: #6b7280;
|
421
|
+
font-size: 0.8rem;
|
422
|
+
}
|
423
|
+
|
424
|
+
.results {
|
425
|
+
background: #f0f9ff;
|
426
|
+
padding: 24px;
|
427
|
+
border-radius: 12px;
|
428
|
+
border: 2px solid #bae6fd;
|
429
|
+
margin: 30px 0;
|
430
|
+
}
|
431
|
+
|
432
|
+
.results h2 {
|
433
|
+
margin-top: 0;
|
434
|
+
color: #0369a1;
|
435
|
+
}
|
436
|
+
|
437
|
+
.result-card {
|
438
|
+
background: white;
|
439
|
+
padding: 16px;
|
440
|
+
border-radius: 8px;
|
441
|
+
border: 1px solid #bae6fd;
|
442
|
+
}
|
443
|
+
|
444
|
+
.result-value {
|
445
|
+
font-weight: bold;
|
446
|
+
color: #007acc;
|
447
|
+
background: #e0f2fe;
|
448
|
+
padding: 2px 6px;
|
449
|
+
border-radius: 4px;
|
450
|
+
}
|
451
|
+
|
452
|
+
.info-section {
|
453
|
+
margin-top: 40px;
|
454
|
+
}
|
455
|
+
|
456
|
+
.info-section h2 {
|
457
|
+
text-align: center;
|
458
|
+
margin-bottom: 30px;
|
459
|
+
color: #374151;
|
460
|
+
}
|
461
|
+
|
462
|
+
.benefits-grid {
|
463
|
+
display: grid;
|
464
|
+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
465
|
+
gap: 20px;
|
466
|
+
}
|
467
|
+
|
468
|
+
.benefit {
|
469
|
+
background: #f9fafb;
|
470
|
+
padding: 20px;
|
471
|
+
border-radius: 12px;
|
472
|
+
border: 1px solid #e5e7eb;
|
473
|
+
text-align: center;
|
474
|
+
}
|
475
|
+
|
476
|
+
.benefit h4 {
|
477
|
+
margin: 0 0 8px 0;
|
478
|
+
color: #374151;
|
479
|
+
font-size: 1.1rem;
|
480
|
+
}
|
481
|
+
|
482
|
+
.benefit p {
|
483
|
+
margin: 0;
|
484
|
+
color: #6b7280;
|
485
|
+
font-size: 0.9rem;
|
486
|
+
}
|
487
|
+
|
488
|
+
.error {
|
489
|
+
color: #dc2626;
|
490
|
+
}
|
491
|
+
|
492
|
+
.error button {
|
493
|
+
background: #dc2626;
|
494
|
+
margin-top: 20px;
|
495
|
+
}
|
496
|
+
|
497
|
+
.error button:hover {
|
498
|
+
background: #b91c1c;
|
499
|
+
}
|
500
|
+
|
501
|
+
details {
|
502
|
+
background: #fef2f2;
|
503
|
+
padding: 16px;
|
504
|
+
border-radius: 8px;
|
505
|
+
border: 1px solid #fecaca;
|
506
|
+
}
|
507
|
+
|
508
|
+
summary {
|
509
|
+
cursor: pointer;
|
510
|
+
font-weight: 600;
|
511
|
+
margin-bottom: 8px;
|
512
|
+
}
|
513
|
+
|
514
|
+
code {
|
515
|
+
background: #f3f4f6;
|
516
|
+
padding: 2px 4px;
|
517
|
+
border-radius: 4px;
|
518
|
+
font-family: monospace;
|
519
|
+
font-size: 0.9em;
|
520
|
+
}
|
521
|
+
|
522
|
+
@media (max-width: 768px) {
|
523
|
+
.app {
|
524
|
+
padding: 10px;
|
525
|
+
}
|
526
|
+
|
527
|
+
header {
|
528
|
+
padding: 20px;
|
529
|
+
}
|
530
|
+
|
531
|
+
header h1 {
|
532
|
+
font-size: 2rem;
|
533
|
+
}
|
534
|
+
|
535
|
+
.demo-grid {
|
536
|
+
grid-template-columns: 1fr;
|
537
|
+
}
|
538
|
+
|
539
|
+
.input-group {
|
540
|
+
flex-direction: column;
|
541
|
+
}
|
542
|
+
|
543
|
+
input {
|
544
|
+
min-width: auto;
|
545
|
+
}
|
546
|
+
}
|
547
|
+
`}</style>
|
548
|
+
</div>
|
549
|
+
);
|
550
|
+
}
|