frontend-hamroun 1.2.16 → 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 -41
- package/templates/basic-app/index.html +6 -6
- package/templates/basic-app/package.json +18 -7
- 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 -1199
- 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 -18
- 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 -21
- 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,68 +0,0 @@
|
|
1
|
-
\documentclass[12pt,a4paper]{report}
|
2
|
-
\usepackage[utf8]{inputenc}
|
3
|
-
\usepackage[french]{babel}
|
4
|
-
\usepackage{graphicx}
|
5
|
-
\usepackage{fancyhdr}
|
6
|
-
\usepackage{hyperref}
|
7
|
-
|
8
|
-
\hypersetup{
|
9
|
-
colorlinks=true,
|
10
|
-
linkcolor=blue,
|
11
|
-
filecolor=magenta,
|
12
|
-
urlcolor=cyan,
|
13
|
-
}
|
14
|
-
|
15
|
-
\pagestyle{fancy}
|
16
|
-
\fancyhf{}
|
17
|
-
\rhead{Projet de Fin d'Études}
|
18
|
-
\lhead{Rapport de Stage}
|
19
|
-
\rfoot{Page \thepage}
|
20
|
-
|
21
|
-
\title{Rapport de Projet de Fin d'Études}
|
22
|
-
\author{Votre Nom}
|
23
|
-
\date{\today}
|
24
|
-
|
25
|
-
\begin{document}
|
26
|
-
|
27
|
-
\maketitle
|
28
|
-
\tableofcontents
|
29
|
-
\newpage
|
30
|
-
|
31
|
-
\chapter{ÉTUDE PREALABLE}
|
32
|
-
|
33
|
-
\section{Introduction}
|
34
|
-
Cette section présente une introduction générale au projet, incluant le contexte, les objectifs et la problématique abordée dans ce projet de fin d'études.
|
35
|
-
|
36
|
-
\section{Organisme d'accueil}
|
37
|
-
Cette section décrit l'organisme d'accueil où s'est déroulé le stage, incluant sa présentation, ses activités principales et sa structure organisationnelle.
|
38
|
-
|
39
|
-
\section{Étude et critique de l'existant}
|
40
|
-
Cette section analyse la situation actuelle avant l'implémentation du projet.
|
41
|
-
|
42
|
-
\subsection{Critique de l'existant}
|
43
|
-
Cette partie détaille les limitations, problèmes et défis identifiés dans le système existant qui ont motivé le développement d'une nouvelle solution.
|
44
|
-
|
45
|
-
\subsection{Solution proposée}
|
46
|
-
Cette partie présente la solution proposée pour résoudre les problèmes identifiés, en décrivant ses principales caractéristiques et avantages.
|
47
|
-
|
48
|
-
\section{Choix méthodologique}
|
49
|
-
|
50
|
-
\subsection{Formalisme de modélisation}
|
51
|
-
Cette section détaille les formalismes de modélisation utilisés pour concevoir et représenter la solution.
|
52
|
-
|
53
|
-
\subsection{Méthodologie}
|
54
|
-
Cette partie décrit l'approche méthodologique adoptée pour la réalisation du projet.
|
55
|
-
|
56
|
-
\subsubsection{Présentation de la méthode SCRUM}
|
57
|
-
Cette partie introduit la méthode SCRUM, ses principes fondamentaux et ses avantages dans le contexte du développement logiciel.
|
58
|
-
|
59
|
-
\subsubsection{La répartition des rôles dans la méthode SCRUM}
|
60
|
-
Cette section explique les différents rôles dans la méthode SCRUM (Product Owner, Scrum Master, équipe de développement) et leurs responsabilités.
|
61
|
-
|
62
|
-
\subsubsection{Le processus de SCRUM}
|
63
|
-
Cette partie détaille le processus SCRUM avec ses différentes cérémonies (Sprint Planning, Daily Scrum, Sprint Review, Sprint Retrospective) et artefacts (Product Backlog, Sprint Backlog, Increment).
|
64
|
-
|
65
|
-
\section{Conclusion}
|
66
|
-
Cette section résume les points clés abordés dans ce chapitre et fait la transition vers le chapitre suivant.
|
67
|
-
|
68
|
-
\end{document}
|
@@ -1,14 +0,0 @@
|
|
1
|
-
\babel@toc {french}{}\relax
|
2
|
-
\contentsline {chapter}{\numberline {1}ÉTUDE PREALABLE}{2}{chapter.1}%
|
3
|
-
\contentsline {section}{\numberline {1.1}Introduction}{2}{section.1.1}%
|
4
|
-
\contentsline {section}{\numberline {1.2}Organisme d'accueil}{2}{section.1.2}%
|
5
|
-
\contentsline {section}{\numberline {1.3}Étude et critique de l'existant}{2}{section.1.3}%
|
6
|
-
\contentsline {subsection}{\numberline {1.3.1}Critique de l'existant}{2}{subsection.1.3.1}%
|
7
|
-
\contentsline {subsection}{\numberline {1.3.2}Solution proposée}{2}{subsection.1.3.2}%
|
8
|
-
\contentsline {section}{\numberline {1.4}Choix méthodologique}{3}{section.1.4}%
|
9
|
-
\contentsline {subsection}{\numberline {1.4.1}Formalisme de modélisation}{3}{subsection.1.4.1}%
|
10
|
-
\contentsline {subsection}{\numberline {1.4.2}Méthodologie}{3}{subsection.1.4.2}%
|
11
|
-
\contentsline {subsubsection}{Présentation de la méthode SCRUM}{3}{section*.2}%
|
12
|
-
\contentsline {subsubsection}{La répartition des rôles dans la méthode SCRUM}{3}{section*.3}%
|
13
|
-
\contentsline {subsubsection}{Le processus de SCRUM}{3}{section*.4}%
|
14
|
-
\contentsline {section}{\numberline {1.5}Conclusion}{3}{section.1.5}%
|
@@ -1,12 +0,0 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<html lang="en">
|
3
|
-
<head>
|
4
|
-
<meta charset="UTF-8">
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
|
-
<title>Frontend Hamroun App</title>
|
7
|
-
</head>
|
8
|
-
<body>
|
9
|
-
<div id="app"></div>
|
10
|
-
<script type="module" src="/src/main.js"></script>
|
11
|
-
</body>
|
12
|
-
</html>
|
@@ -1,14 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"compilerOptions": {
|
3
|
-
"target": "ES2020",
|
4
|
-
"useDefineForClassFields": true,
|
5
|
-
"module": "ESNext",
|
6
|
-
"moduleResolution": "node",
|
7
|
-
"allowSyntheticDefaultImports": true,
|
8
|
-
"resolveJsonModule": true,
|
9
|
-
"checkJs": false,
|
10
|
-
"strict": false
|
11
|
-
},
|
12
|
-
"include": ["src/**/*.js"],
|
13
|
-
"exclude": ["node_modules"]
|
14
|
-
}
|
@@ -1,18 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"name": "frontend-hamroun-app",
|
3
|
-
"private": true,
|
4
|
-
"version": "0.1.0",
|
5
|
-
"type": "module",
|
6
|
-
"scripts": {
|
7
|
-
"dev": "vite",
|
8
|
-
"build": "vite build",
|
9
|
-
"preview": "vite preview"
|
10
|
-
},
|
11
|
-
"dependencies": {
|
12
|
-
"frontend-hamroun": "latest"
|
13
|
-
},
|
14
|
-
"devDependencies": {
|
15
|
-
"vite": "^5.0.10",
|
16
|
-
"vite-plugin-node-polyfills": "^0.23.0"
|
17
|
-
}
|
18
|
-
}
|
@@ -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
|
-
// Return a plain JavaScript object representation of the UI
|
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,65 +0,0 @@
|
|
1
|
-
import { useState, useEffect } 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
|
-
|
7
|
-
interface AppProps {
|
8
|
-
api: ApiClient;
|
9
|
-
}
|
10
|
-
|
11
|
-
export function App({ api }: AppProps) {
|
12
|
-
const [todos, setTodos] = useState([]);
|
13
|
-
const [isLoading, setIsLoading] = useState(true);
|
14
|
-
const [error, setError] = useState<string | null>(null);
|
15
|
-
|
16
|
-
useEffect(() => {
|
17
|
-
// Fetch data when component mounts
|
18
|
-
async function fetchData() {
|
19
|
-
try {
|
20
|
-
setIsLoading(true);
|
21
|
-
const data = await api.getTodos();
|
22
|
-
setTodos(data);
|
23
|
-
setError(null);
|
24
|
-
} catch (err) {
|
25
|
-
setError('Failed to fetch todos');
|
26
|
-
console.error(err);
|
27
|
-
} finally {
|
28
|
-
setIsLoading(false);
|
29
|
-
}
|
30
|
-
}
|
31
|
-
|
32
|
-
fetchData();
|
33
|
-
}, [api]);
|
34
|
-
|
35
|
-
return (
|
36
|
-
<div className="min-h-screen bg-gray-50">
|
37
|
-
<Header title="My Front Package App" />
|
38
|
-
|
39
|
-
<main className="container mx-auto px-4 py-8">
|
40
|
-
<h1 className="text-3xl font-bold text-center mb-8">
|
41
|
-
Welcome to your Front Package app!
|
42
|
-
</h1>
|
43
|
-
|
44
|
-
<div className="max-w-md mx-auto bg-white rounded-xl shadow-md overflow-hidden md:max-w-2xl mb-8">
|
45
|
-
<div className="p-8">
|
46
|
-
<Counter />
|
47
|
-
</div>
|
48
|
-
</div>
|
49
|
-
|
50
|
-
<div className="max-w-md mx-auto bg-white rounded-xl shadow-md overflow-hidden md:max-w-2xl">
|
51
|
-
<div className="p-8">
|
52
|
-
<h2 className="text-xl font-bold mb-4">Todo List</h2>
|
53
|
-
{isLoading ? (
|
54
|
-
<div className="text-center py-4">Loading...</div>
|
55
|
-
) : error ? (
|
56
|
-
<div className="text-red-500 py-4">{error}</div>
|
57
|
-
) : (
|
58
|
-
<TodoList todos={todos} api={api} setTodos={setTodos} />
|
59
|
-
)}
|
60
|
-
</div>
|
61
|
-
</div>
|
62
|
-
</main>
|
63
|
-
</div>
|
64
|
-
);
|
65
|
-
}
|
@@ -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
|
-
}
|
@@ -1,90 +0,0 @@
|
|
1
|
-
import { useState } from 'front-package';
|
2
|
-
import { ApiClient, Todo } from '../api';
|
3
|
-
|
4
|
-
interface TodoListProps {
|
5
|
-
todos: Todo[];
|
6
|
-
api: ApiClient;
|
7
|
-
setTodos: (todos: Todo[]) => void;
|
8
|
-
}
|
9
|
-
|
10
|
-
export function TodoList({ todos, api, setTodos }: TodoListProps) {
|
11
|
-
const [newTodoText, setNewTodoText] = useState('');
|
12
|
-
const [isSubmitting, setIsSubmitting] = useState(false);
|
13
|
-
|
14
|
-
async function handleAddTodo(e: Event) {
|
15
|
-
e.preventDefault();
|
16
|
-
if (!newTodoText.trim()) return;
|
17
|
-
|
18
|
-
try {
|
19
|
-
setIsSubmitting(true);
|
20
|
-
const newTodo = await api.addTodo({
|
21
|
-
title: newTodoText,
|
22
|
-
completed: false
|
23
|
-
});
|
24
|
-
|
25
|
-
setTodos([...todos, newTodo]);
|
26
|
-
setNewTodoText('');
|
27
|
-
} catch (err) {
|
28
|
-
console.error('Failed to add todo:', err);
|
29
|
-
} finally {
|
30
|
-
setIsSubmitting(false);
|
31
|
-
}
|
32
|
-
}
|
33
|
-
|
34
|
-
async function handleToggleTodo(id: string, completed: boolean) {
|
35
|
-
try {
|
36
|
-
await api.updateTodo(id, { completed });
|
37
|
-
setTodos(
|
38
|
-
todos.map(todo =>
|
39
|
-
todo.id === id ? { ...todo, completed } : todo
|
40
|
-
)
|
41
|
-
);
|
42
|
-
} catch (err) {
|
43
|
-
console.error('Failed to update todo:', err);
|
44
|
-
}
|
45
|
-
}
|
46
|
-
|
47
|
-
return (
|
48
|
-
<div>
|
49
|
-
<form onSubmit={handleAddTodo} className="mb-4">
|
50
|
-
<div className="flex gap-2">
|
51
|
-
<input
|
52
|
-
type="text"
|
53
|
-
value={newTodoText}
|
54
|
-
onChange={(e) => setNewTodoText(e.target.value)}
|
55
|
-
placeholder="Add a new todo..."
|
56
|
-
className="flex-1 border rounded px-3 py-2"
|
57
|
-
disabled={isSubmitting}
|
58
|
-
/>
|
59
|
-
<button
|
60
|
-
type="submit"
|
61
|
-
className="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600 transition"
|
62
|
-
disabled={isSubmitting || !newTodoText.trim()}
|
63
|
-
>
|
64
|
-
{isSubmitting ? 'Adding...' : 'Add'}
|
65
|
-
</button>
|
66
|
-
</div>
|
67
|
-
</form>
|
68
|
-
|
69
|
-
<ul className="space-y-2">
|
70
|
-
{todos.length === 0 ? (
|
71
|
-
<li className="text-center py-2 text-gray-500">No todos yet</li>
|
72
|
-
) : (
|
73
|
-
todos.map(todo => (
|
74
|
-
<li key={todo.id} className="flex items-center gap-2 p-2 border-b">
|
75
|
-
<input
|
76
|
-
type="checkbox"
|
77
|
-
checked={todo.completed}
|
78
|
-
onChange={(e) => handleToggleTodo(todo.id, e.target.checked)}
|
79
|
-
className="h-5 w-5 text-blue-600"
|
80
|
-
/>
|
81
|
-
<span className={todo.completed ? 'line-through text-gray-500' : ''}>
|
82
|
-
{todo.title}
|
83
|
-
</span>
|
84
|
-
</li>
|
85
|
-
))
|
86
|
-
)}
|
87
|
-
</ul>
|
88
|
-
</div>
|
89
|
-
);
|
90
|
-
}
|
@@ -1,11 +0,0 @@
|
|
1
|
-
import { render } from 'frontend-hamroun';
|
2
|
-
import { App } from './App.js';
|
3
|
-
|
4
|
-
document.addEventListener('DOMContentLoaded', () => {
|
5
|
-
const rootElement = document.getElementById('app');
|
6
|
-
if (rootElement) {
|
7
|
-
// Call App as a function to create the VDOM structure
|
8
|
-
render(App(), rootElement);
|
9
|
-
console.log('App rendered successfully');
|
10
|
-
}
|
11
|
-
});
|
@@ -1,20 +0,0 @@
|
|
1
|
-
import './main.css';
|
2
|
-
import { render } from 'frontend-hamroun';
|
3
|
-
import { App } from './App';
|
4
|
-
import { createApiClient } from './api';
|
5
|
-
|
6
|
-
// Initialize API client
|
7
|
-
const api = createApiClient({
|
8
|
-
baseUrl: import.meta.env.VITE_API_URL || '/api'
|
9
|
-
});
|
10
|
-
|
11
|
-
// Render the app into the DOM
|
12
|
-
document.addEventListener('DOMContentLoaded', () => {
|
13
|
-
const rootElement = document.getElementById('app');
|
14
|
-
if (rootElement) {
|
15
|
-
render(<App api={api} />, rootElement);
|
16
|
-
console.log('App rendered successfully');
|
17
|
-
} else {
|
18
|
-
console.error('Root element #app not found');
|
19
|
-
}
|
20
|
-
});
|
@@ -1,144 +0,0 @@
|
|
1
|
-
import { render, useState, useEffect, useMemo, useRef, useErrorBoundary, createContext, useContext } from 'frontend-hamroun';
|
2
|
-
import './main.css';
|
3
|
-
|
4
|
-
// Create a theme context
|
5
|
-
const ThemeContext = createContext<'light' | 'dark'>('light');
|
6
|
-
|
7
|
-
// Create a component that will throw an error when clicked
|
8
|
-
function BuggyComponent() {
|
9
|
-
const [shouldError, setShouldError] = useState(false);
|
10
|
-
|
11
|
-
if (shouldError) {
|
12
|
-
throw new Error("Test error from BuggyComponent");
|
13
|
-
}
|
14
|
-
|
15
|
-
return (
|
16
|
-
<button
|
17
|
-
onClick={() => setShouldError(true)}
|
18
|
-
className="bg-red-600 text-white px-4 py-2 rounded mt-4 hover:bg-red-700"
|
19
|
-
>
|
20
|
-
Trigger Error
|
21
|
-
</button>
|
22
|
-
);
|
23
|
-
}
|
24
|
-
|
25
|
-
function App() {
|
26
|
-
const [count, setCount] = useState(0);
|
27
|
-
const [theme, setTheme] = useState<'light' | 'dark'>('light');
|
28
|
-
const renderCount = useRef(0);
|
29
|
-
const [error, resetError] = useErrorBoundary();
|
30
|
-
|
31
|
-
// Demonstrate useEffect
|
32
|
-
useEffect(() => {
|
33
|
-
document.title = `Count: ${count}`;
|
34
|
-
renderCount.current += 1;
|
35
|
-
|
36
|
-
return () => {
|
37
|
-
console.log('Cleanup effect');
|
38
|
-
};
|
39
|
-
}, [count]);
|
40
|
-
|
41
|
-
// Demonstrate useMemo
|
42
|
-
const doubled = useMemo(() => count * 2, [count]);
|
43
|
-
|
44
|
-
if (error) {
|
45
|
-
return (
|
46
|
-
<div className="p-8 max-w-md mx-auto bg-red-50 rounded-lg shadow-lg">
|
47
|
-
<h1 className="text-2xl font-bold text-red-600 mb-4">Something went wrong!</h1>
|
48
|
-
<button
|
49
|
-
onClick={resetError}
|
50
|
-
className="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded"
|
51
|
-
>
|
52
|
-
Try again
|
53
|
-
</button>
|
54
|
-
</div>
|
55
|
-
);
|
56
|
-
}
|
57
|
-
|
58
|
-
return (
|
59
|
-
<ThemeContext.Provider value={theme}>
|
60
|
-
<div className={`p-8 max-w-4xl mx-auto rounded-lg shadow-lg transition-colors ${
|
61
|
-
theme === 'dark'
|
62
|
-
? 'bg-gray-800 text-white'
|
63
|
-
: 'bg-white text-gray-900'
|
64
|
-
}`}>
|
65
|
-
<h1 className="text-3xl font-bold mb-6">Welcome to Frontend Hamroun</h1>
|
66
|
-
|
67
|
-
<div className="mb-6">
|
68
|
-
<button
|
69
|
-
onClick={() => setCount(count - 1)}
|
70
|
-
className="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded"
|
71
|
-
>-</button>
|
72
|
-
<span className="mx-4 text-xl">{count}</span>
|
73
|
-
<button
|
74
|
-
onClick={() => setCount(count + 1)}
|
75
|
-
className="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded"
|
76
|
-
>+</button>
|
77
|
-
</div>
|
78
|
-
|
79
|
-
<p className="mb-2 text-lg">Doubled value: <span className="font-semibold">{doubled}</span></p>
|
80
|
-
<p className="mb-4 text-lg">Render count: <span className="font-semibold">{renderCount.current}</span></p>
|
81
|
-
|
82
|
-
<button
|
83
|
-
onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}
|
84
|
-
className={`px-4 py-2 rounded mb-8 ${
|
85
|
-
theme === 'dark'
|
86
|
-
? 'bg-yellow-400 text-gray-900 hover:bg-yellow-300'
|
87
|
-
: 'bg-gray-800 text-white hover:bg-gray-700'
|
88
|
-
}`}
|
89
|
-
>
|
90
|
-
Toggle Theme ({theme})
|
91
|
-
</button>
|
92
|
-
|
93
|
-
<div className="mt-8 border-t pt-6">
|
94
|
-
<h2 className="text-2xl font-bold mb-4">Test Error Boundary</h2>
|
95
|
-
<BuggyComponent />
|
96
|
-
</div>
|
97
|
-
|
98
|
-
<div className="mt-8 border-t pt-6">
|
99
|
-
<h2 className="text-2xl font-bold mb-4">Test Context</h2>
|
100
|
-
<ContextConsumer />
|
101
|
-
</div>
|
102
|
-
</div>
|
103
|
-
</ThemeContext.Provider>
|
104
|
-
);
|
105
|
-
}
|
106
|
-
|
107
|
-
// Component to test context
|
108
|
-
function ContextConsumer() {
|
109
|
-
// Get the full context object for debugging
|
110
|
-
const themeContext = useContext(ThemeContext);
|
111
|
-
console.log('Theme context object:', themeContext);
|
112
|
-
|
113
|
-
// Access the current theme from the parent component instead
|
114
|
-
// This is a workaround until context is properly implemented
|
115
|
-
return (
|
116
|
-
<div className={`mt-4 p-4 rounded-md border ${
|
117
|
-
themeContext === 'dark' ? 'border-gray-600' : 'border-gray-300'
|
118
|
-
}`}>
|
119
|
-
<p className="mb-2"><strong>Note:</strong> Context API needs a fix in the framework.</p>
|
120
|
-
<p className="mb-1">Context object type: {typeof themeContext}</p>
|
121
|
-
<p className="mb-4">Context object keys: {Object.keys(themeContext as object).join(', ') || 'none'}</p>
|
122
|
-
|
123
|
-
<button
|
124
|
-
onClick={() => {
|
125
|
-
// Since we can't get the value directly from context,
|
126
|
-
// Let's add a button to demonstrate we can still use the Provider
|
127
|
-
const newTheme = document.body.style.backgroundColor === 'rgb(51, 51, 51)'
|
128
|
-
? 'light' : 'dark';
|
129
|
-
|
130
|
-
console.log('Manually changing theme to:', newTheme);
|
131
|
-
// This won't work yet, but demonstrates the intent
|
132
|
-
if (ThemeContext) {
|
133
|
-
console.log('Provider exists, would set value to:', newTheme);
|
134
|
-
}
|
135
|
-
}}
|
136
|
-
className="bg-purple-500 hover:bg-purple-600 text-white px-4 py-2 rounded"
|
137
|
-
>
|
138
|
-
Check Context Implementation
|
139
|
-
</button>
|
140
|
-
</div>
|
141
|
-
);
|
142
|
-
}
|
143
|
-
|
144
|
-
render(<App />, document.getElementById('root')!);
|