@turnipxenon/pineapple 2.4.14 → 2.4.15
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/.idea/workspace.xml +64 -49
- package/.svelte-kit/__package__/app.postcss +15 -1
- package/.svelte-kit/__package__/components/DialogOverlay.svelte +48 -47
- package/.svelte-kit/__package__/components/dialog_manager/DialogManager.d.ts +8 -3
- package/.svelte-kit/__package__/components/dialog_manager/DialogManager.js +35 -11
- package/.svelte-kit/__package__/components/dialog_manager/DialogManagerStore.js +1 -1
- package/.svelte-kit/__package__/components/layouts/SeaweedBaseLayout.svelte +2 -2
- package/.svelte-kit/__package__/components/pineapple/PineappleBaseLayout.svelte +18 -6
- package/.svelte-kit/__package__/components/pineapple/toast/Toast.svelte +1 -0
- package/.svelte-kit/__package__/scripts/pineapple_fiber/PineappleFiberParser.d.ts +2 -0
- package/.svelte-kit/__package__/scripts/pineapple_fiber/PineappleFiberParser.js +137 -0
- package/.svelte-kit/__package__/scripts/pineapple_fiber/PineappleWeaver.js +3 -134
- package/.svelte-kit/__package__/types/pineapple_fiber/DialogState.d.ts +2 -1
- package/.svelte-kit/__package__/types/pineapple_fiber/DialogState.js +1 -0
- package/.svelte-kit/ambient.d.ts +2 -0
- package/.svelte-kit/generated/server/internal.js +1 -1
- package/dist/app.postcss +15 -1
- package/dist/components/DialogOverlay.svelte +48 -47
- package/dist/components/dialog_manager/DialogManager.d.ts +8 -3
- package/dist/components/dialog_manager/DialogManager.js +35 -11
- package/dist/components/dialog_manager/DialogManagerStore.js +1 -1
- package/dist/components/layouts/SeaweedBaseLayout.svelte +2 -2
- package/dist/components/pineapple/PineappleBaseLayout.svelte +18 -6
- package/dist/components/pineapple/toast/Toast.svelte +1 -0
- package/dist/scripts/pineapple_fiber/PineappleFiberParser.d.ts +2 -0
- package/dist/scripts/pineapple_fiber/PineappleFiberParser.js +137 -0
- package/dist/scripts/pineapple_fiber/PineappleWeaver.js +3 -134
- package/dist/types/pineapple_fiber/DialogState.d.ts +2 -1
- package/dist/types/pineapple_fiber/DialogState.js +1 -0
- package/package.json +1 -1
- package/src/lib/app.postcss +15 -1
- package/src/lib/components/DialogOverlay.svelte +56 -54
- package/src/lib/components/dialog_manager/DialogManager.ts +38 -12
- package/src/lib/components/dialog_manager/DialogManagerStore.ts +1 -1
- package/src/lib/components/layouts/SeaweedBaseLayout.svelte +2 -2
- package/src/lib/components/pineapple/PineappleBaseLayout.svelte +19 -6
- package/src/lib/components/pineapple/toast/Toast.svelte +1 -0
- package/src/lib/scripts/pineapple_fiber/PineappleFiberParser.ts +177 -0
- package/src/lib/scripts/pineapple_fiber/PineappleWeaver.ts +3 -176
- package/src/lib/types/pineapple_fiber/DialogState.ts +2 -1
- package/src/routes/(pineapple)/+page.svelte +2 -2
- package/src/routes/(pineapple)/pineapple/+page.svelte +19 -1
- package/src/routes/(pineapple)/pineapple/TestDialog.yarn +7 -0
- package/vite.config.ts +2 -1
- package/.svelte-kit/__package__/components/pineapple/overlay_manager/OverlayManager.d.ts +0 -0
- package/.svelte-kit/__package__/components/pineapple/overlay_manager/OverlayManager.js +0 -1
- package/dist/components/pineapple/overlay_manager/OverlayManager.d.ts +0 -0
- package/dist/components/pineapple/overlay_manager/OverlayManager.js +0 -1
- package/src/lib/components/pineapple/overlay_manager/OverlayManager.ts +0 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { PortraitType } from "../../types/pineapple_fiber/PortraitType";
|
|
2
|
+
const shouldDebug = false;
|
|
3
|
+
export const parseYarn = async (fileContent) => {
|
|
4
|
+
const dialogDetailList = [];
|
|
5
|
+
fileContent.split("===").map((unparsedNode) => {
|
|
6
|
+
// todo: detect empty nodes
|
|
7
|
+
// todo: improve the code readability
|
|
8
|
+
if (unparsedNode.trim() === "") {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const dialogDetails = {
|
|
12
|
+
// todo: dissect the line below and give comments because it is complex
|
|
13
|
+
dialogId: unparsedNode
|
|
14
|
+
.slice(unparsedNode.indexOf("title: "))
|
|
15
|
+
.split("\n")[0]
|
|
16
|
+
.split(" ")
|
|
17
|
+
.pop()
|
|
18
|
+
?.trim(),
|
|
19
|
+
portraitType: PortraitType.AresNeutral,
|
|
20
|
+
textContent: "" // will be filled later below
|
|
21
|
+
};
|
|
22
|
+
let portraitUnset = true;
|
|
23
|
+
// parse the PineappleFiber metatags
|
|
24
|
+
const unparsedBody = unparsedNode.split("---").pop().trim();
|
|
25
|
+
const bodyList = unparsedBody.split("\n");
|
|
26
|
+
let contentIndexStart = 0;
|
|
27
|
+
for (let index = 0; index < bodyList.length; index++) {
|
|
28
|
+
const possibleTagPair = bodyList[index].split(": ");
|
|
29
|
+
const possibleTagName = possibleTagPair[0].toLowerCase();
|
|
30
|
+
if (!["portrait"].includes(possibleTagName)) {
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
contentIndexStart = index + 1; // increase count for each viable tah
|
|
34
|
+
switch (possibleTagName) {
|
|
35
|
+
case "portrait":
|
|
36
|
+
portraitUnset = false;
|
|
37
|
+
// todo: implement a way to match the appropriate portrait based on the metatag
|
|
38
|
+
// from https://stackoverflow.com/a/17381004/17836168
|
|
39
|
+
dialogDetails.portraitType =
|
|
40
|
+
PortraitType[possibleTagPair[1].trim()];
|
|
41
|
+
if (shouldDebug) {
|
|
42
|
+
console.log("Portrait detected:", possibleTagPair[1], " => ", dialogDetails.portraitType);
|
|
43
|
+
}
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// portrait check
|
|
48
|
+
if (portraitUnset) {
|
|
49
|
+
console.warn(`Portrait missing for node: ${dialogDetails.dialogId}`);
|
|
50
|
+
dialogDetails.portraitType = PortraitType.AresNeutral;
|
|
51
|
+
}
|
|
52
|
+
// remove the metatags from the body
|
|
53
|
+
const unprocessedContent = bodyList.slice(contentIndexStart).join("\n");
|
|
54
|
+
const contentPair = unprocessedContent.split("<ChoiceBreak>");
|
|
55
|
+
if (contentPair.length === 2) {
|
|
56
|
+
// parse for the choice names in the options
|
|
57
|
+
let ChoiceParsingState;
|
|
58
|
+
(function (ChoiceParsingState) {
|
|
59
|
+
ChoiceParsingState[ChoiceParsingState["Free"] = 0] = "Free";
|
|
60
|
+
ChoiceParsingState[ChoiceParsingState["Line"] = 1] = "Line"; // previously detected an option, will try to detect for the next option
|
|
61
|
+
})(ChoiceParsingState || (ChoiceParsingState = {}));
|
|
62
|
+
let parsingState = ChoiceParsingState.Free;
|
|
63
|
+
const currentChoiceDetail = { jumpNode: "", name: "" };
|
|
64
|
+
const choiceList = [];
|
|
65
|
+
let shouldSkipChoices = false;
|
|
66
|
+
const checkChoiceForSave = () => {
|
|
67
|
+
if (currentChoiceDetail.name !== "") {
|
|
68
|
+
choiceList.push({
|
|
69
|
+
name: currentChoiceDetail.name,
|
|
70
|
+
jumpNode: currentChoiceDetail.jumpNode
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
contentPair[1]
|
|
75
|
+
.trim()
|
|
76
|
+
.split("\n")
|
|
77
|
+
.filter((line) => {
|
|
78
|
+
const trimmedLine = line.trim();
|
|
79
|
+
if (shouldSkipChoices) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
if (trimmedLine.startsWith("// ignore the rest")) {
|
|
83
|
+
shouldSkipChoices = true;
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
return true;
|
|
87
|
+
})
|
|
88
|
+
.map((line) => {
|
|
89
|
+
const trimmedLine = line.trim();
|
|
90
|
+
switch (parsingState) {
|
|
91
|
+
case ChoiceParsingState.Free:
|
|
92
|
+
if (trimmedLine.startsWith("->")) {
|
|
93
|
+
// save previous choice
|
|
94
|
+
checkChoiceForSave();
|
|
95
|
+
// write start of new choice
|
|
96
|
+
currentChoiceDetail.name = trimmedLine.split(" ").pop();
|
|
97
|
+
parsingState = ChoiceParsingState.Line;
|
|
98
|
+
}
|
|
99
|
+
break;
|
|
100
|
+
case ChoiceParsingState.Line:
|
|
101
|
+
if (trimmedLine.startsWith("<<jump")) {
|
|
102
|
+
const jumpNode = trimmedLine.split(" ").pop();
|
|
103
|
+
currentChoiceDetail.jumpNode = jumpNode.slice(0, jumpNode.length - 2); // remove ">>"
|
|
104
|
+
parsingState = ChoiceParsingState.Free;
|
|
105
|
+
}
|
|
106
|
+
break;
|
|
107
|
+
default:
|
|
108
|
+
console.error(`Unimplemented parsing state: ${parsingState}`);
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
checkChoiceForSave();
|
|
113
|
+
dialogDetails.textContent = contentPair[0];
|
|
114
|
+
// handle choice start tags to a href
|
|
115
|
+
choiceList.forEach((choiceDetail) => {
|
|
116
|
+
const keyword = `<choice ${choiceDetail.name}>`;
|
|
117
|
+
while (dialogDetails.textContent.includes(keyword)) {
|
|
118
|
+
dialogDetails.textContent = dialogDetails.textContent.replace(keyword, `<a class="choice-${choiceDetail.jumpNode} dialog-choice" title="Click to continue the dialog">`);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
const externalKeyword = "<a href=";
|
|
122
|
+
while (dialogDetails.textContent.includes(externalKeyword)) {
|
|
123
|
+
dialogDetails.textContent = dialogDetails.textContent.replace(externalKeyword, "<a target=\"_blank\" class=\"external-link\" href="); // make all external tags with a custom cursor
|
|
124
|
+
}
|
|
125
|
+
const choiceEndKeyword = "</choice>";
|
|
126
|
+
while (dialogDetails.textContent.includes(choiceEndKeyword)) {
|
|
127
|
+
dialogDetails.textContent = dialogDetails.textContent.replace(choiceEndKeyword, "</a>"); // convert all choice end tags to a tags
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
// assume only one which indicates it is choiceless
|
|
132
|
+
dialogDetails.textContent = unprocessedContent;
|
|
133
|
+
}
|
|
134
|
+
dialogDetailList.push(dialogDetails);
|
|
135
|
+
});
|
|
136
|
+
return dialogDetailList;
|
|
137
|
+
};
|
|
@@ -9,147 +9,16 @@
|
|
|
9
9
|
import { getAllFiles } from "../util/FileManagement";
|
|
10
10
|
import fs, { readFileSync } from "fs";
|
|
11
11
|
import { PortraitType } from "../../types/pineapple_fiber/PortraitType";
|
|
12
|
-
|
|
12
|
+
import { parseYarn } from "./PineappleFiberParser";
|
|
13
13
|
const pineappleWeaverRun = () => {
|
|
14
14
|
console.info("Starting Pineapple Weaver.");
|
|
15
15
|
const BASE_PATH = "./src/routes";
|
|
16
16
|
getAllFiles(BASE_PATH, (path) => {
|
|
17
17
|
return path.split(".").pop() === "yarn";
|
|
18
|
-
}).map((filePath) => {
|
|
18
|
+
}).map(async (filePath) => {
|
|
19
19
|
console.info(`Converting: ${filePath}`);
|
|
20
20
|
const fileContent = readFileSync(filePath, "utf-8");
|
|
21
|
-
const dialogDetailList =
|
|
22
|
-
fileContent.split("===").map((unparsedNode) => {
|
|
23
|
-
// todo: detect empty nodes
|
|
24
|
-
// todo: improve the code readability
|
|
25
|
-
if (unparsedNode.trim() === "") {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
const dialogDetails = {
|
|
29
|
-
// todo: dissect the line below and give comments because it is complex
|
|
30
|
-
dialogId: unparsedNode
|
|
31
|
-
.slice(unparsedNode.indexOf("title: "))
|
|
32
|
-
.split("\n")[0]
|
|
33
|
-
.split(" ")
|
|
34
|
-
.pop()
|
|
35
|
-
?.trim(),
|
|
36
|
-
portraitType: PortraitType.AresNeutral,
|
|
37
|
-
textContent: "" // will be filled later below
|
|
38
|
-
};
|
|
39
|
-
let portraitUnset = true;
|
|
40
|
-
// parse the PineappleFiber metatags
|
|
41
|
-
const unparsedBody = unparsedNode.split("---").pop().trim();
|
|
42
|
-
const bodyList = unparsedBody.split("\n");
|
|
43
|
-
let contentIndexStart = 0;
|
|
44
|
-
for (let index = 0; index < bodyList.length; index++) {
|
|
45
|
-
const possibleTagPair = bodyList[index].split(": ");
|
|
46
|
-
const possibleTagName = possibleTagPair[0].toLowerCase();
|
|
47
|
-
if (!["portrait"].includes(possibleTagName)) {
|
|
48
|
-
break;
|
|
49
|
-
}
|
|
50
|
-
contentIndexStart = index + 1; // increase count for each viable tah
|
|
51
|
-
switch (possibleTagName) {
|
|
52
|
-
case "portrait":
|
|
53
|
-
portraitUnset = false;
|
|
54
|
-
// todo: implement a way to match the appropriate portrait based on the metatag
|
|
55
|
-
// from https://stackoverflow.com/a/17381004/17836168
|
|
56
|
-
dialogDetails.portraitType =
|
|
57
|
-
PortraitType[possibleTagPair[1].trim()];
|
|
58
|
-
if (shouldDebug) {
|
|
59
|
-
console.log("Portrait detected:", possibleTagPair[1], " => ", dialogDetails.portraitType);
|
|
60
|
-
}
|
|
61
|
-
break;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
// portrait check
|
|
65
|
-
if (portraitUnset) {
|
|
66
|
-
console.warn(`Portrait missing for node: ${dialogDetails.dialogId}`);
|
|
67
|
-
dialogDetails.portraitType = PortraitType.AresNeutral;
|
|
68
|
-
}
|
|
69
|
-
// remove the metatags from the body
|
|
70
|
-
const unprocessedContent = bodyList.slice(contentIndexStart).join("\n");
|
|
71
|
-
const contentPair = unprocessedContent.split("<ChoiceBreak>");
|
|
72
|
-
if (contentPair.length === 2) {
|
|
73
|
-
// parse for the choice names in the options
|
|
74
|
-
let ChoiceParsingState;
|
|
75
|
-
(function (ChoiceParsingState) {
|
|
76
|
-
ChoiceParsingState[ChoiceParsingState["Free"] = 0] = "Free";
|
|
77
|
-
ChoiceParsingState[ChoiceParsingState["Line"] = 1] = "Line"; // previously detected an option, will try to detect for the next option
|
|
78
|
-
})(ChoiceParsingState || (ChoiceParsingState = {}));
|
|
79
|
-
let parsingState = ChoiceParsingState.Free;
|
|
80
|
-
const currentChoiceDetail = { jumpNode: "", name: "" };
|
|
81
|
-
const choiceList = [];
|
|
82
|
-
let shouldSkipChoices = false;
|
|
83
|
-
const checkChoiceForSave = () => {
|
|
84
|
-
if (currentChoiceDetail.name !== "") {
|
|
85
|
-
choiceList.push({
|
|
86
|
-
name: currentChoiceDetail.name,
|
|
87
|
-
jumpNode: currentChoiceDetail.jumpNode
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
contentPair[1]
|
|
92
|
-
.trim()
|
|
93
|
-
.split("\n")
|
|
94
|
-
.filter((line) => {
|
|
95
|
-
const trimmedLine = line.trim();
|
|
96
|
-
if (shouldSkipChoices) {
|
|
97
|
-
return false;
|
|
98
|
-
}
|
|
99
|
-
if (trimmedLine.startsWith("// ignore the rest")) {
|
|
100
|
-
shouldSkipChoices = true;
|
|
101
|
-
return false;
|
|
102
|
-
}
|
|
103
|
-
return true;
|
|
104
|
-
})
|
|
105
|
-
.map((line) => {
|
|
106
|
-
const trimmedLine = line.trim();
|
|
107
|
-
switch (parsingState) {
|
|
108
|
-
case ChoiceParsingState.Free:
|
|
109
|
-
if (trimmedLine.startsWith("->")) {
|
|
110
|
-
// save previous choice
|
|
111
|
-
checkChoiceForSave();
|
|
112
|
-
// write start of new choice
|
|
113
|
-
currentChoiceDetail.name = trimmedLine.split(" ").pop();
|
|
114
|
-
parsingState = ChoiceParsingState.Line;
|
|
115
|
-
}
|
|
116
|
-
break;
|
|
117
|
-
case ChoiceParsingState.Line:
|
|
118
|
-
if (trimmedLine.startsWith("<<jump")) {
|
|
119
|
-
const jumpNode = trimmedLine.split(" ").pop();
|
|
120
|
-
currentChoiceDetail.jumpNode = jumpNode.slice(0, jumpNode.length - 2); // remove ">>"
|
|
121
|
-
parsingState = ChoiceParsingState.Free;
|
|
122
|
-
}
|
|
123
|
-
break;
|
|
124
|
-
default:
|
|
125
|
-
console.error(`Unimplemented parsing state: ${parsingState}`);
|
|
126
|
-
break;
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
checkChoiceForSave();
|
|
130
|
-
dialogDetails.textContent = contentPair[0];
|
|
131
|
-
// handle choice start tags to a href
|
|
132
|
-
choiceList.forEach((choiceDetail) => {
|
|
133
|
-
const keyword = `<choice ${choiceDetail.name}>`;
|
|
134
|
-
while (dialogDetails.textContent.includes(keyword)) {
|
|
135
|
-
dialogDetails.textContent = dialogDetails.textContent.replace(keyword, `<a class="choice-${choiceDetail.jumpNode} dialog-choice" title="Click to continue the dialog">`);
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
const externalKeyword = "<a href=";
|
|
139
|
-
while (dialogDetails.textContent.includes(externalKeyword)) {
|
|
140
|
-
dialogDetails.textContent = dialogDetails.textContent.replace(externalKeyword, '<a target="_blank" class="external-link" href='); // make all external tags with a custom cursor
|
|
141
|
-
}
|
|
142
|
-
const choiceEndKeyword = "</choice>";
|
|
143
|
-
while (dialogDetails.textContent.includes(choiceEndKeyword)) {
|
|
144
|
-
dialogDetails.textContent = dialogDetails.textContent.replace(choiceEndKeyword, "</a>"); // convert all choice end tags to a tags
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
else {
|
|
148
|
-
// assume only one which indicates it's choiceless
|
|
149
|
-
dialogDetails.textContent = unprocessedContent;
|
|
150
|
-
}
|
|
151
|
-
dialogDetailList.push(dialogDetails);
|
|
152
|
-
});
|
|
21
|
+
const dialogDetailList = await parseYarn(fileContent);
|
|
153
22
|
const dialogDetailToString = (detail) => {
|
|
154
23
|
if (detail.portraitType === undefined) {
|
|
155
24
|
detail.portraitType = PortraitType.AresNeutral;
|
|
@@ -3,4 +3,5 @@ export var DialogState;
|
|
|
3
3
|
DialogState[DialogState["Invisible"] = 0] = "Invisible";
|
|
4
4
|
DialogState[DialogState["Visible"] = 1] = "Visible";
|
|
5
5
|
DialogState[DialogState["Busy"] = 2] = "Busy";
|
|
6
|
+
DialogState[DialogState["Inherit"] = 3] = "Inherit";
|
|
6
7
|
})(DialogState || (DialogState = {}));
|
package/.svelte-kit/ambient.d.ts
CHANGED
|
@@ -46,6 +46,7 @@ declare module '$env/static/private' {
|
|
|
46
46
|
export const HOMEDRIVE: string;
|
|
47
47
|
export const HOMEPATH: string;
|
|
48
48
|
export const IDEA_INITIAL_DIRECTORY: string;
|
|
49
|
+
export const IJ_RESTARTER_LOG: string;
|
|
49
50
|
export const INIT_CWD: string;
|
|
50
51
|
export const JAVA_HOME: string;
|
|
51
52
|
export const LOCALAPPDATA: string;
|
|
@@ -239,6 +240,7 @@ declare module '$env/dynamic/private' {
|
|
|
239
240
|
HOMEDRIVE: string;
|
|
240
241
|
HOMEPATH: string;
|
|
241
242
|
IDEA_INITIAL_DIRECTORY: string;
|
|
243
|
+
IJ_RESTARTER_LOG: string;
|
|
242
244
|
INIT_CWD: string;
|
|
243
245
|
JAVA_HOME: string;
|
|
244
246
|
LOCALAPPDATA: string;
|
|
@@ -21,7 +21,7 @@ export const options = {
|
|
|
21
21
|
app: ({ head, body, assets, nonce, env }) => "<!DOCTYPE html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<link rel=\"icon\" href=\"" + assets + "/favicon.png\" />\n\t\t<meta name=\"viewport\" content=\"width=device-width\" />\n\t\t" + head + "\n\t</head>\n\n\t<body data-sveltekit-preload-data=\"hover\" data-theme=\"crimson\">\n\t\t<div style=\"display: contents\" class=\"h-full overflow-hidden\">" + body + "</div>\n\t</body>\n</html>\n",
|
|
22
22
|
error: ({ status, message }) => "<!doctype html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>" + message + "</title>\n\n\t\t<style>\n\t\t\tbody {\n\t\t\t\t--bg: white;\n\t\t\t\t--fg: #222;\n\t\t\t\t--divider: #ccc;\n\t\t\t\tbackground: var(--bg);\n\t\t\t\tcolor: var(--fg);\n\t\t\t\tfont-family:\n\t\t\t\t\tsystem-ui,\n\t\t\t\t\t-apple-system,\n\t\t\t\t\tBlinkMacSystemFont,\n\t\t\t\t\t'Segoe UI',\n\t\t\t\t\tRoboto,\n\t\t\t\t\tOxygen,\n\t\t\t\t\tUbuntu,\n\t\t\t\t\tCantarell,\n\t\t\t\t\t'Open Sans',\n\t\t\t\t\t'Helvetica Neue',\n\t\t\t\t\tsans-serif;\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tjustify-content: center;\n\t\t\t\theight: 100vh;\n\t\t\t\tmargin: 0;\n\t\t\t}\n\n\t\t\t.error {\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tmax-width: 32rem;\n\t\t\t\tmargin: 0 1rem;\n\t\t\t}\n\n\t\t\t.status {\n\t\t\t\tfont-weight: 200;\n\t\t\t\tfont-size: 3rem;\n\t\t\t\tline-height: 1;\n\t\t\t\tposition: relative;\n\t\t\t\ttop: -0.05rem;\n\t\t\t}\n\n\t\t\t.message {\n\t\t\t\tborder-left: 1px solid var(--divider);\n\t\t\t\tpadding: 0 0 0 1rem;\n\t\t\t\tmargin: 0 0 0 1rem;\n\t\t\t\tmin-height: 2.5rem;\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t}\n\n\t\t\t.message h1 {\n\t\t\t\tfont-weight: 400;\n\t\t\t\tfont-size: 1em;\n\t\t\t\tmargin: 0;\n\t\t\t}\n\n\t\t\t@media (prefers-color-scheme: dark) {\n\t\t\t\tbody {\n\t\t\t\t\t--bg: #222;\n\t\t\t\t\t--fg: #ddd;\n\t\t\t\t\t--divider: #666;\n\t\t\t\t}\n\t\t\t}\n\t\t</style>\n\t</head>\n\t<body>\n\t\t<div class=\"error\">\n\t\t\t<span class=\"status\">" + status + "</span>\n\t\t\t<div class=\"message\">\n\t\t\t\t<h1>" + message + "</h1>\n\t\t\t</div>\n\t\t</div>\n\t</body>\n</html>\n"
|
|
23
23
|
},
|
|
24
|
-
version_hash: "
|
|
24
|
+
version_hash: "1nwz0uu"
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
export async function get_hooks() {
|
package/dist/app.postcss
CHANGED
|
@@ -92,7 +92,7 @@ ul {
|
|
|
92
92
|
.default-page-container {
|
|
93
93
|
@apply flex justify-center items-center;
|
|
94
94
|
margin-top: 4em;
|
|
95
|
-
margin-left:
|
|
95
|
+
margin-left: 1em;
|
|
96
96
|
margin-right: 1em;
|
|
97
97
|
flex-direction: column;
|
|
98
98
|
z-index: 0;
|
|
@@ -191,3 +191,17 @@ a:active {
|
|
|
191
191
|
background: rgba(var(--color-secondary-500));
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
+
.dialog-box {
|
|
195
|
+
background-color: rgb(var(--color-surface-500) / 0.9);
|
|
196
|
+
position: fixed;
|
|
197
|
+
bottom: 0;
|
|
198
|
+
width: var(--dialog-box-width); /*75em + 4em padding*/
|
|
199
|
+
height: var(--dialog-box-height);
|
|
200
|
+
max-width: calc(100vw - ((var(--fab-margin) * 2) + 4em));
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.dark .dialog-box {
|
|
204
|
+
background-color: rgb(var(--color-surface-900) / 0.95);
|
|
205
|
+
--tw-ring-color: rgb(var(--color-text-400));
|
|
206
|
+
/*background-color: red;*/
|
|
207
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script>import AresHappy from "../assets/characters/ares/ares_happy.webp";
|
|
2
2
|
import { onMount } from "svelte";
|
|
3
3
|
import { dialogManager } from "./dialog_manager/DialogManagerStore";
|
|
4
|
+
import { DialogState } from "../types/pineapple_fiber/DialogState";
|
|
4
5
|
let currentMessage = "";
|
|
5
6
|
dialogManager.currentMessage.subscribe((value) => {
|
|
6
7
|
currentMessage = value;
|
|
@@ -15,15 +16,25 @@ onMount(() => {
|
|
|
15
16
|
dialogManager.update(0);
|
|
16
17
|
});
|
|
17
18
|
let hidePercent = 100;
|
|
19
|
+
let isHidden = true;
|
|
18
20
|
dialogManager.hidePercent.subscribe((value) => {
|
|
19
21
|
hidePercent = value * 0.4;
|
|
22
|
+
isHidden = false;
|
|
23
|
+
});
|
|
24
|
+
dialogManager.currentReadableState.subscribe((value) => {
|
|
25
|
+
isHidden = value === DialogState.Invisible;
|
|
26
|
+
if (value === DialogState.Invisible) {
|
|
27
|
+
}
|
|
20
28
|
});
|
|
21
29
|
const onDialogClick = () => {
|
|
22
30
|
dialogManager.skipAnimation();
|
|
23
31
|
};
|
|
24
32
|
</script>
|
|
25
33
|
|
|
26
|
-
<div class="dialog-elements"
|
|
34
|
+
<div class="dialog-elements"
|
|
35
|
+
hidden={isHidden}
|
|
36
|
+
style="--hidePercentWidth: -{hidePercent}vw;
|
|
37
|
+
--hidePercentHeight: {hidePercent}vh;">
|
|
27
38
|
<img src={currentPortrait} alt="Ares" class="dialog-portrait" />
|
|
28
39
|
<div class="card dialog-box variant-ghost-primary" on:click={onDialogClick}>
|
|
29
40
|
<div class="card dialog-name">
|
|
@@ -37,59 +48,49 @@ const onDialogClick = () => {
|
|
|
37
48
|
</div>
|
|
38
49
|
|
|
39
50
|
<style>
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
.dialog-elements > img {
|
|
46
|
-
transform: translateX(var(--hidePercentWidth));
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
.dialog-elements > div {
|
|
50
|
-
transform: translateY(var(--hidePercentHeight));
|
|
51
|
-
}
|
|
51
|
+
.dialog-elements {
|
|
52
|
+
position: fixed;
|
|
53
|
+
z-index: 10;
|
|
54
|
+
}
|
|
52
55
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
bottom: 0;
|
|
57
|
-
left: var(--dialog-left-pad);
|
|
56
|
+
.dialog-elements > img {
|
|
57
|
+
transform: translateX(var(--hidePercentWidth));
|
|
58
|
+
}
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
.dialog-elements > div {
|
|
61
|
+
transform: translateY(var(--hidePercentHeight));
|
|
62
|
+
}
|
|
62
63
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
.dialog-box *,
|
|
65
|
+
.dialog-name * {
|
|
66
|
+
font-size: clamp(1em, 5vw, 1.3em);
|
|
67
|
+
line-height: 1.5em;
|
|
68
|
+
}
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
.dialog-padding :global(p) {
|
|
71
|
+
font-size: clamp(1em, 5vw, 1.3em) !important;
|
|
72
|
+
line-height: 1.5em !important;
|
|
73
|
+
}
|
|
73
74
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
.dialog-padding {
|
|
76
|
+
padding: clamp(1.5em, 5vw, 1.75em) clamp(0em, 5vw - 0.5em, 2em) 0;
|
|
77
|
+
}
|
|
77
78
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
79
|
+
.dialog-name {
|
|
80
|
+
padding-left: 1rem;
|
|
81
|
+
padding-right: 1rem;
|
|
82
|
+
padding-top: 0.5rem;
|
|
83
|
+
position: fixed;
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
/* for centering vertically */
|
|
86
|
+
transform: translateX(clamp(0em, 5vw - 0.5em, 1em)) translateY(-50%);
|
|
86
87
|
}
|
|
87
88
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
89
|
+
.dialog-portrait {
|
|
90
|
+
position: fixed;
|
|
91
|
+
bottom: 0;
|
|
92
|
+
left: clamp(-4rem, calc(5vw - 5em), 0rem);
|
|
93
|
+
height: clamp(30rem, 75vw, 40rem);
|
|
94
|
+
width: auto;
|
|
95
|
+
}
|
|
95
96
|
</style>
|
|
@@ -8,7 +8,7 @@ import { DialogProcessor } from "./DialogProcessor";
|
|
|
8
8
|
export type OnSetDialogChoiceCallback = (newMessage: DialogDetail) => void;
|
|
9
9
|
export declare class DialogManager {
|
|
10
10
|
dialogMessageMap: Map<string, DialogDetail>;
|
|
11
|
-
|
|
11
|
+
currentDialogTree: DialogDetail[];
|
|
12
12
|
fullCurrentMessage: string;
|
|
13
13
|
currentMessageMeta: DialogDetail;
|
|
14
14
|
currentMessage: import("svelte/store").Writable<string>;
|
|
@@ -18,12 +18,14 @@ export declare class DialogManager {
|
|
|
18
18
|
currentPortrait: import("svelte/store").Writable<unknown>;
|
|
19
19
|
portraitMap: Map<string, any>;
|
|
20
20
|
currentState: DialogState;
|
|
21
|
+
currentReadableState: import("svelte/store").Writable<DialogState>;
|
|
21
22
|
hidePercent: import("svelte/motion").Tweened<number>;
|
|
22
23
|
skipNextActiveTime: number;
|
|
23
24
|
dialogProcessor: DialogProcessor;
|
|
24
25
|
_setDialogChoiceQueue: DialogDetail[];
|
|
25
26
|
_setDialogChoiceMutex: boolean;
|
|
26
27
|
onSetDialogListeners: OnSetDialogChoiceCallback[];
|
|
28
|
+
enableDialogueOverlayCache: boolean;
|
|
27
29
|
constructor();
|
|
28
30
|
/**
|
|
29
31
|
* when users interact with the dialog, they can skip the transition like in a game
|
|
@@ -39,9 +41,9 @@ export declare class DialogManager {
|
|
|
39
41
|
* sets the possible dialog that might appear on the Dialog UI
|
|
40
42
|
* note that it overwrites the previous tree and does not append on it due to the possibility
|
|
41
43
|
* of node name conflicts
|
|
42
|
-
* @param
|
|
44
|
+
* @param newDialogTree
|
|
43
45
|
*/
|
|
44
|
-
setDialogTree: (
|
|
46
|
+
setDialogTree: (newDialogTree: DialogDetail[]) => void;
|
|
45
47
|
/**
|
|
46
48
|
* Remember to call this before SetDialogTree
|
|
47
49
|
* and unsubscribe during onDestroy
|
|
@@ -74,4 +76,7 @@ export declare class DialogManager {
|
|
|
74
76
|
* ISSUE #81 https://github.com/TurnipXenon/pineapple/issues/81
|
|
75
77
|
*/
|
|
76
78
|
update: (timestamp: number) => void;
|
|
79
|
+
enableDialogOverlay(enable: boolean): void;
|
|
80
|
+
toggleDialogOverlay(): void;
|
|
81
|
+
parseAndSetDialogTree(dialogYarn: string): Promise<DialogDetail[]>;
|
|
77
82
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { writable } from "svelte/store";
|
|
5
5
|
import { DialogState } from "../../types/pineapple_fiber/DialogState";
|
|
6
6
|
import { tweened } from "svelte/motion";
|
|
7
|
-
import {
|
|
7
|
+
import { backOut } from "svelte/easing";
|
|
8
8
|
import { PortraitType } from "../../types/pineapple_fiber/PortraitType";
|
|
9
9
|
import AresHappy from "../../assets/characters/ares/ares_happy.webp";
|
|
10
10
|
import AresBlushing from "../../assets/characters/ares/ares_blushing.webp";
|
|
@@ -17,10 +17,11 @@ import AresSurprised from "../../assets/characters/ares/ares_surprised.webp";
|
|
|
17
17
|
import AresYay from "../../assets/characters/ares/ares_yay.webp";
|
|
18
18
|
import { defaultDialogMessage, dialogVariableStore, enableDialogueOverlay, updateRate } from "./DialogManagerStore";
|
|
19
19
|
import { DialogProcessor } from "./DialogProcessor";
|
|
20
|
+
import { parseYarn } from "../../scripts/pineapple_fiber/PineappleFiberParser";
|
|
20
21
|
const shouldDebugYarn = false;
|
|
21
22
|
export class DialogManager {
|
|
22
23
|
dialogMessageMap = new Map();
|
|
23
|
-
|
|
24
|
+
currentDialogTree = [];
|
|
24
25
|
fullCurrentMessage = defaultDialogMessage[0].textContent;
|
|
25
26
|
currentMessageMeta = defaultDialogMessage[0];
|
|
26
27
|
currentMessage = writable("");
|
|
@@ -30,9 +31,10 @@ export class DialogManager {
|
|
|
30
31
|
currentPortrait = writable();
|
|
31
32
|
portraitMap = new Map();
|
|
32
33
|
currentState = DialogState.Visible;
|
|
34
|
+
currentReadableState = writable(this.currentState);
|
|
33
35
|
hidePercent = tweened(100, {
|
|
34
36
|
duration: 400,
|
|
35
|
-
easing:
|
|
37
|
+
easing: backOut
|
|
36
38
|
}); // 100 = 100%
|
|
37
39
|
skipNextActiveTime = 0;
|
|
38
40
|
dialogProcessor = new DialogProcessor();
|
|
@@ -40,16 +42,23 @@ export class DialogManager {
|
|
|
40
42
|
_setDialogChoiceQueue = [];
|
|
41
43
|
_setDialogChoiceMutex = false;
|
|
42
44
|
onSetDialogListeners = [];
|
|
45
|
+
enableDialogueOverlayCache = false;
|
|
43
46
|
constructor() {
|
|
44
47
|
enableDialogueOverlay.subscribe((value) => {
|
|
45
48
|
// todo: investigate why we cant put setDialogDefault inside the then clause
|
|
46
49
|
// ISSUE #82 https://github.com/TurnipXenon/pineapple/issues/82
|
|
50
|
+
this.enableDialogueOverlayCache = value;
|
|
47
51
|
if (value) {
|
|
48
|
-
this.hidePercent.set(0)
|
|
49
|
-
|
|
52
|
+
this.hidePercent.set(0).then(() => {
|
|
53
|
+
this.currentState = DialogState.Visible;
|
|
54
|
+
this.currentReadableState.set(this.currentState);
|
|
55
|
+
});
|
|
50
56
|
}
|
|
51
57
|
else {
|
|
52
|
-
this.hidePercent.set(100)
|
|
58
|
+
this.hidePercent.set(100).then(() => {
|
|
59
|
+
this.currentState = DialogState.Invisible;
|
|
60
|
+
this.currentReadableState.set(this.currentState);
|
|
61
|
+
});
|
|
53
62
|
this.setDialogTree([{ textContent: "" }]);
|
|
54
63
|
}
|
|
55
64
|
});
|
|
@@ -78,12 +87,12 @@ export class DialogManager {
|
|
|
78
87
|
* sets the possible dialog that might appear on the Dialog UI
|
|
79
88
|
* note that it overwrites the previous tree and does not append on it due to the possibility
|
|
80
89
|
* of node name conflicts
|
|
81
|
-
* @param
|
|
90
|
+
* @param newDialogTree
|
|
82
91
|
*/
|
|
83
|
-
setDialogTree = (
|
|
84
|
-
this.
|
|
92
|
+
setDialogTree = (newDialogTree) => {
|
|
93
|
+
this.currentDialogTree = newDialogTree;
|
|
85
94
|
this.dialogMessageMap.clear();
|
|
86
|
-
|
|
95
|
+
newDialogTree.map((value) => {
|
|
87
96
|
if (value.dialogId) {
|
|
88
97
|
this.dialogMessageMap.set(value.dialogId, value);
|
|
89
98
|
}
|
|
@@ -100,7 +109,7 @@ export class DialogManager {
|
|
|
100
109
|
this.portraitMap.set(PortraitType.AresSurprised.toString(), AresSurprised);
|
|
101
110
|
this.portraitMap.set(PortraitType.AresYay.toString(), AresYay);
|
|
102
111
|
}
|
|
103
|
-
this.setDialogChoice(
|
|
112
|
+
this.setDialogChoice(newDialogTree[0]);
|
|
104
113
|
};
|
|
105
114
|
/**
|
|
106
115
|
* Remember to call this before SetDialogTree
|
|
@@ -236,4 +245,19 @@ export class DialogManager {
|
|
|
236
245
|
++this.currentIndex;
|
|
237
246
|
window.requestAnimationFrame(this.update);
|
|
238
247
|
};
|
|
248
|
+
enableDialogOverlay(enable) {
|
|
249
|
+
enableDialogueOverlay.set(enable);
|
|
250
|
+
}
|
|
251
|
+
toggleDialogOverlay() {
|
|
252
|
+
enableDialogueOverlay.set(!this.enableDialogueOverlayCache);
|
|
253
|
+
}
|
|
254
|
+
;
|
|
255
|
+
async parseAndSetDialogTree(dialogYarn) {
|
|
256
|
+
return parseYarn(dialogYarn)
|
|
257
|
+
.then((dialogTree) => {
|
|
258
|
+
console.log(dialogTree);
|
|
259
|
+
this.setDialogTree(dialogTree);
|
|
260
|
+
return dialogTree;
|
|
261
|
+
});
|
|
262
|
+
}
|
|
239
263
|
}
|
|
@@ -26,7 +26,7 @@ export const updateRate = 40 / 1000; // *at least* 40ms per letter
|
|
|
26
26
|
// todo: if we go through doing yarn to typescript, move this!
|
|
27
27
|
export const defaultDialogMessage = [
|
|
28
28
|
{
|
|
29
|
-
textContent: `<p>Have you drank water? Or perhaps, you've checked out <a target="_blank" class="external-link" href="http://crouton.net">one of the best webpages</a> out there?`
|
|
29
|
+
textContent: `<p>I don't really have anything to say. Have you drank water? Or perhaps, you've checked out <a target="_blank" class="external-link" href="http://crouton.net">one of the best webpages</a> out there?`
|
|
30
30
|
}
|
|
31
31
|
];
|
|
32
32
|
/**
|
|
@@ -56,8 +56,8 @@ let shouldDisplaySocialIcons = writable(false);
|
|
|
56
56
|
|
|
57
57
|
<style>
|
|
58
58
|
:root {
|
|
59
|
-
--dialog-
|
|
60
|
-
--dialog-box-width: min(calc(50em + 4em), calc(100vw - var(--dialog-
|
|
59
|
+
--dialog-start-pad: clamp(0em, 5vw, 2em);
|
|
60
|
+
--dialog-box-width: min(calc(50em + 4em), calc(100vw - var(--dialog-start-pad) - var(--theme-border-base)));
|
|
61
61
|
--dialog-box-height: clamp(15em, 50vw, 18em);
|
|
62
62
|
}
|
|
63
63
|
|