@raketa-cloud/admin 0.0.3 → 0.0.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/babel.config.js +6 -0
- package/bin/tailwind +2 -0
- package/package.json +22 -30
- package/src/Adapter.js +160 -0
- package/src/HonoAdapter.js +248 -0
- package/src/RaketaContext.js +46 -0
- package/src/helpers/AuthHelper.js +44 -0
- package/src/helpers/FormBuilder.js +226 -0
- package/src/helpers/HTMLBuilder.js +38 -0
- package/src/helpers/Pagination.js +92 -0
- package/src/helpers/SortButton.js +102 -0
- package/src/helpers/form_for.js +6 -0
- package/src/helpers/pagination_helper.js +5 -0
- package/src/helpers/sort_button.js +5 -0
- package/src/index.js +7 -0
- package/src/routeCollection.js +90 -0
- package/src/routeMember.js +40 -0
- package/src/routeNestedCollection.js +90 -0
- package/src/routeNestedMember.js +40 -0
- package/src/setGlobalConfig.js +5 -0
- package/src/setGlobalContext.js +5 -0
- package/src/setupAuthentication.js +99 -0
- package/src/styles/application.css +479 -0
- package/src/tests/Adapter.test.js +39 -0
- package/src/tests/HonoAdapter.test.js +34 -0
- package/src/tests/helpers/Pagination.test.js +65 -0
- package/src/tests/helpers/SortButton.test.js +85 -0
- package/src/tests/routeCollection.test.js +150 -0
- package/src/tests/routeMember.test.js +91 -0
- package/src/tests/routeNestedCollection.test.js +176 -0
- package/src/tests/routeNestedMember.test.js +96 -0
- package/src/views/_auth/login.ejs +92 -0
- package/src/views/layouts/application.ejs +147 -0
- package/src/views/layouts/header.ejs +49 -0
- package/src/views/redirects/index.ejs +1 -0
- package/tailwind.config.js +39 -0
- package/tsconfig.json +15 -0
- package/tsconfig.lint.json +8 -0
- package/dist/index.js +0 -670
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const routeNestedMember = (adapter, parent, resource, handler) => {
|
|
2
|
+
const { before_filter, after_filter, show, edit_form, update } = handler;
|
|
3
|
+
|
|
4
|
+
const mapping = [
|
|
5
|
+
[
|
|
6
|
+
"GET",
|
|
7
|
+
`/${parent}/:parent_id/${resource}`,
|
|
8
|
+
resource,
|
|
9
|
+
`${parent}/${resource}`,
|
|
10
|
+
"show",
|
|
11
|
+
show,
|
|
12
|
+
before_filter,
|
|
13
|
+
after_filter,
|
|
14
|
+
],
|
|
15
|
+
[
|
|
16
|
+
"GET",
|
|
17
|
+
`/${parent}/:parent_id/${resource}/edit`,
|
|
18
|
+
resource,
|
|
19
|
+
`${parent}/${resource}`,
|
|
20
|
+
"edit_form",
|
|
21
|
+
edit_form,
|
|
22
|
+
before_filter,
|
|
23
|
+
after_filter,
|
|
24
|
+
],
|
|
25
|
+
[
|
|
26
|
+
"POST",
|
|
27
|
+
`/${parent}/:parent_id/${resource}`,
|
|
28
|
+
resource,
|
|
29
|
+
`${parent}/${resource}`,
|
|
30
|
+
"edit_form",
|
|
31
|
+
update,
|
|
32
|
+
before_filter,
|
|
33
|
+
after_filter,
|
|
34
|
+
],
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
adapter.routeNestedMember(mapping);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export default routeNestedMember;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
const nodePath = require("node:path");
|
|
2
|
+
import ejs from "ejs";
|
|
3
|
+
import { deleteCookie, getCookie, setCookie } from "hono/cookie";
|
|
4
|
+
import AuthHelper from "./helpers/AuthHelper";
|
|
5
|
+
|
|
6
|
+
function getAuthBearer(c) {
|
|
7
|
+
const authHeader = c.req.header("Authorization") || "";
|
|
8
|
+
|
|
9
|
+
return authHeader.replace("Bearer ", "");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const setupAuthentication = (app, opts) => {
|
|
13
|
+
app.use(async (c, next) => {
|
|
14
|
+
const token = getCookie(c, AuthHelper.cookie_key) || getAuthBearer(c);
|
|
15
|
+
|
|
16
|
+
const status = AuthHelper.isAuthenticated({ path: c.req.path, token });
|
|
17
|
+
|
|
18
|
+
if (!status) {
|
|
19
|
+
return c.redirect("/login");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (token) {
|
|
23
|
+
const { info } = AuthHelper.parseJWT(token);
|
|
24
|
+
c.set("authentication", { token, user: info });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
await next();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
app.get("/login", async (c) => {
|
|
31
|
+
const googleURL = AuthHelper.getGoogleURL();
|
|
32
|
+
const templatePath = `${nodePath.dirname(__filename)}/views/_auth/login.ejs`;
|
|
33
|
+
|
|
34
|
+
const rendered = await ejs.renderFile(templatePath, {
|
|
35
|
+
googleURL,
|
|
36
|
+
error: c.req.query("err"),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
return c.html(rendered);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
app.get("/auth/google/callback", (c) => {
|
|
43
|
+
const token = c.req.query("token") || "";
|
|
44
|
+
|
|
45
|
+
const {
|
|
46
|
+
info: { active },
|
|
47
|
+
} = AuthHelper.parseJWT(token);
|
|
48
|
+
|
|
49
|
+
if (!AuthHelper.verifyJWT(token)) return c.redirect("/login?err=expired");
|
|
50
|
+
if (!active) return c.redirect("/login?err=not_activated");
|
|
51
|
+
|
|
52
|
+
const isLocalhost = c.req.url.includes("http://localhost");
|
|
53
|
+
setCookie(c, AuthHelper.cookie_key, token, {
|
|
54
|
+
path: "/",
|
|
55
|
+
httpOnly: true,
|
|
56
|
+
secure: !isLocalhost,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return c.redirect("/en/pages");
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
app.get("/logout", (c) => {
|
|
63
|
+
deleteCookie(c, AuthHelper.cookie_key);
|
|
64
|
+
return c.redirect("/login");
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Routes related to the remote project handling
|
|
68
|
+
app.get("/remote-login", (c) => {
|
|
69
|
+
const token = getCookie(c, AuthHelper.cookie_key);
|
|
70
|
+
|
|
71
|
+
if (!AuthHelper.verifyJWT(token)) {
|
|
72
|
+
return c.redirect("/login");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
setCookie(c, opts.remote.cookie_key, token, {
|
|
76
|
+
path: "/",
|
|
77
|
+
httpOnly: true,
|
|
78
|
+
secure: true,
|
|
79
|
+
domain: opts.remote.domain,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
return c.redirect([opts.remote.host, c.req.query().redirect_to].join(""));
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
app.get("/profile", (c) => {
|
|
86
|
+
const token = getAuthBearer(c);
|
|
87
|
+
|
|
88
|
+
// TODO: Here we may update the Gateway API to have the check dinamically done in the backend!
|
|
89
|
+
if (AuthHelper.verifyJWT(token)) {
|
|
90
|
+
c.res.status = 200;
|
|
91
|
+
return c.json({ message: "OK" });
|
|
92
|
+
} else {
|
|
93
|
+
c.res.status = 401;
|
|
94
|
+
return c.res.json({ message: "Unauthorized" });
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export default setupAuthentication;
|
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
@tailwind base;
|
|
2
|
+
@tailwind components;
|
|
3
|
+
@tailwind utilities;
|
|
4
|
+
|
|
5
|
+
:root {
|
|
6
|
+
--background: 255, 255, 255;
|
|
7
|
+
--foreground: 0, 0, 0;
|
|
8
|
+
--primary: 110, 110, 178;
|
|
9
|
+
/* --primary: 0, 0, 0; */
|
|
10
|
+
--primary-light: 157, 157, 210;
|
|
11
|
+
--primary-dark: 88, 88, 142;
|
|
12
|
+
/* --primary-dark: 0, 0, 0; */
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@layer components {
|
|
16
|
+
/* Utils */
|
|
17
|
+
.dbg {
|
|
18
|
+
@apply outline-1 outline-dashed outline-red-500;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.chip {
|
|
22
|
+
@apply bg-slate-200 text-raketa-foreground px-2.5 py-1 rounded-full text-xs font-semibold;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.help {
|
|
26
|
+
@apply bg-[#f0f0f8] body-2 p-4 rounded sticky top-6;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* Typography */
|
|
30
|
+
.heading-1 {
|
|
31
|
+
@apply text-2xl font-semibold text-raketa-foreground;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.heading-2 {
|
|
35
|
+
@apply text-lg font-semibold text-raketa-foreground;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.heading-3 {
|
|
39
|
+
@apply font-semibold text-raketa-foreground;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.body-1 {
|
|
43
|
+
@apply leading-[1.5] text-base text-raketa-foreground;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.body-2 {
|
|
47
|
+
@apply leading-[1.5] text-sm text-raketa-foreground;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.body-3 {
|
|
51
|
+
@apply leading-[1.5] text-xs text-raketa-foreground;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* Buttons */
|
|
55
|
+
.btn-primary,
|
|
56
|
+
.btn-secondary {
|
|
57
|
+
@apply inline-block px-3 py-2 font-medium rounded border;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.btn-primary,
|
|
61
|
+
.btn-secondary,
|
|
62
|
+
.btn-text,
|
|
63
|
+
.btn-danger {
|
|
64
|
+
@apply text-sm transition-all duration-300 ease-in-out;
|
|
65
|
+
|
|
66
|
+
&.has-icon {
|
|
67
|
+
@apply flex items-center gap-1.5;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.btn-primary {
|
|
72
|
+
@apply text-white bg-raketa-primary border-raketa-primary hover:bg-raketa-primary-dark hover:border-raketa-primary-dark;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.btn-secondary {
|
|
76
|
+
@apply text-raketa-primary bg-transparent border-raketa-primary hover:bg-raketa-primary-dark hover:border-raketa-primary-dark hover:text-white;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.btn-text,
|
|
80
|
+
.btn-danger {
|
|
81
|
+
@apply inline-block font-medium underline underline-offset-4;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.btn-text {
|
|
85
|
+
@apply text-raketa-primary hover:text-raketa-foreground;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.btn-danger {
|
|
89
|
+
@apply text-red-600 hover:text-raketa-foreground;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.btn-toolbar {
|
|
93
|
+
@apply flex items-center gap-1;
|
|
94
|
+
|
|
95
|
+
.btn-text,
|
|
96
|
+
.btn-danger {
|
|
97
|
+
@apply px-2;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.form-actions {
|
|
102
|
+
@apply flex justify-between items-center;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* Forms */
|
|
106
|
+
.form {
|
|
107
|
+
@apply pb-8;
|
|
108
|
+
|
|
109
|
+
label {
|
|
110
|
+
@apply block cursor-pointer text-sm font-semibold w-fit;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
input,
|
|
114
|
+
select,
|
|
115
|
+
textarea {
|
|
116
|
+
@apply border border-neutral-300 rounded px-3 py-2 w-full shadow-inner;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
textarea {
|
|
120
|
+
@apply min-h-[150px];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.has-error input,
|
|
124
|
+
.has-error select,
|
|
125
|
+
.has-error textarea {
|
|
126
|
+
@apply border-red-600;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.checkbox-group {
|
|
130
|
+
@apply max-h-[200px] overflow-y-auto py-1 px-2 mt-1 rounded shadow-inner border border-neutral-300;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.checkbox-group label {
|
|
134
|
+
@apply flex gap-2 text-nowrap items-center py-2;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.checkbox-group input[type="checkbox"] {
|
|
138
|
+
@apply size-4 px-0;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.checkbox-wrapper {
|
|
142
|
+
@apply flex gap-2 text-nowrap;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.checkbox-wrapper input[type="checkbox"] {
|
|
146
|
+
@apply size-4 px-0;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.inline-form {
|
|
151
|
+
@apply relative;
|
|
152
|
+
|
|
153
|
+
svg {
|
|
154
|
+
@apply absolute top-2.5 left-3.5 text-neutral-400;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
input[type="search"] {
|
|
158
|
+
@apply border border-neutral-300 rounded px-0 py-1.5 pl-8;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* Tables */
|
|
163
|
+
.data-grid {
|
|
164
|
+
@apply text-sm text-left body-1 w-full text-raketa-foreground/60 rounded-t overflow-hidden;
|
|
165
|
+
|
|
166
|
+
th,
|
|
167
|
+
td {
|
|
168
|
+
@apply p-3 border-b border-neutral-200 transition-all duration-100 ease-in-out;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
th {
|
|
172
|
+
@apply bg-neutral-100 text-raketa-foreground;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
tbody {
|
|
176
|
+
tr:hover {
|
|
177
|
+
td {
|
|
178
|
+
@apply border-neutral-300 bg-neutral-50 text-raketa-foreground;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.btn-sort {
|
|
184
|
+
@apply inline-flex items-center gap-1.5 text-raketa-foreground hover:text-raketa-primary;
|
|
185
|
+
|
|
186
|
+
svg {
|
|
187
|
+
@apply text-neutral-400;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
&.is-active {
|
|
191
|
+
svg {
|
|
192
|
+
@apply text-black;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.number {
|
|
198
|
+
@apply text-right;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.bool {
|
|
202
|
+
@apply text-center;
|
|
203
|
+
|
|
204
|
+
svg {
|
|
205
|
+
@apply inline-block;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.with-icon {
|
|
210
|
+
@apply inline-flex items-center gap-1 leading-none relative top-0.5;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.actions {
|
|
214
|
+
@apply w-1 whitespace-nowrap;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
&.alt {
|
|
218
|
+
@apply bg-[#F0F0F8];
|
|
219
|
+
|
|
220
|
+
th {
|
|
221
|
+
@apply bg-[#c6c6e5];
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
tbody {
|
|
225
|
+
tr:hover {
|
|
226
|
+
td {
|
|
227
|
+
@apply border-neutral-300 bg-neutral-50 text-raketa-foreground;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/* Pagination */
|
|
235
|
+
.pagination {
|
|
236
|
+
@apply text-center py-8 text-raketa-foreground/50;
|
|
237
|
+
|
|
238
|
+
& > div {
|
|
239
|
+
@apply inline-flex items-center gap-4;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
input {
|
|
243
|
+
@apply border border-neutral-300 rounded-sm w-20 text-right mr-1;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.is-inactive {
|
|
247
|
+
@apply cursor-not-allowed opacity-30 hover:text-raketa-primary;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/* Hacks */
|
|
252
|
+
.unstyled-details {
|
|
253
|
+
@apply appearance-none;
|
|
254
|
+
|
|
255
|
+
.icon-toggle {
|
|
256
|
+
@apply transition-all ease-in-out duration-300;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.unstyled-details[open] {
|
|
261
|
+
.icon-toggle {
|
|
262
|
+
@apply rotate-180;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.unstyled-details summary::-webkit-details-marker {
|
|
267
|
+
display: none;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.space-the-final-frontier {
|
|
272
|
+
position: fixed;
|
|
273
|
+
top: 50%;
|
|
274
|
+
left: 50%;
|
|
275
|
+
height: 1px;
|
|
276
|
+
width: 1px;
|
|
277
|
+
background-color: #fff;
|
|
278
|
+
border-radius: 50%;
|
|
279
|
+
box-shadow:
|
|
280
|
+
-42vw -4vh 0px 0px #fff,
|
|
281
|
+
25vw -41vh 0px 0px #fff,
|
|
282
|
+
-20vw 49vh 0px 1px #fff,
|
|
283
|
+
5vw 40vh 1px 1px #fff,
|
|
284
|
+
29vw 19vh 1px 0px #fff,
|
|
285
|
+
-44vw -13vh 0px 0px #fff,
|
|
286
|
+
46vw 41vh 0px 1px #fff,
|
|
287
|
+
-3vw -45vh 0px 1px #fff,
|
|
288
|
+
47vw 35vh 1px 0px #fff,
|
|
289
|
+
12vw -8vh 1px 0px #fff,
|
|
290
|
+
-34vw 48vh 1px 1px #fff,
|
|
291
|
+
32vw 26vh 1px 1px #fff,
|
|
292
|
+
32vw -41vh 1px 1px #fff,
|
|
293
|
+
0vw 37vh 1px 1px #fff,
|
|
294
|
+
34vw -26vh 1px 0px #fff,
|
|
295
|
+
-14vw -49vh 1px 0px #fff,
|
|
296
|
+
-12vw 45vh 0px 1px #fff,
|
|
297
|
+
-44vw -33vh 0px 1px #fff,
|
|
298
|
+
-13vw 41vh 0px 0px #fff,
|
|
299
|
+
-36vw -11vh 0px 1px #fff,
|
|
300
|
+
-23vw -24vh 1px 0px #fff,
|
|
301
|
+
-38vw -27vh 0px 1px #fff,
|
|
302
|
+
16vw -19vh 0px 0px #fff,
|
|
303
|
+
28vw 33vh 1px 0px #fff,
|
|
304
|
+
-49vw -4vh 0px 0px #fff,
|
|
305
|
+
16vw 32vh 0px 1px #fff,
|
|
306
|
+
36vw -18vh 1px 0px #fff,
|
|
307
|
+
-25vw -30vh 1px 0px #fff,
|
|
308
|
+
-23vw 24vh 0px 1px #fff,
|
|
309
|
+
-2vw -35vh 1px 1px #fff,
|
|
310
|
+
-25vw 9vh 0px 0px #fff,
|
|
311
|
+
-15vw -34vh 0px 0px #fff,
|
|
312
|
+
-8vw -19vh 1px 0px #fff,
|
|
313
|
+
-20vw -20vh 1px 1px #fff,
|
|
314
|
+
42vw 50vh 0px 1px #fff,
|
|
315
|
+
-32vw 10vh 1px 0px #fff,
|
|
316
|
+
-23vw -17vh 0px 0px #fff,
|
|
317
|
+
44vw 15vh 1px 0px #fff,
|
|
318
|
+
-40vw 33vh 1px 1px #fff,
|
|
319
|
+
-43vw 8vh 0px 0px #fff,
|
|
320
|
+
-48vw -15vh 1px 1px #fff,
|
|
321
|
+
-24vw 17vh 0px 0px #fff,
|
|
322
|
+
-31vw 50vh 1px 0px #fff,
|
|
323
|
+
36vw -38vh 0px 1px #fff,
|
|
324
|
+
-7vw 48vh 0px 0px #fff,
|
|
325
|
+
15vw -32vh 0px 0px #fff,
|
|
326
|
+
29vw -41vh 0px 0px #fff,
|
|
327
|
+
2vw 37vh 1px 0px #fff,
|
|
328
|
+
7vw -40vh 1px 1px #fff,
|
|
329
|
+
15vw 18vh 0px 0px #fff,
|
|
330
|
+
25vw -13vh 1px 1px #fff,
|
|
331
|
+
-46vw -12vh 1px 1px #fff,
|
|
332
|
+
-18vw 22vh 0px 0px #fff,
|
|
333
|
+
23vw -9vh 1px 0px #fff,
|
|
334
|
+
50vw 12vh 0px 1px #fff,
|
|
335
|
+
45vw 2vh 0px 0px #fff,
|
|
336
|
+
14vw -48vh 1px 0px #fff,
|
|
337
|
+
23vw 43vh 0px 1px #fff,
|
|
338
|
+
-40vw 16vh 1px 1px #fff,
|
|
339
|
+
20vw -31vh 0px 1px #fff,
|
|
340
|
+
-17vw 44vh 1px 1px #fff,
|
|
341
|
+
18vw -45vh 0px 0px #fff,
|
|
342
|
+
33vw -6vh 0px 0px #fff,
|
|
343
|
+
0vw 7vh 0px 1px #fff,
|
|
344
|
+
-10vw -18vh 0px 1px #fff,
|
|
345
|
+
-19vw 5vh 1px 0px #fff,
|
|
346
|
+
1vw 42vh 0px 0px #fff,
|
|
347
|
+
22vw 48vh 0px 1px #fff,
|
|
348
|
+
39vw -8vh 1px 1px #fff,
|
|
349
|
+
-6vw -42vh 1px 0px #fff,
|
|
350
|
+
-47vw 34vh 0px 0px #fff,
|
|
351
|
+
-46vw 19vh 0px 1px #fff,
|
|
352
|
+
-12vw -32vh 0px 0px #fff,
|
|
353
|
+
-45vw -38vh 0px 1px #fff,
|
|
354
|
+
-28vw 18vh 1px 0px #fff,
|
|
355
|
+
-38vw -46vh 1px 1px #fff,
|
|
356
|
+
49vw -6vh 1px 1px #fff,
|
|
357
|
+
-28vw 18vh 1px 1px #fff,
|
|
358
|
+
10vw -24vh 0px 1px #fff,
|
|
359
|
+
-5vw -11vh 1px 1px #fff,
|
|
360
|
+
33vw -8vh 1px 0px #fff,
|
|
361
|
+
-16vw 17vh 0px 0px #fff,
|
|
362
|
+
18vw 27vh 0px 1px #fff,
|
|
363
|
+
-8vw -10vh 1px 1px #fff;
|
|
364
|
+
|
|
365
|
+
/* stars were too big with the layers above but left the code in case no one cares -- as in, if noone's just that one other loner who actually cares */
|
|
366
|
+
|
|
367
|
+
box-shadow:
|
|
368
|
+
24vw 9vh 1px 0px #fff,
|
|
369
|
+
12vw -24vh 0px 1px #fff,
|
|
370
|
+
-45vw -22vh 0px 0px #fff,
|
|
371
|
+
-37vw -40vh 0px 1px #fff,
|
|
372
|
+
29vw 19vh 0px 1px #fff,
|
|
373
|
+
4vw -8vh 0px 1px #fff,
|
|
374
|
+
-5vw 21vh 1px 1px #fff,
|
|
375
|
+
-27vw 26vh 1px 1px #fff,
|
|
376
|
+
-47vw -3vh 1px 1px #fff,
|
|
377
|
+
-28vw -30vh 0px 1px #fff,
|
|
378
|
+
-43vw -27vh 0px 1px #fff,
|
|
379
|
+
4vw 22vh 1px 1px #fff,
|
|
380
|
+
36vw 23vh 0px 0px #fff,
|
|
381
|
+
-21vw 24vh 1px 1px #fff,
|
|
382
|
+
-16vw 2vh 1px 0px #fff,
|
|
383
|
+
-16vw -6vh 0px 0px #fff,
|
|
384
|
+
5vw 26vh 0px 0px #fff,
|
|
385
|
+
-34vw 41vh 0px 0px #fff,
|
|
386
|
+
1vw 42vh 1px 1px #fff,
|
|
387
|
+
11vw -13vh 1px 1px #fff,
|
|
388
|
+
48vw -8vh 1px 0px #fff,
|
|
389
|
+
22vw -15vh 0px 0px #fff,
|
|
390
|
+
45vw 49vh 0px 0px #fff,
|
|
391
|
+
43vw -27vh 1px 1px #fff,
|
|
392
|
+
20vw -2vh 0px 0px #fff,
|
|
393
|
+
8vw 22vh 0px 1px #fff,
|
|
394
|
+
39vw 48vh 1px 1px #fff,
|
|
395
|
+
-21vw -11vh 0px 1px #fff,
|
|
396
|
+
-40vw 45vh 0px 1px #fff,
|
|
397
|
+
11vw -30vh 1px 0px #fff,
|
|
398
|
+
26vw 30vh 1px 0px #fff,
|
|
399
|
+
45vw -29vh 0px 1px #fff,
|
|
400
|
+
-2vw 18vh 0px 0px #fff,
|
|
401
|
+
-29vw -45vh 1px 0px #fff,
|
|
402
|
+
-7vw -27vh 1px 1px #fff,
|
|
403
|
+
42vw 24vh 0px 0px #fff,
|
|
404
|
+
45vw -48vh 1px 0px #fff,
|
|
405
|
+
-36vw -18vh 0px 0px #fff,
|
|
406
|
+
-44vw 13vh 0px 1px #fff,
|
|
407
|
+
36vw 16vh 0px 1px #fff,
|
|
408
|
+
40vw 24vh 0px 0px #fff,
|
|
409
|
+
18vw 11vh 0px 0px #fff,
|
|
410
|
+
-15vw -23vh 1px 0px #fff,
|
|
411
|
+
-24vw 48vh 0px 1px #fff,
|
|
412
|
+
27vw -45vh 1px 0px #fff,
|
|
413
|
+
-2vw -24vh 0px 1px #fff,
|
|
414
|
+
-15vw -28vh 0px 0px #fff,
|
|
415
|
+
-43vw 13vh 1px 0px #fff,
|
|
416
|
+
7vw 27vh 1px 0px #fff,
|
|
417
|
+
47vw 5vh 0px 0px #fff,
|
|
418
|
+
-45vw 15vh 1px 1px #fff,
|
|
419
|
+
-5vw -28vh 0px 1px #fff,
|
|
420
|
+
38vw 25vh 1px 1px #fff,
|
|
421
|
+
-39vw -1vh 1px 0px #fff,
|
|
422
|
+
5vw 0vh 1px 0px #fff,
|
|
423
|
+
49vw 13vh 0px 0px #fff,
|
|
424
|
+
48vw 10vh 0px 1px #fff,
|
|
425
|
+
19vw -28vh 0px 0px #fff,
|
|
426
|
+
4vw 7vh 0px 0px #fff,
|
|
427
|
+
21vw 21vh 1px 1px #fff,
|
|
428
|
+
-15vw -15vh 0px 1px #fff,
|
|
429
|
+
-6vw -42vh 1px 0px #fff,
|
|
430
|
+
-15vw 48vh 1px 1px #fff,
|
|
431
|
+
-23vw 25vh 1px 1px #fff,
|
|
432
|
+
-48vw 25vh 0px 1px #fff,
|
|
433
|
+
-31vw -19vh 0px 1px #fff,
|
|
434
|
+
4vw 37vh 1px 1px #fff,
|
|
435
|
+
-43vw 28vh 0px 0px #fff,
|
|
436
|
+
3vw -25vh 0px 1px #fff,
|
|
437
|
+
-39vw 14vh 0px 1px #fff,
|
|
438
|
+
-40vw 31vh 0px 1px #fff,
|
|
439
|
+
35vw -36vh 1px 1px #fff,
|
|
440
|
+
16vw 49vh 0px 0px #fff,
|
|
441
|
+
6vw 39vh 0px 0px #fff,
|
|
442
|
+
3vw -35vh 0px 1px #fff,
|
|
443
|
+
-44vw -2vh 1px 0px #fff,
|
|
444
|
+
-6vw 21vh 1px 0px #fff,
|
|
445
|
+
48vw 9vh 1px 1px #fff,
|
|
446
|
+
-43vw 30vh 1px 1px #fff,
|
|
447
|
+
29vw -12vh 1px 1px #fff,
|
|
448
|
+
-48vw 13vh 1px 0px #fff,
|
|
449
|
+
-42vw 32vh 1px 1px #fff,
|
|
450
|
+
34vw 15vh 1px 1px #fff,
|
|
451
|
+
29vw -37vh 1px 1px #fff,
|
|
452
|
+
28vw 2vh 0px 0px #fff;
|
|
453
|
+
animation: zoom 20s forwards;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
@keyframes zoom {
|
|
457
|
+
0% {
|
|
458
|
+
transform: scale(1);
|
|
459
|
+
}
|
|
460
|
+
100% {
|
|
461
|
+
transform: scale(1.5);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
.animate-float {
|
|
466
|
+
animation: float 6s ease-in-out infinite;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
@keyframes float {
|
|
470
|
+
0% {
|
|
471
|
+
transform: translatey(0px);
|
|
472
|
+
}
|
|
473
|
+
50% {
|
|
474
|
+
transform: translatey(-40px);
|
|
475
|
+
}
|
|
476
|
+
100% {
|
|
477
|
+
transform: translatey(0px);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import Adapter from "../Adapter";
|
|
2
|
+
|
|
3
|
+
const adapter = new Adapter({});
|
|
4
|
+
|
|
5
|
+
describe("Adapter", () => {
|
|
6
|
+
test("parseFormBody returns an object with parsed keys", () => {
|
|
7
|
+
expect(
|
|
8
|
+
adapter.parseFormBody({
|
|
9
|
+
"order[email]": "john@example.com",
|
|
10
|
+
"order[uid]": "order-id",
|
|
11
|
+
"order[vouchers]": ["42", 420],
|
|
12
|
+
"order[items][1][name]": "A beer",
|
|
13
|
+
"order[items][1][price]": 5,
|
|
14
|
+
"order[items][1][qty]": 3,
|
|
15
|
+
"order[items][2][name]": "A t-shirt",
|
|
16
|
+
"order[items][2][price]": 20,
|
|
17
|
+
"order[items][2][qty]": 1,
|
|
18
|
+
})
|
|
19
|
+
).toEqual({
|
|
20
|
+
order: {
|
|
21
|
+
email: "john@example.com",
|
|
22
|
+
uid: "order-id",
|
|
23
|
+
vouchers: ["42", 420],
|
|
24
|
+
items: {
|
|
25
|
+
1: {
|
|
26
|
+
name: "A beer",
|
|
27
|
+
price: 5,
|
|
28
|
+
qty: 3,
|
|
29
|
+
},
|
|
30
|
+
2: {
|
|
31
|
+
name: "A t-shirt",
|
|
32
|
+
price: 20,
|
|
33
|
+
qty: 1,
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import HonoAdapter from "../HonoAdapter";
|
|
2
|
+
|
|
3
|
+
class HonoMock {
|
|
4
|
+
use() {}
|
|
5
|
+
get() {}
|
|
6
|
+
post() {}
|
|
7
|
+
put() {}
|
|
8
|
+
delete() {}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const app = new HonoMock();
|
|
12
|
+
const adapter = new HonoAdapter(app);
|
|
13
|
+
|
|
14
|
+
describe("HonoAdapter", () => {
|
|
15
|
+
test("getMethod returns Hono's get for invalid verbs", () => {
|
|
16
|
+
expect(adapter.getMethod("not existing")).toBe(app.get);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test("getMethod for GET", () => {
|
|
20
|
+
expect(adapter.getMethod("GET")).toBe(app.get);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test("getMethod for POST", () => {
|
|
24
|
+
expect(adapter.getMethod("POST")).toBe(app.post);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test("getMethod for PUT", () => {
|
|
28
|
+
expect(adapter.getMethod("PUT")).toBe(app.put);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test("getMethod for DELETE", () => {
|
|
32
|
+
expect(adapter.getMethod("DELETE")).toBe(app.delete);
|
|
33
|
+
});
|
|
34
|
+
});
|