elegance-js 1.12.0 → 1.14.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.
- package/dist/build.mjs +1 -1
- package/dist/client/client.mjs +19 -26
- package/dist/compile_docs.mjs +1 -1
- package/dist/dynamic_page.mjs +1 -1
- package/dist/global.d.ts +1 -4
- package/dist/page_compiler.mjs +16 -4
- package/dist/server/generateHTMLTemplate.mjs +1 -1
- package/dist/server/server.mjs +1 -1
- package/dist/server/state.d.ts +1 -1
- package/package.json +1 -1
- package/scripts/bootstrap.js +165 -48
package/dist/build.mjs
CHANGED
|
@@ -266,7 +266,7 @@ var generateHTMLTemplate = ({
|
|
|
266
266
|
let HTMLTemplate = `<head><meta name="viewport" content="width=device-width, initial-scale=1.0">`;
|
|
267
267
|
HTMLTemplate += '<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"><meta charset="UTF-8">';
|
|
268
268
|
for (const module of requiredClientModules) {
|
|
269
|
-
HTMLTemplate += `<script src="/shipped/${module}.js" defer="true"></script>`;
|
|
269
|
+
HTMLTemplate += `<script data-module="true" src="/shipped/${module}.js" defer="true"></script>`;
|
|
270
270
|
}
|
|
271
271
|
if (addPageScriptTag === true) {
|
|
272
272
|
HTMLTemplate += `<script data-tag="true" type="module" src="${pageURL === "" ? "" : "/"}${pageURL}/${name}_data.js" defer="true"></script>`;
|
package/dist/client/client.mjs
CHANGED
|
@@ -156,26 +156,6 @@ Object.assign(window, {
|
|
|
156
156
|
type: 2 /* OBSERVER */
|
|
157
157
|
};
|
|
158
158
|
},
|
|
159
|
-
/*
|
|
160
|
-
observe: (subjects: ClientSubject[], updateCallback: () => any) => {
|
|
161
|
-
const pageData = pd[currentPage];
|
|
162
|
-
|
|
163
|
-
const keys = [];
|
|
164
|
-
|
|
165
|
-
for (const subject of subjects) {
|
|
166
|
-
const key = subject.id + Date.now();
|
|
167
|
-
|
|
168
|
-
keys.push({
|
|
169
|
-
key: key,
|
|
170
|
-
subject: subject.id,
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
pageData.stateManager.observe(subject, updateCallback, key);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
return { keys }
|
|
177
|
-
},
|
|
178
|
-
*/
|
|
179
159
|
eventListener: (subjects, eventListener) => {
|
|
180
160
|
return {
|
|
181
161
|
subjects,
|
|
@@ -377,13 +357,26 @@ var fetchPage = async (targetURL) => {
|
|
|
377
357
|
console.info(`Fetching ${pathname}`);
|
|
378
358
|
const res = await fetch(targetURL);
|
|
379
359
|
const newDOM = domParser.parseFromString(await res.text(), "text/html");
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
360
|
+
{
|
|
361
|
+
const dataScripts = Array.from(newDOM.querySelectorAll('script[data-module="true"]'));
|
|
362
|
+
const currentScripts = Array.from(document.head.querySelectorAll('script[data-module="true"]'));
|
|
363
|
+
for (const dataScript of dataScripts) {
|
|
364
|
+
const existing = currentScripts.find((s) => s.src === dataScript.src);
|
|
365
|
+
if (existing) {
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
document.head.appendChild(dataScript);
|
|
369
|
+
}
|
|
383
370
|
}
|
|
384
|
-
|
|
385
|
-
const
|
|
386
|
-
|
|
371
|
+
{
|
|
372
|
+
const pageDataScript = newDOM.querySelector('script[data-tag="true"]');
|
|
373
|
+
if (!pageDataScript) {
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
if (!pd[pathname]) {
|
|
377
|
+
const { data } = await import(pageDataScript.src);
|
|
378
|
+
pd[pathname] = data;
|
|
379
|
+
}
|
|
387
380
|
}
|
|
388
381
|
pageStringCache.set(pathname, xmlSerializer.serializeToString(newDOM));
|
|
389
382
|
return newDOM;
|
package/dist/compile_docs.mjs
CHANGED
|
@@ -269,7 +269,7 @@ var generateHTMLTemplate = ({
|
|
|
269
269
|
let HTMLTemplate = `<head><meta name="viewport" content="width=device-width, initial-scale=1.0">`;
|
|
270
270
|
HTMLTemplate += '<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"><meta charset="UTF-8">';
|
|
271
271
|
for (const module of requiredClientModules) {
|
|
272
|
-
HTMLTemplate += `<script src="/shipped/${module}.js" defer="true"></script>`;
|
|
272
|
+
HTMLTemplate += `<script data-module="true" src="/shipped/${module}.js" defer="true"></script>`;
|
|
273
273
|
}
|
|
274
274
|
if (addPageScriptTag === true) {
|
|
275
275
|
HTMLTemplate += `<script data-tag="true" type="module" src="${pageURL === "" ? "" : "/"}${pageURL}/${name}_data.js" defer="true"></script>`;
|
package/dist/dynamic_page.mjs
CHANGED
|
@@ -223,7 +223,7 @@ var generateHTMLTemplate = ({
|
|
|
223
223
|
let HTMLTemplate = `<head><meta name="viewport" content="width=device-width, initial-scale=1.0">`;
|
|
224
224
|
HTMLTemplate += '<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"><meta charset="UTF-8">';
|
|
225
225
|
for (const module of requiredClientModules) {
|
|
226
|
-
HTMLTemplate += `<script src="/shipped/${module}.js" defer="true"></script>`;
|
|
226
|
+
HTMLTemplate += `<script data-module="true" src="/shipped/${module}.js" defer="true"></script>`;
|
|
227
227
|
}
|
|
228
228
|
if (addPageScriptTag === true) {
|
|
229
229
|
HTMLTemplate += `<script data-tag="true" type="module" src="${pageURL === "" ? "" : "/"}${pageURL}/${name}_data.js" defer="true"></script>`;
|
package/dist/global.d.ts
CHANGED
|
@@ -27,10 +27,7 @@ declare global {
|
|
|
27
27
|
children: null;
|
|
28
28
|
options: Record<string, any> | Child;
|
|
29
29
|
};
|
|
30
|
-
type
|
|
31
|
-
build: "once" | "interval" | "request";
|
|
32
|
-
};
|
|
33
|
-
type Page = (AnyBuiltElement) | (() => AnyBuiltElement);
|
|
30
|
+
type Page = (AnyBuiltElement) | (() => AnyBuiltElement) | (() => Promise<AnyBuiltElement>);
|
|
34
31
|
type ObjectAttribute<T> = T extends ObjectAttributeType.STATE ? {
|
|
35
32
|
type: ObjectAttributeType;
|
|
36
33
|
id: string | number;
|
package/dist/page_compiler.mjs
CHANGED
|
@@ -223,7 +223,7 @@ var generateHTMLTemplate = ({
|
|
|
223
223
|
let HTMLTemplate = `<head><meta name="viewport" content="width=device-width, initial-scale=1.0">`;
|
|
224
224
|
HTMLTemplate += '<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"><meta charset="UTF-8">';
|
|
225
225
|
for (const module of requiredClientModules) {
|
|
226
|
-
HTMLTemplate += `<script src="/shipped/${module}.js" defer="true"></script>`;
|
|
226
|
+
HTMLTemplate += `<script data-module="true" src="/shipped/${module}.js" defer="true"></script>`;
|
|
227
227
|
}
|
|
228
228
|
if (addPageScriptTag === true) {
|
|
229
229
|
HTMLTemplate += `<script data-tag="true" type="module" src="${pageURL === "" ? "" : "/"}${pageURL}/${name}_data.js" defer="true"></script>`;
|
|
@@ -646,6 +646,12 @@ var generateClientPageData = async (pageLocation, state, objectAttributes, pageL
|
|
|
646
646
|
console.error("Failed to transform client page js!", error);
|
|
647
647
|
});
|
|
648
648
|
if (!transformedResult) return { sendHardReloadInstruction };
|
|
649
|
+
if (fs.existsSync(pageDataPath)) {
|
|
650
|
+
const content = fs.readFileSync(pageDataPath).toString();
|
|
651
|
+
if (content !== transformedResult.code) {
|
|
652
|
+
sendHardReloadInstruction = true;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
649
655
|
fs.writeFileSync(pageDataPath, transformedResult.code, "utf-8");
|
|
650
656
|
return { sendHardReloadInstruction };
|
|
651
657
|
};
|
|
@@ -730,7 +736,7 @@ return __exports
|
|
|
730
736
|
console.warn(`WARNING: ${filePath} should export a const page, which is of type () => BuiltElement<"body">.`);
|
|
731
737
|
}
|
|
732
738
|
if (typeof pageElements === "function") {
|
|
733
|
-
if (pageElements.constructor.name === "
|
|
739
|
+
if (pageElements.constructor.name === "AsyncFunction") {
|
|
734
740
|
pageElements = await pageElements();
|
|
735
741
|
} else {
|
|
736
742
|
pageElements = pageElements();
|
|
@@ -798,7 +804,7 @@ var shipPlugin = {
|
|
|
798
804
|
name: "ship",
|
|
799
805
|
setup(build2) {
|
|
800
806
|
build2.onLoad({ filter: /\.(js|ts|jsx|tsx)$/ }, async (args) => {
|
|
801
|
-
|
|
807
|
+
let contents = await fs.promises.readFile(args.path, "utf8");
|
|
802
808
|
const lines = contents.split(/\r?\n/);
|
|
803
809
|
let prepender = "";
|
|
804
810
|
for (let i = 0; i < lines.length - 1; i++) {
|
|
@@ -830,11 +836,15 @@ var shipPlugin = {
|
|
|
830
836
|
path: pkgPath,
|
|
831
837
|
globalName: importName
|
|
832
838
|
});
|
|
839
|
+
const replacement = `const ${importName} = globalThis.${importName};`;
|
|
840
|
+
lines.splice(i, 2, replacement);
|
|
841
|
+
i--;
|
|
833
842
|
}
|
|
834
843
|
}
|
|
835
844
|
if (prepender !== "") {
|
|
836
845
|
prepender += "];";
|
|
837
846
|
}
|
|
847
|
+
contents = lines.join("\n");
|
|
838
848
|
return {
|
|
839
849
|
contents: prepender + contents,
|
|
840
850
|
loader: path.extname(args.path).slice(1)
|
|
@@ -906,7 +916,9 @@ var build = async () => {
|
|
|
906
916
|
outfile: path.join(DIST_DIR, "shipped", plugin.globalName + ".js"),
|
|
907
917
|
format: "iife",
|
|
908
918
|
platform: "browser",
|
|
909
|
-
globalName: plugin.globalName
|
|
919
|
+
globalName: plugin.globalName,
|
|
920
|
+
minify: true,
|
|
921
|
+
treeShaking: true
|
|
910
922
|
});
|
|
911
923
|
log("Built a client module.");
|
|
912
924
|
}
|
|
@@ -205,7 +205,7 @@ var generateHTMLTemplate = ({
|
|
|
205
205
|
let HTMLTemplate = `<head><meta name="viewport" content="width=device-width, initial-scale=1.0">`;
|
|
206
206
|
HTMLTemplate += '<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"><meta charset="UTF-8">';
|
|
207
207
|
for (const module of requiredClientModules) {
|
|
208
|
-
HTMLTemplate += `<script src="/shipped/${module}.js" defer="true"></script>`;
|
|
208
|
+
HTMLTemplate += `<script data-module="true" src="/shipped/${module}.js" defer="true"></script>`;
|
|
209
209
|
}
|
|
210
210
|
if (addPageScriptTag === true) {
|
|
211
211
|
HTMLTemplate += `<script data-tag="true" type="module" src="${pageURL === "" ? "" : "/"}${pageURL}/${name}_data.js" defer="true"></script>`;
|
package/dist/server/server.mjs
CHANGED
|
@@ -223,7 +223,7 @@ var generateHTMLTemplate = ({
|
|
|
223
223
|
let HTMLTemplate = `<head><meta name="viewport" content="width=device-width, initial-scale=1.0">`;
|
|
224
224
|
HTMLTemplate += '<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"><meta charset="UTF-8">';
|
|
225
225
|
for (const module of requiredClientModules) {
|
|
226
|
-
HTMLTemplate += `<script src="/shipped/${module}.js" defer="true"></script>`;
|
|
226
|
+
HTMLTemplate += `<script data-module="true" src="/shipped/${module}.js" defer="true"></script>`;
|
|
227
227
|
}
|
|
228
228
|
if (addPageScriptTag === true) {
|
|
229
229
|
HTMLTemplate += `<script data-tag="true" type="module" src="${pageURL === "" ? "" : "/"}${pageURL}/${name}_data.js" defer="true"></script>`;
|
package/dist/server/state.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ type ReactiveMap<T extends any[], D extends Dependencies> = (this: {
|
|
|
19
19
|
bind: string | undefined;
|
|
20
20
|
}, template: (item: T[number], index: number, ...deps: {
|
|
21
21
|
[K in keyof D]: ClientSubjectGeneric<D[K]>["value"];
|
|
22
|
-
}) => Child, deps
|
|
22
|
+
}) => Child, deps?: [...D]) => Child;
|
|
23
23
|
type Dependencies = {
|
|
24
24
|
type: ObjectAttributeType;
|
|
25
25
|
value: unknown;
|
package/package.json
CHANGED
package/scripts/bootstrap.js
CHANGED
|
@@ -18,12 +18,34 @@ const envDtsPath = "env.d.ts";
|
|
|
18
18
|
const tsconfigPath = "tsconfig.json";
|
|
19
19
|
|
|
20
20
|
const pageTsContent = `
|
|
21
|
-
import { eventListener, state } from "elegance-js
|
|
22
|
-
import { loadHook } from "elegance-js/server/loadHook";
|
|
23
|
-
import { observe } from "elegance-js/server/observe";
|
|
21
|
+
import { observe, loadHook, eventListener, state } from "elegance-js";
|
|
24
22
|
|
|
23
|
+
/*
|
|
24
|
+
This is state.
|
|
25
|
+
It uses a simple observer model in the browser (see the observer function)
|
|
26
|
+
|
|
27
|
+
You can update it's value using state.value, and when you want the observers
|
|
28
|
+
of said state to refresh, call state.signal().
|
|
29
|
+
|
|
30
|
+
You can update the state to whatever value you want it to be,
|
|
31
|
+
before the page is finished building.
|
|
32
|
+
|
|
33
|
+
Once the page is built, all state values are shipped to the browser as-is.
|
|
34
|
+
*/
|
|
25
35
|
const counter = state(0);
|
|
26
36
|
|
|
37
|
+
/*
|
|
38
|
+
The server keeps track of every call to the loadHook() function,
|
|
39
|
+
does some preprocessing, and ships the loadhook to the browser.
|
|
40
|
+
The browser, after the page loads, runs the content of the function (the second paramater)
|
|
41
|
+
passed into the loadHook call.
|
|
42
|
+
|
|
43
|
+
Loadhook takes in as it's first parameter, a dependency list of state()'s that
|
|
44
|
+
the loadHook can then reference in the browser.
|
|
45
|
+
|
|
46
|
+
For newbies, note that the content of loadHook is *browser code*, and thus
|
|
47
|
+
cannot be trusted!
|
|
48
|
+
*/
|
|
27
49
|
loadHook(
|
|
28
50
|
[counter],
|
|
29
51
|
(_, counter) => {
|
|
@@ -36,57 +58,149 @@ loadHook(
|
|
|
36
58
|
},
|
|
37
59
|
)
|
|
38
60
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
61
|
+
/*
|
|
62
|
+
State can also be an array!
|
|
63
|
+
In which case, the reactiveMap() method is added onto the state.
|
|
64
|
+
This allows you to run client-side code, which dynamically changes
|
|
65
|
+
the page's HTML content based on the state of the array in the browser.
|
|
66
|
+
*/
|
|
67
|
+
const ReactiveMap = () => {
|
|
68
|
+
const arrayState = state([
|
|
69
|
+
"John","Mary","William","Kimberly",
|
|
70
|
+
]);
|
|
47
71
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
72
|
+
return arrayState.reactiveMap((item, index) => {
|
|
73
|
+
index += 1;
|
|
74
|
+
|
|
75
|
+
return div({
|
|
76
|
+
},
|
|
77
|
+
index + ". ", item,
|
|
78
|
+
)
|
|
79
|
+
})
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/*
|
|
83
|
+
This is the actual content of the page.
|
|
84
|
+
|
|
85
|
+
It does not *have* to be an async function.
|
|
86
|
+
Page can be any value, as long as it resolves into a Child (a built element, eg. string, a return value of an element creation call, etc)
|
|
87
|
+
*/
|
|
88
|
+
export const page: Page = async () => {
|
|
89
|
+
const pageName = state("Elegance.JS");
|
|
52
90
|
|
|
53
|
-
|
|
54
|
-
|
|
91
|
+
/*
|
|
92
|
+
The below is an element creation function.
|
|
93
|
+
The syntax is roughly similar to how HTML works.
|
|
94
|
+
|
|
95
|
+
A call like: h1("Hello World!")
|
|
96
|
+
|
|
97
|
+
Would generate the HTML: <h1>Hello World!</h1>
|
|
98
|
+
|
|
99
|
+
The first parameter to an element may be another element (child), or an options object.
|
|
100
|
+
|
|
101
|
+
Options objects are used to set things like classNames, style, ids. etc.
|
|
102
|
+
|
|
103
|
+
For example this call: h1({
|
|
104
|
+
id: "my-id",
|
|
105
|
+
},
|
|
106
|
+
"Hello World!"
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
Turns into this HTML: <h1 id="my-id">Hello World!</h1>
|
|
110
|
+
*/
|
|
111
|
+
return body ({
|
|
112
|
+
class: "text-white flex min-h-screen items-start sm:justify-center p-4 bg-black flex-col gap-4 max-w-[500px] w-full mx-auto",
|
|
55
113
|
},
|
|
56
|
-
|
|
57
|
-
class: "
|
|
58
|
-
href: "https://elegance.js.org/",
|
|
59
|
-
target: "_blank",
|
|
114
|
+
h1 ({
|
|
115
|
+
class: "text-4xl font-inter font-semibold bg-clip-text text-transparent bg-gradient-to-tl from-[#EEB844] to-[#FF4FED] oveflow-clip",
|
|
60
116
|
},
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
div ({
|
|
64
|
-
class: "blur-[50px] absolute group-hover:bg-red-400 inset-0 bg-transparent duration-200 pointer-events-none -z-10",
|
|
65
|
-
"aria-hidden": "true",
|
|
66
|
-
}),
|
|
117
|
+
`Welcome to ${pageName.value}!`,
|
|
67
118
|
),
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
119
|
+
|
|
120
|
+
ReactiveMap(),
|
|
121
|
+
|
|
122
|
+
p ({
|
|
123
|
+
},
|
|
124
|
+
"Edit page.ts to get started.",
|
|
125
|
+
),
|
|
126
|
+
|
|
127
|
+
div({
|
|
128
|
+
class: "flex items-start gap-4 mt-2",
|
|
129
|
+
},
|
|
130
|
+
a ({
|
|
131
|
+
class: "px-4 py-2 rounded-md bg-red-400 text-black font-semibold relative group hover:scale-[1.05] duration-200",
|
|
132
|
+
href: "https://elegance.js.org/",
|
|
133
|
+
target: "_blank",
|
|
134
|
+
},
|
|
135
|
+
"Documentation",
|
|
136
|
+
|
|
137
|
+
div ({
|
|
138
|
+
class: "blur-[50px] absolute group-hover:bg-red-400 inset-0 bg-transparent duration-200 pointer-events-none -z-10",
|
|
139
|
+
"aria-hidden": "true",
|
|
140
|
+
}),
|
|
141
|
+
),
|
|
142
|
+
|
|
143
|
+
button ({
|
|
144
|
+
class: "hover:cursor-pointer px-4 py-2 rounded-md bg-zinc-200 text-black font-semibold relative group hover:scale-[1.05] duration-200",
|
|
145
|
+
/*
|
|
146
|
+
Normally, element attributes can only be a string, number or boolean.
|
|
147
|
+
|
|
148
|
+
However, exceptions are made for *object attributes*.
|
|
149
|
+
These are special values that usually perform client-side actions.
|
|
150
|
+
|
|
151
|
+
Take the below for example.
|
|
152
|
+
The eventListener() takes in a dependency array, and a callback function.
|
|
153
|
+
|
|
154
|
+
It then returns an ObjectAttribute of type EVENT_LISTENER.
|
|
155
|
+
|
|
156
|
+
The elegance-compiler, when it sees this, packs up the callback function and state references,
|
|
157
|
+
and ships it to the page.
|
|
75
158
|
|
|
76
|
-
|
|
77
|
-
|
|
159
|
+
The page, when it loads, then binds the eventListener callback to the corresponding event (in this case, "onclick").
|
|
160
|
+
|
|
161
|
+
ObjectAttributes do not show up in HTML!
|
|
162
|
+
*/
|
|
163
|
+
onClick: eventListener(
|
|
164
|
+
[counter],
|
|
165
|
+
(_, counter) => {
|
|
166
|
+
counter.value++;
|
|
167
|
+
|
|
168
|
+
counter.signal();
|
|
169
|
+
},
|
|
170
|
+
),
|
|
171
|
+
|
|
172
|
+
/*
|
|
173
|
+
This is another ObjectAttribute, just like eventListener
|
|
174
|
+
It takes in an array of state it should watch,
|
|
175
|
+
and when that state calls its state.signal() method,
|
|
176
|
+
|
|
177
|
+
The observer calls it's callback function with the new values,
|
|
178
|
+
and whatever is returned, is the new value of the property.
|
|
179
|
+
|
|
180
|
+
So in this instance, whenever counter.signal() is called
|
|
181
|
+
this observer displays Counter: VALUE, and makes it the
|
|
182
|
+
innerText of this button.
|
|
183
|
+
*/
|
|
184
|
+
innerText: observe([counter], (counter) => \`Counter: \${counter}\`),
|
|
185
|
+
},
|
|
186
|
+
div ({
|
|
187
|
+
class: "blur-[50px] absolute group-hover:bg-zinc-200 inset-0 bg-transparent duration-200 pointer-events-none -z-10",
|
|
188
|
+
"aria-hidden": "true",
|
|
189
|
+
}),
|
|
78
190
|
),
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
|
|
191
|
+
)
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/*
|
|
196
|
+
This is the metadata of the page.
|
|
197
|
+
Aka the <head> element which gets served alongside the page content.
|
|
198
|
+
|
|
199
|
+
It *must* be a function that resolves into a head() result.
|
|
200
|
+
|
|
201
|
+
In it, you should do things like link your stylesheets,
|
|
202
|
+
set page titles, all that goodness.
|
|
203
|
+
*/
|
|
90
204
|
export const metadata = () => head ({},
|
|
91
205
|
link ({
|
|
92
206
|
rel: "stylesheet",
|
|
@@ -94,7 +208,7 @@ export const metadata = () => head ({},
|
|
|
94
208
|
}),
|
|
95
209
|
|
|
96
210
|
title ({},
|
|
97
|
-
"Elegance.JS"
|
|
211
|
+
"Elegance.JS Demo"
|
|
98
212
|
),
|
|
99
213
|
)
|
|
100
214
|
|
|
@@ -114,6 +228,9 @@ const tsconfigContent = JSON.stringify({
|
|
|
114
228
|
},
|
|
115
229
|
include: ["pages/**/*", "env.d.ts"],
|
|
116
230
|
exclude: ["node_modules"],
|
|
231
|
+
paths: {
|
|
232
|
+
"@/": ["./"],
|
|
233
|
+
}
|
|
117
234
|
}, null, 2);
|
|
118
235
|
|
|
119
236
|
const indexCssContent = `
|