@workadventure/map-starter-kit-core 0.0.1
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/.github/workflows/release.yml +47 -0
- package/LICENSE +21 -0
- package/package.json +43 -0
- package/public/assets/index.js +80 -0
- package/public/images/badumtss.svg +12 -0
- package/public/images/brand-discord.svg +22 -0
- package/public/images/brand-github.svg +19 -0
- package/public/images/brand-linkedin.svg +23 -0
- package/public/images/brand-x.svg +20 -0
- package/public/images/brand-youtube.svg +20 -0
- package/public/images/favicon.svg +50 -0
- package/public/images/logo.svg +72 -0
- package/public/images/unknown-room-image copy.png +0 -0
- package/public/images/unknown-room-image.png +0 -0
- package/public/styles/styles.css +431 -0
- package/public/styles/styles.css.map +1 -0
- package/semantic-release.config.js +8 -0
- package/src/controllers/FrontController.ts +95 -0
- package/src/controllers/MapController.ts +104 -0
- package/src/controllers/UploaderController.ts +333 -0
- package/src/getCoreRoot.ts +40 -0
- package/src/server.ts +124 -0
- package/src/views/index.html +169 -0
- package/src/views/step1-git.html +154 -0
- package/src/views/step2-hosting.html +153 -0
- package/src/views/step3-steps-selfhosted.html +502 -0
- package/src/views/step3-steps.html +549 -0
- package/src/views/step4-validated-selfhosted.html +188 -0
- package/src/views/step4-validated.html +80 -0
- package/tsconfig.json +35 -0
- package/vite.config.ts +53 -0
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
* {
|
|
2
|
+
box-sizing: border-box;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
html,
|
|
6
|
+
body {
|
|
7
|
+
min-height: 100%;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
body {
|
|
11
|
+
display: flex;
|
|
12
|
+
flex-direction: column;
|
|
13
|
+
margin: 0;
|
|
14
|
+
font-family: "Roboto", Arial, sans-serif;
|
|
15
|
+
text-align: center;
|
|
16
|
+
background: #1b2a41;
|
|
17
|
+
color: white;
|
|
18
|
+
}
|
|
19
|
+
body .bg {
|
|
20
|
+
background-size: cover;
|
|
21
|
+
position: fixed;
|
|
22
|
+
width: 100%;
|
|
23
|
+
height: 100%;
|
|
24
|
+
z-index: 0;
|
|
25
|
+
filter: blur(8px);
|
|
26
|
+
opacity: 0.35;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
h1,
|
|
30
|
+
h2 {
|
|
31
|
+
font-weight: bold;
|
|
32
|
+
font-size: 1.3rem;
|
|
33
|
+
margin: 0;
|
|
34
|
+
}
|
|
35
|
+
h1 strong,
|
|
36
|
+
h2 strong {
|
|
37
|
+
color: #66E979;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
header {
|
|
41
|
+
background: rgba(27, 42, 65, 0.85);
|
|
42
|
+
border-radius: 16px;
|
|
43
|
+
height: 86px;
|
|
44
|
+
display: flex;
|
|
45
|
+
align-items: center;
|
|
46
|
+
position: fixed;
|
|
47
|
+
width: calc(100% - 32px);
|
|
48
|
+
z-index: 1;
|
|
49
|
+
padding: 0 28px;
|
|
50
|
+
}
|
|
51
|
+
header .logo {
|
|
52
|
+
display: block;
|
|
53
|
+
position: relative;
|
|
54
|
+
}
|
|
55
|
+
header .socials {
|
|
56
|
+
display: flex;
|
|
57
|
+
justify-content: center;
|
|
58
|
+
margin-right: 48px;
|
|
59
|
+
column-gap: 12px;
|
|
60
|
+
}
|
|
61
|
+
header .btn-header-wrapper {
|
|
62
|
+
display: flex;
|
|
63
|
+
align-items: center;
|
|
64
|
+
justify-content: space-around;
|
|
65
|
+
column-gap: 12px;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.content {
|
|
69
|
+
padding: 16px;
|
|
70
|
+
position: relative;
|
|
71
|
+
z-index: 1;
|
|
72
|
+
}
|
|
73
|
+
.content main {
|
|
74
|
+
min-height: 100vh;
|
|
75
|
+
display: flex;
|
|
76
|
+
align-items: center;
|
|
77
|
+
justify-content: center;
|
|
78
|
+
gap: 32px;
|
|
79
|
+
flex-wrap: wrap;
|
|
80
|
+
padding-top: 134px;
|
|
81
|
+
padding-bottom: 121px;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.btn {
|
|
85
|
+
display: inline-block;
|
|
86
|
+
padding: 13px 20px 12px;
|
|
87
|
+
background-color: rgba(65, 86, 246, 0.9);
|
|
88
|
+
color: white;
|
|
89
|
+
border-radius: 8px;
|
|
90
|
+
text-decoration: none;
|
|
91
|
+
text-align: center;
|
|
92
|
+
width: auto;
|
|
93
|
+
position: relative;
|
|
94
|
+
font-size: 15px;
|
|
95
|
+
outline: none;
|
|
96
|
+
border: none;
|
|
97
|
+
transition: all 0.5s ease-out;
|
|
98
|
+
cursor: pointer;
|
|
99
|
+
}
|
|
100
|
+
.btn:hover {
|
|
101
|
+
filter: brightness(135%);
|
|
102
|
+
}
|
|
103
|
+
.btn.btn-light {
|
|
104
|
+
background-color: rgba(255, 255, 255, 0.1);
|
|
105
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.card-map {
|
|
109
|
+
max-width: 342px;
|
|
110
|
+
border-radius: 12px;
|
|
111
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
112
|
+
overflow: hidden;
|
|
113
|
+
display: flex;
|
|
114
|
+
flex-direction: column;
|
|
115
|
+
flex-wrap: wrap;
|
|
116
|
+
align-items: center;
|
|
117
|
+
background: rgba(27, 42, 65, 0.5);
|
|
118
|
+
height: fit-content;
|
|
119
|
+
min-width: 340px;
|
|
120
|
+
}
|
|
121
|
+
.card-map .map-cover {
|
|
122
|
+
min-height: 230px;
|
|
123
|
+
width: 100%;
|
|
124
|
+
background-size: cover;
|
|
125
|
+
background-position: center;
|
|
126
|
+
}
|
|
127
|
+
.card-map .map-date {
|
|
128
|
+
font-family: "Roboto Condensed", Arial, sans-serif;
|
|
129
|
+
font-style: normal;
|
|
130
|
+
font-weight: 400;
|
|
131
|
+
font-size: 14px;
|
|
132
|
+
line-height: 24px;
|
|
133
|
+
display: flex;
|
|
134
|
+
align-items: center;
|
|
135
|
+
text-align: center;
|
|
136
|
+
color: #ffffff;
|
|
137
|
+
opacity: 0.5;
|
|
138
|
+
margin-top: 12px;
|
|
139
|
+
}
|
|
140
|
+
.card-map .map-name {
|
|
141
|
+
font-family: "Roboto", "Arial", sans-serif;
|
|
142
|
+
font-style: normal;
|
|
143
|
+
font-weight: 700;
|
|
144
|
+
font-size: 20px;
|
|
145
|
+
line-height: 28px;
|
|
146
|
+
display: flex;
|
|
147
|
+
align-items: center;
|
|
148
|
+
text-align: center;
|
|
149
|
+
color: #ffffff;
|
|
150
|
+
}
|
|
151
|
+
.card-map .map-detail {
|
|
152
|
+
display: flex;
|
|
153
|
+
align-items: center;
|
|
154
|
+
gap: 12px;
|
|
155
|
+
margin-bottom: 6px;
|
|
156
|
+
}
|
|
157
|
+
.card-map .map-detail .map-file {
|
|
158
|
+
font-family: "Roboto Condensed", Arial, sans-serif;
|
|
159
|
+
font-style: italic;
|
|
160
|
+
font-weight: 400;
|
|
161
|
+
font-size: 13px;
|
|
162
|
+
line-height: 20px;
|
|
163
|
+
display: flex;
|
|
164
|
+
align-items: center;
|
|
165
|
+
text-align: center;
|
|
166
|
+
color: #ffffff;
|
|
167
|
+
}
|
|
168
|
+
.card-map .map-detail .map-weight {
|
|
169
|
+
font-family: "Roboto Condensed", Arial, sans-serif;
|
|
170
|
+
font-style: italic;
|
|
171
|
+
font-weight: 400;
|
|
172
|
+
font-size: 13px;
|
|
173
|
+
line-height: 20px;
|
|
174
|
+
display: flex;
|
|
175
|
+
align-items: center;
|
|
176
|
+
text-align: center;
|
|
177
|
+
color: #ffffff;
|
|
178
|
+
}
|
|
179
|
+
.card-map .map-desc {
|
|
180
|
+
font-style: normal;
|
|
181
|
+
font-weight: 400;
|
|
182
|
+
font-size: 14px;
|
|
183
|
+
line-height: 20px;
|
|
184
|
+
display: flex;
|
|
185
|
+
align-items: center;
|
|
186
|
+
text-align: center;
|
|
187
|
+
color: #ffffff;
|
|
188
|
+
margin-bottom: 16px;
|
|
189
|
+
padding: 2px 12px;
|
|
190
|
+
}
|
|
191
|
+
.card-map .map-copyright {
|
|
192
|
+
font-size: 12px;
|
|
193
|
+
opacity: 0.7;
|
|
194
|
+
padding: 2px 12px;
|
|
195
|
+
}
|
|
196
|
+
.card-map .map-testurl {
|
|
197
|
+
display: flex;
|
|
198
|
+
flex-direction: column;
|
|
199
|
+
align-items: center;
|
|
200
|
+
padding: 12px;
|
|
201
|
+
gap: 12px;
|
|
202
|
+
width: 100%;
|
|
203
|
+
background: #1b2a41;
|
|
204
|
+
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.form-center {
|
|
208
|
+
display: flex;
|
|
209
|
+
flex-direction: column;
|
|
210
|
+
align-items: center;
|
|
211
|
+
width: 100%;
|
|
212
|
+
padding-bottom: 80px;
|
|
213
|
+
}
|
|
214
|
+
.form-center.steps {
|
|
215
|
+
align-items: start;
|
|
216
|
+
text-align: left;
|
|
217
|
+
gap: 48px;
|
|
218
|
+
max-width: 780px;
|
|
219
|
+
margin: auto;
|
|
220
|
+
transition: all 1s ease-out;
|
|
221
|
+
}
|
|
222
|
+
.form-center.steps .step {
|
|
223
|
+
display: flex;
|
|
224
|
+
flex-direction: column;
|
|
225
|
+
gap: 8px;
|
|
226
|
+
width: 100%;
|
|
227
|
+
}
|
|
228
|
+
.form-center.steps .step.inactive {
|
|
229
|
+
opacity: 0.35;
|
|
230
|
+
pointer-events: none;
|
|
231
|
+
}
|
|
232
|
+
.form-center.steps .step .step-title {
|
|
233
|
+
display: flex;
|
|
234
|
+
align-items: center;
|
|
235
|
+
gap: 12px;
|
|
236
|
+
margin-bottom: 12px;
|
|
237
|
+
}
|
|
238
|
+
.form-center.steps .step .step-title .step-number {
|
|
239
|
+
border-radius: 8px;
|
|
240
|
+
padding: 6px 12px;
|
|
241
|
+
border: 1px solid rgb(255, 255, 255);
|
|
242
|
+
}
|
|
243
|
+
.form-center.steps .step .alert {
|
|
244
|
+
display: flex;
|
|
245
|
+
flex-direction: row;
|
|
246
|
+
justify-content: center;
|
|
247
|
+
align-items: center;
|
|
248
|
+
padding: 12px 12px 12px 24px;
|
|
249
|
+
gap: 32px;
|
|
250
|
+
background: rgba(233, 109, 81, 0.2);
|
|
251
|
+
border: 1px solid rgba(233, 109, 81, 0.5);
|
|
252
|
+
border-radius: 16px;
|
|
253
|
+
align-self: stretch;
|
|
254
|
+
text-align: left;
|
|
255
|
+
}
|
|
256
|
+
.form-center.steps .step .alert .alert-text {
|
|
257
|
+
font-family: "Roboto Condensed";
|
|
258
|
+
font-style: normal;
|
|
259
|
+
font-weight: 700;
|
|
260
|
+
font-size: 16px;
|
|
261
|
+
line-height: 24px;
|
|
262
|
+
color: #F4D5CB;
|
|
263
|
+
}
|
|
264
|
+
.form-center.steps .step .step-text {
|
|
265
|
+
font-style: normal;
|
|
266
|
+
font-weight: 400;
|
|
267
|
+
font-size: 16px;
|
|
268
|
+
line-height: 24px;
|
|
269
|
+
color: rgba(255, 255, 255, 0.75);
|
|
270
|
+
}
|
|
271
|
+
.form-center.steps .step input[type=text], .form-center.steps .step input[type=password], .form-center.steps .step input[type=url] {
|
|
272
|
+
display: flex;
|
|
273
|
+
flex-direction: row;
|
|
274
|
+
align-items: center;
|
|
275
|
+
padding: 0px 6px 0px 16px;
|
|
276
|
+
color: white;
|
|
277
|
+
font-size: 18px;
|
|
278
|
+
gap: 4px;
|
|
279
|
+
height: 52px;
|
|
280
|
+
width: 100%;
|
|
281
|
+
background: #1B2A41;
|
|
282
|
+
border: 1px solid #3C5E90;
|
|
283
|
+
border-radius: 12px;
|
|
284
|
+
flex: none;
|
|
285
|
+
order: 0;
|
|
286
|
+
align-self: stretch;
|
|
287
|
+
flex-grow: 0;
|
|
288
|
+
}
|
|
289
|
+
.form-center.steps .step input[type=text].error, .form-center.steps .step input[type=password].error, .form-center.steps .step input[type=url].error {
|
|
290
|
+
border: 1px solid #E96D51;
|
|
291
|
+
color: #E96D51;
|
|
292
|
+
}
|
|
293
|
+
.form-center.steps .step input[type=text].success, .form-center.steps .step input[type=password].success, .form-center.steps .step input[type=url].success {
|
|
294
|
+
color: #66E979;
|
|
295
|
+
border: 1px solid #66E979;
|
|
296
|
+
}
|
|
297
|
+
.form-center h1 {
|
|
298
|
+
font-family: "Oswald";
|
|
299
|
+
font-weight: 400;
|
|
300
|
+
font-size: 40px;
|
|
301
|
+
}
|
|
302
|
+
.form-center .sub-heading {
|
|
303
|
+
font-size: 14px;
|
|
304
|
+
line-height: 24px;
|
|
305
|
+
margin-bottom: 48px;
|
|
306
|
+
}
|
|
307
|
+
.form-center .radio-wrapper {
|
|
308
|
+
display: flex;
|
|
309
|
+
gap: 32px;
|
|
310
|
+
}
|
|
311
|
+
.form-center .radio-wrapper .radio-card {
|
|
312
|
+
cursor: pointer;
|
|
313
|
+
}
|
|
314
|
+
.form-center .radio-wrapper .radio-card .radio {
|
|
315
|
+
opacity: 0;
|
|
316
|
+
display: none;
|
|
317
|
+
}
|
|
318
|
+
.form-center .radio-wrapper .radio-card .radio:hover ~ .card-details {
|
|
319
|
+
background: rgba(255, 255, 255, 0.1);
|
|
320
|
+
}
|
|
321
|
+
.form-center .radio-wrapper .radio-card .radio:checked ~ .card-details {
|
|
322
|
+
background: white;
|
|
323
|
+
}
|
|
324
|
+
.form-center .radio-wrapper .radio-card .radio:checked ~ .card-details h2 {
|
|
325
|
+
color: #4156F6;
|
|
326
|
+
}
|
|
327
|
+
.form-center .radio-wrapper .radio-card .radio:checked ~ .card-details svg {
|
|
328
|
+
display: flex;
|
|
329
|
+
}
|
|
330
|
+
.form-center .radio-wrapper .radio-card .radio:checked ~ .card-details div strong {
|
|
331
|
+
color: #1B2A41;
|
|
332
|
+
}
|
|
333
|
+
.form-center .radio-wrapper .radio-card .radio:checked ~ .card-details div {
|
|
334
|
+
color: #1B2A41;
|
|
335
|
+
}
|
|
336
|
+
.form-center .radio-wrapper .radio-card .card-details {
|
|
337
|
+
border: 1px solid rgb(255, 255, 255);
|
|
338
|
+
border-radius: 24px;
|
|
339
|
+
padding: 32px 48px;
|
|
340
|
+
transition: all 1s ease-out;
|
|
341
|
+
position: relative;
|
|
342
|
+
}
|
|
343
|
+
.form-center .radio-wrapper .radio-card .card-details h2 {
|
|
344
|
+
font-family: "Oswald";
|
|
345
|
+
font-weight: 400;
|
|
346
|
+
font-size: 26px;
|
|
347
|
+
margin-bottom: 8px;
|
|
348
|
+
}
|
|
349
|
+
.form-center .radio-wrapper .radio-card .card-details svg {
|
|
350
|
+
display: none;
|
|
351
|
+
position: absolute;
|
|
352
|
+
right: 24px;
|
|
353
|
+
top: 24px;
|
|
354
|
+
}
|
|
355
|
+
.form-center .radio-wrapper .radio-card .card-details div {
|
|
356
|
+
font-size: 16px;
|
|
357
|
+
line-height: 24px;
|
|
358
|
+
color: rgba(255, 255, 255, 0.5);
|
|
359
|
+
}
|
|
360
|
+
.form-center .radio-wrapper .radio-card .card-details div strong {
|
|
361
|
+
display: block;
|
|
362
|
+
font-weight: 700;
|
|
363
|
+
color: rgb(255, 255, 255);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.button-wrapper {
|
|
367
|
+
background: rgba(27, 42, 65, 0.85);
|
|
368
|
+
display: flex;
|
|
369
|
+
align-items: center;
|
|
370
|
+
position: fixed;
|
|
371
|
+
left: 0;
|
|
372
|
+
bottom: 0;
|
|
373
|
+
width: 100%;
|
|
374
|
+
z-index: 1;
|
|
375
|
+
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
|
376
|
+
padding: 16px;
|
|
377
|
+
flex-direction: row;
|
|
378
|
+
justify-content: center;
|
|
379
|
+
text-align: center;
|
|
380
|
+
}
|
|
381
|
+
.button-wrapper a,
|
|
382
|
+
.button-wrapper .btn {
|
|
383
|
+
display: flex;
|
|
384
|
+
flex-direction: row;
|
|
385
|
+
justify-content: center;
|
|
386
|
+
align-items: center;
|
|
387
|
+
text-align: center;
|
|
388
|
+
padding: 16px 64px;
|
|
389
|
+
font-size: 18px;
|
|
390
|
+
gap: 8px;
|
|
391
|
+
background: #e96d51;
|
|
392
|
+
border-radius: 8px;
|
|
393
|
+
color: white;
|
|
394
|
+
text-decoration: none;
|
|
395
|
+
}
|
|
396
|
+
.button-wrapper a.btn,
|
|
397
|
+
.button-wrapper .btn.btn {
|
|
398
|
+
transition: all 1s ease-out;
|
|
399
|
+
}
|
|
400
|
+
.button-wrapper a.btn.btn-ghost,
|
|
401
|
+
.button-wrapper .btn.btn.btn-ghost {
|
|
402
|
+
background: rgba(255, 255, 255, 0.1);
|
|
403
|
+
}
|
|
404
|
+
.button-wrapper a.btn.btn-ghost:hover,
|
|
405
|
+
.button-wrapper .btn.btn.btn-ghost:hover {
|
|
406
|
+
background: rgba(255, 255, 255, 0.2);
|
|
407
|
+
}
|
|
408
|
+
.button-wrapper a.btn.btn-secondary,
|
|
409
|
+
.button-wrapper .btn.btn.btn-secondary {
|
|
410
|
+
background: #4156F6;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
.bg-image {
|
|
414
|
+
position: absolute;
|
|
415
|
+
top: 0;
|
|
416
|
+
left: 0;
|
|
417
|
+
width: 100%;
|
|
418
|
+
height: 100%;
|
|
419
|
+
background-size: cover;
|
|
420
|
+
background-position: center;
|
|
421
|
+
transition: opacity 2s ease-in-out;
|
|
422
|
+
filter: blur(2px);
|
|
423
|
+
opacity: 0;
|
|
424
|
+
z-index: -1;
|
|
425
|
+
}
|
|
426
|
+
.bg-image.active {
|
|
427
|
+
opacity: 0.60;
|
|
428
|
+
z-index: 0;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/*# sourceMappingURL=styles.css.map */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sourceRoot":"","sources":["styles.scss"],"names":[],"mappings":"AAAA;EACE;;;AAEF;AAAA;EAEE;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAIJ;AAAA;EAEE;EACA;EACA;;AACA;AAAA;EACE;;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EACE;EACA;;AAEF;EACE;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;;;AAIJ;EACE;EACA;EACA;;AACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EACE;;AAEF;EACE;EACA;;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EACE;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;;AACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAIJ;EACE;EACA;EACA;EACA;;AACA;EACE;EACA;EACA;EACA;EACA;EACA;;AACA;EACE;EACA;EACA;EACA;;AACA;EACE;EACA;;AAEF;EACE;EACA;EACA;EACA;;AACA;EACE;EACA;EACA;;AAGJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EACE;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACE;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EACE;EACA;;AAEF;EACE;EACA;;AAKR;EACE;EACA;EACA;;AAEF;EACE;EACA;EACA;;AAEF;EACE;EACA;;AAEE;EACE;EACA;;AACA;EACE;;AAEF;EACE;;AACA;EACE;;AAEF;EACE;;AAGA;EACE;;AAFJ;EAIE;;AAIN;EACE;EACA;EACA;EACA;EACA;;AACA;EACE;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;;AACA;EACE;EACA;EACA;;;AAQZ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;AAAA;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;AAAA;EACE;;AACA;AAAA;EACE;;AACA;AAAA;EACE;;AAGJ;AAAA;EACE","file":"styles.css"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import * as fs from "node:fs";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import Mustache from 'mustache';
|
|
5
|
+
import { getCoreRoot } from '../getCoreRoot.js';
|
|
6
|
+
|
|
7
|
+
export class FrontController {
|
|
8
|
+
private app: express.Application;
|
|
9
|
+
|
|
10
|
+
constructor(app: express.Application) {
|
|
11
|
+
this.app = app;
|
|
12
|
+
// Assets are now configured in app.ts
|
|
13
|
+
this.setupRoutes();
|
|
14
|
+
this.setupRoutesStep1();
|
|
15
|
+
this.setupRoutesStep2();
|
|
16
|
+
this.setupRoutesStep3();
|
|
17
|
+
this.setupRoutesStep4();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
private setupRoutes() {
|
|
21
|
+
// Route for the Mustache renderer on "/"
|
|
22
|
+
this.app.get('/', async (_, res) => {
|
|
23
|
+
try {
|
|
24
|
+
res.send(await this.renderTemplate('index'));
|
|
25
|
+
} catch (error) {
|
|
26
|
+
console.error('Error rendering template:', error);
|
|
27
|
+
res.status(500).send('Error rendering template');
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Render a template file
|
|
34
|
+
* @param filename - The filename of the template to render
|
|
35
|
+
* @returns The rendered template
|
|
36
|
+
*/
|
|
37
|
+
private async renderTemplate(filename: string): Promise<string> {
|
|
38
|
+
const coreRoot = getCoreRoot();
|
|
39
|
+
const templatesDir = path.join(coreRoot, 'src/views');
|
|
40
|
+
if(!fs.existsSync(templatesDir)) {
|
|
41
|
+
throw new Error(`Templates directory not found: ${templatesDir}`);
|
|
42
|
+
}
|
|
43
|
+
const templatePath = path.join(templatesDir, `${filename}.html`);
|
|
44
|
+
const template = await fs.promises.readFile(templatePath, 'utf-8');
|
|
45
|
+
// Render the template with Mustache (without data for now)
|
|
46
|
+
return Mustache.render(template, {});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Setup the routes for file "step1-git.html"
|
|
51
|
+
* @returns void
|
|
52
|
+
*/
|
|
53
|
+
private setupRoutesStep1() {
|
|
54
|
+
this.app.get('/step1-git', async (_, res) => {
|
|
55
|
+
res.send(await this.renderTemplate('step1-git'));
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Setup the routes for file "step2-hosting.html"
|
|
61
|
+
* @returns void
|
|
62
|
+
*/
|
|
63
|
+
private setupRoutesStep2() {
|
|
64
|
+
this.app.get('/step2-hosting', async (_, res) => {
|
|
65
|
+
res.send(await this.renderTemplate('step2-hosting'));
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Setup the routes for file "step3-steps.html"
|
|
71
|
+
* @returns void
|
|
72
|
+
*/
|
|
73
|
+
private setupRoutesStep3() {
|
|
74
|
+
this.app.get('/step3-steps', async (_, res) => {
|
|
75
|
+
res.send(await this.renderTemplate('step3-steps'));
|
|
76
|
+
});
|
|
77
|
+
this.app.get('/step3-steps-selfhosted', async (_, res) => {
|
|
78
|
+
res.send(await this.renderTemplate('step3-steps-selfhosted'));
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Setup the routes for file "step4-map.html"
|
|
84
|
+
* @returns void
|
|
85
|
+
*/
|
|
86
|
+
private setupRoutesStep4() {
|
|
87
|
+
this.app.get('/step4-validated', async (_, res) => {
|
|
88
|
+
res.send(await this.renderTemplate('step4-validated'));
|
|
89
|
+
});
|
|
90
|
+
this.app.get('/step4-validated-selfhosted', async (_, res) => {
|
|
91
|
+
res.send(await this.renderTemplate('step4-validated-selfhosted'));
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import * as fs from "node:fs";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
|
|
5
|
+
export class MapController {
|
|
6
|
+
private router: express.Router;
|
|
7
|
+
private app: express.Application;
|
|
8
|
+
|
|
9
|
+
constructor(app: express.Application) {
|
|
10
|
+
this.app = app;
|
|
11
|
+
this.router = express.Router();
|
|
12
|
+
this.setupRoutes();
|
|
13
|
+
// Register the router on the application with the "/maps" prefix
|
|
14
|
+
this.app.use('/maps', this.router);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Setup the routes for the map controller
|
|
19
|
+
* @returns void
|
|
20
|
+
*/
|
|
21
|
+
private setupRoutes() {
|
|
22
|
+
// Route to retrieve the list of maps with their properties
|
|
23
|
+
this.router.get('/list', async (_, res) => {
|
|
24
|
+
try {
|
|
25
|
+
const mapsDir = './';
|
|
26
|
+
const maps = await this.getMapsWithProperties(mapsDir);
|
|
27
|
+
res.json(maps);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
console.error('Error getting maps list:', error);
|
|
30
|
+
res.status(500).json({ error: 'Error getting maps list' });
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Get the list of maps with their properties
|
|
37
|
+
* @param dir - The directory to search for maps
|
|
38
|
+
* @param baseDir - The base directory to use for relative paths
|
|
39
|
+
* @returns The list of maps with their properties
|
|
40
|
+
*/
|
|
41
|
+
private async getMapsWithProperties(dir: string, baseDir: string = dir): Promise<any[]> {
|
|
42
|
+
let files = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
43
|
+
const maps: any[] = [];
|
|
44
|
+
|
|
45
|
+
for (const file of files) {
|
|
46
|
+
const fullPath = path.join(dir, file.name);
|
|
47
|
+
|
|
48
|
+
// Exclude the "dist" folder
|
|
49
|
+
if(file.name === 'dist') continue;
|
|
50
|
+
|
|
51
|
+
if (file.isDirectory()) {
|
|
52
|
+
// Recursively search subdirectories
|
|
53
|
+
const subMaps = await this.getMapsWithProperties(fullPath, baseDir);
|
|
54
|
+
maps.push(...subMaps);
|
|
55
|
+
} else if (file.name.endsWith('.tmj')) {
|
|
56
|
+
try {
|
|
57
|
+
// Read and parse TMJ file
|
|
58
|
+
const tmjContent = await fs.promises.readFile(fullPath, 'utf-8');
|
|
59
|
+
const tmjData = JSON.parse(tmjContent);
|
|
60
|
+
|
|
61
|
+
// Extract properties
|
|
62
|
+
const properties = tmjData.properties || [];
|
|
63
|
+
const findProperty = (key: string) => {
|
|
64
|
+
const item = properties.find((p: any) => p.name === key);
|
|
65
|
+
return item ? item.value : null;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// Get file stats for size and date
|
|
69
|
+
const stats = await fs.promises.stat(fullPath);
|
|
70
|
+
const fileSizeInMB = (stats.size / (1024 * 1024)).toFixed(2);
|
|
71
|
+
const lastModified = stats.mtime;
|
|
72
|
+
|
|
73
|
+
// Get relative path
|
|
74
|
+
const relativePath = path.relative(baseDir, fullPath).replace(/\\/g, '/');
|
|
75
|
+
|
|
76
|
+
// Extract filename without extension
|
|
77
|
+
const filename = path.basename(file.name, '.tmj');
|
|
78
|
+
|
|
79
|
+
maps.push({
|
|
80
|
+
path: relativePath,
|
|
81
|
+
filename: filename,
|
|
82
|
+
mapName: findProperty('mapName') || filename,
|
|
83
|
+
mapImage: findProperty('mapImage') || null,
|
|
84
|
+
mapDescription: findProperty('mapDescription') || '',
|
|
85
|
+
mapCopyright: findProperty('mapCopyright') || '',
|
|
86
|
+
size: fileSizeInMB,
|
|
87
|
+
lastModified: lastModified.toISOString(),
|
|
88
|
+
lastModifiedFormatted: lastModified.toLocaleDateString('fr-FR', {
|
|
89
|
+
day: '2-digit',
|
|
90
|
+
month: '2-digit',
|
|
91
|
+
year: 'numeric',
|
|
92
|
+
hour: '2-digit',
|
|
93
|
+
minute: '2-digit'
|
|
94
|
+
})
|
|
95
|
+
});
|
|
96
|
+
} catch (error) {
|
|
97
|
+
console.error(`Error reading TMJ file ${fullPath}:`, error);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return maps;
|
|
103
|
+
}
|
|
104
|
+
}
|