create-elit 3.2.6 → 3.2.8
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.js +37 -319
- package/dist/templates/README.md +23 -0
- package/dist/templates/elit.config.ts +59 -0
- package/dist/templates/package.json +14 -0
- package/dist/templates/public/favicon.svg +22 -0
- package/dist/templates/public/index.html +14 -0
- package/dist/templates/src/client.ts +15 -0
- package/dist/templates/src/components/Footer.ts +20 -0
- package/dist/templates/src/components/Header.ts +70 -0
- package/dist/templates/src/components/index.ts +2 -0
- package/dist/templates/src/main.ts +22 -0
- package/dist/templates/src/pages/ChatListPage.ts +144 -0
- package/dist/templates/src/pages/ChatPage.ts +186 -0
- package/dist/templates/src/pages/ForgotPasswordPage.ts +110 -0
- package/dist/templates/src/pages/HomePage.ts +166 -0
- package/dist/templates/src/pages/LoginPage.ts +182 -0
- package/dist/templates/src/pages/PrivateChatPage.ts +268 -0
- package/dist/templates/src/pages/ProfilePage.ts +342 -0
- package/dist/templates/src/pages/RegisterPage.ts +230 -0
- package/dist/templates/src/router.ts +30 -0
- package/dist/templates/src/server.ts +595 -0
- package/dist/templates/src/styles.ts +1181 -0
- package/dist/templates/tsconfig.json +23 -0
- package/package.json +2 -3
package/dist/index.js
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { mkdir, writeFile } from "fs/promises";
|
|
5
|
-
import { join, resolve } from "path";
|
|
4
|
+
import { mkdir, writeFile, readFile, readdir } from "fs/promises";
|
|
5
|
+
import { join, resolve, dirname } from "path";
|
|
6
6
|
import { existsSync } from "fs";
|
|
7
|
+
import { fileURLToPath } from "url";
|
|
8
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
var __dirname = dirname(__filename);
|
|
10
|
+
async function getElitVersion() {
|
|
11
|
+
const packageJsonPath = resolve(__dirname, "../package.json");
|
|
12
|
+
const packageJson = JSON.parse(await readFile(packageJsonPath, "utf-8"));
|
|
13
|
+
return packageJson.version;
|
|
14
|
+
}
|
|
7
15
|
var colors = {
|
|
8
16
|
reset: "\x1B[0m",
|
|
9
17
|
cyan: "\x1B[36m",
|
|
@@ -19,15 +27,40 @@ function getProjectName() {
|
|
|
19
27
|
const args = process.argv.slice(2);
|
|
20
28
|
return args[0] || "my-elit-app";
|
|
21
29
|
}
|
|
30
|
+
async function copyDirectory(src, dest, replacements) {
|
|
31
|
+
await mkdir(dest, { recursive: true });
|
|
32
|
+
const entries = await readdir(src, { withFileTypes: true });
|
|
33
|
+
for (const entry of entries) {
|
|
34
|
+
const srcPath = join(src, entry.name);
|
|
35
|
+
const destPath = join(dest, entry.name);
|
|
36
|
+
if (entry.isDirectory()) {
|
|
37
|
+
await copyDirectory(srcPath, destPath, replacements);
|
|
38
|
+
} else {
|
|
39
|
+
await copyAndReplaceFile(srcPath, destPath, replacements);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async function copyAndReplaceFile(src, dest, replacements) {
|
|
44
|
+
let content = await readFile(src, "utf-8");
|
|
45
|
+
for (const [placeholder, value] of Object.entries(replacements)) {
|
|
46
|
+
content = content.split(placeholder).join(value);
|
|
47
|
+
}
|
|
48
|
+
await writeFile(dest, content, "utf-8");
|
|
49
|
+
}
|
|
22
50
|
async function createProject(projectName2) {
|
|
23
51
|
const projectPath = resolve(process.cwd(), projectName2);
|
|
52
|
+
const templatesPath = resolve(__dirname, "templates");
|
|
24
53
|
if (existsSync(projectPath)) {
|
|
25
54
|
log(`Error: Directory "${projectName2}" already exists!`, "red");
|
|
26
55
|
process.exit(1);
|
|
27
56
|
}
|
|
28
57
|
log(`Creating a new Elit app in ${projectPath}...`, "cyan");
|
|
29
|
-
|
|
30
|
-
|
|
58
|
+
const elitVersion = await getElitVersion();
|
|
59
|
+
const replacements = {
|
|
60
|
+
"ELIT_PROJECT_NAME": projectName2,
|
|
61
|
+
"ELIT_VERSION": elitVersion
|
|
62
|
+
};
|
|
63
|
+
await copyDirectory(templatesPath, projectPath, replacements);
|
|
31
64
|
log("\nSuccess! Created " + projectName2, "green");
|
|
32
65
|
log("\nInside that directory, you can run several commands:", "dim");
|
|
33
66
|
log("\n npm run dev", "cyan");
|
|
@@ -42,321 +75,6 @@ async function createProject(projectName2) {
|
|
|
42
75
|
log(" npm run dev\n", "cyan");
|
|
43
76
|
log("Happy coding! \u{1F680}", "green");
|
|
44
77
|
}
|
|
45
|
-
async function generateTemplate(projectPath, projectName2) {
|
|
46
|
-
const packageJson = {
|
|
47
|
-
name: projectName2,
|
|
48
|
-
version: "0.0.0",
|
|
49
|
-
type: "module",
|
|
50
|
-
scripts: {
|
|
51
|
-
dev: "elit dev",
|
|
52
|
-
build: "elit build",
|
|
53
|
-
preview: "elit preview"
|
|
54
|
-
},
|
|
55
|
-
dependencies: {
|
|
56
|
-
elit: "^3.2.6"
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
await writeFile(
|
|
60
|
-
join(projectPath, "package.json"),
|
|
61
|
-
JSON.stringify(packageJson, null, 2)
|
|
62
|
-
);
|
|
63
|
-
const tsConfig = {
|
|
64
|
-
compilerOptions: {
|
|
65
|
-
target: "ES2020",
|
|
66
|
-
module: "ESNext",
|
|
67
|
-
moduleResolution: "bundler",
|
|
68
|
-
lib: ["ES2020", "DOM", "DOM.Iterable"],
|
|
69
|
-
strict: true,
|
|
70
|
-
esModuleInterop: true,
|
|
71
|
-
skipLibCheck: true,
|
|
72
|
-
resolveJsonModule: true,
|
|
73
|
-
isolatedModules: true,
|
|
74
|
-
types: ["node"]
|
|
75
|
-
},
|
|
76
|
-
include: ["src"]
|
|
77
|
-
};
|
|
78
|
-
await writeFile(
|
|
79
|
-
join(projectPath, "tsconfig.json"),
|
|
80
|
-
JSON.stringify(tsConfig, null, 2)
|
|
81
|
-
);
|
|
82
|
-
const gitignore = `node_modules
|
|
83
|
-
dist
|
|
84
|
-
.env
|
|
85
|
-
.env.local
|
|
86
|
-
*.log
|
|
87
|
-
.DS_Store
|
|
88
|
-
`;
|
|
89
|
-
await writeFile(join(projectPath, ".gitignore"), gitignore);
|
|
90
|
-
const readme = `# ${projectName2}
|
|
91
|
-
|
|
92
|
-
A new Elit project created with create-elit.
|
|
93
|
-
|
|
94
|
-
## Getting Started
|
|
95
|
-
|
|
96
|
-
\`\`\`bash
|
|
97
|
-
npm install
|
|
98
|
-
npm run dev
|
|
99
|
-
\`\`\`
|
|
100
|
-
|
|
101
|
-
Visit http://localhost:3000 to view your app.
|
|
102
|
-
|
|
103
|
-
## Available Scripts
|
|
104
|
-
|
|
105
|
-
- \`npm run dev\` - Start development server with HMR
|
|
106
|
-
- \`npm run build\` - Build for production
|
|
107
|
-
- \`npm run preview\` - Preview production build
|
|
108
|
-
|
|
109
|
-
## Learn More
|
|
110
|
-
|
|
111
|
-
- [Elit Documentation](https://d-osc.github.io/elit)
|
|
112
|
-
- [GitHub Repository](https://github.com/d-osc/elit)
|
|
113
|
-
`;
|
|
114
|
-
await writeFile(join(projectPath, "README.md"), readme);
|
|
115
|
-
const elitConfig = `import { server } from './src/server';
|
|
116
|
-
import { client } from './src/client';
|
|
117
|
-
|
|
118
|
-
export default {
|
|
119
|
-
dev: {
|
|
120
|
-
port: 3000,
|
|
121
|
-
host: 'localhost',
|
|
122
|
-
open: true,
|
|
123
|
-
logging: true,
|
|
124
|
-
clients: [{
|
|
125
|
-
root: '.',
|
|
126
|
-
basePath: '',
|
|
127
|
-
ssr: () => client,
|
|
128
|
-
api: server
|
|
129
|
-
}]
|
|
130
|
-
},
|
|
131
|
-
build: [{
|
|
132
|
-
entry: './src/main.ts',
|
|
133
|
-
outDir: './dist',
|
|
134
|
-
outFile: 'main.js',
|
|
135
|
-
format: 'esm',
|
|
136
|
-
minify: true,
|
|
137
|
-
sourcemap: true,
|
|
138
|
-
target: 'es2020',
|
|
139
|
-
copy: [
|
|
140
|
-
{ from: './public/index.html', to: './index.html' }
|
|
141
|
-
]
|
|
142
|
-
}],
|
|
143
|
-
preview: {
|
|
144
|
-
port: 3000,
|
|
145
|
-
host: 'localhost',
|
|
146
|
-
open: false,
|
|
147
|
-
logging: true,
|
|
148
|
-
root: './dist',
|
|
149
|
-
basePath: '',
|
|
150
|
-
index: './index.html'
|
|
151
|
-
}
|
|
152
|
-
};
|
|
153
|
-
`;
|
|
154
|
-
await writeFile(join(projectPath, "elit.config.ts"), elitConfig);
|
|
155
|
-
await mkdir(join(projectPath, "public"), { recursive: true });
|
|
156
|
-
const indexHtml = `<!DOCTYPE html>
|
|
157
|
-
<html lang="en">
|
|
158
|
-
<head>
|
|
159
|
-
<meta charset="UTF-8">
|
|
160
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
161
|
-
<title>${projectName2}</title>
|
|
162
|
-
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
|
163
|
-
<meta name="description" content="Built with Elit - Full-stack TypeScript framework">
|
|
164
|
-
</head>
|
|
165
|
-
<body>
|
|
166
|
-
<div id="root"></div>
|
|
167
|
-
<script type="module" src="/main.js"></script>
|
|
168
|
-
</body>
|
|
169
|
-
</html>
|
|
170
|
-
`;
|
|
171
|
-
await writeFile(join(projectPath, "public", "index.html"), indexHtml);
|
|
172
|
-
await mkdir(join(projectPath, "src"), { recursive: true });
|
|
173
|
-
const mainTs = `import { div, h1, h2, button, p } from 'elit/el';
|
|
174
|
-
import { createState, reactive } from 'elit/state';
|
|
175
|
-
import { render } from 'elit/dom';
|
|
176
|
-
import './styles.ts';
|
|
177
|
-
|
|
178
|
-
// Create reactive state
|
|
179
|
-
export const count = createState(0);
|
|
180
|
-
|
|
181
|
-
// Create app
|
|
182
|
-
export const app = div({ className: 'container' },
|
|
183
|
-
div({ className: 'card' },
|
|
184
|
-
h1('Welcome to Elit! \u{1F680}'),
|
|
185
|
-
p('A lightweight TypeScript framework with reactive state management'),
|
|
186
|
-
|
|
187
|
-
div({ className: 'counter' },
|
|
188
|
-
h2('Counter Example'),
|
|
189
|
-
reactive(count, (value) =>
|
|
190
|
-
div({ className: 'count-display' }, \`Count: \${value}\`)
|
|
191
|
-
),
|
|
192
|
-
div({ className: 'button-group' },
|
|
193
|
-
button({
|
|
194
|
-
onclick: () => count.value--,
|
|
195
|
-
className: 'btn btn-secondary'
|
|
196
|
-
}, '- Decrement'),
|
|
197
|
-
button({
|
|
198
|
-
onclick: () => count.value = 0,
|
|
199
|
-
className: 'btn btn-secondary'
|
|
200
|
-
}, 'Reset'),
|
|
201
|
-
button({
|
|
202
|
-
onclick: () => count.value++,
|
|
203
|
-
className: 'btn btn-primary'
|
|
204
|
-
}, '+ Increment')
|
|
205
|
-
)
|
|
206
|
-
)
|
|
207
|
-
)
|
|
208
|
-
);
|
|
209
|
-
|
|
210
|
-
render('root', app);
|
|
211
|
-
console.log('[Main] App rendered');
|
|
212
|
-
`;
|
|
213
|
-
await writeFile(join(projectPath, "src", "main.ts"), mainTs);
|
|
214
|
-
const stylesTs = `import styles from 'elit/style';
|
|
215
|
-
|
|
216
|
-
// Global styles
|
|
217
|
-
styles.addTag('*', {
|
|
218
|
-
margin: 0,
|
|
219
|
-
padding: 0,
|
|
220
|
-
boxSizing: 'border-box'
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
styles.addTag('body', {
|
|
224
|
-
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
225
|
-
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
|
226
|
-
minHeight: '100vh',
|
|
227
|
-
display: 'flex',
|
|
228
|
-
alignItems: 'center',
|
|
229
|
-
justifyContent: 'center',
|
|
230
|
-
padding: '2rem'
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
// Container
|
|
234
|
-
styles.addClass('container', {
|
|
235
|
-
width: '100%',
|
|
236
|
-
maxWidth: '600px'
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
// Card
|
|
240
|
-
styles.addClass('card', {
|
|
241
|
-
background: 'white',
|
|
242
|
-
borderRadius: '16px',
|
|
243
|
-
padding: '3rem',
|
|
244
|
-
boxShadow: '0 20px 60px rgba(0, 0, 0, 0.3)'
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
// Typography
|
|
248
|
-
styles.addTag('h1', {
|
|
249
|
-
fontSize: '2.5rem',
|
|
250
|
-
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
|
251
|
-
WebkitBackgroundClip: 'text',
|
|
252
|
-
WebkitTextFillColor: 'transparent',
|
|
253
|
-
backgroundClip: 'text',
|
|
254
|
-
marginBottom: '1rem'
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
styles.addTag('h2', {
|
|
258
|
-
fontSize: '1.5rem',
|
|
259
|
-
color: '#333',
|
|
260
|
-
marginBottom: '1rem'
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
styles.addTag('p', {
|
|
264
|
-
color: '#666',
|
|
265
|
-
marginBottom: '2rem',
|
|
266
|
-
lineHeight: 1.6
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
// Counter section
|
|
270
|
-
styles.addClass('counter', {
|
|
271
|
-
marginTop: '2rem',
|
|
272
|
-
paddingTop: '2rem',
|
|
273
|
-
borderTop: '2px solid #f0f0f0'
|
|
274
|
-
});
|
|
275
|
-
|
|
276
|
-
styles.addClass('count-display', {
|
|
277
|
-
fontSize: '3rem',
|
|
278
|
-
fontWeight: 'bold',
|
|
279
|
-
color: '#667eea',
|
|
280
|
-
textAlign: 'center',
|
|
281
|
-
margin: '2rem 0'
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
// Button group
|
|
285
|
-
styles.addClass('button-group', {
|
|
286
|
-
display: 'flex',
|
|
287
|
-
gap: '1rem',
|
|
288
|
-
justifyContent: 'center'
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
// Buttons
|
|
292
|
-
styles.addClass('btn', {
|
|
293
|
-
padding: '0.75rem 1.5rem',
|
|
294
|
-
border: 'none',
|
|
295
|
-
borderRadius: '8px',
|
|
296
|
-
fontSize: '1rem',
|
|
297
|
-
fontWeight: 600,
|
|
298
|
-
cursor: 'pointer',
|
|
299
|
-
transition: 'all 0.2s'
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
styles.addClass('btn-primary', {
|
|
303
|
-
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
|
304
|
-
color: 'white'
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
styles.addPseudoClass('hover', {
|
|
308
|
-
transform: 'translateY(-2px)',
|
|
309
|
-
boxShadow: '0 4px 12px rgba(102, 126, 234, 0.4)'
|
|
310
|
-
}, '.btn-primary');
|
|
311
|
-
|
|
312
|
-
styles.addClass('btn-secondary', {
|
|
313
|
-
background: '#f0f0f0',
|
|
314
|
-
color: '#333'
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
styles.addPseudoClass('hover', {
|
|
318
|
-
background: '#e0e0e0',
|
|
319
|
-
transform: 'translateY(-2px)'
|
|
320
|
-
}, '.btn-secondary');
|
|
321
|
-
|
|
322
|
-
styles.addPseudoClass('active', {
|
|
323
|
-
transform: 'translateY(0)'
|
|
324
|
-
}, '.btn');
|
|
325
|
-
|
|
326
|
-
styles.inject('global-styles');
|
|
327
|
-
export default styles;
|
|
328
|
-
`;
|
|
329
|
-
await writeFile(join(projectPath, "src", "styles.ts"), stylesTs);
|
|
330
|
-
const clientTs = `import { div, html, head, body, title, link, script, meta } from 'elit/el';
|
|
331
|
-
|
|
332
|
-
export const client = html(
|
|
333
|
-
head(
|
|
334
|
-
title('${projectName2} - Elit App'),
|
|
335
|
-
link({ rel: 'icon', type: 'image/svg+xml', href: 'favicon.svg' }),
|
|
336
|
-
meta({ charset: 'UTF-8' }),
|
|
337
|
-
meta({ name: 'viewport', content: 'width=device-width, initial-scale=1.0' }),
|
|
338
|
-
meta({ name: 'description', content: 'Elit - Full-stack TypeScript framework with dev server, HMR, routing, SSR, and REST API.' })
|
|
339
|
-
),
|
|
340
|
-
body(
|
|
341
|
-
div({ id: 'root' }),
|
|
342
|
-
script({ type: 'module', src: '/src/main.js' })
|
|
343
|
-
)
|
|
344
|
-
);
|
|
345
|
-
`;
|
|
346
|
-
await writeFile(join(projectPath, "src", "client.ts"), clientTs);
|
|
347
|
-
const serverTs = `import { ServerRouter } from 'elit/server';
|
|
348
|
-
|
|
349
|
-
export const router = new ServerRouter();
|
|
350
|
-
|
|
351
|
-
router.get('/api/hello', async (ctx) => {
|
|
352
|
-
ctx.res.setHeader('Content-Type', 'application/json');
|
|
353
|
-
ctx.res.end(JSON.stringify({ message: 'Hello from Elit ServerRouter!' }));
|
|
354
|
-
});
|
|
355
|
-
|
|
356
|
-
export const server = router;
|
|
357
|
-
`;
|
|
358
|
-
await writeFile(join(projectPath, "src", "server.ts"), serverTs);
|
|
359
|
-
}
|
|
360
78
|
var projectName = getProjectName();
|
|
361
79
|
log("\n\u{1F680} Create Elit App\n", "cyan");
|
|
362
80
|
createProject(projectName).catch((err) => {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# ELIT_PROJECT_NAME
|
|
2
|
+
|
|
3
|
+
A new Elit project created with create-elit.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install
|
|
9
|
+
npm run dev
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Visit http://localhost:3003 to view your app.
|
|
13
|
+
|
|
14
|
+
## Available Scripts
|
|
15
|
+
|
|
16
|
+
- `npm run dev` - Start development server with HMR
|
|
17
|
+
- `npm run build` - Build for production
|
|
18
|
+
- `npm run preview` - Preview production build
|
|
19
|
+
|
|
20
|
+
## Learn More
|
|
21
|
+
|
|
22
|
+
- [Elit Documentation](https://d-osc.github.io/elit)
|
|
23
|
+
- [GitHub Repository](https://github.com/d-osc/elit)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { server } from './src/server';
|
|
2
|
+
import { client } from './src/client';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
dev: {
|
|
6
|
+
port: 3003,
|
|
7
|
+
host: 'localhost',
|
|
8
|
+
open: true,
|
|
9
|
+
logging: true,
|
|
10
|
+
clients: [{
|
|
11
|
+
root: '.',
|
|
12
|
+
basePath: '',
|
|
13
|
+
ssr: () => client,
|
|
14
|
+
api: server
|
|
15
|
+
}]
|
|
16
|
+
},
|
|
17
|
+
build: [{
|
|
18
|
+
entry: './src/main.ts',
|
|
19
|
+
outDir: './dist',
|
|
20
|
+
outFile: 'main.js',
|
|
21
|
+
format: 'esm',
|
|
22
|
+
minify: true,
|
|
23
|
+
sourcemap: true,
|
|
24
|
+
target: 'es2020',
|
|
25
|
+
copy: [
|
|
26
|
+
{
|
|
27
|
+
from: './public/index.html', to: './index.html',
|
|
28
|
+
transform: (content: string, config: { basePath: string; projectName: string; }) => {
|
|
29
|
+
// Replace script src
|
|
30
|
+
let html = content.replace('src="../src/main.ts"', 'src="main.js"');
|
|
31
|
+
|
|
32
|
+
// Replace project name placeholder
|
|
33
|
+
html = html.replace(/ELIT_PROJECT_NAME/g, config.projectName);
|
|
34
|
+
|
|
35
|
+
// Inject base tag if basePath is configured
|
|
36
|
+
if (config.basePath) {
|
|
37
|
+
const baseTag = `<base href="${config.basePath}/">`;
|
|
38
|
+
html = html.replace(
|
|
39
|
+
'<meta name="viewport" content="width=device-width, initial-scale=1.0">',
|
|
40
|
+
`<meta name="viewport" content="width=device-width, initial-scale=1.0">\n ${baseTag}`
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return html;
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
{ from: './public/favicon.svg', to: './favicon.svg' }
|
|
48
|
+
]
|
|
49
|
+
}],
|
|
50
|
+
preview: {
|
|
51
|
+
port: 3000,
|
|
52
|
+
host: 'localhost',
|
|
53
|
+
open: false,
|
|
54
|
+
logging: true,
|
|
55
|
+
root: './dist',
|
|
56
|
+
basePath: '',
|
|
57
|
+
index: './index.html'
|
|
58
|
+
}
|
|
59
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ELIT_PROJECT_NAME",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "elit dev",
|
|
7
|
+
"build": "elit build",
|
|
8
|
+
"preview": "elit preview"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@types/node": "^25.0.9",
|
|
12
|
+
"elit": "^ELIT_VERSION"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="grad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
4
|
+
<stop offset="0%" stop-color="#6366f1"/>
|
|
5
|
+
<stop offset="100%" stop-color="#8b5cf6"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
</defs>
|
|
8
|
+
|
|
9
|
+
<!-- Clean background -->
|
|
10
|
+
<rect width="100" height="100" rx="20" fill="url(#grad)"/>
|
|
11
|
+
|
|
12
|
+
<!-- Simple E shape - 3 horizontal bars -->
|
|
13
|
+
<rect x="28" y="25" width="44" height="8" rx="4" fill="white"/>
|
|
14
|
+
<rect x="28" y="46" width="32" height="8" rx="4" fill="white"/>
|
|
15
|
+
<rect x="28" y="67" width="44" height="8" rx="4" fill="white"/>
|
|
16
|
+
|
|
17
|
+
<!-- Vertical connector -->
|
|
18
|
+
<rect x="28" y="25" width="8" height="50" rx="4" fill="white"/>
|
|
19
|
+
|
|
20
|
+
<!-- Single accent dot -->
|
|
21
|
+
<circle cx="72" cy="50" r="6" fill="white" opacity="0.5"/>
|
|
22
|
+
</svg>
|
|
@@ -0,0 +1,14 @@
|
|
|
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>ELIT_PROJECT_NAME</title>
|
|
7
|
+
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
|
8
|
+
<meta name="description" content="Built with Elit - Full-stack TypeScript framework">
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<div id="root"></div>
|
|
12
|
+
<script type="module" src="../src/main.ts"></script>
|
|
13
|
+
</body>
|
|
14
|
+
</html>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { div, html, head, body, title, link, script, meta } from 'elit/el';
|
|
2
|
+
|
|
3
|
+
export const client = html(
|
|
4
|
+
head(
|
|
5
|
+
title('ELIT_PROJECT_NAME - Elit App'),
|
|
6
|
+
link({ rel: 'icon', type: 'image/svg+xml', href: 'public/favicon.svg' }),
|
|
7
|
+
meta({ charset: 'UTF-8' }),
|
|
8
|
+
meta({ name: 'viewport', content: 'width=device-width, initial-scale=1.0' }),
|
|
9
|
+
meta({ name: 'description', content: 'Elit - Full-stack TypeScript framework with dev server, HMR, routing, SSR, and REST API.' })
|
|
10
|
+
),
|
|
11
|
+
body(
|
|
12
|
+
div({ id: 'app' }),
|
|
13
|
+
script({ type: 'module', src: '/src/main.js' })
|
|
14
|
+
)
|
|
15
|
+
);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { footer, div, p, a } from 'elit/el';
|
|
2
|
+
|
|
3
|
+
export function Footer() {
|
|
4
|
+
return footer({ className: 'footer' },
|
|
5
|
+
div({ className: 'footer-content' },
|
|
6
|
+
div({ className: 'footer-section' },
|
|
7
|
+
p({ className: 'footer-title' }, 'My Elit App'),
|
|
8
|
+
p({ className: 'footer-text' }, 'Built with Elit Framework')
|
|
9
|
+
),
|
|
10
|
+
div({ className: 'footer-section' },
|
|
11
|
+
a({ href: 'https://github.com', target: '_blank', className: 'footer-link' }, 'GitHub'),
|
|
12
|
+
a({ href: '#', className: 'footer-link' }, 'Documentation'),
|
|
13
|
+
a({ href: '#', className: 'footer-link' }, 'Support')
|
|
14
|
+
),
|
|
15
|
+
div({ className: 'footer-section' },
|
|
16
|
+
p({ className: 'footer-copyright' }, '© 2026 My Elit App. All rights reserved.')
|
|
17
|
+
)
|
|
18
|
+
)
|
|
19
|
+
);
|
|
20
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { header, nav, div, a, h1, button, span } from 'elit/el';
|
|
2
|
+
import { createState, reactive } from 'elit/state';
|
|
3
|
+
import type { Router } from 'elit';
|
|
4
|
+
|
|
5
|
+
export function Header(router: Router) {
|
|
6
|
+
// Check if user is logged in (has token in localStorage)
|
|
7
|
+
const isLoggedIn = createState(!!localStorage.getItem('token'));
|
|
8
|
+
const user = createState(() => {
|
|
9
|
+
const userStr = localStorage.getItem('user');
|
|
10
|
+
return userStr ? JSON.parse(userStr) : null;
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
// Listen for storage changes to update header when login/logout happens
|
|
14
|
+
const handleStorageChange = (e: StorageEvent) => {
|
|
15
|
+
if (e.key === 'token' || e.key === 'user') {
|
|
16
|
+
isLoggedIn.value = !!localStorage.getItem('token');
|
|
17
|
+
const userStr = localStorage.getItem('user');
|
|
18
|
+
user.value = userStr ? JSON.parse(userStr) : null;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// Also listen for custom storage events (same-tab updates)
|
|
23
|
+
const handleCustomStorageChange = () => {
|
|
24
|
+
isLoggedIn.value = !!localStorage.getItem('token');
|
|
25
|
+
const userStr = localStorage.getItem('user');
|
|
26
|
+
user.value = userStr ? JSON.parse(userStr) : null;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
window.addEventListener('storage', handleStorageChange);
|
|
30
|
+
window.addEventListener('elit:storage', handleCustomStorageChange);
|
|
31
|
+
|
|
32
|
+
const handleLogout = () => {
|
|
33
|
+
localStorage.removeItem('token');
|
|
34
|
+
localStorage.removeItem('user');
|
|
35
|
+
isLoggedIn.value = false;
|
|
36
|
+
router.push('/');
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return header({ className: 'header' },
|
|
40
|
+
nav({ className: 'nav' },
|
|
41
|
+
div({ className: 'nav-brand' },
|
|
42
|
+
a({ href: '#/', className: 'brand-link' },
|
|
43
|
+
h1({ className: 'brand-title' }, 'ELIT_PROJECT_NAME')
|
|
44
|
+
)
|
|
45
|
+
),
|
|
46
|
+
|
|
47
|
+
reactive(isLoggedIn, (loggedIn) => {
|
|
48
|
+
if (loggedIn) {
|
|
49
|
+
return div({ className: 'nav-menu' },
|
|
50
|
+
a({ href: '#/chat/list', className: 'nav-link' }, 'Messages'),
|
|
51
|
+
a({ href: '#/profile', className: 'nav-link' }, 'Profile'),
|
|
52
|
+
reactive(user, (u) => u ? span({ className: 'nav-user' }, `Welcome, ${u.name}`) : null),
|
|
53
|
+
button({
|
|
54
|
+
className: 'btn btn-secondary btn-sm',
|
|
55
|
+
onclick: handleLogout
|
|
56
|
+
}, 'Logout')
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return div({ className: 'nav-menu' },
|
|
61
|
+
a({ href: '#/login', className: 'nav-link' }, 'Login'),
|
|
62
|
+
button({
|
|
63
|
+
className: 'btn btn-primary btn-sm',
|
|
64
|
+
onclick: () => router.push('/register')
|
|
65
|
+
}, 'Sign Up')
|
|
66
|
+
);
|
|
67
|
+
})
|
|
68
|
+
)
|
|
69
|
+
);
|
|
70
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { div, main } from 'elit/el';
|
|
2
|
+
import { reactive } from 'elit/state';
|
|
3
|
+
import { dom } from 'elit/dom';
|
|
4
|
+
import { injectStyles } from './styles';
|
|
5
|
+
import { router, RouterView } from './router';
|
|
6
|
+
import { Header } from './components/Header';
|
|
7
|
+
import { Footer } from './components/Footer';
|
|
8
|
+
|
|
9
|
+
injectStyles()
|
|
10
|
+
// Create reactive state (shared between SSR and client)
|
|
11
|
+
// Main App
|
|
12
|
+
const App = () =>
|
|
13
|
+
div(
|
|
14
|
+
Header(router),
|
|
15
|
+
main(
|
|
16
|
+
reactive(router.currentRoute, () => RouterView())
|
|
17
|
+
),
|
|
18
|
+
Footer()
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
// Render
|
|
22
|
+
dom.render('#app', App());
|