Skip to content

Commit

Permalink
add localstorage saving
Browse files Browse the repository at this point in the history
  • Loading branch information
Ashwagandhae committed Aug 10, 2023
1 parent db149b9 commit 99359d0
Show file tree
Hide file tree
Showing 13 changed files with 620 additions and 154 deletions.
4 changes: 2 additions & 2 deletions src/lib/components/AddTab.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

<div class="addTab" class:hasSwitch class:switch={switchSpeakers}>
<div class="buttons">
<TutorialHighlight step={4}>
<TutorialHighlight step={5}>
<Button
text={debateStyle.primary.name}
palette="accent"
Expand All @@ -32,7 +32,7 @@
/>
</TutorialHighlight>
{#if debateStyle.secondary != null}
<TutorialHighlight step={5}>
<TutorialHighlight step={6}>
<Button
text={debateStyle.secondary.name}
palette="accent-secondary"
Expand Down
120 changes: 9 additions & 111 deletions src/lib/components/DownloadUpload.svelte
Original file line number Diff line number Diff line change
@@ -1,118 +1,10 @@
<script lang="ts">
import { flows } from '$lib/models/store';
import Button from './Button.svelte';
import { Workbook, type Buffer } from 'exceljs';
import type { Box } from '../models/type';
import { downloadJson, downloadXlsx } from '$lib/models/file';
export let closePopup: () => void;
function download() {
let data: string = JSON.stringify($flows, (key, value) => {
if (key === 'history') {
return undefined;
}
return value;
});
let element: HTMLAnchorElement = document.createElement('a');
element.setAttribute('href', 'data:text/json;charset=utf-8, ' + encodeURIComponent(data));
element.setAttribute('download', 'flow.json');
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
closePopup();
}
function downloadXLSX() {
let wb: Workbook = new Workbook();
for (let flow of $flows) {
let data: string[][] = [];
function childToData(box: Box, x: number, y: number) {
let height = 0;
for (let child of box.children) {
height += childToData(child, x + 1, y + height);
}
// acutally add it to data
while (!data[y]) {
// make list of empty strings of length flow.columns.length
let row: string[] = Array.from({ length: flow.columns.length }, () => '');
data.push(row);
}
// exclude root
if (x >= 0) {
data[y][x] = box.content;
}
// return 1 height if no children
return Math.max(1, height);
}
childToData(flow, -1, 0);
let name: string = flow.content;
if (name.length >= 31) {
name = name.substring(0, 31);
}
let ws = wb.addWorksheet(name);
ws.columns = flow.columns.map(function (column: string) {
return { header: column, width: 25 };
});
for (let y = 0; y < data.length; y++) {
// make space for header with + 2
let row = ws.getRow(y + 2);
for (let x = 0; x < data[y].length; x++) {
// light red
let fill = 'FFFFCCCC';
// darker red
let border = 'FFFF9999';
if ((x % 2 == 0 && !flow.invert) || (x % 2 == 1 && flow.invert)) {
// light blue
fill = 'FFCCE5FF';
// darker blue
border = 'FF99CCFF';
}
let cell = row.getCell(x + 1);
cell.value = data[y][x];
cell.fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: fill }
};
cell.border = {
top: { style: 'thin', color: { argb: border } },
left: { style: 'thin', color: { argb: border } },
bottom: { style: 'thin', color: { argb: border } },
right: { style: 'thin', color: { argb: border } }
};
cell.alignment = { wrapText: true };
}
}
// bold headers
ws.getRow(1).font = { bold: true };
}
wb.xlsx
.writeBuffer()
.then(function (value: Buffer) {
// build anchor tag and attach file (works in chrome)
let a: HTMLAnchorElement = document.createElement('a');
let data: Blob = new Blob([value], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
});
let url: string = URL.createObjectURL(data);
a.href = url;
a.download = 'flow.xlsx';
document.body.appendChild(a);
a.click();
setTimeout(function () {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 0);
})
.catch(function (error) {
console.log(error.message);
});
closePopup();
}
function openUploadDialog() {
(document.getElementById('uploadId') as HTMLElement).click();
closePopup();
Expand All @@ -126,7 +18,10 @@
text="download as JSON"
tooltip="saves JSON file on your computer"
tooltipLayout="top"
on:click={download}
on:click={() => {
downloadJson($flows);
closePopup();
}}
disabled={$flows.length == 0}
disabledReason={'nothing to download'}
palette="accent"
Expand All @@ -140,7 +35,10 @@
text="download as XLSX"
tooltip="saves XLSX file on your computer"
tooltipLayout="top"
on:click={downloadXLSX}
on:click={() => {
downloadXlsx($flows);
closePopup();
}}
disabled={$flows.length == 0}
disabledReason={'nothing to download'}
palette="accent-secondary"
Expand Down
14 changes: 14 additions & 0 deletions src/lib/components/Prelude.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script lang="ts">
import Tutorial from './Tutorial.svelte';
import SavedFlows from './SavedFlows.svelte';
import { savedFlowsDatas } from '$lib/models/autoSave';
let showTutorial = false;
$: savedFlowsExist = Object.keys($savedFlowsDatas).length > 0;
</script>

{#if savedFlowsExist && !showTutorial}
<SavedFlows savedFlowsDatas={$savedFlowsDatas} bind:showTutorial />
{:else}
<Tutorial bind:showTutorial {savedFlowsExist} />
{/if}
179 changes: 179 additions & 0 deletions src/lib/components/SavedFlow.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
<script lang="ts">
import Button from './Button.svelte';
import {
deleteFlows,
loadSavedFlows,
type SavedFlowsData,
downloadSavedFlows
} from '$lib/models/autoSave';
import { hiddenButtons, savedFlow } from '$lib/models/transition';
function prettyDate(date: string) {
const today = new Date();
const dateObj = new Date(date);
if (
today.getDate() === dateObj.getDate() &&
today.getMonth() === dateObj.getMonth() &&
today.getFullYear() === dateObj.getFullYear()
) {
return dateObj.toLocaleTimeString('en-US', {
hour: 'numeric',
minute: 'numeric',
hour12: true
});
} else {
return dateObj.toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric'
});
}
}
export let flowData: SavedFlowsData;
export let key: string;
let showHidden = false;
</script>

