Skip to content

Commit

Permalink
File handling
Browse files Browse the repository at this point in the history
  • Loading branch information
Amphiluke committed Dec 1, 2023
1 parent ffb5b20 commit 4aa3686
Show file tree
Hide file tree
Showing 16 changed files with 276 additions and 119 deletions.
3 changes: 3 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ module.exports = {
ecmaVersion: 2022,
sourceType: "module",
},
globals: {
__PACKAGE_VERSION__: "readonly",
},
plugins: [
"@stylistic/js",
"vue",
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "lindsvg-pwa",
"private": true,
"version": "2.0.2",
"version": "2.1.0",
"type": "module",
"scripts": {
"lint": "eslint \"src/**/*.{mjs,vue}\"",
Expand Down
Binary file added public/app-icons/doc-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/App.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
<script setup>
import {onMounted} from "vue";
import {applyLaunchParams} from "./pwaCtrl.mjs";
import PlotArea from "./components/PlotArea.vue";
import TheSidebar from "./components/TheSidebar.vue";
import ThePopover from "./components/ThePopover.vue";
onMounted(() => applyLaunchParams());
</script>

<template>
Expand Down
13 changes: 11 additions & 2 deletions src/components/PanelCollections.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup>
import {ref, computed} from "vue";
import {ref, computed, onMounted} from "vue";
import {refDebounced} from "@vueuse/core";
import {useCollectionsStore, isUserDefined, USER_DEFINED_COLLECTION_ID} from "../stores/collections.mjs";
import {useLSystemStore} from "../stores/lSystem.mjs";
Expand Down Expand Up @@ -51,6 +51,15 @@ function addLSystem() {
function deleteLSystem(lid) {
collectionsStore.deleteLSystem(lid);
}
onMounted(() => {
let searchParams = new URLSearchParams(location.search);
let cid = searchParams.get("cid");
let lid = searchParams.get("lid");
if (cid && lid) {
plot(cid, lid);
}
});
</script>

<template>
Expand Down Expand Up @@ -177,7 +186,7 @@ function deleteLSystem(lid) {
.collectionName {
background: var(--color-surface);
box-shadow: 0 4px 7px 2px var(--color-surface), 0 -4px 0 0 var(--color-surface);
box-shadow: 0 4px 7px 2px var(--color-surface);
margin-block: 0 8px;
padding-block: 13px 5px;
position: sticky;
Expand Down
106 changes: 0 additions & 106 deletions src/components/PanelExporting.vue

This file was deleted.

2 changes: 1 addition & 1 deletion src/components/PanelSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ function plot() {
&:has([data-label="B"]),
&:has([data-label="F"]) {
background: rgb(from var(--color-accent) r g b / calc(alpha - 0.92));
background: rgb(from var(--color-accent) r g b / 0.08);
}
}
Expand Down
179 changes: 179 additions & 0 deletions src/components/PanelSharing.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
<script setup>
import {computed, useCssModule} from "vue";
import {useCollectionsStore, isUserDefined} from "../stores/collections.mjs";
import {useLSystemStore} from "../stores/lSystem.mjs";
import {useInterfaceStore} from "../stores/interface.mjs";
import {useObjectUrl, useFileDialog} from "@vueuse/core";
import interfaceStyles from "../styles/interface.module.css";
import panelStyles from "../styles/panel.module.css";
let collectionsStore = useCollectionsStore();
let lSystemStore = useLSystemStore();
let interfaceStore = useInterfaceStore();
let cssModule = useCssModule();
let fileDialog = useFileDialog({accept: ".lsvg", multiple: false, reset: true});
fileDialog.onChange(async ([file]) => {
try {
let config = JSON.parse(await file.text());
lSystemStore.setup(config);
lSystemStore.buildSVG();
} catch (error) {
interfaceStore.requestPopover({text: "Unfortunately, this file cannot be opened"});
console.error("Unable to open the file", error);
}
});
let svgBlob = computed(() => new Blob([lSystemStore.svgCode], {type: "image/svg+xml"}));
let svgURL = useObjectUrl(svgBlob);
let lsvgBlob = computed(() => {
let lsvg = JSON.stringify({
_version: __PACKAGE_VERSION__,
axiom: lSystemStore.axiom,
alpha: lSystemStore.alpha,
theta: lSystemStore.theta,
step: lSystemStore.step,
iterations: lSystemStore.iterations,
rules: lSystemStore.rules,
attributes: lSystemStore.attributes,
});
return new Blob([lsvg], {type: "application/json"});
});
let lsvgURL = useObjectUrl(lsvgBlob);
let permalink = computed(() => {
if (!collectionsStore.selectedCID || !collectionsStore.selectedLID || isUserDefined(collectionsStore.selectedCID)) {
return "";
}
let {location} = window;
let url = new URL(location.origin + location.pathname);
url.searchParams.set("cid", collectionsStore.selectedCID);
url.searchParams.set("lid", collectionsStore.selectedLID);
return url.toString();
});
async function copyPermalink({target}) {
await navigator.clipboard.writeText(permalink.value);
target.classList.add(cssModule.copySuccess);
setTimeout(() => target.classList.remove(cssModule.copySuccess), 4000);
}
</script>

<template>
<section :class="panelStyles.panel">
<h2 :class="panelStyles.title">
Sharing
</h2>
<form
action="#"
:class="[panelStyles.body, interfaceStyles.thinScroll]"
@submit.prevent
>
<div :class="$style.fileControls">
<h3>Open file…</h3>
<button
type="button"
:class="[interfaceStyles.button, $style.fileButton]"
@click="fileDialog.open"
>
LSVG
</button>

<h3>Save file…</h3>
<a
:href="lsvgURL"
:class="[interfaceStyles.button, $style.fileButton]"
:download="(collectionsStore.selectedLID || 'l-system') + '.lsvg'"
>
LSVG
</a>
<a
:href="svgURL"
:class="[interfaceStyles.button, $style.fileButton]"
:download="(collectionsStore.selectedLID || 'l-system') + '.svg'"
>
SVG
</a>
</div>

<hr>

<h3>Permalink for the selected L-system</h3>
<textarea
:class="$style.permalinkField"
:value="permalink"
readonly
@click="$event.target.select()"
/>
<button
type="button"
:class="[interfaceStyles.button, $style.permalinkCopyButton]"
:disabled="!permalink"
@click="copyPermalink"
>
<span :class="$style.permalinkCopyReady">Copy</span>
<span :class="$style.permalinkCopyDone">Copied!</span>
</button>
<p :class="$style.note">
Note that permalinks are only available for L-systems from the predefined collections.
Any manual changes in L-system parameters are not preserved.
</p>
</form>
</section>
</template>

<style module>
.fileControls {
align-items: center;
display: grid;
gap: 20px 10px;
grid-template-columns: 1fr 25% 25%;
& h3 {
font: inherit;
grid-column: 1 / 2;
margin: 0;
}
& .fileButton {
--border-alpha: 0.3;
border-color: rgb(from var(--color-accent) r g b / var(--border-alpha));
border-radius: 5px;
font: inherit;
&:hover,
&:focus-visible {
--border-alpha: 0.6;
background: none;
}
}
}
.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;
}
}
.note {
color: var(--color-on-surface-mid);
font-size: 0.85em;
}
</style>
Loading

0 comments on commit 4aa3686

Please sign in to comment.