@turnipxenon/pineapple 2.4.13 → 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/discord.xml +1 -1
- package/.idea/workspace.xml +179 -149
- package/.svelte-kit/__package__/app.postcss +43 -3
- package/.svelte-kit/__package__/assets/icons/close.svg +1 -0
- package/.svelte-kit/__package__/components/Card.svelte +1 -1
- package/.svelte-kit/__package__/components/Chip.svelte +1 -0
- 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/{layouts → pineapple}/PineappleBaseLayout.svelte +66 -30
- package/.svelte-kit/__package__/components/pineapple/toast/DefaultToastBody.d.ts +8 -0
- package/.svelte-kit/__package__/components/pineapple/toast/DefaultToastBody.js +1 -0
- package/.svelte-kit/__package__/components/pineapple/toast/DefaultToastBody.svelte +48 -0
- package/.svelte-kit/__package__/components/pineapple/toast/DefaultToastBody.svelte.d.ts +20 -0
- package/.svelte-kit/__package__/components/pineapple/toast/Toast.d.ts +27 -0
- package/.svelte-kit/__package__/components/pineapple/toast/Toast.js +37 -0
- package/.svelte-kit/__package__/components/pineapple/toast/Toast.svelte +90 -0
- package/.svelte-kit/__package__/components/pineapple/toast/Toast.svelte.d.ts +14 -0
- package/.svelte-kit/__package__/components/pineapple/toast/custom-toast/TestCustomToast.d.ts +5 -0
- package/.svelte-kit/__package__/components/pineapple/toast/custom-toast/TestCustomToast.js +1 -0
- package/.svelte-kit/__package__/components/pineapple/toast/custom-toast/TestCustomToast.svelte +1 -0
- package/.svelte-kit/__package__/components/pineapple/toast/custom-toast/TestCustomToast.svelte.d.ts +23 -0
- package/.svelte-kit/__package__/index.d.ts +1 -1
- package/.svelte-kit/__package__/index.js +1 -1
- 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/client/app.js +1 -1
- package/.svelte-kit/generated/client/nodes/5.js +1 -1
- package/.svelte-kit/generated/server/internal.js +1 -1
- package/.svelte-kit/types/route_meta_data.json +1 -1
- package/.svelte-kit/types/src/routes/$types.d.ts +1 -1
- package/.svelte-kit/types/src/routes/(pineapple)/$types.d.ts +1 -1
- package/.svelte-kit/types/src/routes/(pineapple)/{personal → pineapple}/$types.d.ts +1 -1
- package/dist/app.postcss +43 -3
- package/dist/assets/icons/close.svg +1 -0
- package/dist/components/Card.svelte +1 -1
- package/dist/components/Chip.svelte +1 -0
- 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/{layouts → pineapple}/PineappleBaseLayout.svelte +66 -30
- package/dist/components/pineapple/toast/DefaultToastBody.d.ts +8 -0
- package/dist/components/pineapple/toast/DefaultToastBody.js +1 -0
- package/dist/components/pineapple/toast/DefaultToastBody.svelte +48 -0
- package/dist/components/pineapple/toast/DefaultToastBody.svelte.d.ts +20 -0
- package/dist/components/pineapple/toast/Toast.d.ts +27 -0
- package/dist/components/pineapple/toast/Toast.js +37 -0
- package/dist/components/pineapple/toast/Toast.svelte +90 -0
- package/dist/components/pineapple/toast/Toast.svelte.d.ts +14 -0
- package/dist/components/pineapple/toast/custom-toast/TestCustomToast.d.ts +5 -0
- package/dist/components/pineapple/toast/custom-toast/TestCustomToast.js +1 -0
- package/dist/components/pineapple/toast/custom-toast/TestCustomToast.svelte +1 -0
- package/dist/components/pineapple/toast/custom-toast/TestCustomToast.svelte.d.ts +23 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- 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/docs/OverlaySpec.md +23 -0
- package/docs/pull_request_template.md +34 -0
- package/package.json +1 -1
- package/src/lib/app.postcss +43 -3
- package/src/lib/assets/icons/close.svg +1 -0
- package/src/lib/components/Card.svelte +1 -1
- package/src/lib/components/Chip.svelte +1 -0
- 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 +220 -0
- package/src/lib/components/pineapple/toast/DefaultToastBody.svelte +43 -0
- package/src/lib/components/pineapple/toast/DefaultToastBody.ts +10 -0
- package/src/lib/components/pineapple/toast/Toast.svelte +114 -0
- package/src/lib/components/pineapple/toast/Toast.ts +57 -0
- package/src/lib/components/pineapple/toast/custom-toast/TestCustomToast.svelte +1 -0
- package/src/lib/components/pineapple/toast/custom-toast/TestCustomToast.ts +6 -0
- package/src/lib/index.ts +1 -1
- 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)/+layout.svelte +1 -1
- package/src/routes/(pineapple)/+page.svelte +3 -3
- package/src/routes/(pineapple)/pineapple/+page.svelte +62 -0
- package/src/routes/(pineapple)/pineapple/TestDialog.yarn +7 -0
- package/vite.config.ts +2 -1
- package/src/lib/components/layouts/PineappleBaseLayout.svelte +0 -182
- package/src/routes/(pineapple)/personal/+page.svelte +0 -37
- /package/.svelte-kit/__package__/components/{layouts → pineapple}/PineappleBaseLayout.svelte.d.ts +0 -0
- /package/dist/components/{layouts → pineapple}/PineappleBaseLayout.svelte.d.ts +0 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import type { DialogDetail } from "$pkg/types/pineapple_fiber/DialogDetail";
|
|
2
|
+
import { PortraitType } from "$pkg/types/pineapple_fiber/PortraitType";
|
|
3
|
+
|
|
4
|
+
interface ChoiceDetail {
|
|
5
|
+
name: string;
|
|
6
|
+
jumpNode: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const shouldDebug = false;
|
|
10
|
+
|
|
11
|
+
export const parseYarn = async (fileContent: string): Promise<DialogDetail[]> => {
|
|
12
|
+
const dialogDetailList: DialogDetail[] = [];
|
|
13
|
+
|
|
14
|
+
fileContent.split("===").map((unparsedNode) => {
|
|
15
|
+
// todo: detect empty nodes
|
|
16
|
+
// todo: improve the code readability
|
|
17
|
+
if (unparsedNode.trim() === "") {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const dialogDetails: DialogDetail = {
|
|
22
|
+
// todo: dissect the line below and give comments because it is complex
|
|
23
|
+
dialogId: unparsedNode
|
|
24
|
+
.slice(unparsedNode.indexOf("title: "))
|
|
25
|
+
.split("\n")[0]
|
|
26
|
+
.split(" ")
|
|
27
|
+
.pop()
|
|
28
|
+
?.trim(),
|
|
29
|
+
portraitType: PortraitType.AresNeutral,
|
|
30
|
+
textContent: "" // will be filled later below
|
|
31
|
+
};
|
|
32
|
+
let portraitUnset = true;
|
|
33
|
+
|
|
34
|
+
// parse the PineappleFiber metatags
|
|
35
|
+
const unparsedBody = unparsedNode.split("---").pop()!.trim();
|
|
36
|
+
const bodyList = unparsedBody.split("\n");
|
|
37
|
+
let contentIndexStart = 0;
|
|
38
|
+
for (let index = 0; index < bodyList.length; index++) {
|
|
39
|
+
const possibleTagPair = bodyList[index].split(": ");
|
|
40
|
+
const possibleTagName = possibleTagPair[0].toLowerCase();
|
|
41
|
+
|
|
42
|
+
if (!["portrait"].includes(possibleTagName)) {
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
contentIndexStart = index + 1; // increase count for each viable tah
|
|
47
|
+
switch (possibleTagName) {
|
|
48
|
+
case "portrait":
|
|
49
|
+
portraitUnset = false;
|
|
50
|
+
// todo: implement a way to match the appropriate portrait based on the metatag
|
|
51
|
+
// from https://stackoverflow.com/a/17381004/17836168
|
|
52
|
+
dialogDetails.portraitType =
|
|
53
|
+
PortraitType[possibleTagPair[1].trim() as keyof typeof PortraitType];
|
|
54
|
+
if (shouldDebug) {
|
|
55
|
+
console.log(
|
|
56
|
+
"Portrait detected:",
|
|
57
|
+
possibleTagPair[1],
|
|
58
|
+
" => ",
|
|
59
|
+
dialogDetails.portraitType
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// portrait check
|
|
67
|
+
if (portraitUnset) {
|
|
68
|
+
console.warn(`Portrait missing for node: ${dialogDetails.dialogId}`);
|
|
69
|
+
dialogDetails.portraitType = PortraitType.AresNeutral;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// remove the metatags from the body
|
|
73
|
+
const unprocessedContent = bodyList.slice(contentIndexStart).join("\n");
|
|
74
|
+
const contentPair = unprocessedContent.split("<ChoiceBreak>");
|
|
75
|
+
|
|
76
|
+
if (contentPair.length === 2) {
|
|
77
|
+
// parse for the choice names in the options
|
|
78
|
+
enum ChoiceParsingState {
|
|
79
|
+
Free, // detects for the next option
|
|
80
|
+
Line // previously detected an option, will try to detect for the next option
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
let parsingState: ChoiceParsingState = ChoiceParsingState.Free;
|
|
84
|
+
const currentChoiceDetail: ChoiceDetail = { jumpNode: "", name: "" };
|
|
85
|
+
const choiceList: ChoiceDetail[] = [];
|
|
86
|
+
let shouldSkipChoices = false;
|
|
87
|
+
|
|
88
|
+
const checkChoiceForSave = () => {
|
|
89
|
+
if (currentChoiceDetail.name !== "") {
|
|
90
|
+
choiceList.push({
|
|
91
|
+
name: currentChoiceDetail.name,
|
|
92
|
+
jumpNode: currentChoiceDetail.jumpNode
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
contentPair[1]
|
|
98
|
+
.trim()
|
|
99
|
+
.split("\n")
|
|
100
|
+
.filter((line) => {
|
|
101
|
+
const trimmedLine = line.trim();
|
|
102
|
+
if (shouldSkipChoices) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (trimmedLine.startsWith("// ignore the rest")) {
|
|
107
|
+
shouldSkipChoices = true;
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return true;
|
|
112
|
+
})
|
|
113
|
+
.map((line) => {
|
|
114
|
+
const trimmedLine = line.trim();
|
|
115
|
+
|
|
116
|
+
switch (parsingState) {
|
|
117
|
+
case ChoiceParsingState.Free:
|
|
118
|
+
if (trimmedLine.startsWith("->")) {
|
|
119
|
+
// save previous choice
|
|
120
|
+
checkChoiceForSave();
|
|
121
|
+
|
|
122
|
+
// write start of new choice
|
|
123
|
+
currentChoiceDetail.name = trimmedLine.split(" ").pop()!;
|
|
124
|
+
parsingState = ChoiceParsingState.Line;
|
|
125
|
+
}
|
|
126
|
+
break;
|
|
127
|
+
|
|
128
|
+
case ChoiceParsingState.Line:
|
|
129
|
+
if (trimmedLine.startsWith("<<jump")) {
|
|
130
|
+
const jumpNode = trimmedLine.split(" ").pop()!;
|
|
131
|
+
currentChoiceDetail.jumpNode = jumpNode.slice(0, jumpNode.length - 2); // remove ">>"
|
|
132
|
+
parsingState = ChoiceParsingState.Free;
|
|
133
|
+
}
|
|
134
|
+
break;
|
|
135
|
+
|
|
136
|
+
default:
|
|
137
|
+
console.error(`Unimplemented parsing state: ${parsingState}`);
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
checkChoiceForSave();
|
|
142
|
+
|
|
143
|
+
dialogDetails.textContent = contentPair[0];
|
|
144
|
+
|
|
145
|
+
// handle choice start tags to a href
|
|
146
|
+
choiceList.forEach((choiceDetail) => {
|
|
147
|
+
const keyword = `<choice ${choiceDetail.name}>`;
|
|
148
|
+
while (dialogDetails.textContent.includes(keyword)) {
|
|
149
|
+
dialogDetails.textContent = dialogDetails.textContent.replace(
|
|
150
|
+
keyword,
|
|
151
|
+
`<a class="choice-${choiceDetail.jumpNode} dialog-choice" title="Click to continue the dialog">`
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
const externalKeyword = "<a href=";
|
|
157
|
+
while (dialogDetails.textContent.includes(externalKeyword)) {
|
|
158
|
+
dialogDetails.textContent = dialogDetails.textContent.replace(
|
|
159
|
+
externalKeyword,
|
|
160
|
+
"<a target=\"_blank\" class=\"external-link\" href="
|
|
161
|
+
); // make all external tags with a custom cursor
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const choiceEndKeyword = "</choice>";
|
|
165
|
+
while (dialogDetails.textContent.includes(choiceEndKeyword)) {
|
|
166
|
+
dialogDetails.textContent = dialogDetails.textContent.replace(choiceEndKeyword, "</a>"); // convert all choice end tags to a tags
|
|
167
|
+
}
|
|
168
|
+
} else {
|
|
169
|
+
// assume only one which indicates it is choiceless
|
|
170
|
+
dialogDetails.textContent = unprocessedContent;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
dialogDetailList.push(dialogDetails);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
return dialogDetailList;
|
|
177
|
+
};
|
|
@@ -11,190 +11,17 @@ import { getAllFiles } from "$pkg/scripts/util/FileManagement";
|
|
|
11
11
|
import fs, { readFileSync } from "fs";
|
|
12
12
|
import type { DialogDetail } from "$pkg/types/pineapple_fiber/DialogDetail";
|
|
13
13
|
import { PortraitType } from "$pkg/types/pineapple_fiber/PortraitType";
|
|
14
|
-
|
|
15
|
-
// import { getAllFiles } from "../util/FileManagement";
|
|
16
|
-
// import fs, { readFileSync } from "fs";
|
|
17
|
-
// import type { DialogDetail } from "../../types/pineapple_fiber/DialogDetail";
|
|
18
|
-
// import { PortraitType } from "../../types/pineapple_fiber/PortraitType";
|
|
19
|
-
|
|
20
|
-
interface ChoiceDetail {
|
|
21
|
-
name: string;
|
|
22
|
-
jumpNode: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const shouldDebug = false;
|
|
14
|
+
import { parseYarn } from "$pkg/scripts/pineapple_fiber/PineappleFiberParser";
|
|
26
15
|
|
|
27
16
|
const pineappleWeaverRun = () => {
|
|
28
17
|
console.info("Starting Pineapple Weaver.");
|
|
29
18
|
const BASE_PATH = "./src/routes";
|
|
30
19
|
getAllFiles(BASE_PATH, (path: string): boolean => {
|
|
31
20
|
return path.split(".").pop() === "yarn";
|
|
32
|
-
}).map((filePath) => {
|
|
21
|
+
}).map(async (filePath) => {
|
|
33
22
|
console.info(`Converting: ${filePath}`);
|
|
34
23
|
const fileContent = readFileSync(filePath, "utf-8");
|
|
35
|
-
const dialogDetailList: DialogDetail[] =
|
|
36
|
-
|
|
37
|
-
fileContent.split("===").map((unparsedNode) => {
|
|
38
|
-
// todo: detect empty nodes
|
|
39
|
-
// todo: improve the code readability
|
|
40
|
-
if (unparsedNode.trim() === "") {
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const dialogDetails: DialogDetail = {
|
|
45
|
-
// todo: dissect the line below and give comments because it is complex
|
|
46
|
-
dialogId: unparsedNode
|
|
47
|
-
.slice(unparsedNode.indexOf("title: "))
|
|
48
|
-
.split("\n")[0]
|
|
49
|
-
.split(" ")
|
|
50
|
-
.pop()
|
|
51
|
-
?.trim(),
|
|
52
|
-
portraitType: PortraitType.AresNeutral,
|
|
53
|
-
textContent: "" // will be filled later below
|
|
54
|
-
};
|
|
55
|
-
let portraitUnset = true;
|
|
56
|
-
|
|
57
|
-
// parse the PineappleFiber metatags
|
|
58
|
-
const unparsedBody = unparsedNode.split("---").pop()!.trim();
|
|
59
|
-
const bodyList = unparsedBody.split("\n");
|
|
60
|
-
let contentIndexStart = 0;
|
|
61
|
-
for (let index = 0; index < bodyList.length; index++) {
|
|
62
|
-
const possibleTagPair = bodyList[index].split(": ");
|
|
63
|
-
const possibleTagName = possibleTagPair[0].toLowerCase();
|
|
64
|
-
|
|
65
|
-
if (!["portrait"].includes(possibleTagName)) {
|
|
66
|
-
break;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
contentIndexStart = index + 1; // increase count for each viable tah
|
|
70
|
-
switch (possibleTagName) {
|
|
71
|
-
case "portrait":
|
|
72
|
-
portraitUnset = false;
|
|
73
|
-
// todo: implement a way to match the appropriate portrait based on the metatag
|
|
74
|
-
// from https://stackoverflow.com/a/17381004/17836168
|
|
75
|
-
dialogDetails.portraitType =
|
|
76
|
-
PortraitType[possibleTagPair[1].trim() as keyof typeof PortraitType];
|
|
77
|
-
if (shouldDebug) {
|
|
78
|
-
console.log(
|
|
79
|
-
"Portrait detected:",
|
|
80
|
-
possibleTagPair[1],
|
|
81
|
-
" => ",
|
|
82
|
-
dialogDetails.portraitType
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
break;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// portrait check
|
|
90
|
-
if (portraitUnset) {
|
|
91
|
-
console.warn(`Portrait missing for node: ${dialogDetails.dialogId}`);
|
|
92
|
-
dialogDetails.portraitType = PortraitType.AresNeutral;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// remove the metatags from the body
|
|
96
|
-
const unprocessedContent = bodyList.slice(contentIndexStart).join("\n");
|
|
97
|
-
const contentPair = unprocessedContent.split("<ChoiceBreak>");
|
|
98
|
-
|
|
99
|
-
if (contentPair.length === 2) {
|
|
100
|
-
// parse for the choice names in the options
|
|
101
|
-
enum ChoiceParsingState {
|
|
102
|
-
Free, // detects for the next option
|
|
103
|
-
Line // previously detected an option, will try to detect for the next option
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
let parsingState: ChoiceParsingState = ChoiceParsingState.Free;
|
|
107
|
-
const currentChoiceDetail: ChoiceDetail = { jumpNode: "", name: "" };
|
|
108
|
-
const choiceList: ChoiceDetail[] = [];
|
|
109
|
-
let shouldSkipChoices = false;
|
|
110
|
-
|
|
111
|
-
const checkChoiceForSave = () => {
|
|
112
|
-
if (currentChoiceDetail.name !== "") {
|
|
113
|
-
choiceList.push({
|
|
114
|
-
name: currentChoiceDetail.name,
|
|
115
|
-
jumpNode: currentChoiceDetail.jumpNode
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
contentPair[1]
|
|
121
|
-
.trim()
|
|
122
|
-
.split("\n")
|
|
123
|
-
.filter((line) => {
|
|
124
|
-
const trimmedLine = line.trim();
|
|
125
|
-
if (shouldSkipChoices) {
|
|
126
|
-
return false;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
if (trimmedLine.startsWith("// ignore the rest")) {
|
|
130
|
-
shouldSkipChoices = true;
|
|
131
|
-
return false;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return true;
|
|
135
|
-
})
|
|
136
|
-
.map((line) => {
|
|
137
|
-
const trimmedLine = line.trim();
|
|
138
|
-
|
|
139
|
-
switch (parsingState) {
|
|
140
|
-
case ChoiceParsingState.Free:
|
|
141
|
-
if (trimmedLine.startsWith("->")) {
|
|
142
|
-
// save previous choice
|
|
143
|
-
checkChoiceForSave();
|
|
144
|
-
|
|
145
|
-
// write start of new choice
|
|
146
|
-
currentChoiceDetail.name = trimmedLine.split(" ").pop()!;
|
|
147
|
-
parsingState = ChoiceParsingState.Line;
|
|
148
|
-
}
|
|
149
|
-
break;
|
|
150
|
-
|
|
151
|
-
case ChoiceParsingState.Line:
|
|
152
|
-
if (trimmedLine.startsWith("<<jump")) {
|
|
153
|
-
const jumpNode = trimmedLine.split(" ").pop()!;
|
|
154
|
-
currentChoiceDetail.jumpNode = jumpNode.slice(0, jumpNode.length - 2); // remove ">>"
|
|
155
|
-
parsingState = ChoiceParsingState.Free;
|
|
156
|
-
}
|
|
157
|
-
break;
|
|
158
|
-
|
|
159
|
-
default:
|
|
160
|
-
console.error(`Unimplemented parsing state: ${parsingState}`);
|
|
161
|
-
break;
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
checkChoiceForSave();
|
|
165
|
-
|
|
166
|
-
dialogDetails.textContent = contentPair[0];
|
|
167
|
-
|
|
168
|
-
// handle choice start tags to a href
|
|
169
|
-
choiceList.forEach((choiceDetail) => {
|
|
170
|
-
const keyword = `<choice ${choiceDetail.name}>`;
|
|
171
|
-
while (dialogDetails.textContent.includes(keyword)) {
|
|
172
|
-
dialogDetails.textContent = dialogDetails.textContent.replace(
|
|
173
|
-
keyword,
|
|
174
|
-
`<a class="choice-${choiceDetail.jumpNode} dialog-choice" title="Click to continue the dialog">`
|
|
175
|
-
);
|
|
176
|
-
}
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
const externalKeyword = "<a href=";
|
|
180
|
-
while (dialogDetails.textContent.includes(externalKeyword)) {
|
|
181
|
-
dialogDetails.textContent = dialogDetails.textContent.replace(
|
|
182
|
-
externalKeyword,
|
|
183
|
-
'<a target="_blank" class="external-link" href='
|
|
184
|
-
); // make all external tags with a custom cursor
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
const choiceEndKeyword = "</choice>";
|
|
188
|
-
while (dialogDetails.textContent.includes(choiceEndKeyword)) {
|
|
189
|
-
dialogDetails.textContent = dialogDetails.textContent.replace(choiceEndKeyword, "</a>"); // convert all choice end tags to a tags
|
|
190
|
-
}
|
|
191
|
-
} else {
|
|
192
|
-
// assume only one which indicates it's choiceless
|
|
193
|
-
dialogDetails.textContent = unprocessedContent;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
dialogDetailList.push(dialogDetails);
|
|
197
|
-
});
|
|
24
|
+
const dialogDetailList: DialogDetail[] = await parseYarn(fileContent);
|
|
198
25
|
|
|
199
26
|
const dialogDetailToString = (detail: DialogDetail): string => {
|
|
200
27
|
if (detail.portraitType === undefined) {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { PUBLIC_CRINGE_USERNAME } from "$env/static/public";
|
|
3
3
|
|
|
4
4
|
import { createGoToFunction } from "$pkg/util/create_go_to_function";
|
|
5
|
-
import PineappleBaseLayout from "$pkg/components/
|
|
5
|
+
import PineappleBaseLayout from "$pkg/components/pineapple/PineappleBaseLayout.svelte";
|
|
6
6
|
</script>
|
|
7
7
|
|
|
8
8
|
<svelte:head>
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
<h1 class="mb-8">Directory</h1>
|
|
19
19
|
|
|
20
20
|
<div class="btn-group-vertical variant-filled-secondary">
|
|
21
|
-
<button on:click={createGoToFunction("
|
|
22
|
-
<button on:click={createGoToFunction("portfolio")}><h2>
|
|
21
|
+
<button on:click={createGoToFunction("pineapple")}><h2>Pineapple playground</h2></button>
|
|
22
|
+
<button on:click={createGoToFunction("portfolio")}><h2>Seaweed playrground</h2></button>
|
|
23
23
|
</div>
|
|
24
24
|
</div>
|
|
25
25
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { PUBLIC_CRINGE_USERNAME } from "$env/static/public";
|
|
3
|
+
import { showComponentInToast, showTextInToast } from "$pkg/components/pineapple/toast/Toast";
|
|
4
|
+
import TestCard from "$pkg/components/pineapple/toast/custom-toast/TestCustomToast.svelte";
|
|
5
|
+
import TestDialogYarn from "./TestDialog.yarn?raw";
|
|
6
|
+
import { dialogManager } from "$pkg";
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
let testingQueueNumber = 1;
|
|
10
|
+
const testingRandomPhrases = [
|
|
11
|
+
"Niko",
|
|
12
|
+
"Niko the Baikal seal",
|
|
13
|
+
"Niko the Baikal seal\nfrom Toba Aquarium"
|
|
14
|
+
];
|
|
15
|
+
const testDialogYarn = TestDialogYarn;
|
|
16
|
+
|
|
17
|
+
let parsed = false;
|
|
18
|
+
const onTestDialogClick = () => {
|
|
19
|
+
if (!parsed) {
|
|
20
|
+
dialogManager.parseAndSetDialogTree(testDialogYarn).then(() => {
|
|
21
|
+
dialogManager.toggleDialogOverlay();
|
|
22
|
+
});
|
|
23
|
+
parsed = true;
|
|
24
|
+
} else {
|
|
25
|
+
dialogManager.toggleDialogOverlay();
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<svelte:head>
|
|
31
|
+
<title>Welcome to {PUBLIC_CRINGE_USERNAME}'s Home</title>
|
|
32
|
+
<meta content="Welcome to {PUBLIC_CRINGE_USERNAME}'s Home" name="og:title" />
|
|
33
|
+
<meta
|
|
34
|
+
content="Welcome to {PUBLIC_CRINGE_USERNAME}'s home! It's a neat place to be at if you're feeling lost. Come hang around!"
|
|
35
|
+
name="og:description"
|
|
36
|
+
/>
|
|
37
|
+
</svelte:head>
|
|
38
|
+
|
|
39
|
+
<div class="card default-card">
|
|
40
|
+
<button
|
|
41
|
+
class="btn variant-filled-secondary"
|
|
42
|
+
on:click={() => {
|
|
43
|
+
showComponentInToast({componentAndProps: {component: TestCard, props: undefined}});
|
|
44
|
+
}}><h3>Test custom toast</h3></button>
|
|
45
|
+
<button
|
|
46
|
+
class="btn variant-filled-secondary"
|
|
47
|
+
on:click={() => {
|
|
48
|
+
showTextInToast(`${testingQueueNumber} ${testingRandomPhrases[testingQueueNumber]}`);
|
|
49
|
+
testingQueueNumber = (testingQueueNumber + 1) % testingRandomPhrases.length;
|
|
50
|
+
}}><h3>Handy toast</h3></button>
|
|
51
|
+
<button
|
|
52
|
+
class="btn variant-filled-secondary"
|
|
53
|
+
on:click={onTestDialogClick}><h3>Test dialog</h3></button>
|
|
54
|
+
</div>
|
|
55
|
+
|
|
56
|
+
<style lang="postcss">
|
|
57
|
+
.default-card {
|
|
58
|
+
display: flex;
|
|
59
|
+
flex-wrap: wrap;
|
|
60
|
+
gap: 2em;
|
|
61
|
+
}
|
|
62
|
+
</style>
|
package/vite.config.ts
CHANGED
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
// For auto dark/light mode
|
|
3
|
-
import {AppBar, AppShell, autoModeWatcher, LightSwitch} from "@skeletonlabs/skeleton";
|
|
4
|
-
import RandomizedBackground from "$lib/components/RandomizedBackground.svelte";
|
|
5
|
-
|
|
6
|
-
// navigation
|
|
7
|
-
import {page} from "$app/stores";
|
|
8
|
-
// store
|
|
9
|
-
import {enableBackground} from "$lib/store";
|
|
10
|
-
import type {BreadcrumbData} from "$lib/types/BreadcrumbData";
|
|
11
|
-
// assets
|
|
12
|
-
import DialogOverlay from "$lib/components/DialogOverlay.svelte";
|
|
13
|
-
import AresLogo from "$lib/assets/characters/ares/ares_logo.webp";
|
|
14
|
-
import FABIcon from "$lib/assets/placeholder/placeholder_circle.png";
|
|
15
|
-
import {enableDialogueOverlay} from "$lib/components/dialog_manager/DialogManagerStore";
|
|
16
|
-
// todo: clean up all these imports!
|
|
17
|
-
|
|
18
|
-
let pages: BreadcrumbData[] = [];
|
|
19
|
-
|
|
20
|
-
const updateBreadcrumb = (pathname: string) => {
|
|
21
|
-
pages = [];
|
|
22
|
-
let basePath = "";
|
|
23
|
-
pathname.split("/").forEach((value, index) => {
|
|
24
|
-
if (index === 0) {
|
|
25
|
-
basePath = "/";
|
|
26
|
-
pages.push({
|
|
27
|
-
path: "/",
|
|
28
|
-
name: "Home"
|
|
29
|
-
});
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (value === "") {
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
basePath += value + "/";
|
|
38
|
-
pages.push({
|
|
39
|
-
path: basePath,
|
|
40
|
-
name: value
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
pages = pages;
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
$: updateBreadcrumb($page.url.pathname); // run every time we navigate
|
|
47
|
-
|
|
48
|
-
let enableBackgroundValue = true;
|
|
49
|
-
enableBackground.subscribe((value) => {
|
|
50
|
-
enableBackgroundValue = value;
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
let enableDialogueOverlayValue = true;
|
|
54
|
-
enableDialogueOverlay.subscribe((value) => {
|
|
55
|
-
enableDialogueOverlayValue = value;
|
|
56
|
-
});
|
|
57
|
-
</script>
|
|
58
|
-
|
|
59
|
-
<!-- App Shell -->
|
|
60
|
-
<svelte:head>
|
|
61
|
-
{@html `<script>${autoModeWatcher.toString()} autoModeWatcher();</script>`}
|
|
62
|
-
</svelte:head>
|
|
63
|
-
|
|
64
|
-
<!--todo: turn off hidden when it's time-->
|
|
65
|
-
<button type="button" class="fab" on:click={()=>{
|
|
66
|
-
enableDialogueOverlay.set(!enableDialogueOverlayValue);
|
|
67
|
-
}}>
|
|
68
|
-
<img src={FABIcon} alt="interactive floating action button represented as a turnip">
|
|
69
|
-
</button>
|
|
70
|
-
|
|
71
|
-
<AppShell>
|
|
72
|
-
<svelte:fragment slot="header">
|
|
73
|
-
<!-- App Bar -->
|
|
74
|
-
<AppBar slotDefault="place-content-start" slotTrail="place-content-end">
|
|
75
|
-
<svelte:fragment slot="lead">
|
|
76
|
-
<!--TODO: add logo or something for the lead in layout-->
|
|
77
|
-
<img
|
|
78
|
-
alt="Ares's head titled towards the left with his tongue out and winking"
|
|
79
|
-
class="ares-logo"
|
|
80
|
-
src={AresLogo}
|
|
81
|
-
/>
|
|
82
|
-
<span class="mr-2"/>
|
|
83
|
-
<ol class="breadcrumb">
|
|
84
|
-
{#each pages as crumb, i}
|
|
85
|
-
{#if i < pages.length - 1}
|
|
86
|
-
<li class="crumb">
|
|
87
|
-
<a href={crumb.path}>{crumb.name.charAt(0).toUpperCase() + crumb.name.slice(1)}</a>
|
|
88
|
-
</li>
|
|
89
|
-
<li class="crumb-separator" aria-hidden="true">›</li>
|
|
90
|
-
{:else}
|
|
91
|
-
<li class="crumb">{crumb.name.charAt(0).toUpperCase() + crumb.name.slice(1)}</li>
|
|
92
|
-
{/if}
|
|
93
|
-
{/each}
|
|
94
|
-
</ol>
|
|
95
|
-
</svelte:fragment>
|
|
96
|
-
<svelte:fragment slot="trail">
|
|
97
|
-
<LightSwitch bgLight="bg-surface-400"/>
|
|
98
|
-
</svelte:fragment>
|
|
99
|
-
</AppBar>
|
|
100
|
-
</svelte:fragment>
|
|
101
|
-
|
|
102
|
-
<RandomizedBackground enable={enableBackgroundValue}/>
|
|
103
|
-
|
|
104
|
-
{#if enableDialogueOverlayValue}
|
|
105
|
-
<!-- Page Route Content -->
|
|
106
|
-
<div class="default-page-container">
|
|
107
|
-
<slot/>
|
|
108
|
-
<div class="footer-space"/>
|
|
109
|
-
</div>
|
|
110
|
-
<DialogOverlay/>
|
|
111
|
-
{:else}
|
|
112
|
-
<DialogOverlay/>
|
|
113
|
-
<slot/>
|
|
114
|
-
{/if}
|
|
115
|
-
</AppShell>
|
|
116
|
-
|
|
117
|
-
<style lang="postcss">
|
|
118
|
-
:root {
|
|
119
|
-
--dialog-left-pad: clamp(0em, 5vw, 2em);
|
|
120
|
-
--dialog-box-width: min(calc(50em + 4em), calc(100vw - var(--dialog-left-pad) - var(--theme-border-base)));
|
|
121
|
-
--dialog-box-height: clamp(15em, 50vw, 18em);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
.default-page-container {
|
|
125
|
-
@apply flex justify-center items-center;
|
|
126
|
-
margin-top: 4em;
|
|
127
|
-
margin-left: clamp(1em, 15vw, 10em);
|
|
128
|
-
margin-right: 1em;
|
|
129
|
-
flex-direction: column;
|
|
130
|
-
z-index: 0;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
.ares-logo {
|
|
134
|
-
object-fit: contain;
|
|
135
|
-
height: 2em;
|
|
136
|
-
margin-inline-end: 0.5em;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/* breadcrumb does not work due to a lot of magic stuff i do
|
|
140
|
-
the code below is from skeleton's tailwind css:
|
|
141
|
-
https://github.com/skeletonlabs/skeleton/blob/54f4ecedabf2be6d94a670b56dc8821095ca3fc9/packages/plugin/src/styles/components/breadcrumbs.css
|
|
142
|
-
|
|
143
|
-
it likely disappeared due to code gen shenanigans and package magic */
|
|
144
|
-
.breadcrumb,
|
|
145
|
-
.breadcrumb-nonresponsive {
|
|
146
|
-
@apply flex items-center space-x-4 w-full overflow-x-auto;
|
|
147
|
-
/*@apply flex items-center space-x-4 w-full hide-scrollbar overflow-x-auto;*/
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
.crumb {
|
|
151
|
-
@apply flex justify-center items-center space-x-2;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
.crumb-separator {
|
|
155
|
-
@apply flex text-surface-700-200-token opacity-50;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/* === Auto-Responsive === */
|
|
159
|
-
|
|
160
|
-
.breadcrumb li {
|
|
161
|
-
@apply hidden md:block;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
.breadcrumb li:nth-last-child(3),
|
|
165
|
-
.breadcrumb li:nth-last-child(2),
|
|
166
|
-
.breadcrumb li:nth-last-child(1) {
|
|
167
|
-
@apply block;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
.fab {
|
|
171
|
-
position: fixed;
|
|
172
|
-
bottom: 2em;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
.fab:dir(ltr) {
|
|
176
|
-
right: 2em;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
.fab:dir(rtl) {
|
|
180
|
-
left: 2em;
|
|
181
|
-
}
|
|
182
|
-
</style>
|