sprygen 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/README.md +80 -0
  2. package/dist/cli.js +55 -0
  3. package/package.json +53 -0
  4. package/templates/auth/AuthController.java.ejs +40 -0
  5. package/templates/auth/JwtAuthFilter.java.ejs +62 -0
  6. package/templates/auth/JwtService.java.ejs +81 -0
  7. package/templates/auth/SecurityConfig.java.ejs +65 -0
  8. package/templates/auth/UserDetailsServiceImpl.java.ejs +24 -0
  9. package/templates/entity/Entity.java.ejs +40 -0
  10. package/templates/entity/EntityController.java.ejs +92 -0
  11. package/templates/entity/EntityControllerTest.java.ejs +24 -0
  12. package/templates/entity/EntityDto.java.ejs +32 -0
  13. package/templates/entity/EntityRepository.java.ejs +9 -0
  14. package/templates/entity/EntityService.java.ejs +32 -0
  15. package/templates/project/java/config/CorsConfig.java.ejs +24 -0
  16. package/templates/project/java/config/SecurityConfig.java.ejs +76 -0
  17. package/templates/project/java/config/SecurityConfigSession.java.ejs +73 -0
  18. package/templates/project/java/config/SwaggerConfig.java.ejs +31 -0
  19. package/templates/project/java/controller/AdminController.java.ejs +82 -0
  20. package/templates/project/java/controller/AuthController.java.ejs +86 -0
  21. package/templates/project/java/controller/HomeController.java.ejs +63 -0
  22. package/templates/project/java/controller/ProfileController.java.ejs +65 -0
  23. package/templates/project/java/controller/UserController.java.ejs +35 -0
  24. package/templates/project/java/dto/AuthRequest.java.ejs +15 -0
  25. package/templates/project/java/dto/AuthResponse.java.ejs +18 -0
  26. package/templates/project/java/dto/ProfileUpdateRequest.java.ejs +20 -0
  27. package/templates/project/java/dto/RegisterRequest.java.ejs +30 -0
  28. package/templates/project/java/dto/UserDto.java.ejs +17 -0
  29. package/templates/project/java/entity/Role.java.ejs +6 -0
  30. package/templates/project/java/entity/User.java.ejs +97 -0
  31. package/templates/project/java/repository/UserRepository.java.ejs +11 -0
  32. package/templates/project/java/security/JwtAuthFilter.java.ejs +62 -0
  33. package/templates/project/java/security/UserDetailsServiceImpl.java.ejs +21 -0
  34. package/templates/project/java/service/JwtService.java.ejs +81 -0
  35. package/templates/project/java/service/UserService.java.ejs +32 -0
  36. package/templates/project/resources/application.yml.ejs +50 -0
  37. package/templates/project/resources/logback-spring.xml.ejs +41 -0
  38. package/templates/project/static/admin.html.ejs +163 -0
  39. package/templates/project/static/assets/app.js.ejs +340 -0
  40. package/templates/project/static/assets/style.css +533 -0
  41. package/templates/project/static/css/style.css +595 -0
  42. package/templates/project/static/dashboard.html.ejs +119 -0
  43. package/templates/project/static/index.html.ejs +96 -0
  44. package/templates/project/static/js/api.js +30 -0
  45. package/templates/project/static/js/auth.js +44 -0
  46. package/templates/project/static/js/nav.js.ejs +82 -0
  47. package/templates/project/static/js/ui.js +57 -0
  48. package/templates/project/static/login.html.ejs +71 -0
  49. package/templates/project/static/profile.html.ejs +163 -0
  50. package/templates/project/static/register.html.ejs +82 -0
  51. package/templates/project/thymeleaf/admin/users.html.ejs +111 -0
  52. package/templates/project/thymeleaf/dashboard.html.ejs +109 -0
  53. package/templates/project/thymeleaf/layout.html.ejs +75 -0
  54. package/templates/project/thymeleaf/login.html.ejs +56 -0
  55. package/templates/project/thymeleaf/profile.html.ejs +133 -0
  56. package/templates/project/thymeleaf/register.html.ejs +56 -0
