millas 0.1.4 → 0.1.5
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/package.json +1 -1
- package/src/commands/migrate.js +1 -1
- package/src/router/Router.js +604 -326
package/package.json
CHANGED
package/src/commands/migrate.js
CHANGED
|
@@ -11,7 +11,7 @@ module.exports = function (program) {
|
|
|
11
11
|
.description('Detect model changes and generate migration files')
|
|
12
12
|
.action(async () => {
|
|
13
13
|
const ctx = getProjectContext();
|
|
14
|
-
const
|
|
14
|
+
const ModelInspector = require('../orm/migration/ModelInspector');
|
|
15
15
|
const inspector = new ModelInspector(
|
|
16
16
|
ctx.modelsPath,
|
|
17
17
|
ctx.migrationsPath,
|
package/src/router/Router.js
CHANGED
|
@@ -9,382 +9,658 @@ const WELCOME_PAGE = `<!DOCTYPE html>
|
|
|
9
9
|
<meta charset="UTF-8">
|
|
10
10
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
11
11
|
<title>Millas — Installation successful!</title>
|
|
12
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css" integrity="sha512-Avb2QiuDEEvB4bZJYdft2mNjVShBftLdPG8FJ0V7irTLQ8Uo0qcPxh4Plh7eecDqFDBs4pIAczCMWwKY3KDg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
|
13
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
14
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
15
|
+
<link href="https://fonts.googleapis.com/css2?family=Libre+Baskerville:ital,wght@0,400;0,700;1,400&family=DM+Mono:wght@400;500&family=DM+Sans:wght@300;400;500;600&display=swap" rel="stylesheet">
|
|
12
16
|
<style>
|
|
13
|
-
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
|
|
14
|
-
|
|
15
17
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
16
18
|
|
|
17
19
|
:root {
|
|
18
|
-
--bg:
|
|
19
|
-
--
|
|
20
|
-
--
|
|
21
|
-
--border:
|
|
22
|
-
--border2:
|
|
23
|
-
--primary:
|
|
24
|
-
--primary-
|
|
25
|
-
--
|
|
26
|
-
--
|
|
27
|
-
--
|
|
28
|
-
--
|
|
29
|
-
--
|
|
30
|
-
--
|
|
20
|
+
--bg: #f5f3ee;
|
|
21
|
+
--bg2: #edeae3;
|
|
22
|
+
--white: #ffffff;
|
|
23
|
+
--border: #d6d0c4;
|
|
24
|
+
--border2: #c4bdb0;
|
|
25
|
+
--primary: #2563eb;
|
|
26
|
+
--primary-dk: #1d4ed8;
|
|
27
|
+
--primary-lt: #eff6ff;
|
|
28
|
+
--accent: #059669;
|
|
29
|
+
--accent-lt: #ecfdf5;
|
|
30
|
+
--warn: #d97706;
|
|
31
|
+
--warn-lt: #fffbeb;
|
|
32
|
+
--text: #1c1917;
|
|
33
|
+
--text2: #44403c;
|
|
34
|
+
--muted: #78716c;
|
|
35
|
+
--faint: #a8a29e;
|
|
31
36
|
}
|
|
32
37
|
|
|
33
38
|
html { scroll-behavior: smooth; }
|
|
34
39
|
|
|
35
40
|
body {
|
|
36
|
-
font-family: '
|
|
41
|
+
font-family: 'DM Sans', system-ui, sans-serif;
|
|
37
42
|
background: var(--bg);
|
|
38
43
|
color: var(--text);
|
|
39
44
|
min-height: 100vh;
|
|
40
45
|
line-height: 1.6;
|
|
41
|
-
overflow-x: hidden;
|
|
42
46
|
}
|
|
43
47
|
|
|
44
|
-
/* ──
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
pointer-events: none;
|
|
63
|
-
z-index: 0;
|
|
64
|
-
opacity: 0.5;
|
|
65
|
-
}
|
|
66
|
-
.orb-1 { width: 500px; height: 500px; background: radial-gradient(circle, rgba(99,102,241,0.15), transparent 70%); top: -100px; left: -100px; animation: drift1 18s ease-in-out infinite; }
|
|
67
|
-
.orb-2 { width: 400px; height: 400px; background: radial-gradient(circle, rgba(168,85,247,0.1), transparent 70%); bottom: -80px; right: -80px; animation: drift2 22s ease-in-out infinite; }
|
|
68
|
-
@keyframes drift1 { 0%,100%{transform:translate(0,0)} 50%{transform:translate(60px,40px)} }
|
|
69
|
-
@keyframes drift2 { 0%,100%{transform:translate(0,0)} 50%{transform:translate(-40px,-60px)} }
|
|
70
|
-
|
|
71
|
-
/* ── Layout ── */
|
|
72
|
-
.page { position: relative; z-index: 1; max-width: 900px; margin: 0 auto; padding: 60px 24px 80px; }
|
|
73
|
-
|
|
74
|
-
/* ── Hero ── */
|
|
75
|
-
.hero { text-align: center; margin-bottom: 64px; }
|
|
76
|
-
|
|
77
|
-
.logo-wrap {
|
|
78
|
-
display: inline-flex; align-items: center; justify-content: center;
|
|
79
|
-
width: 80px; height: 80px; border-radius: 22px;
|
|
80
|
-
background: linear-gradient(135deg, #6366f1, #a855f7);
|
|
81
|
-
font-size: 36px; margin-bottom: 28px;
|
|
82
|
-
box-shadow: 0 0 40px rgba(99,102,241,0.3), 0 0 80px rgba(99,102,241,0.1);
|
|
83
|
-
animation: pulse 3s ease-in-out infinite;
|
|
84
|
-
}
|
|
85
|
-
@keyframes pulse { 0%,100%{box-shadow:0 0 40px rgba(99,102,241,0.3),0 0 80px rgba(99,102,241,0.1)} 50%{box-shadow:0 0 60px rgba(99,102,241,0.5),0 0 120px rgba(99,102,241,0.2)} }
|
|
86
|
-
|
|
87
|
-
.version-badge {
|
|
88
|
-
display: inline-flex; align-items: center; gap: 6px;
|
|
89
|
-
background: var(--surface2); border: 1px solid var(--border2);
|
|
90
|
-
color: var(--primary-h); border-radius: 99px;
|
|
91
|
-
padding: 4px 14px; font-size: 12px; font-weight: 600;
|
|
92
|
-
margin-bottom: 24px; letter-spacing: 0.3px;
|
|
93
|
-
}
|
|
94
|
-
.version-dot { width: 6px; height: 6px; background: var(--green); border-radius: 50%; animation: blink 2s ease-in-out infinite; }
|
|
95
|
-
@keyframes blink { 0%,100%{opacity:1} 50%{opacity:0.3} }
|
|
96
|
-
|
|
97
|
-
h1 {
|
|
98
|
-
font-size: clamp(36px, 6vw, 56px);
|
|
99
|
-
font-weight: 700;
|
|
100
|
-
letter-spacing: -1.5px;
|
|
101
|
-
line-height: 1.1;
|
|
102
|
-
margin-bottom: 20px;
|
|
103
|
-
background: linear-gradient(135deg, #fff 0%, #94a3b8 100%);
|
|
104
|
-
-webkit-background-clip: text;
|
|
105
|
-
-webkit-text-fill-color: transparent;
|
|
106
|
-
background-clip: text;
|
|
107
|
-
}
|
|
108
|
-
h1 span {
|
|
109
|
-
background: linear-gradient(135deg, #6366f1, #a855f7);
|
|
110
|
-
-webkit-background-clip: text;
|
|
111
|
-
-webkit-text-fill-color: transparent;
|
|
112
|
-
background-clip: text;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
.hero-sub {
|
|
48
|
+
/* ── Top bar ── */
|
|
49
|
+
.topbar {
|
|
50
|
+
background: var(--white);
|
|
51
|
+
border-bottom: 1px solid var(--border);
|
|
52
|
+
padding: 0 32px;
|
|
53
|
+
display: flex;
|
|
54
|
+
align-items: center;
|
|
55
|
+
justify-content: space-between;
|
|
56
|
+
height: 52px;
|
|
57
|
+
position: sticky;
|
|
58
|
+
top: 0;
|
|
59
|
+
z-index: 100;
|
|
60
|
+
}
|
|
61
|
+
.topbar-brand {
|
|
62
|
+
display: flex;
|
|
63
|
+
align-items: center;
|
|
64
|
+
gap: 10px;
|
|
65
|
+
font-family: 'Libre Baskerville', Georgia, serif;
|
|
116
66
|
font-size: 17px;
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
67
|
+
font-weight: 700;
|
|
68
|
+
color: var(--text);
|
|
69
|
+
text-decoration: none;
|
|
70
|
+
letter-spacing: -0.2px;
|
|
71
|
+
}
|
|
72
|
+
.topbar-brand .brand-icon {
|
|
73
|
+
width: 28px;
|
|
74
|
+
height: 28px;
|
|
75
|
+
background: var(--primary);
|
|
76
|
+
border-radius: 6px;
|
|
77
|
+
display: flex;
|
|
78
|
+
align-items: center;
|
|
79
|
+
justify-content: center;
|
|
80
|
+
color: white;
|
|
81
|
+
font-size: 13px;
|
|
121
82
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
83
|
+
.topbar-links {
|
|
84
|
+
display: flex;
|
|
85
|
+
align-items: center;
|
|
86
|
+
gap: 4px;
|
|
87
|
+
}
|
|
88
|
+
.topbar-links a {
|
|
89
|
+
display: flex;
|
|
90
|
+
align-items: center;
|
|
91
|
+
gap: 6px;
|
|
92
|
+
padding: 6px 12px;
|
|
93
|
+
border-radius: 6px;
|
|
94
|
+
text-decoration: none;
|
|
95
|
+
font-size: 13px;
|
|
96
|
+
font-weight: 500;
|
|
97
|
+
color: var(--muted);
|
|
98
|
+
transition: background .15s, color .15s;
|
|
125
99
|
}
|
|
126
|
-
.
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
100
|
+
.topbar-links a:hover { background: var(--bg); color: var(--text); }
|
|
101
|
+
.topbar-links a i { font-size: 12px; }
|
|
102
|
+
|
|
103
|
+
/* ── Layout ── */
|
|
104
|
+
.layout {
|
|
105
|
+
display: grid;
|
|
106
|
+
grid-template-columns: 220px 1fr;
|
|
107
|
+
min-height: calc(100vh - 52px);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* ── Sidebar ── */
|
|
111
|
+
.sidebar {
|
|
112
|
+
background: var(--white);
|
|
113
|
+
border-right: 1px solid var(--border);
|
|
114
|
+
padding: 28px 0;
|
|
115
|
+
position: sticky;
|
|
116
|
+
top: 52px;
|
|
117
|
+
height: calc(100vh - 52px);
|
|
118
|
+
overflow-y: auto;
|
|
119
|
+
}
|
|
120
|
+
.sidebar-section {
|
|
121
|
+
padding: 0 16px 20px;
|
|
122
|
+
}
|
|
123
|
+
.sidebar-label {
|
|
124
|
+
font-size: 10px;
|
|
125
|
+
font-weight: 600;
|
|
126
|
+
letter-spacing: 0.8px;
|
|
127
|
+
text-transform: uppercase;
|
|
128
|
+
color: var(--faint);
|
|
129
|
+
padding: 0 8px;
|
|
130
|
+
margin-bottom: 6px;
|
|
131
|
+
}
|
|
132
|
+
.sidebar-link {
|
|
133
|
+
display: flex;
|
|
134
|
+
align-items: center;
|
|
135
|
+
gap: 9px;
|
|
136
|
+
padding: 7px 10px;
|
|
137
|
+
border-radius: 7px;
|
|
138
|
+
text-decoration: none;
|
|
139
|
+
font-size: 13.5px;
|
|
140
|
+
font-weight: 500;
|
|
141
|
+
color: var(--text2);
|
|
142
|
+
transition: background .15s, color .15s;
|
|
143
|
+
margin-bottom: 1px;
|
|
144
|
+
}
|
|
145
|
+
.sidebar-link i {
|
|
146
|
+
width: 16px;
|
|
147
|
+
text-align: center;
|
|
148
|
+
font-size: 13px;
|
|
149
|
+
color: var(--faint);
|
|
150
|
+
flex-shrink: 0;
|
|
151
|
+
}
|
|
152
|
+
.sidebar-link:hover { background: var(--bg); color: var(--text); }
|
|
153
|
+
.sidebar-link:hover i { color: var(--primary); }
|
|
154
|
+
.sidebar-link.active { background: var(--primary-lt); color: var(--primary); }
|
|
155
|
+
.sidebar-link.active i { color: var(--primary); }
|
|
156
|
+
.sidebar-divider {
|
|
157
|
+
height: 1px;
|
|
158
|
+
background: var(--border);
|
|
159
|
+
margin: 4px 16px 20px;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* ── Main content ── */
|
|
163
|
+
.main {
|
|
164
|
+
padding: 40px 48px 60px;
|
|
165
|
+
max-width: 820px;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/* ── Success banner ── */
|
|
169
|
+
.success-banner {
|
|
170
|
+
background: var(--accent-lt);
|
|
171
|
+
border: 1px solid #a7f3d0;
|
|
172
|
+
border-left: 4px solid var(--accent);
|
|
173
|
+
border-radius: 8px;
|
|
174
|
+
padding: 14px 18px;
|
|
175
|
+
display: flex;
|
|
176
|
+
align-items: flex-start;
|
|
177
|
+
gap: 12px;
|
|
178
|
+
margin-bottom: 36px;
|
|
179
|
+
}
|
|
180
|
+
.success-banner i {
|
|
181
|
+
color: var(--accent);
|
|
182
|
+
font-size: 16px;
|
|
183
|
+
margin-top: 1px;
|
|
184
|
+
flex-shrink: 0;
|
|
185
|
+
}
|
|
186
|
+
.success-banner-text { font-size: 14px; color: #065f46; line-height: 1.5; }
|
|
187
|
+
.success-banner-text strong { font-weight: 600; display: block; margin-bottom: 2px; }
|
|
188
|
+
|
|
189
|
+
/* ── Page heading ── */
|
|
190
|
+
.page-heading {
|
|
191
|
+
margin-bottom: 36px;
|
|
192
|
+
padding-bottom: 28px;
|
|
193
|
+
border-bottom: 1px solid var(--border);
|
|
132
194
|
}
|
|
133
|
-
.
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
195
|
+
.page-heading h1 {
|
|
196
|
+
font-family: 'Libre Baskerville', Georgia, serif;
|
|
197
|
+
font-size: 30px;
|
|
198
|
+
font-weight: 700;
|
|
199
|
+
letter-spacing: -0.5px;
|
|
200
|
+
line-height: 1.2;
|
|
201
|
+
color: var(--text);
|
|
202
|
+
margin-bottom: 8px;
|
|
137
203
|
}
|
|
138
|
-
.
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
204
|
+
.page-heading p {
|
|
205
|
+
font-size: 15px;
|
|
206
|
+
color: var(--muted);
|
|
207
|
+
max-width: 560px;
|
|
208
|
+
}
|
|
209
|
+
.page-heading p code {
|
|
210
|
+
font-family: 'DM Mono', monospace;
|
|
211
|
+
font-size: 12.5px;
|
|
212
|
+
background: var(--bg2);
|
|
213
|
+
color: var(--primary);
|
|
214
|
+
padding: 1px 6px;
|
|
215
|
+
border-radius: 4px;
|
|
216
|
+
border: 1px solid var(--border);
|
|
142
217
|
}
|
|
143
|
-
.btn-ghost:hover { background: var(--surface2); color: var(--text); border-color: var(--primary); }
|
|
144
218
|
|
|
145
|
-
/* ──
|
|
146
|
-
.
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
219
|
+
/* ── Info strip ── */
|
|
220
|
+
.info-strip {
|
|
221
|
+
display: grid;
|
|
222
|
+
grid-template-columns: repeat(3, 1fr);
|
|
223
|
+
gap: 14px;
|
|
224
|
+
margin-bottom: 36px;
|
|
150
225
|
}
|
|
151
|
-
.
|
|
226
|
+
.info-card {
|
|
227
|
+
background: var(--white);
|
|
228
|
+
border: 1px solid var(--border);
|
|
229
|
+
border-radius: 9px;
|
|
230
|
+
padding: 16px 18px;
|
|
231
|
+
}
|
|
232
|
+
.info-card-label {
|
|
233
|
+
font-size: 11px;
|
|
234
|
+
font-weight: 600;
|
|
235
|
+
letter-spacing: 0.5px;
|
|
236
|
+
text-transform: uppercase;
|
|
237
|
+
color: var(--faint);
|
|
238
|
+
margin-bottom: 6px;
|
|
239
|
+
display: flex;
|
|
240
|
+
align-items: center;
|
|
241
|
+
gap: 6px;
|
|
242
|
+
}
|
|
243
|
+
.info-card-label i { font-size: 10px; }
|
|
244
|
+
.info-card-value {
|
|
245
|
+
font-size: 14px;
|
|
246
|
+
font-weight: 600;
|
|
247
|
+
color: var(--text);
|
|
248
|
+
display: flex;
|
|
249
|
+
align-items: center;
|
|
250
|
+
gap: 7px;
|
|
251
|
+
}
|
|
252
|
+
.dot-green {
|
|
253
|
+
width: 7px; height: 7px; border-radius: 50%;
|
|
254
|
+
background: var(--accent);
|
|
255
|
+
box-shadow: 0 0 6px rgba(5,150,105,0.4);
|
|
256
|
+
flex-shrink: 0;
|
|
257
|
+
}
|
|
258
|
+
.info-card-value a {
|
|
259
|
+
color: var(--primary);
|
|
260
|
+
text-decoration: none;
|
|
261
|
+
font-weight: 600;
|
|
262
|
+
}
|
|
263
|
+
.info-card-value a:hover { text-decoration: underline; }
|
|
264
|
+
|
|
265
|
+
/* ── Section titles ── */
|
|
266
|
+
.section-title {
|
|
267
|
+
font-size: 12px;
|
|
268
|
+
font-weight: 600;
|
|
269
|
+
letter-spacing: 0.6px;
|
|
270
|
+
text-transform: uppercase;
|
|
271
|
+
color: var(--faint);
|
|
272
|
+
margin-bottom: 14px;
|
|
273
|
+
display: flex;
|
|
274
|
+
align-items: center;
|
|
275
|
+
gap: 8px;
|
|
276
|
+
}
|
|
277
|
+
.section-title::after {
|
|
152
278
|
content: '';
|
|
153
|
-
|
|
154
|
-
height: 1px;
|
|
279
|
+
flex: 1;
|
|
280
|
+
height: 1px;
|
|
281
|
+
background: var(--border);
|
|
155
282
|
}
|
|
156
|
-
.divider span { background: var(--bg); padding: 0 16px; position: relative; }
|
|
157
283
|
|
|
158
|
-
/* ── Feature
|
|
159
|
-
.
|
|
284
|
+
/* ── Feature table ── */
|
|
285
|
+
.feature-table {
|
|
286
|
+
background: var(--white);
|
|
287
|
+
border: 1px solid var(--border);
|
|
288
|
+
border-radius: 10px;
|
|
289
|
+
overflow: hidden;
|
|
290
|
+
margin-bottom: 36px;
|
|
291
|
+
}
|
|
292
|
+
.feature-table-row {
|
|
160
293
|
display: grid;
|
|
161
|
-
grid-template-columns:
|
|
162
|
-
|
|
163
|
-
|
|
294
|
+
grid-template-columns: 40px 1fr;
|
|
295
|
+
align-items: start;
|
|
296
|
+
padding: 14px 18px;
|
|
297
|
+
gap: 14px;
|
|
298
|
+
border-bottom: 1px solid var(--border);
|
|
299
|
+
transition: background .12s;
|
|
164
300
|
}
|
|
165
|
-
.feature {
|
|
166
|
-
|
|
301
|
+
.feature-table-row:last-child { border-bottom: none; }
|
|
302
|
+
.feature-table-row:hover { background: var(--bg); }
|
|
303
|
+
.feature-icon-wrap {
|
|
304
|
+
width: 34px; height: 34px;
|
|
305
|
+
background: var(--bg2);
|
|
167
306
|
border: 1px solid var(--border);
|
|
168
|
-
border-radius:
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
.feature-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
.
|
|
180
|
-
.
|
|
181
|
-
|
|
307
|
+
border-radius: 8px;
|
|
308
|
+
display: flex;
|
|
309
|
+
align-items: center;
|
|
310
|
+
justify-content: center;
|
|
311
|
+
flex-shrink: 0;
|
|
312
|
+
margin-top: 1px;
|
|
313
|
+
}
|
|
314
|
+
.feature-icon-wrap i {
|
|
315
|
+
font-size: 14px;
|
|
316
|
+
color: var(--primary);
|
|
317
|
+
}
|
|
318
|
+
.feature-body {}
|
|
319
|
+
.feature-name {
|
|
320
|
+
font-size: 14px;
|
|
321
|
+
font-weight: 600;
|
|
322
|
+
color: var(--text);
|
|
323
|
+
margin-bottom: 2px;
|
|
324
|
+
}
|
|
325
|
+
.feature-desc {
|
|
326
|
+
font-size: 13px;
|
|
327
|
+
color: var(--muted);
|
|
328
|
+
line-height: 1.55;
|
|
329
|
+
}
|
|
330
|
+
.feature-desc code {
|
|
331
|
+
font-family: 'DM Mono', monospace;
|
|
332
|
+
font-size: 11.5px;
|
|
333
|
+
background: var(--bg2);
|
|
334
|
+
color: var(--primary);
|
|
335
|
+
padding: 1px 5px;
|
|
336
|
+
border-radius: 4px;
|
|
337
|
+
border: 1px solid var(--border);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/* ── Code blocks ── */
|
|
341
|
+
.code-wrap {
|
|
342
|
+
background: var(--white);
|
|
182
343
|
border: 1px solid var(--border);
|
|
183
|
-
border-radius:
|
|
344
|
+
border-radius: 10px;
|
|
184
345
|
overflow: hidden;
|
|
346
|
+
margin-bottom: 36px;
|
|
185
347
|
}
|
|
186
348
|
.code-header {
|
|
187
|
-
background: var(--
|
|
188
|
-
padding: 10px 16px;
|
|
349
|
+
background: var(--bg2);
|
|
189
350
|
border-bottom: 1px solid var(--border);
|
|
190
|
-
|
|
191
|
-
|
|
351
|
+
padding: 9px 16px;
|
|
352
|
+
display: flex;
|
|
353
|
+
align-items: center;
|
|
354
|
+
justify-content: space-between;
|
|
355
|
+
gap: 10px;
|
|
356
|
+
}
|
|
357
|
+
.code-header-left {
|
|
358
|
+
display: flex;
|
|
359
|
+
align-items: center;
|
|
360
|
+
gap: 8px;
|
|
361
|
+
}
|
|
362
|
+
.code-header-left i {
|
|
363
|
+
color: var(--faint);
|
|
364
|
+
font-size: 12px;
|
|
365
|
+
}
|
|
366
|
+
.code-filename {
|
|
367
|
+
font-family: 'DM Mono', monospace;
|
|
368
|
+
font-size: 12px;
|
|
369
|
+
color: var(--text2);
|
|
370
|
+
font-weight: 500;
|
|
371
|
+
}
|
|
372
|
+
.code-lang {
|
|
373
|
+
font-size: 11px;
|
|
374
|
+
font-weight: 600;
|
|
375
|
+
letter-spacing: 0.4px;
|
|
376
|
+
text-transform: uppercase;
|
|
377
|
+
color: var(--faint);
|
|
378
|
+
background: var(--border);
|
|
379
|
+
padding: 2px 7px;
|
|
380
|
+
border-radius: 4px;
|
|
192
381
|
}
|
|
193
|
-
.code-dots { display: flex; gap: 6px; }
|
|
194
|
-
.code-dot { width: 10px; height: 10px; border-radius: 50%; }
|
|
195
|
-
.code-dot:nth-child(1){background:#ef4444} .code-dot:nth-child(2){background:#f59e0b} .code-dot:nth-child(3){background:#22c55e}
|
|
196
|
-
.code-filename { font-family: 'JetBrains Mono', monospace; margin-left: 4px; }
|
|
197
382
|
pre {
|
|
198
|
-
padding: 20px
|
|
199
|
-
font-family: '
|
|
200
|
-
font-size:
|
|
201
|
-
line-height: 1.
|
|
383
|
+
padding: 20px 22px;
|
|
384
|
+
font-family: 'DM Mono', monospace;
|
|
385
|
+
font-size: 12.5px;
|
|
386
|
+
line-height: 1.75;
|
|
202
387
|
overflow-x: auto;
|
|
203
|
-
color:
|
|
204
|
-
}
|
|
205
|
-
.kw { color: #
|
|
206
|
-
.fn { color: #
|
|
207
|
-
.str { color: #
|
|
208
|
-
.cm { color:
|
|
209
|
-
.cl { color: #
|
|
210
|
-
.pm { color:
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
388
|
+
color: var(--text2);
|
|
389
|
+
}
|
|
390
|
+
.kw { color: #7c3aed; font-weight: 500; }
|
|
391
|
+
.fn { color: #2563eb; }
|
|
392
|
+
.str { color: #059669; }
|
|
393
|
+
.cm { color: var(--faint); font-style: italic; }
|
|
394
|
+
.cl { color: #b45309; }
|
|
395
|
+
.pm { color: var(--text); }
|
|
396
|
+
.num { color: #dc2626; }
|
|
397
|
+
|
|
398
|
+
/* ── Warning notice ── */
|
|
399
|
+
.notice {
|
|
400
|
+
background: var(--warn-lt);
|
|
401
|
+
border: 1px solid #fde68a;
|
|
402
|
+
border-left: 4px solid var(--warn);
|
|
403
|
+
border-radius: 8px;
|
|
404
|
+
padding: 13px 16px;
|
|
405
|
+
display: flex;
|
|
406
|
+
align-items: flex-start;
|
|
407
|
+
gap: 10px;
|
|
408
|
+
margin-bottom: 36px;
|
|
409
|
+
font-size: 13.5px;
|
|
410
|
+
color: #78350f;
|
|
411
|
+
line-height: 1.55;
|
|
412
|
+
}
|
|
413
|
+
.notice i { color: var(--warn); font-size: 14px; margin-top: 2px; flex-shrink: 0; }
|
|
414
|
+
.notice code {
|
|
415
|
+
font-family: 'DM Mono', monospace;
|
|
416
|
+
font-size: 11.5px;
|
|
417
|
+
background: #fef3c7;
|
|
418
|
+
padding: 1px 5px;
|
|
419
|
+
border-radius: 4px;
|
|
420
|
+
border: 1px solid #fde68a;
|
|
421
|
+
color: #92400e;
|
|
224
422
|
}
|
|
225
|
-
.status-icon { font-size: 20px; }
|
|
226
|
-
.status-label { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.5px; font-weight: 600; }
|
|
227
|
-
.status-value { font-size: 14px; font-weight: 600; color: var(--text); }
|
|
228
|
-
.status-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--green); box-shadow: 0 0 8px rgba(34,197,94,0.5); flex-shrink: 0; }
|
|
229
423
|
|
|
230
424
|
/* ── Footer ── */
|
|
231
|
-
footer {
|
|
232
|
-
|
|
233
|
-
padding-top: 40px;
|
|
425
|
+
.page-footer {
|
|
426
|
+
padding-top: 28px;
|
|
234
427
|
border-top: 1px solid var(--border);
|
|
235
|
-
|
|
428
|
+
display: flex;
|
|
429
|
+
align-items: center;
|
|
430
|
+
justify-content: space-between;
|
|
431
|
+
flex-wrap: wrap;
|
|
432
|
+
gap: 12px;
|
|
433
|
+
}
|
|
434
|
+
.page-footer-left {
|
|
236
435
|
font-size: 13px;
|
|
237
|
-
|
|
436
|
+
color: var(--faint);
|
|
238
437
|
}
|
|
239
|
-
.footer-links {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
.notice {
|
|
245
|
-
background: linear-gradient(135deg, rgba(99,102,241,0.08), rgba(168,85,247,0.05));
|
|
246
|
-
border: 1px solid rgba(99,102,241,0.2);
|
|
247
|
-
border-radius: 12px;
|
|
248
|
-
padding: 16px 20px;
|
|
438
|
+
.page-footer-links {
|
|
439
|
+
display: flex;
|
|
440
|
+
gap: 16px;
|
|
441
|
+
}
|
|
442
|
+
.page-footer-links a {
|
|
249
443
|
font-size: 13px;
|
|
250
|
-
color: var(--
|
|
251
|
-
|
|
252
|
-
display: flex;
|
|
444
|
+
color: var(--muted);
|
|
445
|
+
text-decoration: none;
|
|
446
|
+
display: flex;
|
|
447
|
+
align-items: center;
|
|
448
|
+
gap: 5px;
|
|
449
|
+
transition: color .15s;
|
|
253
450
|
}
|
|
254
|
-
.
|
|
255
|
-
|
|
451
|
+
.page-footer-links a i { font-size: 11px; }
|
|
452
|
+
.page-footer-links a:hover { color: var(--primary); }
|
|
256
453
|
|
|
257
|
-
@media(max-width:
|
|
258
|
-
.
|
|
259
|
-
|
|
260
|
-
.
|
|
454
|
+
@media(max-width: 768px) {
|
|
455
|
+
.layout { grid-template-columns: 1fr; }
|
|
456
|
+
.sidebar { display: none; }
|
|
457
|
+
.main { padding: 28px 20px 48px; }
|
|
458
|
+
.info-strip { grid-template-columns: 1fr; }
|
|
261
459
|
}
|
|
262
460
|
</style>
|
|
263
461
|
</head>
|
|
264
462
|
<body>
|
|
265
|
-
<div class="orb orb-1"></div>
|
|
266
|
-
<div class="orb orb-2"></div>
|
|
267
463
|
|
|
268
|
-
|
|
464
|
+
<!-- Top bar -->
|
|
465
|
+
<nav class="topbar">
|
|
466
|
+
<a href="/" class="topbar-brand">
|
|
467
|
+
<div class="brand-icon"><i class="fa-solid fa-bolt"></i></div>
|
|
468
|
+
Millas
|
|
469
|
+
</a>
|
|
470
|
+
<div class="topbar-links">
|
|
471
|
+
<a href="/admin"><i class="fa-solid fa-gauge-high"></i> Admin</a>
|
|
472
|
+
<a href="/api/health"><i class="fa-solid fa-heart-pulse"></i> Health</a>
|
|
473
|
+
<a href="https://github.com/millas-framework/millas" target="_blank"><i class="fa-brands fa-github"></i> GitHub</a>
|
|
474
|
+
</div>
|
|
475
|
+
</nav>
|
|
476
|
+
|
|
477
|
+
<div class="layout">
|
|
478
|
+
|
|
479
|
+
<!-- Sidebar -->
|
|
480
|
+
<aside class="sidebar">
|
|
481
|
+
<div class="sidebar-section">
|
|
482
|
+
<div class="sidebar-label">Navigation</div>
|
|
483
|
+
<a href="/admin" class="sidebar-link">
|
|
484
|
+
<i class="fa-solid fa-gauge-high"></i> Admin Panel
|
|
485
|
+
</a>
|
|
486
|
+
<a href="/api/health" class="sidebar-link">
|
|
487
|
+
<i class="fa-solid fa-heart-pulse"></i> API Health
|
|
488
|
+
</a>
|
|
489
|
+
</div>
|
|
269
490
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
<div class="
|
|
273
|
-
|
|
274
|
-
<
|
|
275
|
-
|
|
491
|
+
<div class="sidebar-divider"></div>
|
|
492
|
+
|
|
493
|
+
<div class="sidebar-section">
|
|
494
|
+
<div class="sidebar-label">Framework</div>
|
|
495
|
+
<a href="#routing" class="sidebar-link active">
|
|
496
|
+
<i class="fa-solid fa-route"></i> Routing
|
|
497
|
+
</a>
|
|
498
|
+
<a href="#database" class="sidebar-link">
|
|
499
|
+
<i class="fa-solid fa-database"></i> Database / ORM
|
|
500
|
+
</a>
|
|
501
|
+
<a href="#auth" class="sidebar-link">
|
|
502
|
+
<i class="fa-solid fa-lock"></i> Authentication
|
|
503
|
+
</a>
|
|
504
|
+
<a href="#mail" class="sidebar-link">
|
|
505
|
+
<i class="fa-solid fa-envelope"></i> Mail
|
|
506
|
+
</a>
|
|
507
|
+
<a href="#queue" class="sidebar-link">
|
|
508
|
+
<i class="fa-solid fa-layer-group"></i> Queue
|
|
509
|
+
</a>
|
|
510
|
+
<a href="#cache" class="sidebar-link">
|
|
511
|
+
<i class="fa-solid fa-bolt"></i> Cache
|
|
512
|
+
</a>
|
|
513
|
+
<a href="#storage" class="sidebar-link">
|
|
514
|
+
<i class="fa-solid fa-folder-open"></i> Storage
|
|
515
|
+
</a>
|
|
276
516
|
</div>
|
|
277
|
-
|
|
278
|
-
<
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
517
|
+
|
|
518
|
+
<div class="sidebar-divider"></div>
|
|
519
|
+
|
|
520
|
+
<div class="sidebar-section">
|
|
521
|
+
<div class="sidebar-label">External</div>
|
|
522
|
+
<a href="https://www.npmjs.com/package/millas" target="_blank" class="sidebar-link">
|
|
523
|
+
<i class="fa-brands fa-npm"></i> npm package
|
|
524
|
+
</a>
|
|
525
|
+
<a href="https://github.com/millas-framework/millas" target="_blank" class="sidebar-link">
|
|
526
|
+
<i class="fa-brands fa-github"></i> GitHub
|
|
527
|
+
</a>
|
|
285
528
|
</div>
|
|
286
|
-
</
|
|
529
|
+
</aside>
|
|
287
530
|
|
|
288
|
-
<!--
|
|
289
|
-
<
|
|
290
|
-
<span class="notice-icon">💡</span>
|
|
291
|
-
<span>
|
|
292
|
-
To remove this page, define your own route in <code>routes/web.js</code>:
|
|
293
|
-
<br>
|
|
294
|
-
<code style="margin-top:6px;display:inline-block">Route.get('/', (req, res) => res.json({ hello: 'world' }))</code>
|
|
295
|
-
</span>
|
|
296
|
-
</div>
|
|
531
|
+
<!-- Main -->
|
|
532
|
+
<main class="main">
|
|
297
533
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
<
|
|
302
|
-
|
|
303
|
-
<
|
|
304
|
-
<div class="status-value">Running</div>
|
|
534
|
+
<!-- Success banner -->
|
|
535
|
+
<div class="success-banner">
|
|
536
|
+
<i class="fa-solid fa-circle-check"></i>
|
|
537
|
+
<div class="success-banner-text">
|
|
538
|
+
<strong>Installation successful!</strong>
|
|
539
|
+
Millas v0.1.2 is running. Define a route at <code style="font-family:'DM Mono',monospace;font-size:12px;background:rgba(5,150,105,0.08);color:#065f46;padding:1px 6px;border-radius:4px;border:1px solid #a7f3d0">GET /</code> in <code style="font-family:'DM Mono',monospace;font-size:12px;background:rgba(5,150,105,0.08);color:#065f46;padding:1px 6px;border-radius:4px;border:1px solid #a7f3d0">routes/web.js</code> to replace this page.
|
|
305
540
|
</div>
|
|
306
541
|
</div>
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
542
|
+
|
|
543
|
+
<!-- Heading -->
|
|
544
|
+
<div class="page-heading">
|
|
545
|
+
<h1>Millas Framework</h1>
|
|
546
|
+
<p>
|
|
547
|
+
A Node.js web framework built on Express. This welcome page is shown
|
|
548
|
+
because no route is registered at <code>/</code>. Add one to get started.
|
|
549
|
+
</p>
|
|
313
550
|
</div>
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
<div class="
|
|
551
|
+
|
|
552
|
+
<!-- Status strip -->
|
|
553
|
+
<div class="info-strip">
|
|
554
|
+
<div class="info-card">
|
|
555
|
+
<div class="info-card-label"><i class="fa-solid fa-server"></i> Server</div>
|
|
556
|
+
<div class="info-card-value"><span class="dot-green"></span> Running</div>
|
|
319
557
|
</div>
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
<div class="
|
|
558
|
+
<div class="info-card">
|
|
559
|
+
<div class="info-card-label"><i class="fa-solid fa-gauge-high"></i> Admin panel</div>
|
|
560
|
+
<div class="info-card-value"><a href="/admin">/admin →</a></div>
|
|
561
|
+
</div>
|
|
562
|
+
<div class="info-card">
|
|
563
|
+
<div class="info-card-label"><i class="fa-solid fa-heart-pulse"></i> API health</div>
|
|
564
|
+
<div class="info-card-value"><a href="/api/health">/api/health →</a></div>
|
|
326
565
|
</div>
|
|
327
566
|
</div>
|
|
328
|
-
</div>
|
|
329
|
-
|
|
330
|
-
<div class="divider"><span>What's included</span></div>
|
|
331
567
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
<
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
<div class="feature">
|
|
340
|
-
<div class="feature-icon">🗃️</div>
|
|
341
|
-
<div class="feature-title">ORM + Migrations</div>
|
|
342
|
-
<div class="feature-desc">Model-driven schema with <code>millas makemigrations</code> and <code>millas migrate</code>.</div>
|
|
343
|
-
</div>
|
|
344
|
-
<div class="feature">
|
|
345
|
-
<div class="feature-icon">🔐</div>
|
|
346
|
-
<div class="feature-title">Authentication</div>
|
|
347
|
-
<div class="feature-desc">JWT out of the box. Register, login, refresh, password reset — all via <code>Auth.login()</code>.</div>
|
|
348
|
-
</div>
|
|
349
|
-
<div class="feature">
|
|
350
|
-
<div class="feature-icon">📬</div>
|
|
351
|
-
<div class="feature-title">Mail</div>
|
|
352
|
-
<div class="feature-desc">SMTP, SendGrid, Mailgun. Template engine with <code>{{ variable }}</code>, loops, and conditionals.</div>
|
|
353
|
-
</div>
|
|
354
|
-
<div class="feature">
|
|
355
|
-
<div class="feature-icon">⚙️</div>
|
|
356
|
-
<div class="feature-title">Queue System</div>
|
|
357
|
-
<div class="feature-desc">Background jobs with <code>dispatch(new Job())</code>. Database and sync drivers included.</div>
|
|
358
|
-
</div>
|
|
359
|
-
<div class="feature">
|
|
360
|
-
<div class="feature-icon">📡</div>
|
|
361
|
-
<div class="feature-title">Event System</div>
|
|
362
|
-
<div class="feature-desc">Fire and listen to events. Listeners can run inline or through the queue.</div>
|
|
363
|
-
</div>
|
|
364
|
-
<div class="feature">
|
|
365
|
-
<div class="feature-icon">⚡</div>
|
|
366
|
-
<div class="feature-title">Cache</div>
|
|
367
|
-
<div class="feature-desc">Memory, file, and null drivers. Tag-based invalidation with <code>Cache.tags('users').flush()</code>.</div>
|
|
368
|
-
</div>
|
|
369
|
-
<div class="feature">
|
|
370
|
-
<div class="feature-icon">🗂️</div>
|
|
371
|
-
<div class="feature-title">File Storage</div>
|
|
372
|
-
<div class="feature-desc">Local disk with multiple named disks. Upload, copy, move, list, stream files.</div>
|
|
568
|
+
<!-- Notice -->
|
|
569
|
+
<div class="notice">
|
|
570
|
+
<i class="fa-solid fa-triangle-exclamation"></i>
|
|
571
|
+
<span>
|
|
572
|
+
This welcome page is only visible while no <code>GET /</code> route is defined.
|
|
573
|
+
As soon as you add one to <code>routes/web.js</code>, it disappears automatically.
|
|
574
|
+
</span>
|
|
373
575
|
</div>
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
576
|
+
|
|
577
|
+
<!-- Included features -->
|
|
578
|
+
<div class="section-title">What’s included</div>
|
|
579
|
+
<div class="feature-table">
|
|
580
|
+
|
|
581
|
+
<div class="feature-table-row" id="routing">
|
|
582
|
+
<div class="feature-icon-wrap"><i class="fa-solid fa-route"></i></div>
|
|
583
|
+
<div class="feature-body">
|
|
584
|
+
<div class="feature-name">Expressive Router</div>
|
|
585
|
+
<div class="feature-desc">Route groups, prefixes, middleware chains, resource routes, and the <code>Route.auth()</code> shortcut for all auth endpoints in one line.</div>
|
|
586
|
+
</div>
|
|
587
|
+
</div>
|
|
588
|
+
|
|
589
|
+
<div class="feature-table-row" id="database">
|
|
590
|
+
<div class="feature-icon-wrap"><i class="fa-solid fa-database"></i></div>
|
|
591
|
+
<div class="feature-body">
|
|
592
|
+
<div class="feature-name">ORM & Migrations</div>
|
|
593
|
+
<div class="feature-desc">Model-driven schema management. Run <code>millas makemigrations</code> to detect changes and <code>millas migrate</code> to apply them.</div>
|
|
594
|
+
</div>
|
|
595
|
+
</div>
|
|
596
|
+
|
|
597
|
+
<div class="feature-table-row" id="auth">
|
|
598
|
+
<div class="feature-icon-wrap"><i class="fa-solid fa-lock"></i></div>
|
|
599
|
+
<div class="feature-body">
|
|
600
|
+
<div class="feature-name">Authentication</div>
|
|
601
|
+
<div class="feature-desc">JWT out of the box. Register, login, token refresh, and password reset — all accessible via <code>Auth.login()</code>.</div>
|
|
602
|
+
</div>
|
|
603
|
+
</div>
|
|
604
|
+
|
|
605
|
+
<div class="feature-table-row" id="mail">
|
|
606
|
+
<div class="feature-icon-wrap"><i class="fa-solid fa-envelope"></i></div>
|
|
607
|
+
<div class="feature-body">
|
|
608
|
+
<div class="feature-name">Mail</div>
|
|
609
|
+
<div class="feature-desc">SMTP, SendGrid, and Mailgun drivers. Template engine with <code>{{ variable }}</code> interpolation, loops, and conditionals.</div>
|
|
610
|
+
</div>
|
|
611
|
+
</div>
|
|
612
|
+
|
|
613
|
+
<div class="feature-table-row" id="queue">
|
|
614
|
+
<div class="feature-icon-wrap"><i class="fa-solid fa-layer-group"></i></div>
|
|
615
|
+
<div class="feature-body">
|
|
616
|
+
<div class="feature-name">Queue System</div>
|
|
617
|
+
<div class="feature-desc">Background job processing with <code>dispatch(new Job())</code>. Database and synchronous drivers included.</div>
|
|
618
|
+
</div>
|
|
619
|
+
</div>
|
|
620
|
+
|
|
621
|
+
<div class="feature-table-row">
|
|
622
|
+
<div class="feature-icon-wrap"><i class="fa-solid fa-satellite-dish"></i></div>
|
|
623
|
+
<div class="feature-body">
|
|
624
|
+
<div class="feature-name">Event System</div>
|
|
625
|
+
<div class="feature-desc">Fire and listen to events across your application. Listeners can run inline or be pushed through the queue.</div>
|
|
626
|
+
</div>
|
|
627
|
+
</div>
|
|
628
|
+
|
|
629
|
+
<div class="feature-table-row" id="cache">
|
|
630
|
+
<div class="feature-icon-wrap"><i class="fa-solid fa-bolt"></i></div>
|
|
631
|
+
<div class="feature-body">
|
|
632
|
+
<div class="feature-name">Cache</div>
|
|
633
|
+
<div class="feature-desc">Memory, file, and null drivers. Tag-based invalidation with <code>Cache.tags('users').flush()</code>.</div>
|
|
634
|
+
</div>
|
|
635
|
+
</div>
|
|
636
|
+
|
|
637
|
+
<div class="feature-table-row" id="storage">
|
|
638
|
+
<div class="feature-icon-wrap"><i class="fa-solid fa-folder-open"></i></div>
|
|
639
|
+
<div class="feature-body">
|
|
640
|
+
<div class="feature-name">File Storage</div>
|
|
641
|
+
<div class="feature-desc">Local disk with multiple named disks. Upload, copy, move, list, and stream files.</div>
|
|
642
|
+
</div>
|
|
643
|
+
</div>
|
|
644
|
+
|
|
645
|
+
<div class="feature-table-row">
|
|
646
|
+
<div class="feature-icon-wrap"><i class="fa-solid fa-shield-halved"></i></div>
|
|
647
|
+
<div class="feature-body">
|
|
648
|
+
<div class="feature-name">Admin Panel</div>
|
|
649
|
+
<div class="feature-desc">Register any model and get a full CRUD dashboard at <a href="/admin" style="color:var(--primary)">/admin</a> automatically — no extra configuration required.</div>
|
|
650
|
+
</div>
|
|
651
|
+
</div>
|
|
652
|
+
|
|
378
653
|
</div>
|
|
379
|
-
</div>
|
|
380
654
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
<
|
|
384
|
-
<div class="code-block">
|
|
655
|
+
<!-- Quick start code -->
|
|
656
|
+
<div class="section-title">Quick start</div>
|
|
657
|
+
<div class="code-wrap">
|
|
385
658
|
<div class="code-header">
|
|
386
|
-
<div class="code-
|
|
387
|
-
|
|
659
|
+
<div class="code-header-left">
|
|
660
|
+
<i class="fa-regular fa-file-code"></i>
|
|
661
|
+
<span class="code-filename">routes/web.js</span>
|
|
662
|
+
</div>
|
|
663
|
+
<span class="code-lang">JavaScript</span>
|
|
388
664
|
</div>
|
|
389
665
|
<pre><span class="cm">// Replace this welcome page by defining GET /</span>
|
|
390
666
|
<span class="kw">module</span>.<span class="fn">exports</span> = <span class="kw">function</span> (<span class="pm">Route</span>) {
|
|
@@ -406,15 +682,16 @@ const WELCOME_PAGE = `<!DOCTYPE html>
|
|
|
406
682
|
|
|
407
683
|
};</pre>
|
|
408
684
|
</div>
|
|
409
|
-
</div>
|
|
410
685
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
<
|
|
414
|
-
<div class="code-block">
|
|
686
|
+
<!-- CLI reference -->
|
|
687
|
+
<div class="section-title">CLI reference</div>
|
|
688
|
+
<div class="code-wrap">
|
|
415
689
|
<div class="code-header">
|
|
416
|
-
<div class="code-
|
|
417
|
-
|
|
690
|
+
<div class="code-header-left">
|
|
691
|
+
<i class="fa-solid fa-terminal"></i>
|
|
692
|
+
<span class="code-filename">terminal</span>
|
|
693
|
+
</div>
|
|
694
|
+
<span class="code-lang">Shell</span>
|
|
418
695
|
</div>
|
|
419
696
|
<pre><span class="cm"># Generate files</span>
|
|
420
697
|
millas make:controller <span class="cl">PostController</span> --resource
|
|
@@ -431,20 +708,21 @@ millas migrate:rollback <span class="cm"># undo last batch</span>
|
|
|
431
708
|
millas route:list <span class="cm"># show all registered routes</span>
|
|
432
709
|
millas queue:work <span class="cm"># start background job worker</span></pre>
|
|
433
710
|
</div>
|
|
434
|
-
</div>
|
|
435
711
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
<
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
712
|
+
<!-- Footer -->
|
|
713
|
+
<div class="page-footer">
|
|
714
|
+
<div class="page-footer-left">Millas v0.1.2 — Built on Node.js & Express</div>
|
|
715
|
+
<div class="page-footer-links">
|
|
716
|
+
<a href="/admin"><i class="fa-solid fa-gauge-high"></i> Admin</a>
|
|
717
|
+
<a href="/api/health"><i class="fa-solid fa-heart-pulse"></i> Health</a>
|
|
718
|
+
<a href="https://www.npmjs.com/package/millas" target="_blank"><i class="fa-brands fa-npm"></i> npm</a>
|
|
719
|
+
<a href="https://github.com/millas-framework/millas" target="_blank"><i class="fa-brands fa-github"></i> GitHub</a>
|
|
720
|
+
</div>
|
|
443
721
|
</div>
|
|
444
|
-
<span>Built with Millas · Node.js · Express</span>
|
|
445
|
-
</footer>
|
|
446
722
|
|
|
723
|
+
</main>
|
|
447
724
|
</div>
|
|
725
|
+
|
|
448
726
|
</body>
|
|
449
727
|
</html>`;
|
|
450
728
|
|