Loading Gist
This commit is contained in:
@@ -12,3 +12,7 @@
|
||||
.action-btn {
|
||||
@apply rounded p-2 bg-indigo-400 shadow flex-auto text-white hover:bg-indigo-500;
|
||||
}
|
||||
|
||||
.input {
|
||||
@apply flex-1 border-indigo-400 border-solid border-2 rounded;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import Card from '$lib/components/card/card.svelte';
|
||||
import type { State } from '$lib/types';
|
||||
import { base64State, codeStore } from '$lib/util/state';
|
||||
import { codeStore } from '$lib/util/state';
|
||||
import { toBase64 } from 'js-base64';
|
||||
import moment from 'moment';
|
||||
|
||||
@@ -103,11 +104,27 @@
|
||||
);
|
||||
};
|
||||
|
||||
const onCopyMarkdown = (event: Event) => {
|
||||
event.target.select();
|
||||
const onCopyMarkdown = () => {
|
||||
document.getElementById('markdown').select();
|
||||
document.execCommand('Copy');
|
||||
};
|
||||
|
||||
let gistURL = '';
|
||||
codeStore.subscribe((state) => {
|
||||
if (state.loader?.type === 'gist') {
|
||||
// @ts-ignore Gist will have url
|
||||
gistURL = state.loader.config.url;
|
||||
}
|
||||
});
|
||||
|
||||
const loadGist = () => {
|
||||
if (!gistURL) {
|
||||
alert('Please enter a Gist URL first');
|
||||
}
|
||||
goto(`/edit?gist=${gistURL}`);
|
||||
location.reload();
|
||||
};
|
||||
|
||||
let iUrl: string;
|
||||
let svgUrl: string;
|
||||
let mdCode: string;
|
||||
@@ -126,7 +143,7 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<Card title="Actions" isOpen={false}>
|
||||
<Card title="Actions" isOpen={true}>
|
||||
<div class="flex flex-wrap gap-2 m-2">
|
||||
{#if isClipboardAvailable()}
|
||||
<button class="action-btn w-full" on:click={onCopyClipboard}
|
||||
@@ -160,8 +177,22 @@
|
||||
</div>
|
||||
|
||||
<div class="w-full flex gap-2 items-center">
|
||||
<label for="markdown">Copy Markdown</label>
|
||||
<input class="flex-1" id="markdown" type="text" value={mdCode} on:click={onCopyMarkdown} />
|
||||
<input class="input" id="markdown" type="text" value={mdCode} on:click={onCopyMarkdown} />
|
||||
<label for="markdown">
|
||||
<button class="btn text-white flex-auto" on:click={onCopyMarkdown}> Copy Markdown </button>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="w-full flex gap-2 items-center">
|
||||
<input
|
||||
class="input"
|
||||
id="gist"
|
||||
type="text"
|
||||
bind:value={gistURL}
|
||||
placeholder="Enter Gist URL" />
|
||||
<label for="gist">
|
||||
<button class="btn text-white flex-auto" on:click={loadGist}> Load Gist </button>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
Vendored
+4
@@ -36,6 +36,10 @@ export interface GistLoaderConfig {
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface LoadingState {
|
||||
loading: boolean;
|
||||
message?: string;
|
||||
}
|
||||
export interface FileLoaderConfig {
|
||||
codeURL: string;
|
||||
configURL?: string;
|
||||
|
||||
@@ -55,9 +55,15 @@ const getGistData = async (gistURL: string): Promise<GistData> => {
|
||||
};
|
||||
|
||||
const getStateFromGist = (gist: GistData): State => {
|
||||
const state = {
|
||||
const state: State = {
|
||||
...defaultState,
|
||||
code: gist.code
|
||||
code: gist.code,
|
||||
loader: {
|
||||
type: 'gist',
|
||||
config: {
|
||||
url: gist.url
|
||||
}
|
||||
}
|
||||
};
|
||||
gist.config && (state.mermaid = gist.config);
|
||||
return state;
|
||||
@@ -81,6 +87,8 @@ export const loadGistData = async (gistURL: string): Promise<State> => {
|
||||
}
|
||||
gistHistory.reverse();
|
||||
const state = getStateFromGist(gistHistory.slice(-1).pop());
|
||||
// @ts-ignore Ignore
|
||||
state.loader.config.url = gistURL;
|
||||
for (const gist of gistHistory) {
|
||||
addHistoryEntry({
|
||||
state: getStateFromGist(gist),
|
||||
|
||||
@@ -7,7 +7,7 @@ const loaders: Record<string, Loader> = {
|
||||
|
||||
export const loadDataFromUrl = async (): Promise<void> => {
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
let state: State;
|
||||
let state: State = defaultState;
|
||||
let code: string, config: string;
|
||||
const codeURL: string = searchParams.get('code');
|
||||
const configURL: string = searchParams.get('config');
|
||||
@@ -23,8 +23,12 @@ export const loadDataFromUrl = async (): Promise<void> => {
|
||||
if (!code) {
|
||||
for (const [key, value] of searchParams.entries()) {
|
||||
if (key in loaders) {
|
||||
state = await loaders[key](value);
|
||||
break;
|
||||
try {
|
||||
state = await loaders[key](value);
|
||||
break;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { writable, Writable } from 'svelte/store';
|
||||
import type { LoadingState } from '$lib/types';
|
||||
|
||||
const defaultLoading: LoadingState = {
|
||||
loading: false
|
||||
};
|
||||
|
||||
export const loadingStateStore: Writable<LoadingState> = writable(defaultLoading);
|
||||
export const initLoading = async <T>(message: string, task: Promise<T>): Promise<T> => {
|
||||
loadingStateStore.set({
|
||||
loading: true,
|
||||
message
|
||||
});
|
||||
const result: T = await task;
|
||||
loadingStateStore.set({
|
||||
loading: false
|
||||
});
|
||||
return result;
|
||||
};
|
||||
@@ -2,6 +2,7 @@ import type { State } from '$lib/types';
|
||||
import { initURLSubscription, loadState, updateCodeStore } from './state';
|
||||
import { analytics, initAnalytics } from './stats';
|
||||
import { loadDataFromUrl } from './fileLoaders/loader';
|
||||
import { initLoading } from './loading';
|
||||
|
||||
export const loadStateFromURL = (): void => {
|
||||
loadState(window.location.hash.slice(1));
|
||||
@@ -15,7 +16,7 @@ export const syncDiagram = (): void => {
|
||||
|
||||
export const initHandler = async (): Promise<void> => {
|
||||
loadStateFromURL();
|
||||
await loadDataFromUrl().catch(console.error);
|
||||
await initLoading('Loading Gist...', loadDataFromUrl().catch(console.error));
|
||||
syncDiagram();
|
||||
initURLSubscription();
|
||||
await initAnalytics();
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import '../app.postcss';
|
||||
import { base } from '$app/paths';
|
||||
import { onMount } from 'svelte';
|
||||
import { loadingStateStore } from '$lib/util/loading';
|
||||
// This can be removed once https://github.com/sveltejs/kit/issues/1612 is fixed.
|
||||
// Then move it into src and vite will bundle it automatically.
|
||||
onMount(() => {
|
||||
@@ -23,3 +24,44 @@
|
||||
<main class="h-screen">
|
||||
<slot />
|
||||
</main>
|
||||
|
||||
{#if $loadingStateStore.loading}
|
||||
<div
|
||||
class="w-screen h-screen z-50 absolute left-0 top-0 bg-gray-600 opacity-50 flex align-middle justify-center">
|
||||
<div class="text-indigo-100 text-4xl font-bold my-auto">
|
||||
<div class="loader mx-auto" />
|
||||
<div>{$loadingStateStore.message}</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.loader {
|
||||
border: 0.45em solid #f3f3f3;
|
||||
border-radius: 50%;
|
||||
border-top: 0.45em solid #6365f1;
|
||||
width: 3em;
|
||||
height: 3em;
|
||||
-webkit-animation: spin 2s linear infinite; /* Safari */
|
||||
animation: spin 2s linear infinite;
|
||||
}
|
||||
|
||||
/* Safari */
|
||||
@-webkit-keyframes spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user