@@ -0,0 +1,533 @@
1
+ /* ============================================================
2
+ Sprygen — Shared UI Stylesheet
3
+ Professional Green theme · GitHub-dark inspired
4
+ ============================================================ */
5
+
6
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
7
+
8
+ /* ---------- Reset & Base ---------- */
9
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
10
+
11
+ :root {
12
+ --bg: #0d1117;
13
+ --bg-secondary: #161b22;
14
+ --bg-card: #161b22;
15
+ --bg-input: #0d1117;
16
+
17
+ --border: #30363d;
18
+ --border-light: #21262d;
19
+
20
+ --primary: #2da44e;
21
+ --primary-hover: #26913d;
22
+ --primary-faint: rgba(45, 164, 78, 0.12);
23
+ --primary-glow: rgba(45, 164, 78, 0.25);
24
+
25
+ --text: #e6edf3;
26
+ --text-muted: #8b949e;
27
+ --text-dim: #484f58;
28
+
29
+ --success: #2da44e;
30
+ --danger: #f85149;
31
+ --warning: #d29922;
32
+
33
+ --sidebar-w: 240px;
34
+ --radius: 6px;
35
+ --shadow: 0 8px 24px rgba(1, 4, 9, 0.6);
36
+ }
37
+
38
+ html { font-size: 16px; }
39
+
40
+ body {
41
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
42
+ background: var(--bg);
43
+ color: var(--text);
44
+ min-height: 100vh;
45
+ line-height: 1.5;
46
+ }
47
+
48
+ /* ---------- Layout ---------- */
49
+ #app { min-height: 100vh; }
50
+
51
+ .layout {
52
+ display: flex;
53
+ min-height: 100vh;
54
+ }
55
+
56
+ /* ---------- Sidebar ---------- */
57
+ .sidebar {
58
+ width: var(--sidebar-w);
59
+ background: var(--bg-secondary);
60
+ border-right: 1px solid var(--border);
61
+ display: flex;
62
+ flex-direction: column;
63
+ position: fixed;
64
+ top: 0; left: 0; bottom: 0;
65
+ z-index: 100;
66
+ }
67
+
68
+ .sidebar-brand {
69
+ padding: 16px;
70
+ border-bottom: 1px solid var(--border);
71
+ display: flex;
72
+ align-items: center;
73
+ gap: 10px;
74
+ }
75
+
76
+ .sidebar-brand .logo-icon {
77
+ width: 28px; height: 28px;
78
+ background: var(--primary);
79
+ border-radius: 4px;
80
+ display: flex; align-items: center; justify-content: center;
81
+ font-size: 14px;
82
+ flex-shrink: 0;
83
+ }
84
+
85
+ .sidebar-brand .logo-text {
86
+ font-weight: 700;
87
+ font-size: 0.95rem;
88
+ color: var(--text);
89
+ letter-spacing: 0;
90
+ }
91
+
92
+ .sidebar-nav {
93
+ flex: 1;
94
+ padding: 8px;
95
+ display: flex;
96
+ flex-direction: column;
97
+ gap: 1px;
98
+ overflow-y: auto;
99
+ }
100
+
101
+ .nav-section-label {
102
+ font-size: 0.7rem;
103
+ font-weight: 600;
104
+ text-transform: uppercase;
105
+ letter-spacing: 0.8px;
106
+ color: var(--text-dim);
107
+ padding: 16px 8px 6px;
108
+ }
109
+
110
+ .nav-link {
111
+ display: flex;
112
+ align-items: center;
113
+ gap: 8px;
114
+ padding: 7px 10px;
115
+ border-radius: var(--radius);
116
+ color: var(--text-muted);
117
+ text-decoration: none;
118
+ font-size: 0.865rem;
119
+ font-weight: 500;
120
+ transition: background 0.15s, color 0.15s;
121
+ cursor: pointer;
122
+ border: none;
123
+ background: none;
124
+ width: 100%;
125
+ text-align: left;
126
+ }
127
+
128
+ .nav-link:hover {
129
+ background: rgba(177, 186, 196, 0.08);
130
+ color: var(--text);
131
+ }
132
+
133
+ .nav-link.active {
134
+ background: var(--primary-faint);
135
+ color: var(--primary);
136
+ font-weight: 600;
137
+ }
138
+
139
+ .nav-link .icon { width: 16px; text-align: center; font-style: normal; flex-shrink: 0; }
140
+
141
+ .sidebar-footer {
142
+ padding: 12px;
143
+ border-top: 1px solid var(--border);
144
+ }
145
+
146
+ .user-widget {
147
+ display: flex;
148
+ align-items: center;
149
+ gap: 10px;
150
+ padding: 8px;
151
+ border-radius: var(--radius);
152
+ }
153
+
154
+ .user-avatar {
155
+ width: 32px; height: 32px;
156
+ border-radius: 50%;
157
+ background: var(--primary);
158
+ display: flex; align-items: center; justify-content: center;
159
+ font-size: 0.75rem;
160
+ font-weight: 700;
161
+ flex-shrink: 0;
162
+ color: white;
163
+ border: 2px solid var(--border);
164
+ }
165
+
166
+ .user-info { flex: 1; min-width: 0; }
167
+ .user-name { font-size: 0.82rem; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
168
+ .user-role { font-size: 0.72rem; color: var(--text-muted); }
169
+
170
+ /* ---------- Main Content ---------- */
171
+ .main {
172
+ margin-left: var(--sidebar-w);
173
+ flex: 1;
174
+ min-height: 100vh;
175
+ display: flex;
176
+ flex-direction: column;
177
+ }
178
+
179
+ .topbar {
180
+ padding: 14px 24px;
181
+ border-bottom: 1px solid var(--border);
182
+ background: var(--bg-secondary);
183
+ display: flex;
184
+ align-items: center;
185
+ justify-content: space-between;
186
+ position: sticky;
187
+ top: 0;
188
+ z-index: 50;
189
+ }
190
+
191
+ .topbar-title { font-size: 0.95rem; font-weight: 600; }
192
+
193
+ .page { padding: 24px; max-width: 1100px; }
194
+
195
+ /* ---------- Cards ---------- */
196
+ .card {
197
+ background: var(--bg-card);
198
+ border: 1px solid var(--border);
199
+ border-radius: var(--radius);
200
+ }
201
+
202
+ .card-body { padding: 20px; }
203
+ .card-title { font-size: 0.9rem; font-weight: 600; margin-bottom: 2px; }
204
+ .card-muted { font-size: 0.8rem; color: var(--text-muted); }
205
+
206
+ /* Stat cards */
207
+ .stats-grid {
208
+ display: grid;
209
+ grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
210
+ gap: 12px;
211
+ margin-bottom: 24px;
212
+ }
213
+
214
+ .stat-card {
215
+ background: var(--bg-card);
216
+ border: 1px solid var(--border);
217
+ border-radius: var(--radius);
218
+ padding: 16px;
219
+ display: flex;
220
+ flex-direction: column;
221
+ gap: 6px;
222
+ }
223
+
224
+ .stat-icon { font-size: 1.1rem; line-height: 1; }
225
+ .stat-value { font-size: 1.6rem; font-weight: 700; line-height: 1; color: var(--text); }
226
+ .stat-label { font-size: 0.72rem; color: var(--text-muted); font-weight: 500; text-transform: uppercase; letter-spacing: 0.4px; }
227
+
228
+ /* ---------- Tables ---------- */
229
+ .table-wrap { overflow-x: auto; }
230
+
231
+ table { width: 100%; border-collapse: collapse; }
232
+ thead { }
233
+ thead th {
234
+ padding: 10px 14px;
235
+ font-size: 0.75rem;
236
+ font-weight: 600;
237
+ text-transform: uppercase;
238
+ letter-spacing: 0.4px;
239
+ color: var(--text-muted);
240
+ text-align: left;
241
+ border-bottom: 1px solid var(--border);
242
+ white-space: nowrap;
243
+ }
244
+ tbody tr { border-bottom: 1px solid var(--border-light); transition: background 0.1s; }
245
+ tbody tr:last-child { border-bottom: none; }
246
+ tbody tr:hover { background: rgba(177, 186, 196, 0.04); }
247
+ tbody td { padding: 12px 14px; font-size: 0.865rem; }
248
+
249
+ /* ---------- Badges ---------- */
250
+ .badge {
251
+ display: inline-flex;
252
+ align-items: center;
253
+ padding: 2px 8px;
254
+ border-radius: 99px;
255
+ font-size: 0.7rem;
256
+ font-weight: 600;
257
+ }
258
+ .badge-admin { background: rgba(210, 153, 34, 0.12); color: #d29922; border: 1px solid rgba(210, 153, 34, 0.25); }
259
+ .badge-user { background: rgba(139, 148, 158, 0.1); color: var(--text-muted); border: 1px solid var(--border); }
260
+ .badge-success { background: rgba(45, 164, 78, 0.12); color: var(--primary); border: 1px solid rgba(45, 164, 78, 0.25); }
261
+
262
+ /* Method tags */
263
+ .method { font-family: 'SFMono-Regular', Consolas, monospace; font-size: 0.72rem; font-weight: 700; }
264
+ .method-get { color: #79c0ff; }
265
+ .method-post { color: #3fb950; }
266
+ .method-put { color: #e3b341; }
267
+ .method-delete { color: #f85149; }
268
+
269
+ /* ---------- Forms ---------- */
270
+ .form-group { display: flex; flex-direction: column; gap: 6px; margin-bottom: 14px; }
271
+
272
+ label { font-size: 0.8rem; font-weight: 500; color: var(--text-muted); }
273
+
274
+ input, textarea, select {
275
+ background: var(--bg-input);
276
+ border: 1px solid var(--border);
277
+ border-radius: var(--radius);
278
+ padding: 8px 12px;
279
+ color: var(--text);
280
+ font-family: inherit;
281
+ font-size: 0.865rem;
282
+ transition: border-color 0.15s, box-shadow 0.15s;
283
+ width: 100%;
284
+ }
285
+
286
+ input:focus, textarea:focus, select:focus {
287
+ outline: none;
288
+ border-color: var(--primary);
289
+ box-shadow: 0 0 0 3px var(--primary-glow);
290
+ }
291
+
292
+ input::placeholder, textarea::placeholder { color: var(--text-dim); }
293
+
294
+ /* ---------- Buttons ---------- */
295
+ .btn {
296
+ display: inline-flex;
297
+ align-items: center;
298
+ justify-content: center;
299
+ gap: 6px;
300
+ padding: 7px 16px;
301
+ border-radius: var(--radius);
302
+ font-family: inherit;
303
+ font-size: 0.865rem;
304
+ font-weight: 600;
305
+ cursor: pointer;
306
+ border: 1px solid transparent;
307
+ transition: background 0.15s, border-color 0.15s, box-shadow 0.15s;
308
+ text-decoration: none;
309
+ white-space: nowrap;
310
+ line-height: 1.4;
311
+ }
312
+
313
+ .btn-primary {
314
+ background: var(--primary);
315
+ border-color: var(--primary);
316
+ color: #fff;
317
+ }
318
+ .btn-primary:hover {
319
+ background: var(--primary-hover);
320
+ border-color: var(--primary-hover);
321
+ }
322
+
323
+ .btn-outline {
324
+ background: transparent;
325
+ border-color: var(--border);
326
+ color: var(--text-muted);
327
+ }
328
+ .btn-outline:hover {
329
+ border-color: #8b949e;
330
+ color: var(--text);
331
+ background: rgba(177, 186, 196, 0.08);
332
+ }
333
+
334
+ .btn-danger {
335
+ background: transparent;
336
+ border-color: rgba(248, 81, 73, 0.4);
337
+ color: var(--danger);
338
+ }
339
+ .btn-danger:hover {
340
+ background: rgba(248, 81, 73, 0.1);
341
+ border-color: var(--danger);
342
+ }
343
+
344
+ .btn-sm { padding: 4px 10px; font-size: 0.78rem; }
345
+ .btn-full { width: 100%; }
346
+ .btn:disabled { opacity: 0.5; cursor: not-allowed; }
347
+
348
+ /* ---------- Auth Pages ---------- */
349
+ .auth-page {
350
+ min-height: 100vh;
351
+ display: flex;
352
+ align-items: center;
353
+ justify-content: center;
354
+ padding: 20px;
355
+ background: var(--bg);
356
+ }
357
+
358
+ .auth-container { width: 100%; max-width: 400px; }
359
+
360
+ .auth-brand { text-align: center; margin-bottom: 24px; }
361
+
362
+ .auth-brand .logo-icon-lg {
363
+ width: 44px; height: 44px;
364
+ margin: 0 auto 12px;
365
+ background: var(--primary);
366
+ border-radius: 8px;
367
+ display: flex; align-items: center; justify-content: center;
368
+ font-size: 20px;
369
+ }
370
+
371
+ .auth-brand h1 {
372
+ font-size: 1.25rem;
373
+ font-weight: 700;
374
+ color: var(--text);
375
+ margin-bottom: 4px;
376
+ }
377
+
378
+ .auth-brand p { font-size: 0.865rem; color: var(--text-muted); }
379
+
380
+ .auth-card {
381
+ background: var(--bg-card);
382
+ border: 1px solid var(--border);
383
+ border-radius: 8px;
384
+ padding: 24px;
385
+ }
386
+
387
+ .divider {
388
+ border: none;
389
+ border-top: 1px solid var(--border);
390
+ margin: 16px 0;
391
+ }
392
+
393
+ /* ---------- Alert / Toast ---------- */
394
+ .alert {
395
+ padding: 10px 14px;
396
+ border-radius: var(--radius);
397
+ font-size: 0.82rem;
398
+ margin-bottom: 14px;
399
+ border: 1px solid transparent;
400
+ display: none;
401
+ }
402
+ .alert.visible { display: block; }
403
+ .alert-error { background: rgba(248, 81, 73, 0.1); border-color: rgba(248, 81, 73, 0.3); color: #ffa198; }
404
+ .alert-success { background: rgba(45, 164, 78, 0.1); border-color: rgba(45, 164, 78, 0.3); color: #56d364; }
405
+
406
+ .toast {
407
+ position: fixed;
408
+ bottom: 20px;
409
+ right: 20px;
410
+ padding: 12px 18px;
411
+ border-radius: var(--radius);
412
+ font-size: 0.865rem;
413
+ font-weight: 500;
414
+ border: 1px solid transparent;
415
+ z-index: 9999;
416
+ transform: translateY(60px);
417
+ opacity: 0;
418
+ transition: transform 0.25s ease, opacity 0.25s ease;
419
+ max-width: 320px;
420
+ }
421
+ .toast.show { transform: translateY(0); opacity: 1; }
422
+ .toast-success { background: #1f3d2a; border-color: rgba(45, 164, 78, 0.4); color: #56d364; }
423
+ .toast-error { background: #3d1f1f; border-color: rgba(248, 81, 73, 0.4); color: #ffa198; }
424
+
425
+ /* ---------- Profile ---------- */
426
+ .profile-hero {
427
+ display: flex;
428
+ align-items: center;
429
+ gap: 20px;
430
+ margin-bottom: 24px;
431
+ padding: 20px;
432
+ background: var(--bg-card);
433
+ border: 1px solid var(--border);
434
+ border-radius: var(--radius);
435
+ }
436
+
437
+ .profile-avatar-lg {
438
+ width: 60px; height: 60px;
439
+ border-radius: 50%;
440
+ background: var(--primary);
441
+ display: flex; align-items: center; justify-content: center;
442
+ font-size: 1.4rem;
443
+ font-weight: 700;
444
+ flex-shrink: 0;
445
+ color: white;
446
+ border: 3px solid var(--border);
447
+ }
448
+
449
+ .profile-hero-info h2 { font-size: 1.1rem; font-weight: 700; margin-bottom: 2px; }
450
+ .profile-hero-info p { font-size: 0.82rem; color: var(--text-muted); }
451
+
452
+ /* ---------- Landing ---------- */
453
+ .landing-wrap {
454
+ max-width: 1000px;
455
+ margin: 0 auto;
456
+ padding: 60px 24px 40px;
457
+ }
458
+
459
+ .landing-hero { margin-bottom: 48px; }
460
+
461
+ .landing-hero h1 {
462
+ font-size: 2.2rem;
463
+ font-weight: 700;
464
+ line-height: 1.25;
465
+ margin-bottom: 12px;
466
+ color: var(--text);
467
+ }
468
+
469
+ .landing-hero h1 .accent { color: var(--primary); }
470
+
471
+ .landing-hero p {
472
+ font-size: 1rem;
473
+ color: var(--text-muted);
474
+ max-width: 520px;
475
+ line-height: 1.7;
476
+ margin-bottom: 24px;
477
+ }
478
+
479
+ .landing-cta { display: flex; gap: 10px; align-items: center; }
480
+
481
+ .pills { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 20px; }
482
+
483
+ .pill {
484
+ padding: 4px 10px;
485
+ border-radius: 99px;
486
+ font-size: 0.72rem;
487
+ font-weight: 500;
488
+ background: var(--primary-faint);
489
+ border: 1px solid rgba(45, 164, 78, 0.2);
490
+ color: var(--primary);
491
+ }
492
+
493
+ /* ---------- Section headers ---------- */
494
+ .section-header {
495
+ display: flex;
496
+ align-items: center;
497
+ justify-content: space-between;
498
+ margin-bottom: 14px;
499
+ }
500
+ .section-title { font-size: 0.9rem; font-weight: 600; }
501
+
502
+ /* ---------- Page header ---------- */
503
+ .page-header { margin-bottom: 20px; }
504
+ .page-header h1 { font-size: 1.2rem; font-weight: 700; margin-bottom: 4px; }
505
+ .page-header p { font-size: 0.865rem; color: var(--text-muted); }
506
+
507
+ /* ---------- Code / mono ---------- */
508
+ .mono { font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace; font-size: 0.82rem; }
509
+
510
+ /* ---------- Utilities ---------- */
511
+ .hidden { display: none !important; }
512
+ .text-muted { color: var(--text-muted); }
513
+ .text-danger { color: var(--danger); }
514
+ .text-success { color: var(--success); }
515
+ .flex { display: flex; }
516
+ .gap-2 { gap: 8px; }
517
+ .items-center { align-items: center; }
518
+ .mt-4 { margin-top: 16px; }
519
+
520
+ /* ---------- Responsive ---------- */
521
+ @media (max-width: 768px) {
522
+ .sidebar { display: none; }
523
+ .main { margin-left: 0; }
524
+ .page { padding: 16px; }
525
+ .landing-hero h1 { font-size: 1.6rem; }
526
+ .stats-grid { grid-template-columns: 1fr 1fr; }
527
+ }
528
+
529
+ /* ---------- Scrollbar ---------- */
530
+ ::-webkit-scrollbar { width: 6px; height: 6px; }
531
+ ::-webkit-scrollbar-track { background: transparent; }
532
+ ::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
533
+ ::-webkit-scrollbar-thumb:hover { background: #484f58; }