From 7aa9063f79e3fe461ff96a1e8a2111c3d33e7bdc Mon Sep 17 00:00:00 2001
From: Amphiluke
Date: Sun, 10 Dec 2023 15:35:14 +0700
Subject: [PATCH] Implement permalinking with GitHub gists
---
package-lock.json | 4 +-
package.json | 2 +-
src/App.vue | 4 +-
src/assets/icons.svg | 2 +-
src/components/PanelAbout.vue | 2 +-
src/components/PanelCollections.vue | 35 ++++----
src/components/PanelSharing.vue | 124 +++++++++++-----------------
src/launchCtrl.mjs | 83 +++++++++++++++++++
src/pwaCtrl.mjs | 36 --------
src/stores/bank.mjs | 2 +-
src/styles/interface.module.css | 13 +++
11 files changed, 175 insertions(+), 132 deletions(-)
create mode 100644 src/launchCtrl.mjs
diff --git a/package-lock.json b/package-lock.json
index 403a3b5..f3e4ef6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "lindsvg-pwa",
- "version": "2.2.2",
+ "version": "2.3.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "lindsvg-pwa",
- "version": "2.2.2",
+ "version": "2.3.0",
"dependencies": {
"@vueuse/core": "^10.6.1",
"lindsvg": "^1.3.2",
diff --git a/package.json b/package.json
index 29351d3..e54c295 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "lindsvg-pwa",
"private": true,
- "version": "2.2.2",
+ "version": "2.3.0",
"type": "module",
"scripts": {
"lint": "eslint \"src/**/*.{mjs,vue}\"",
diff --git a/src/App.vue b/src/App.vue
index 06c9b47..d0832ff 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,11 +1,11 @@
diff --git a/src/assets/icons.svg b/src/assets/icons.svg
index 598c48b..239b81d 100644
--- a/src/assets/icons.svg
+++ b/src/assets/icons.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/src/components/PanelAbout.vue b/src/components/PanelAbout.vue
index 711c4b2..e740cde 100644
--- a/src/components/PanelAbout.vue
+++ b/src/components/PanelAbout.vue
@@ -22,7 +22,7 @@ let appVersion = __PACKAGE_VERSION__;
There are a few L-system collections built in the app for demonstration purposes. These L-systems were gathered from various sources including the web, books, and articles. I appreciate the authors of these L-systems (you may find their names in the app sources).
Links
-
+
-
Advanced examples
diff --git a/src/components/PanelCollections.vue b/src/components/PanelCollections.vue
index 7942b27..3094bd3 100644
--- a/src/components/PanelCollections.vue
+++ b/src/components/PanelCollections.vue
@@ -1,5 +1,5 @@
@@ -117,6 +115,14 @@ onMounted(() => {
title="Delete this L-system"
@click="deleteLSystem(lid)"
/>
+
@@ -174,30 +166,14 @@ async function copyPermalink({target}) {
}
}
- .permalinkField {
- box-sizing: border-box;
- height: 55px;
- margin-top: 10px;
- resize: vertical;
- width: 100%;
- }
-
- .permalinkCopyButton {
- margin: 5px 0;
- width: 100%;
-
- &.copySuccess {
- pointer-events: none;
- }
-
- &:not(.copySuccess) .permalinkCopyDone,
- &.copySuccess .permalinkCopyReady {
- display: none;
- }
+ .copyButton {
+ cursor: pointer;
+ fill: var(--color-accent);
+ margin-inline: 4px;
}
- .note {
- color: var(--color-on-surface-mid);
- font-size: 0.85em;
+ .permalink {
+ color: var(--color-accent);
+ word-wrap: break-word;
}
diff --git a/src/launchCtrl.mjs b/src/launchCtrl.mjs
new file mode 100644
index 0000000..78958fc
--- /dev/null
+++ b/src/launchCtrl.mjs
@@ -0,0 +1,83 @@
+import {useInterfaceStore} from "./stores/interface.mjs";
+import {useLSystemStore} from "./stores/lSystem.mjs";
+import {useCollectionsStore} from "./stores/collections.mjs";
+
+export function processLaunchOptions() {
+ return processLaunchQueue() || processBundledPermalink() || processGistPermalink();
+}
+
+function extractQuery(...names) {
+ let url = new URL(location.href);
+ let params = Object.fromEntries(names.map((name) => [name, url.searchParams.get(name)]));
+ names.forEach((name) => url.searchParams.delete(name));
+ window.history.replaceState(null, "", url);
+ return params;
+}
+
+function processLaunchQueue() {
+ let launchParamsSupported = ("launchQueue" in window) && ("files" in window.LaunchParams.prototype);
+ /** @see https://github.com/WICG/web-app-launch/issues/92#issuecomment-1505562033 */
+ if (!launchParamsSupported || extractQuery("action").action !== "handleFile") {
+ return false;
+ }
+ /** @see https://github.com/WICG/file-handling/blob/main/explainer.md */
+ window.launchQueue.setConsumer(async ({files}) => {
+ if (!files.length) {
+ return;
+ }
+ try {
+ let blob = await files[0].getFile();
+ let config = JSON.parse(await blob.text());
+ let lSystemStore = useLSystemStore();
+ lSystemStore.setup(config);
+ lSystemStore.buildSVG();
+ } catch (error) {
+ useInterfaceStore().requestPopover({text: "Unfortunately, this file cannot be opened"});
+ console.error("Unable to open the file", error);
+ }
+ });
+ return true;
+}
+
+function processBundledPermalink() {
+ let {cid, lid} = extractQuery("cid", "lid");
+ if (!cid || !lid) {
+ return false;
+ }
+ let collectionsStore = useCollectionsStore();
+ collectionsStore.selectedCID = cid;
+ collectionsStore.selectedLID = lid;
+ let lSystemStore = useLSystemStore();
+ lSystemStore.setup(collectionsStore.selectedLSystem);
+ lSystemStore.buildSVG();
+ return true;
+}
+
+function processGistPermalink() {
+ let {gist} = extractQuery("gist");
+ if (!gist) {
+ return false;
+ }
+ fetch(`https://api.github.com/gists/${gist}`, {
+ method: "GET",
+ headers: {
+ Accept: "application/vnd.github+json",
+ "X-GitHub-Api-Version": "2022-11-28",
+ },
+ mode: "cors",
+ credentials: "omit",
+ })
+ .then((response) => response.json())
+ .then((data) => {
+ let {content} = Object.values(data.files)[0];
+ let config = JSON.parse(content);
+ let lSystemStore = useLSystemStore();
+ lSystemStore.setup(config);
+ lSystemStore.buildSVG();
+ })
+ .catch((reason) => {
+ useInterfaceStore().requestPopover({text: "Unfortunately, this gist cannot be opened"});
+ console.error("Unable to open the gist", reason);
+ });
+ return true;
+}
diff --git a/src/pwaCtrl.mjs b/src/pwaCtrl.mjs
index f460cee..02cd902 100644
--- a/src/pwaCtrl.mjs
+++ b/src/pwaCtrl.mjs
@@ -1,6 +1,5 @@
import "./sw.js?worker";
import {useInterfaceStore, POPOVER_ACCEPT} from "./stores/interface.mjs";
-import {useLSystemStore} from "./stores/lSystem.mjs";
export const USING_PWA = import.meta.env.PROD && ("serviceWorker" in navigator);
@@ -36,38 +35,3 @@ async function suggestUpdate(newSW) {
}
});
}
-
-let launchParamsSupported = ("launchQueue" in window) && ("files" in window.LaunchParams.prototype);
-
-/** @see https://github.com/WICG/web-app-launch/issues/92#issuecomment-1505562033 */
-function handleActionURL(action) {
- let url = new URL(location.href);
- if (url.searchParams.get("action") !== action) {
- return false;
- }
- url.searchParams.delete("action");
- window.history.replaceState(null, "", url);
- return true;
-}
-
-export function applyLaunchParams() {
- if (!launchParamsSupported || !handleActionURL("handleFile")) {
- return;
- }
- /** @see https://github.com/WICG/file-handling/blob/main/explainer.md */
- window.launchQueue.setConsumer(async ({files}) => {
- if (!files.length) {
- return;
- }
- try {
- let blob = await files[0].getFile();
- let config = JSON.parse(await blob.text());
- let lSystemStore = useLSystemStore();
- lSystemStore.setup(config);
- lSystemStore.buildSVG();
- } catch (error) {
- useInterfaceStore().requestPopover({text: "Unfortunately, this file cannot be opened"});
- console.error("Unable to open the file", error);
- }
- });
-}
diff --git a/src/stores/bank.mjs b/src/stores/bank.mjs
index 10a4d2d..1ec609e 100644
--- a/src/stores/bank.mjs
+++ b/src/stores/bank.mjs
@@ -275,7 +275,7 @@ export default [
step: 15,
},
{
- lid: "Sierpinski arrowhead curve",
+ lid: "Sierpinski arrowhead",
axiom: "A",
rules: {
A: "FC-FA-FC",
diff --git a/src/styles/interface.module.css b/src/styles/interface.module.css
index 847b679..0f6f3fb 100644
--- a/src/styles/interface.module.css
+++ b/src/styles/interface.module.css
@@ -102,6 +102,11 @@
mask-position: -75px 0;
}
+.iconButtonLink::before {
+ -webkit-mask-position: -200px 0;
+ mask-position: -200px 0;
+}
+
@keyframes add-breath {
0% {
transform: rotate(45deg) scale(0.8);
@@ -122,3 +127,11 @@
animation: add-breath 1.2s ease-in-out infinite alternate;
}
}
+
+.list {
+ padding-left: 30px;
+
+ & > li {
+ margin-block: 0.3em;
+ }
+}