frontend-hamroun 1.2.15 → 1.2.17
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/README.md +4 -0
- package/bin/cli.js +673 -0
- package/dist/component.d.ts +1 -1
- package/dist/context.d.ts +4 -3
- package/dist/index.client.d.ts +11 -0
- package/dist/index.d.ts +9 -89
- package/dist/index.js +396 -67
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +392 -0
- package/dist/index.mjs.map +1 -0
- package/dist/jsx-runtime/jsx-runtime.d.ts +0 -1
- package/dist/jsx-runtime.d.ts +1 -1
- package/dist/renderer.d.ts +0 -10
- package/dist/server-renderer.d.ts +0 -3
- package/dist/server-types.d.ts +42 -0
- package/package.json +69 -50
- package/templates/basic-app/index.html +6 -6
- package/templates/basic-app/package.json +15 -11
- package/templates/basic-app/postcss.config.js +0 -1
- package/templates/basic-app/src/main.tsx +1 -10
- package/templates/basic-app/tailwind.config.js +2 -23
- package/templates/basic-app/tsconfig.json +4 -17
- package/templates/basic-app/vite.config.ts +3 -54
- package/templates/fullstack-app/api/hello.ts +18 -0
- package/templates/fullstack-app/api/users/[id].ts +73 -0
- package/templates/fullstack-app/api/users/index.ts +32 -0
- package/templates/fullstack-app/package.json +31 -0
- package/templates/fullstack-app/server.ts +46 -0
- package/templates/fullstack-app/src/pages/index.tsx +59 -0
- package/templates/ssr-template/vite.config.ts +1 -11
- package/bin/cli.cjs +0 -16
- package/bin/cli.mjs +0 -237
- package/dist/backend/api-utils.d.ts +0 -38
- package/dist/backend/api-utils.js +0 -135
- package/dist/backend/auth.d.ts +0 -134
- package/dist/backend/auth.js +0 -387
- package/dist/backend/database.d.ts +0 -27
- package/dist/backend/database.js +0 -91
- package/dist/backend/model.d.ts +0 -43
- package/dist/backend/model.js +0 -178
- package/dist/backend/router.d.ts +0 -27
- package/dist/backend/router.js +0 -137
- package/dist/backend/server.d.ts +0 -19
- package/dist/backend/server.js +0 -268
- package/dist/backend/types.d.ts +0 -217
- package/dist/backend/types.js +0 -1
- package/dist/batch.js +0 -22
- package/dist/cli/index.d.ts +0 -2
- package/dist/cli/index.js +0 -215
- package/dist/component.js +0 -84
- package/dist/components/Counter.js +0 -2
- package/dist/context.js +0 -18
- package/dist/frontend-hamroun.es.js +0 -1378
- package/dist/frontend-hamroun.umd.js +0 -66
- package/dist/hooks.js +0 -164
- package/dist/jsx-runtime/index.d.ts +0 -11
- package/dist/jsx-runtime/index.js +0 -19
- package/dist/jsx-runtime/jsx-dev-runtime.js +0 -1
- package/dist/jsx-runtime/jsx-runtime.js +0 -95
- package/dist/jsx-runtime.js +0 -192
- package/dist/renderer.js +0 -51
- package/dist/server-renderer.js +0 -102
- package/dist/types.js +0 -1
- package/dist/vdom.js +0 -27
- package/scripts/build-cli.js +0 -1107
- package/scripts/generate.js +0 -134
- package/src/backend/api-utils.ts +0 -178
- package/src/backend/auth.ts +0 -544
- package/src/backend/database.ts +0 -104
- package/src/backend/model.ts +0 -198
- package/src/backend/router.ts +0 -176
- package/src/backend/server.ts +0 -330
- package/src/backend/types.ts +0 -257
- package/src/batch.ts +0 -24
- package/src/cli/index.js +0 -554
- package/src/cli/index.ts +0 -257
- package/src/component.ts +0 -98
- package/src/components/Counter.tsx +0 -4
- package/src/context.ts +0 -29
- package/src/hooks.ts +0 -211
- package/src/index.ts +0 -144
- package/src/jsx-runtime/index.ts +0 -27
- package/src/jsx-runtime/jsx-dev-runtime.ts +0 -0
- package/src/jsx-runtime/jsx-runtime.ts +0 -104
- package/src/jsx-runtime.ts +0 -226
- package/src/renderer.ts +0 -55
- package/src/server-renderer.ts +0 -114
- package/src/shims.d.ts +0 -20
- package/src/types/bcrypt.d.ts +0 -30
- package/src/types/jsonwebtoken.d.ts +0 -55
- package/src/types.d.ts +0 -26
- package/src/types.ts +0 -21
- package/src/vdom.ts +0 -34
- package/templates/basic/.eslintignore +0 -5
- package/templates/basic/.eslintrc.json +0 -25
- package/templates/basic/docs/rapport_pfe.aux +0 -27
- package/templates/basic/docs/rapport_pfe.log +0 -399
- package/templates/basic/docs/rapport_pfe.out +0 -10
- package/templates/basic/docs/rapport_pfe.pdf +0 -0
- package/templates/basic/docs/rapport_pfe.tex +0 -68
- package/templates/basic/docs/rapport_pfe.toc +0 -14
- package/templates/basic/index.html +0 -12
- package/templates/basic/jsconfig.json +0 -14
- package/templates/basic/package.json +0 -20
- package/templates/basic/postcss.config.js +0 -7
- package/templates/basic/src/App.js +0 -105
- package/templates/basic/src/App.tsx +0 -65
- package/templates/basic/src/api.ts +0 -58
- package/templates/basic/src/components/Counter.tsx +0 -26
- package/templates/basic/src/components/Header.tsx +0 -9
- package/templates/basic/src/components/TodoList.tsx +0 -90
- package/templates/basic/src/main.css +0 -3
- package/templates/basic/src/main.js +0 -11
- package/templates/basic/src/main.ts +0 -20
- package/templates/basic/src/main.tsx +0 -144
- package/templates/basic/src/server.ts +0 -99
- package/templates/basic/tailwind.config.js +0 -32
- package/templates/basic/tsconfig.json +0 -20
- package/templates/basic/tsconfig.node.json +0 -10
- package/templates/basic/vite.config.js +0 -18
- package/templates/basic/vite.config.ts +0 -86
- package/templates/basic-app/src/App.js +0 -105
- package/templates/basic-app/src/App.tsx +0 -143
- package/templates/basic-app/src/api.ts +0 -58
- package/templates/basic-app/src/components/Counter.tsx +0 -26
- package/templates/basic-app/src/components/Header.tsx +0 -9
- package/templates/basic-app/src/components/TodoList.tsx +0 -90
- package/templates/basic-app/src/main.js +0 -10
- package/templates/basic-app/src/main.ts +0 -21
- package/templates/basic-app/src/react/index.ts +0 -35
- package/templates/basic-app/src/react/jsx-dev-runtime.ts +0 -13
- package/templates/basic-app/src/react/jsx-runtime.ts +0 -12
- package/templates/basic-app/src/server.ts +0 -99
- package/templates/basic-app/src/shims.ts +0 -9
- package/templates/basic-app/tsconfig.node.json +0 -10
- package/templates/basic-app/vite.config.js +0 -22
- package/templates/full-stack/.env.example +0 -11
- package/templates/full-stack/README.md +0 -51
- package/templates/full-stack/index.html +0 -12
- package/templates/full-stack/jsconfig.json +0 -14
- package/templates/full-stack/package.json +0 -20
- package/templates/full-stack/src/App.js +0 -105
- package/templates/full-stack/src/client/App.tsx +0 -50
- package/templates/full-stack/src/client/components/Header.tsx +0 -42
- package/templates/full-stack/src/client/components/UserList.tsx +0 -29
- package/templates/full-stack/src/client/main.tsx +0 -5
- package/templates/full-stack/src/main.css +0 -3
- package/templates/full-stack/src/main.js +0 -11
- package/templates/full-stack/src/main.ts +0 -20
- package/templates/full-stack/src/server/index.ts +0 -99
- package/templates/full-stack/src/server/routes/auth.ts +0 -39
- package/templates/full-stack/src/server/routes/users.ts +0 -48
- package/templates/full-stack/src/shims.ts +0 -9
- package/templates/full-stack/tsconfig.json +0 -20
- package/templates/full-stack/tsconfig.node.json +0 -10
- package/templates/full-stack/tsconfig.server.json +0 -15
- package/templates/full-stack/vite.config.js +0 -18
- package/templates/full-stack/vite.config.ts +0 -85
@@ -1,99 +0,0 @@
|
|
1
|
-
import { createServer, Router, Database, ApiRoute } from 'front-package';
|
2
|
-
import { fileURLToPath } from 'url';
|
3
|
-
import { dirname, join } from 'path';
|
4
|
-
import fs from 'fs';
|
5
|
-
|
6
|
-
// Setup paths for server
|
7
|
-
const __filename = fileURLToPath(import.meta.url);
|
8
|
-
const __dirname = dirname(__filename);
|
9
|
-
const DIST_PATH = process.env.NODE_ENV === 'production'
|
10
|
-
? join(__dirname, '..')
|
11
|
-
: join(__dirname, '../dist');
|
12
|
-
|
13
|
-
// Initialize database
|
14
|
-
const db = new Database({
|
15
|
-
filePath: join(__dirname, '../data/db.json'),
|
16
|
-
defaultData: {
|
17
|
-
todos: [
|
18
|
-
{ id: '1', title: 'Learn Front Package', completed: false },
|
19
|
-
{ id: '2', title: 'Build an app', completed: false },
|
20
|
-
{ id: '3', title: 'Deploy to production', completed: false }
|
21
|
-
]
|
22
|
-
}
|
23
|
-
});
|
24
|
-
|
25
|
-
// Create API routes
|
26
|
-
const apiRouter = new Router();
|
27
|
-
|
28
|
-
// GET /api/todos
|
29
|
-
apiRouter.get('/todos', async (req, res) => {
|
30
|
-
const todos = await db.getAll('todos');
|
31
|
-
res.json(todos);
|
32
|
-
});
|
33
|
-
|
34
|
-
// GET /api/todos/:id
|
35
|
-
apiRouter.get('/todos/:id', async (req, res) => {
|
36
|
-
const todo = await db.getById('todos', req.params.id);
|
37
|
-
if (!todo) {
|
38
|
-
return res.status(404).json({ error: 'Todo not found' });
|
39
|
-
}
|
40
|
-
res.json(todo);
|
41
|
-
});
|
42
|
-
|
43
|
-
// POST /api/todos
|
44
|
-
apiRouter.post('/todos', async (req, res) => {
|
45
|
-
const { title, completed = false } = req.body;
|
46
|
-
|
47
|
-
if (!title) {
|
48
|
-
return res.status(400).json({ error: 'Title is required' });
|
49
|
-
}
|
50
|
-
|
51
|
-
const newTodo = {
|
52
|
-
id: Date.now().toString(),
|
53
|
-
title,
|
54
|
-
completed
|
55
|
-
};
|
56
|
-
|
57
|
-
await db.insert('todos', newTodo);
|
58
|
-
res.status(201).json(newTodo);
|
59
|
-
});
|
60
|
-
|
61
|
-
// PATCH /api/todos/:id
|
62
|
-
apiRouter.patch('/todos/:id', async (req, res) => {
|
63
|
-
const todo = await db.getById('todos', req.params.id);
|
64
|
-
if (!todo) {
|
65
|
-
return res.status(404).json({ error: 'Todo not found' });
|
66
|
-
}
|
67
|
-
|
68
|
-
const updatedTodo = { ...todo, ...req.body };
|
69
|
-
await db.update('todos', req.params.id, updatedTodo);
|
70
|
-
res.json(updatedTodo);
|
71
|
-
});
|
72
|
-
|
73
|
-
// DELETE /api/todos/:id
|
74
|
-
apiRouter.delete('/todos/:id', async (req, res) => {
|
75
|
-
const todo = await db.getById('todos', req.params.id);
|
76
|
-
if (!todo) {
|
77
|
-
return res.status(404).json({ error: 'Todo not found' });
|
78
|
-
}
|
79
|
-
|
80
|
-
await db.delete('todos', req.params.id);
|
81
|
-
res.status(204).end();
|
82
|
-
});
|
83
|
-
|
84
|
-
// Create server
|
85
|
-
const server = createServer({
|
86
|
-
port: process.env.PORT ? parseInt(process.env.PORT) : 3000,
|
87
|
-
staticDir: DIST_PATH,
|
88
|
-
routes: [
|
89
|
-
new ApiRoute('/api', apiRouter)
|
90
|
-
]
|
91
|
-
});
|
92
|
-
|
93
|
-
// Start server
|
94
|
-
server.start().then(() => {
|
95
|
-
console.log(`Server running at http://localhost:${server.port}`);
|
96
|
-
}).catch(err => {
|
97
|
-
console.error('Failed to start server:', err);
|
98
|
-
process.exit(1);
|
99
|
-
});
|
@@ -1,32 +0,0 @@
|
|
1
|
-
/** @type {import('tailwindcss').Config} */
|
2
|
-
export default {
|
3
|
-
content: [
|
4
|
-
"./index.html",
|
5
|
-
"./src/**/*.{js,ts,jsx,tsx}",
|
6
|
-
],
|
7
|
-
theme: {
|
8
|
-
extend: {
|
9
|
-
colors: {
|
10
|
-
primary: {
|
11
|
-
50: '#f0f9ff',
|
12
|
-
100: '#e0f2fe',
|
13
|
-
200: '#bae6fd',
|
14
|
-
300: '#7dd3fc',
|
15
|
-
400: '#38bdf8',
|
16
|
-
500: '#0ea5e9',
|
17
|
-
600: '#0284c7',
|
18
|
-
700: '#0369a1',
|
19
|
-
800: '#075985',
|
20
|
-
900: '#0c4a6e',
|
21
|
-
},
|
22
|
-
},
|
23
|
-
fontFamily: {
|
24
|
-
sans: ['Inter var', 'sans-serif'],
|
25
|
-
},
|
26
|
-
},
|
27
|
-
},
|
28
|
-
plugins: [
|
29
|
-
require('@tailwindcss/forms'),
|
30
|
-
require('@tailwindcss/typography'),
|
31
|
-
],
|
32
|
-
}
|
@@ -1,20 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"compilerOptions": {
|
3
|
-
"target": "ES2020",
|
4
|
-
"useDefineForClassFields": true,
|
5
|
-
"module": "ESNext",
|
6
|
-
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
7
|
-
"skipLibCheck": true,
|
8
|
-
"moduleResolution": "bundler",
|
9
|
-
"allowImportingTsExtensions": true,
|
10
|
-
"resolveJsonModule": true,
|
11
|
-
"isolatedModules": true,
|
12
|
-
"noEmit": true,
|
13
|
-
"strict": true,
|
14
|
-
"noUnusedLocals": true,
|
15
|
-
"noUnusedParameters": true,
|
16
|
-
"noFallthroughCasesInSwitch": true
|
17
|
-
},
|
18
|
-
"include": ["src"],
|
19
|
-
"references": [{ "path": "./tsconfig.node.json" }]
|
20
|
-
}
|
@@ -1,18 +0,0 @@
|
|
1
|
-
import { defineConfig } from 'vite';
|
2
|
-
import { nodePolyfills } from 'vite-plugin-node-polyfills';
|
3
|
-
|
4
|
-
export default defineConfig({
|
5
|
-
build: {
|
6
|
-
outDir: 'dist',
|
7
|
-
emptyOutDir: true
|
8
|
-
},
|
9
|
-
server: {
|
10
|
-
port: 3000,
|
11
|
-
open: true
|
12
|
-
},
|
13
|
-
plugins: [
|
14
|
-
nodePolyfills({
|
15
|
-
protocolImports: true,
|
16
|
-
}),
|
17
|
-
]
|
18
|
-
});
|
@@ -1,86 +0,0 @@
|
|
1
|
-
import { defineConfig } from 'vite';
|
2
|
-
import { nodePolyfills } from 'vite-plugin-node-polyfills';
|
3
|
-
|
4
|
-
export default defineConfig({
|
5
|
-
esbuild: {
|
6
|
-
jsxFactory: 'jsx',
|
7
|
-
jsxFragment: 'Fragment'
|
8
|
-
},
|
9
|
-
build: {
|
10
|
-
outDir: 'dist',
|
11
|
-
emptyOutDir: true,
|
12
|
-
rollupOptions: {
|
13
|
-
// Mark testing dependencies and Node.js dependencies as external
|
14
|
-
external: [
|
15
|
-
'mock-aws-s3',
|
16
|
-
'aws-sdk',
|
17
|
-
'nock',
|
18
|
-
'jest',
|
19
|
-
'jest-mock',
|
20
|
-
'@testing-library/react',
|
21
|
-
'@testing-library/jest-dom',
|
22
|
-
'@mswjs/interceptors',
|
23
|
-
'node-pre-gyp',
|
24
|
-
'bcrypt',
|
25
|
-
'jsonwebtoken',
|
26
|
-
'mongoose',
|
27
|
-
'express',
|
28
|
-
'compression',
|
29
|
-
'helmet',
|
30
|
-
'morgan',
|
31
|
-
/node:.*/
|
32
|
-
]
|
33
|
-
}
|
34
|
-
},
|
35
|
-
server: {
|
36
|
-
port: 3000,
|
37
|
-
open: true
|
38
|
-
},
|
39
|
-
optimizeDeps: {
|
40
|
-
esbuildOptions: {
|
41
|
-
// Node.js global to browser globalThis
|
42
|
-
define: {
|
43
|
-
global: 'globalThis'
|
44
|
-
},
|
45
|
-
// Enable esbuild polyfill plugins
|
46
|
-
plugins: [
|
47
|
-
{
|
48
|
-
name: 'node-modules-polyfill',
|
49
|
-
setup(build) {
|
50
|
-
// Exclude node:* imports and html files
|
51
|
-
build.onResolve({ filter: /^node:/ }, () => {
|
52
|
-
return { external: true };
|
53
|
-
});
|
54
|
-
build.onResolve({ filter: /\.html$/ }, () => {
|
55
|
-
return { external: true };
|
56
|
-
});
|
57
|
-
}
|
58
|
-
}
|
59
|
-
]
|
60
|
-
},
|
61
|
-
// Exclude problematic dependencies from optimization
|
62
|
-
exclude: [
|
63
|
-
'mock-aws-s3',
|
64
|
-
'aws-sdk',
|
65
|
-
'nock',
|
66
|
-
'@mswjs/interceptors',
|
67
|
-
'node-pre-gyp',
|
68
|
-
'bcrypt'
|
69
|
-
]
|
70
|
-
},
|
71
|
-
plugins: [
|
72
|
-
// Add node polyfills for browser environment
|
73
|
-
nodePolyfills({
|
74
|
-
// Whether to polyfill `node:` protocol imports
|
75
|
-
protocolImports: true,
|
76
|
-
}),
|
77
|
-
],
|
78
|
-
resolve: {
|
79
|
-
// Add node compatibility
|
80
|
-
alias: {
|
81
|
-
// Handle missing imports specifically
|
82
|
-
'@mswjs/interceptors/presets/node': { find: /^@mswjs\/interceptors\/presets\/node/, replacement: '{}' },
|
83
|
-
'./util/nw-pre-gyp/index.html': { find: './util/nw-pre-gyp/index.html', replacement: '{}' }
|
84
|
-
}
|
85
|
-
}
|
86
|
-
});
|
@@ -1,105 +0,0 @@
|
|
1
|
-
import { useState, useRef } from 'frontend-hamroun';
|
2
|
-
|
3
|
-
export function App() {
|
4
|
-
const [count, setCount] = useState(0);
|
5
|
-
const renderCount = useRef(0);
|
6
|
-
|
7
|
-
renderCount.current++;
|
8
|
-
|
9
|
-
// Using plain JS objects instead of JSX
|
10
|
-
return {
|
11
|
-
type: 'div',
|
12
|
-
props: {
|
13
|
-
style: {
|
14
|
-
fontFamily: 'Arial, sans-serif',
|
15
|
-
maxWidth: '600px',
|
16
|
-
margin: '0 auto',
|
17
|
-
padding: '2rem'
|
18
|
-
},
|
19
|
-
children: [
|
20
|
-
{
|
21
|
-
type: 'h1',
|
22
|
-
props: {
|
23
|
-
style: { textAlign: 'center' },
|
24
|
-
children: 'Frontend Hamroun App'
|
25
|
-
}
|
26
|
-
},
|
27
|
-
{
|
28
|
-
type: 'p',
|
29
|
-
props: {
|
30
|
-
style: { textAlign: 'center' },
|
31
|
-
children: `Render count: ${renderCount.current}`
|
32
|
-
}
|
33
|
-
},
|
34
|
-
{
|
35
|
-
type: 'div',
|
36
|
-
props: {
|
37
|
-
style: {
|
38
|
-
display: 'flex',
|
39
|
-
flexDirection: 'column',
|
40
|
-
alignItems: 'center',
|
41
|
-
padding: '1rem',
|
42
|
-
border: '1px solid #ccc',
|
43
|
-
borderRadius: '8px'
|
44
|
-
},
|
45
|
-
children: [
|
46
|
-
{
|
47
|
-
type: 'h2',
|
48
|
-
props: {
|
49
|
-
children: 'Counter Example'
|
50
|
-
}
|
51
|
-
},
|
52
|
-
{
|
53
|
-
type: 'p',
|
54
|
-
props: {
|
55
|
-
children: `Count: ${count}`
|
56
|
-
}
|
57
|
-
},
|
58
|
-
{
|
59
|
-
type: 'div',
|
60
|
-
props: {
|
61
|
-
style: {
|
62
|
-
display: 'flex',
|
63
|
-
gap: '8px'
|
64
|
-
},
|
65
|
-
children: [
|
66
|
-
{
|
67
|
-
type: 'button',
|
68
|
-
props: {
|
69
|
-
onClick: () => setCount(count - 1),
|
70
|
-
style: {
|
71
|
-
padding: '8px 16px',
|
72
|
-
backgroundColor: '#ff4d4d',
|
73
|
-
color: 'white',
|
74
|
-
border: 'none',
|
75
|
-
borderRadius: '4px',
|
76
|
-
cursor: 'pointer'
|
77
|
-
},
|
78
|
-
children: 'Decrement'
|
79
|
-
}
|
80
|
-
},
|
81
|
-
{
|
82
|
-
type: 'button',
|
83
|
-
props: {
|
84
|
-
onClick: () => setCount(count + 1),
|
85
|
-
style: {
|
86
|
-
padding: '8px 16px',
|
87
|
-
backgroundColor: '#4d79ff',
|
88
|
-
color: 'white',
|
89
|
-
border: 'none',
|
90
|
-
borderRadius: '4px',
|
91
|
-
cursor: 'pointer'
|
92
|
-
},
|
93
|
-
children: 'Increment'
|
94
|
-
}
|
95
|
-
}
|
96
|
-
]
|
97
|
-
}
|
98
|
-
}
|
99
|
-
]
|
100
|
-
}
|
101
|
-
}
|
102
|
-
]
|
103
|
-
}
|
104
|
-
};
|
105
|
-
}
|
@@ -1,143 +0,0 @@
|
|
1
|
-
import { useState, useEffect, useContext, useRef } from 'frontend-hamroun';
|
2
|
-
import { Header } from './components/Header';
|
3
|
-
import { Counter } from './components/Counter';
|
4
|
-
import { ApiClient } from './api.js';
|
5
|
-
import { TodoList } from './components/TodoList.js';
|
6
|
-
import { AppContext } from './main';
|
7
|
-
|
8
|
-
interface AppProps {
|
9
|
-
api: ApiClient;
|
10
|
-
}
|
11
|
-
|
12
|
-
// Use function declaration style instead of JSX component syntax
|
13
|
-
export function App(props: any) {
|
14
|
-
const [count, setCount] = useState(0);
|
15
|
-
const [theme, setTheme] = useState('light');
|
16
|
-
const renderCount = useRef(0);
|
17
|
-
|
18
|
-
renderCount.current++;
|
19
|
-
|
20
|
-
// Return a standard object structure rather than JSX
|
21
|
-
return {
|
22
|
-
type: 'div',
|
23
|
-
props: {
|
24
|
-
style: {
|
25
|
-
fontFamily: 'Arial, sans-serif',
|
26
|
-
maxWidth: '600px',
|
27
|
-
margin: '0 auto',
|
28
|
-
padding: '2rem',
|
29
|
-
backgroundColor: theme === 'dark' ? '#222' : '#fff',
|
30
|
-
color: theme === 'dark' ? '#fff' : '#222'
|
31
|
-
},
|
32
|
-
children: [
|
33
|
-
{
|
34
|
-
type: 'h1',
|
35
|
-
props: {
|
36
|
-
style: { textAlign: 'center' },
|
37
|
-
children: 'Frontend Hamroun App'
|
38
|
-
}
|
39
|
-
},
|
40
|
-
{
|
41
|
-
type: 'p',
|
42
|
-
props: {
|
43
|
-
style: { textAlign: 'center' },
|
44
|
-
children: `This component has rendered ${renderCount.current} times`
|
45
|
-
}
|
46
|
-
},
|
47
|
-
{
|
48
|
-
type: 'div',
|
49
|
-
props: {
|
50
|
-
style: {
|
51
|
-
display: 'flex',
|
52
|
-
justifyContent: 'center',
|
53
|
-
marginBottom: '1rem'
|
54
|
-
},
|
55
|
-
children: {
|
56
|
-
type: 'button',
|
57
|
-
props: {
|
58
|
-
onClick: () => setTheme(theme === 'light' ? 'dark' : 'light'),
|
59
|
-
style: {
|
60
|
-
padding: '8px 16px',
|
61
|
-
backgroundColor: '#4b5563',
|
62
|
-
color: 'white',
|
63
|
-
border: 'none',
|
64
|
-
borderRadius: '4px',
|
65
|
-
cursor: 'pointer'
|
66
|
-
},
|
67
|
-
children: `Switch to ${theme === 'light' ? 'dark' : 'light'} mode`
|
68
|
-
}
|
69
|
-
}
|
70
|
-
}
|
71
|
-
},
|
72
|
-
{
|
73
|
-
type: 'div',
|
74
|
-
props: {
|
75
|
-
style: {
|
76
|
-
display: 'flex',
|
77
|
-
flexDirection: 'column',
|
78
|
-
alignItems: 'center',
|
79
|
-
padding: '1rem',
|
80
|
-
border: '1px solid #ccc',
|
81
|
-
borderRadius: '8px'
|
82
|
-
},
|
83
|
-
children: [
|
84
|
-
{
|
85
|
-
type: 'h2',
|
86
|
-
props: {
|
87
|
-
children: 'Counter Example'
|
88
|
-
}
|
89
|
-
},
|
90
|
-
{
|
91
|
-
type: 'p',
|
92
|
-
props: {
|
93
|
-
children: `Count: ${count}`
|
94
|
-
}
|
95
|
-
},
|
96
|
-
{
|
97
|
-
type: 'div',
|
98
|
-
props: {
|
99
|
-
style: {
|
100
|
-
display: 'flex',
|
101
|
-
gap: '8px'
|
102
|
-
},
|
103
|
-
children: [
|
104
|
-
{
|
105
|
-
type: 'button',
|
106
|
-
props: {
|
107
|
-
onClick: () => setCount(count - 1),
|
108
|
-
style: {
|
109
|
-
padding: '8px 16px',
|
110
|
-
backgroundColor: '#ff4d4d',
|
111
|
-
color: 'white',
|
112
|
-
border: 'none',
|
113
|
-
borderRadius: '4px',
|
114
|
-
cursor: 'pointer'
|
115
|
-
},
|
116
|
-
children: 'Decrement'
|
117
|
-
}
|
118
|
-
},
|
119
|
-
{
|
120
|
-
type: 'button',
|
121
|
-
props: {
|
122
|
-
onClick: () => setCount(count + 1),
|
123
|
-
style: {
|
124
|
-
padding: '8px 16px',
|
125
|
-
backgroundColor: '#4d79ff',
|
126
|
-
color: 'white',
|
127
|
-
border: 'none',
|
128
|
-
borderRadius: '4px',
|
129
|
-
cursor: 'pointer'
|
130
|
-
},
|
131
|
-
children: 'Increment'
|
132
|
-
}
|
133
|
-
}
|
134
|
-
]
|
135
|
-
}
|
136
|
-
}
|
137
|
-
]
|
138
|
-
}
|
139
|
-
}
|
140
|
-
]
|
141
|
-
}
|
142
|
-
};
|
143
|
-
}
|
@@ -1,58 +0,0 @@
|
|
1
|
-
export interface Todo {
|
2
|
-
id: string;
|
3
|
-
title: string;
|
4
|
-
completed: boolean;
|
5
|
-
}
|
6
|
-
|
7
|
-
export interface ApiClientOptions {
|
8
|
-
baseUrl: string;
|
9
|
-
}
|
10
|
-
|
11
|
-
export interface ApiClient {
|
12
|
-
getTodos: () => Promise<Todo[]>;
|
13
|
-
getTodo: (id: string) => Promise<Todo>;
|
14
|
-
addTodo: (todo: Omit<Todo, 'id'>) => Promise<Todo>;
|
15
|
-
updateTodo: (id: string, updates: Partial<Omit<Todo, 'id'>>) => Promise<Todo>;
|
16
|
-
deleteTodo: (id: string) => Promise<void>;
|
17
|
-
}
|
18
|
-
|
19
|
-
export function createApiClient(options: ApiClientOptions): ApiClient {
|
20
|
-
const { baseUrl } = options;
|
21
|
-
|
22
|
-
async function fetchJson<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
|
23
|
-
const response = await fetch(`${baseUrl}${endpoint}`, {
|
24
|
-
...options,
|
25
|
-
headers: {
|
26
|
-
'Content-Type': 'application/json',
|
27
|
-
...options.headers,
|
28
|
-
},
|
29
|
-
});
|
30
|
-
|
31
|
-
if (!response.ok) {
|
32
|
-
const error = await response.text();
|
33
|
-
throw new Error(error || `API request failed with status ${response.status}`);
|
34
|
-
}
|
35
|
-
|
36
|
-
return response.json();
|
37
|
-
}
|
38
|
-
|
39
|
-
return {
|
40
|
-
getTodos: () => fetchJson<Todo[]>('/todos'),
|
41
|
-
|
42
|
-
getTodo: (id: string) => fetchJson<Todo>(`/todos/${id}`),
|
43
|
-
|
44
|
-
addTodo: (todo) => fetchJson<Todo>('/todos', {
|
45
|
-
method: 'POST',
|
46
|
-
body: JSON.stringify(todo),
|
47
|
-
}),
|
48
|
-
|
49
|
-
updateTodo: (id: string, updates) => fetchJson<Todo>(`/todos/${id}`, {
|
50
|
-
method: 'PATCH',
|
51
|
-
body: JSON.stringify(updates),
|
52
|
-
}),
|
53
|
-
|
54
|
-
deleteTodo: (id: string) => fetchJson<void>(`/todos/${id}`, {
|
55
|
-
method: 'DELETE',
|
56
|
-
}),
|
57
|
-
};
|
58
|
-
}
|
@@ -1,26 +0,0 @@
|
|
1
|
-
import { useState } from 'front-package';
|
2
|
-
|
3
|
-
export function Counter() {
|
4
|
-
const [count, setCount] = useState(0);
|
5
|
-
|
6
|
-
return (
|
7
|
-
<div className="text-center">
|
8
|
-
<h2 className="text-xl font-bold mb-4">Counter Example</h2>
|
9
|
-
<p className="mb-4">Count: <span className="font-bold">{count}</span></p>
|
10
|
-
<div className="flex justify-center gap-2">
|
11
|
-
<button
|
12
|
-
onClick={() => setCount(count - 1)}
|
13
|
-
className="px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600 transition"
|
14
|
-
>
|
15
|
-
Decrement
|
16
|
-
</button>
|
17
|
-
<button
|
18
|
-
onClick={() => setCount(count + 1)}
|
19
|
-
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition"
|
20
|
-
>
|
21
|
-
Increment
|
22
|
-
</button>
|
23
|
-
</div>
|
24
|
-
</div>
|
25
|
-
);
|
26
|
-
}
|