<div class="flow" transition:savedFlow>
<div class="infoView">
<div class="infos">
{#each flowData.flowInfos as info}
<div
class="info"
class:palette-accent={!info.invert}
class:palette-accent-secondary={info.invert}
>
{info.content}
</div>
{/each}
</div>
</div>
<div class="fixed">
<div class="times">
<div class="time">
{prettyDate(flowData.modified)}
</div>
</div>
<div class="flowButtons">
<Button
icon="upload"
text="open"
on:click={() => {
loadSavedFlows(key, true);
}}
/>
<Button
icon={showHidden ? 'delete' : 'ellipses'}
on:click={() => (showHidden = !showHidden)}
/>
{#if showHidden}
<div class="hidden" transition:hiddenButtons>
<div class="time">created {prettyDate(flowData.created)}</div>
<div class="time">edited {prettyDate(flowData.modified)}</div>
<Button
icon="copy"
text={'open copy'}
tooltip={'save changes in new'}
on:click={() => {
loadSavedFlows(key, false);
}}
/>
<Button
icon="download"
text={'download'}
tooltip={'download as JSON'}
on:click={() => {
downloadSavedFlows(key);
}}
/>

<Button
icon="trash"
text={'delete'}
tooltip={'delete flow data'}
on:click={() => {
deleteFlows(key);
}}
/>
</div>
{/if}
</div>
</div>
</div>

<style>
.flow {
display: grid;
flex-direction: row;
width: 100%;
position: relative;
grid-template-columns: 1fr auto;
gap: var(--padding);
}
.infoView {
overflow-x: scroll;
position: relative;
border-radius: var(--border-radius);
}
.infos {
display: flex;
flex-direction: row;
width: max-content;
gap: var(--padding);
}
.info {
padding: var(--padding);
border-radius: var(--border-radius);
background-color: var(--this-background-indent);
color: var(--this-text);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
height: var(--button-size);
display: flex;
align-items: center;
}
.fixed {
display: flex;
flex-direction: row;
gap: var(--padding);
}
.times {
display: flex;
flex-direction: row;
align-items: center;
}
.time {
padding: var(--padding);
border-radius: var(--border-radius);
color: var(--this-text);
background-color: var(--background-indent);
height: var(--button-size);
display: flex;
align-items: center;
white-space: nowrap;
}
.hidden > .time {
background: none;
}
.flowButtons {
display: flex;
flex-direction: row;
gap: var(--padding);
}
.hidden {
z-index: 900;
position: absolute;
top: calc(var(--button-size) + var(--padding) * 2);
right: calc(-1 * var(--padding));
display: flex;
flex-direction: column;
align-items: flex-end;
gap: var(--padding);
padding: var(--padding);
background: var(--background-back);
border-radius: var(--border-radius);
}
</style>
Loading

0 comments on commit 99359d0

Please sign in to comment.