mirror of
https://github.com/LukeHagar/OpenAPI.gg.git
synced 2025-12-09 12:37:48 +00:00
saving progress
but not happy with my implementation, I should switch to a table file, save, load style menu
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
||||
"@typescript-eslint/parser": "^7.0.0",
|
||||
"autoprefixer": "10.4.19",
|
||||
"dexie": "^4.0.7",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-svelte": "^2.35.1",
|
||||
|
||||
8
pnpm-lock.yaml
generated
8
pnpm-lock.yaml
generated
@@ -57,6 +57,9 @@ importers:
|
||||
autoprefixer:
|
||||
specifier: 10.4.19
|
||||
version: 10.4.19(postcss@8.4.38)
|
||||
dexie:
|
||||
specifier: ^4.0.7
|
||||
version: 4.0.7
|
||||
eslint:
|
||||
specifier: ^8.56.0
|
||||
version: 8.57.0
|
||||
@@ -852,6 +855,9 @@ packages:
|
||||
devalue@5.0.0:
|
||||
resolution: {integrity: sha512-gO+/OMXF7488D+u3ue+G7Y4AA3ZmUnB3eHJXmBTgNHvr4ZNzl36A0ZtG+XCRNYCkYx/bFmw4qtkoFLa+wSrwAA==}
|
||||
|
||||
dexie@4.0.7:
|
||||
resolution: {integrity: sha512-M+Lo6rk4pekIfrc2T0o2tvVJwL6EAAM/B78DNfb8aaxFVoI1f8/rz5KTxuAnApkwqTSuxx7T5t0RKH7qprapGg==}
|
||||
|
||||
didyoumean@1.2.2:
|
||||
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
|
||||
|
||||
@@ -2439,6 +2445,8 @@ snapshots:
|
||||
|
||||
devalue@5.0.0: {}
|
||||
|
||||
dexie@4.0.7: {}
|
||||
|
||||
didyoumean@1.2.2: {}
|
||||
|
||||
dir-glob@3.0.1:
|
||||
|
||||
19
src/lib/components/FileManagement/CreateNewButton.svelte
Normal file
19
src/lib/components/FileManagement/CreateNewButton.svelte
Normal file
@@ -0,0 +1,19 @@
|
||||
<script lang="ts">
|
||||
import { localStoragePrefix } from '$lib';
|
||||
</script>
|
||||
|
||||
<button
|
||||
class="btn variant-ghost-success"
|
||||
on:click={() => {
|
||||
if (
|
||||
confirm(
|
||||
'This operation clears all the current values, unsaved data will be lost, are you sure?'
|
||||
)
|
||||
) {
|
||||
// remove `openApi` from localStorage
|
||||
localStorage.removeItem(`${localStoragePrefix}openApi`);
|
||||
}
|
||||
}}
|
||||
>
|
||||
Create New
|
||||
</button>
|
||||
16
src/lib/components/FileManagement/DeleteButton.svelte
Normal file
16
src/lib/components/FileManagement/DeleteButton.svelte
Normal file
@@ -0,0 +1,16 @@
|
||||
<script lang="ts">
|
||||
import { db, type APISpec } from '$lib/db';
|
||||
|
||||
export let spec: APISpec;
|
||||
</script>
|
||||
|
||||
<button
|
||||
class="btn variant-ghost-error"
|
||||
on:click={async () => {
|
||||
if (confirm(`Are you sure you want to delete '${spec.name}'?`)) {
|
||||
await db.apiSpecs.delete(spec.id);
|
||||
}
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
80
src/lib/components/FileManagement/DownloadButtons.svelte
Normal file
80
src/lib/components/FileManagement/DownloadButtons.svelte
Normal file
@@ -0,0 +1,80 @@
|
||||
<script lang="ts">
|
||||
import { localStoragePrefix, openApiStore } from '$lib';
|
||||
import filenamify from 'filenamify';
|
||||
import { stringify } from 'yaml';
|
||||
|
||||
$: fileName = filenamify($openApiStore?.info?.title) || 'openapi';
|
||||
</script>
|
||||
|
||||
<label class="flex flex-col text-xs">
|
||||
<span>Download</span>
|
||||
<button
|
||||
class="btn btn-sm grow variant-ghost-tertiary mb-1"
|
||||
on:click={() => {
|
||||
const openApiStorage = localStorage.getItem(`${localStoragePrefix}openApi`);
|
||||
if (!openApiStorage) return;
|
||||
const openApi = JSON.parse(openApiStorage);
|
||||
const blob = new Blob(
|
||||
[stringify(openApi, null, { indent: 2, aliasDuplicateObjects: false })],
|
||||
{ type: 'application/yaml' }
|
||||
);
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `${fileName}.yaml`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="size-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m.75 12 3 3m0 0 3-3m-3 3v-6m-1.5-9H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"
|
||||
/>
|
||||
</svg>
|
||||
YAML
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-sm grow variant-ghost-tertiary"
|
||||
on:click={() => {
|
||||
const openApiStorage = localStorage.getItem(`${localStoragePrefix}openApi`);
|
||||
if (!openApiStorage) return;
|
||||
const openApi = JSON.parse(openApiStorage);
|
||||
const blob = new Blob([JSON.stringify(openApi, null, 2)], {
|
||||
type: 'application/json'
|
||||
});
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `${fileName}.json`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="size-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m.75 12 3 3m0 0 3-3m-3 3v-6m-1.5-9H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"
|
||||
/>
|
||||
</svg>
|
||||
JSON
|
||||
</button>
|
||||
</label>
|
||||
74
src/lib/components/FileManagement/Upload.svelte
Normal file
74
src/lib/components/FileManagement/Upload.svelte
Normal file
@@ -0,0 +1,74 @@
|
||||
<script lang="ts">
|
||||
import { openApiStore } from '$lib';
|
||||
import { db } from '$lib/db';
|
||||
import type { OpenAPIV3_1 } from '$lib/openAPITypes';
|
||||
import {
|
||||
FileButton,
|
||||
FileDropzone,
|
||||
getModalStore,
|
||||
type ModalSettings,
|
||||
type ModalStore
|
||||
} from '@skeletonlabs/skeleton';
|
||||
import { liveQuery } from 'dexie';
|
||||
import { parse } from 'yaml';
|
||||
|
||||
let files: FileList | undefined;
|
||||
|
||||
function onFileUpload(e: Event): void {
|
||||
console.log('onFileUpload');
|
||||
if (!files) return;
|
||||
const file = files[0];
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
const result = reader.result as string;
|
||||
const isJson = file.name.endsWith('.json');
|
||||
let content: OpenAPIV3_1.Document;
|
||||
try {
|
||||
if (isJson) {
|
||||
content = JSON.parse(result);
|
||||
} else {
|
||||
content = parse(result);
|
||||
}
|
||||
openApiStore.set(content);
|
||||
} catch (error) {
|
||||
console.error(`Error parsing ${isJson ? 'json' : 'yaml'} file`, error);
|
||||
}
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
</script>
|
||||
|
||||
<FileDropzone
|
||||
bind:files
|
||||
label="upload"
|
||||
accept=".yml,.yaml,.json"
|
||||
on:dragover|once={() => {
|
||||
files = undefined;
|
||||
}}
|
||||
on:change={onFileUpload}
|
||||
type="file"
|
||||
name="openapispec"
|
||||
>
|
||||
<svelte:fragment slot="lead">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="size-6 mx-auto"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m6.75 12-3-3m0 0-3 3m3-3v6m-1.5-15H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"
|
||||
/>
|
||||
</svg>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="message">
|
||||
<p class="mb-2 text-sm text-gray-500 dark:text-gray-400">
|
||||
<span class="font-semibold">Click to upload</span> or drag and drop
|
||||
</p>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="meta">JSON, YAML</svelte:fragment></FileDropzone
|
||||
>
|
||||
@@ -8,6 +8,7 @@
|
||||
<div class="border-token rounded-container-token space-y-1 p-4">
|
||||
<div class="flex flex-row justify-between">
|
||||
<h4 class="h4">License</h4>
|
||||
{#if $openApiStore.info.license}
|
||||
<label class="text-sm space-x-2">
|
||||
<span>Pick a license</span>
|
||||
<select
|
||||
@@ -30,8 +31,10 @@
|
||||
</optgroup>
|
||||
</select>
|
||||
</label>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if $openApiStore.info.license}
|
||||
<label class="text-sm space-y-1">
|
||||
<span>Name (required)</span>
|
||||
<input
|
||||
@@ -62,4 +65,19 @@
|
||||
bind:value={$openApiStore.info.license.url}
|
||||
/>
|
||||
</label>
|
||||
{:else}
|
||||
<button
|
||||
type="button"
|
||||
class="btn variant-filled-primary"
|
||||
on:click={() => {
|
||||
$openApiStore.info.license = {
|
||||
name: '',
|
||||
identifier: '',
|
||||
url: ''
|
||||
};
|
||||
}}
|
||||
>
|
||||
Add License
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
</div>
|
||||
<div class="border-token rounded-container-token bg-surface-backdrop-token space-y-1 p-4">
|
||||
<h4 class="h4">Contact Information</h4>
|
||||
{#if $openApiStore.info.contact}
|
||||
<label class="space-y-1">
|
||||
<span class="text-sm">Name (optional)</span>
|
||||
<input
|
||||
@@ -80,6 +81,22 @@
|
||||
bind:value={$openApiStore.info.contact.url}
|
||||
/>
|
||||
</label>
|
||||
{:else}
|
||||
<button
|
||||
type="button"
|
||||
class="btn variant-filled-primary"
|
||||
on:click={() => {
|
||||
$openApiStore.info.contact = {
|
||||
name: '',
|
||||
email: '',
|
||||
url: ''
|
||||
};
|
||||
}}
|
||||
>
|
||||
Add Contact
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<LicenseAtom />
|
||||
</form>
|
||||
|
||||
24
src/lib/db.ts
Normal file
24
src/lib/db.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import type { OpenAPIV3_1 } from "$lib/openAPITypes";
|
||||
import Dexie, { type Table } from 'dexie';
|
||||
import { persisted } from "svelte-persisted-store";
|
||||
|
||||
export const selectedSpec = persisted<APISpec | undefined>(`selectedSpec`, undefined)
|
||||
|
||||
export interface APISpec {
|
||||
id?: string;
|
||||
name: string;
|
||||
spec: OpenAPIV3_1.Document;
|
||||
}
|
||||
|
||||
export class MySubClassedDexie extends Dexie {
|
||||
apiSpecs!: Table<APISpec>;
|
||||
|
||||
constructor() {
|
||||
super('oasDesigner');
|
||||
this.version(1).stores({
|
||||
apiSpecs: '++id, name, spec', // Primary key and indexed props
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const db = new MySubClassedDexie();
|
||||
@@ -16,12 +16,14 @@ export const operationCount = (openApiDoc: OpenAPIV3_1.Document) => {
|
||||
|
||||
export const pathCount = (openApiDoc: OpenAPIV3_1.Document) => {
|
||||
let count = 0;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
for (const path in openApiDoc.paths) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
export const openApiStore = persisted<OpenAPIV3_1.Document>(`${localStoragePrefix}openApi`, {
|
||||
openapi: '3.1.0', // OpenAPI version
|
||||
info: {
|
||||
|
||||
@@ -1,4 +1,30 @@
|
||||
<div class="w-full h-full flex flex-col items-center justify-center grow">
|
||||
<script lang="ts">
|
||||
import CreateNewButton from '$lib/components/FileManagement/CreateNewButton.svelte';
|
||||
import DeleteButton from '$lib/components/FileManagement/DeleteButton.svelte';
|
||||
import Upload from '$lib/components/FileManagement/Upload.svelte';
|
||||
import { db, selectedSpec } from '$lib/db';
|
||||
import { liveQuery } from 'dexie';
|
||||
|
||||
let apiSpecs = liveQuery(() => db.apiSpecs.toArray());
|
||||
$: console.log($apiSpecs);
|
||||
</script>
|
||||
|
||||
<div class="grid place-content-center h-full gap-2 px-1">
|
||||
<label class="flex flex-col text-xs">
|
||||
<span>Select an API</span>
|
||||
<select bind:value={$selectedSpec} class="select w-64">
|
||||
{#if $apiSpecs}
|
||||
{#each $apiSpecs as spec (spec.id)}
|
||||
<option value={spec}>{spec.name}</option>
|
||||
{/each}
|
||||
{/if}
|
||||
</select>
|
||||
</label>
|
||||
<CreateNewButton />
|
||||
<Upload />
|
||||
<DeleteButton />
|
||||
</div>
|
||||
<!-- <div class="w-full h-full flex flex-col items-center justify-center grow">
|
||||
<h1 class="h1">
|
||||
<span
|
||||
class="bg-gradient-to-br from-blue-500 to-cyan-300 bg-clip-text text-transparent box-decoration-clone"
|
||||
@@ -20,4 +46,4 @@
|
||||
Deploy.
|
||||
</span>
|
||||
</h1>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
@@ -12,31 +12,21 @@
|
||||
import { parse, stringify } from 'yaml';
|
||||
import { openApiStore } from '$lib';
|
||||
import filenamify from 'filenamify';
|
||||
import { liveQuery } from 'dexie';
|
||||
import { db, type APISpec } from '$lib/db';
|
||||
import Upload from '$lib/components/FileManagement/Upload.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import DownloadButtons from '$lib/components/FileManagement/DownloadButtons.svelte';
|
||||
|
||||
let files: FileList | undefined;
|
||||
let currentSpec: APISpec | undefined;
|
||||
$: if (currentSpec) {
|
||||
$openApiStore = currentSpec.spec;
|
||||
}
|
||||
|
||||
let apiSpecs = liveQuery(() => db.apiSpecs.toArray());
|
||||
$: console.log($apiSpecs);
|
||||
|
||||
$: fileName = filenamify($openApiStore.info.title) || 'openapi';
|
||||
|
||||
function onFileUpload(e: Event): void {
|
||||
if (!files) return;
|
||||
|
||||
const file = files[0];
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
const result = reader.result as string;
|
||||
const isJson = file.name.endsWith('.json');
|
||||
try {
|
||||
if (isJson) {
|
||||
openApiStore.set(JSON.parse(result));
|
||||
} else {
|
||||
openApiStore.set(parse(result));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error parsing ${isJson ? 'json' : 'yaml'} file`, error);
|
||||
}
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
</script>
|
||||
|
||||
<AppRail width="w-28" aspectRatio="aspect-[3/2]" background="variant-ghost-surface" border="ring-0">
|
||||
@@ -143,113 +133,10 @@
|
||||
</AppRailAnchor>
|
||||
|
||||
<svelte:fragment slot="trail">
|
||||
<FileButton
|
||||
bind:files
|
||||
accept=".yml,.yaml,.json"
|
||||
button="btn text-sm rounded-none text-wrap variant-soft-primary flex flex-col justify-center items-center h-20 w-full"
|
||||
on:change={onFileUpload}
|
||||
type="file"
|
||||
name="openapispec"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="size-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m6.75 12-3-3m0 0-3 3m3-3v6m-1.5-15H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"
|
||||
/>
|
||||
</svg>
|
||||
Upload
|
||||
</FileButton>
|
||||
<button
|
||||
type="button"
|
||||
class="btn text-sm rounded-none text-wrap variant-soft-primary flex flex-col justify-center items-center h-20 w-full"
|
||||
on:click={() => {
|
||||
const openApiStorage = localStorage.getItem(`${localStoragePrefix}openApi`);
|
||||
if (!openApiStorage) return;
|
||||
const openApi = JSON.parse(openApiStorage);
|
||||
const blob = new Blob([JSON.stringify(openApi, null, 2)], { type: 'application/json' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `${fileName}.json`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="size-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m.75 12 3 3m0 0 3-3m-3 3v-6m-1.5-9H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"
|
||||
/>
|
||||
</svg>
|
||||
Download JSON
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn text-sm rounded-none text-wrap variant-soft-primary flex flex-col justify-center items-center h-20 w-full"
|
||||
on:click={() => {
|
||||
const openApiStorage = localStorage.getItem(`${localStoragePrefix}openApi`);
|
||||
if (!openApiStorage) return;
|
||||
const openApi = JSON.parse(openApiStorage);
|
||||
const blob = new Blob(
|
||||
[stringify(openApi, null, { indent: 2, aliasDuplicateObjects: false })],
|
||||
{ type: 'application/yaml' }
|
||||
);
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `${fileName}.yaml`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="size-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m.75 12 3 3m0 0 3-3m-3 3v-6m-1.5-9H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"
|
||||
/>
|
||||
</svg>
|
||||
Download YAML
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn text-sm rounded-none text-wrap variant-soft-error hover:variant-soft-error flex justify-center items-center h-16 w-full"
|
||||
on:click={() => {
|
||||
if (confirm('Are you sure you want to reset ALL current inputs?')) {
|
||||
// remove `openApi` from localStorage
|
||||
localStorage.removeItem(`${localStoragePrefix}openApi`);
|
||||
window.location.pathname = '/';
|
||||
}
|
||||
}}
|
||||
>
|
||||
Clear all inputs
|
||||
</button>
|
||||
<div class="flex justify-center items-center h-10 w-full my-4">
|
||||
<div class="p-2">
|
||||
<DownloadButtons />
|
||||
</div>
|
||||
<div class="flex justify-center my-4">
|
||||
<LightSwitch />
|
||||
</div>
|
||||
<AppRailAnchor href="https://www.speakeasyapi.dev/openapi" target="_blank">
|
||||
|
||||
Reference in New Issue
Block a user