mirror of
https://github.com/gradio-app/gradio.git
synced 2025-03-31 12:20:26 +08:00
ali components
This commit is contained in:
parent
a3dd2e5710
commit
8a3e08defa
@ -74,7 +74,6 @@ iface = gr.Interface(
|
||||
examples=[
|
||||
["the quick brown fox", "jumps over the lazy dog", 10, 12, 4, True, ["foo", "baz"], "baz", "bar", "files/cheetah1.jpg", "files/cheetah1.jpg", "files/cheetah1.jpg", "files/cheetah1.jpg", "files/world.mp4", "files/cantina.wav", "files/cantina.wav","files/titanic.csv", [[1,2,3],[3,4,5]], "files/time.csv"]
|
||||
] * 3,
|
||||
theme="huggingface",
|
||||
title="Kitchen Sink",
|
||||
description="Try out all the components!",
|
||||
article="Learn more about [Gradio](http://gradio.app)"
|
||||
|
@ -5,7 +5,7 @@ def reverse_audio(audio):
|
||||
sr, data = audio
|
||||
return (sr, np.flipud(data))
|
||||
|
||||
iface = gr.Interface(reverse_audio, "microphone", "audio", examples="audio")
|
||||
iface = gr.Interface(reverse_audio, "audio", "audio", examples="audio")
|
||||
|
||||
if __name__ == "__main__":
|
||||
iface.launch()
|
||||
|
BIN
demo/zip_two_files/tmp.zip
Normal file
BIN
demo/zip_two_files/tmp.zip
Normal file
Binary file not shown.
23
frontend-svelte/package-lock.json
generated
23
frontend-svelte/package-lock.json
generated
@ -10,6 +10,7 @@
|
||||
"dependencies": {
|
||||
"@rollup/plugin-replace": "^3.0.1",
|
||||
"autoprefixer": "^9.8.8",
|
||||
"mime-types": "^2.1.34",
|
||||
"node-sass": "^7.0.1",
|
||||
"sirv-cli": "^1.0.0",
|
||||
"svelte-preprocess": "^4.10.1",
|
||||
@ -17,6 +18,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-commonjs": "^17.0.0",
|
||||
"@rollup/plugin-json": "^4.1.0",
|
||||
"@rollup/plugin-node-resolve": "^11.0.0",
|
||||
"postcss": "^8.4.5",
|
||||
"postcss-nested": "^5.0.6",
|
||||
@ -158,6 +160,18 @@
|
||||
"rollup": "^2.30.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/plugin-json": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz",
|
||||
"integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@rollup/pluginutils": "^3.0.8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"rollup": "^1.20.0 || ^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/plugin-node-resolve": {
|
||||
"version": "11.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz",
|
||||
@ -4363,6 +4377,15 @@
|
||||
"resolve": "^1.17.0"
|
||||
}
|
||||
},
|
||||
"@rollup/plugin-json": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz",
|
||||
"integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@rollup/pluginutils": "^3.0.8"
|
||||
}
|
||||
},
|
||||
"@rollup/plugin-node-resolve": {
|
||||
"version": "11.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz",
|
||||
|
@ -9,6 +9,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-commonjs": "^17.0.0",
|
||||
"@rollup/plugin-json": "^4.1.0",
|
||||
"@rollup/plugin-node-resolve": "^11.0.0",
|
||||
"postcss": "^8.4.5",
|
||||
"postcss-nested": "^5.0.6",
|
||||
@ -17,11 +18,13 @@
|
||||
"rollup-plugin-livereload": "^2.0.0",
|
||||
"rollup-plugin-svelte": "^7.0.0",
|
||||
"rollup-plugin-terser": "^7.0.0",
|
||||
"mime-types": "^2.1.34",
|
||||
"svelte": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@rollup/plugin-replace": "^3.0.1",
|
||||
"autoprefixer": "^9.8.8",
|
||||
"mime-types": "^2.1.34",
|
||||
"node-sass": "^7.0.1",
|
||||
"sirv-cli": "^1.0.0",
|
||||
"svelte-preprocess": "^4.10.1",
|
||||
|
@ -6,6 +6,7 @@ import livereload from 'rollup-plugin-livereload';
|
||||
import { terser } from 'rollup-plugin-terser';
|
||||
import css from 'rollup-plugin-css-only';
|
||||
import replace from '@rollup/plugin-replace';
|
||||
import json from "@rollup/plugin-json";
|
||||
|
||||
const production = !process.env.ROLLUP_WATCH;
|
||||
|
||||
@ -39,6 +40,7 @@ export default {
|
||||
file: 'public/build/bundle.js'
|
||||
},
|
||||
plugins: [
|
||||
json(),
|
||||
replace({
|
||||
process: JSON.stringify({
|
||||
env: {
|
||||
|
@ -19,10 +19,10 @@
|
||||
class="gradio-page container mx-auto flex flex-col box-border flex-grow text-gray-700 dark:text-gray-50"
|
||||
>
|
||||
<div class="content pt-4 px-4 mb-4">
|
||||
{#if title !== undefined}
|
||||
{#if title}
|
||||
<h1 class="title text-center p-4 text-4xl">{title}</h1>
|
||||
{/if}
|
||||
{#if description !== undefined}
|
||||
{#if description}
|
||||
<p class="description pb-4">{description}</p>
|
||||
{/if}
|
||||
<Interface {input_components} {output_components} {theme} {fn} />
|
||||
|
9
frontend-svelte/src/components/Dummy.svelte
Normal file
9
frontend-svelte/src/components/Dummy.svelte
Normal file
@ -0,0 +1,9 @@
|
||||
<script>
|
||||
export let value, setValue, theme;
|
||||
export let choices;
|
||||
</script>
|
||||
|
||||
<div class="dummy" {theme}>DUMMY</div>
|
||||
|
||||
<style lang="postcss">
|
||||
</style>
|
@ -1,11 +1,49 @@
|
||||
import InputNumber from "./input/Number.svelte";
|
||||
import InputRadio from "./input/Radio.svelte";
|
||||
import InputAudio from "./input/Audio.svelte";
|
||||
import InputFile from "./input/File.svelte";
|
||||
import InputImage from "./input/Image.svelte";
|
||||
import InputVideo from "./input/Video.svelte";
|
||||
import InputDropdown from "./input/Dropdown.svelte";
|
||||
|
||||
import OutputTextbox from "./output/Textbox.svelte";
|
||||
import OutputImage from "./output/Image.svelte";
|
||||
import OutputVideo from "./output/Video.svelte";
|
||||
import OutputAudio from "./output/Audio.svelte";
|
||||
import OutputFile from "./output/File.svelte";
|
||||
import OutputJson from "./output/Json.svelte";
|
||||
import OutputHtml from "./output/Html.svelte";
|
||||
import OutputDataframe from "./output/Dataframe.svelte";
|
||||
|
||||
import Dummy from "./Dummy.svelte"
|
||||
|
||||
export const inputComponentMap = {
|
||||
"audio": InputAudio,
|
||||
"checkbox": Dummy,
|
||||
"checkboxgroup": Dummy,
|
||||
"dataframe": Dummy,
|
||||
"dropdown": InputDropdown,
|
||||
"file": InputFile,
|
||||
"image": InputImage,
|
||||
"number": InputNumber,
|
||||
"radio": InputRadio,
|
||||
"slider": Dummy,
|
||||
"textbox": Dummy,
|
||||
"timeseries": Dummy,
|
||||
"video": InputVideo,
|
||||
}
|
||||
|
||||
export const outputComponentMap = {
|
||||
"audio": OutputAudio,
|
||||
"carousel": Dummy,
|
||||
"dataframe": OutputDataframe,
|
||||
"file": OutputFile,
|
||||
"highlightedtext": Dummy,
|
||||
"html": OutputHtml,
|
||||
"image": OutputImage,
|
||||
"json": OutputJson,
|
||||
"label": Dummy,
|
||||
"textbox": OutputTextbox,
|
||||
"timeseries": Dummy,
|
||||
"video": OutputVideo,
|
||||
}
|
||||
|
35
frontend-svelte/src/components/input/Audio.svelte
Normal file
35
frontend-svelte/src/components/input/Audio.svelte
Normal file
@ -0,0 +1,35 @@
|
||||
<script>
|
||||
import Upload from "../utils/Upload.svelte";
|
||||
|
||||
export let value, setValue, theme;
|
||||
export let source;
|
||||
let recording = false;
|
||||
|
||||
const startRecording = () => {};
|
||||
const stopRecording = () => {};
|
||||
</script>
|
||||
|
||||
<div class="input-audio">
|
||||
{#if value === null}
|
||||
{#if source === "microphone"}
|
||||
{#if recording}
|
||||
<button class="stop" onClick={stopRecording}> Recording... </button>
|
||||
{:else}
|
||||
<button class="start" onClick={startRecording}> Record </button>
|
||||
{/if}
|
||||
{:else if source === "upload"}
|
||||
<Upload filetype="audio/*" load={setValue} {theme}>
|
||||
Drop Audio Here
|
||||
<br />- or -<br />
|
||||
Click to Upload
|
||||
</Upload>
|
||||
{/if}
|
||||
{:else}
|
||||
<audio controls>
|
||||
<source src={value.data} />
|
||||
</audio>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="postcss">
|
||||
</style>
|
46
frontend-svelte/src/components/input/Dropdown.svelte
Normal file
46
frontend-svelte/src/components/input/Dropdown.svelte
Normal file
@ -0,0 +1,46 @@
|
||||
<script>
|
||||
export let value, setValue, theme;
|
||||
export let choices;
|
||||
</script>
|
||||
|
||||
<div class="input-dropdown group inline-block relative" {theme}>
|
||||
<button
|
||||
class="selector py-2 px-3 font-semibold rounded inline-flex items-center"
|
||||
>
|
||||
{value}
|
||||
<svg class="caret ml-2 fill-current h-4 w-4" viewBox="0 0 20 20">
|
||||
<path
|
||||
d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<div
|
||||
class="dropdown-menu-holder absolute hidden group-hover:block pt-1 z-10 bg-none"
|
||||
>
|
||||
<ul class="dropdown-menu max-h-80 overflow-y-auto">
|
||||
{#each choices as choice, i}
|
||||
<li
|
||||
class="dropdown-item first:rounded-t transition last:rounded-b py-2 px-3 block whitespace-nowrap cursor-pointer"
|
||||
on:click={() => setValue(choice)}
|
||||
key={i}
|
||||
>
|
||||
{choice}
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="postcss">
|
||||
.input-dropdown[theme="default"] {
|
||||
.selector {
|
||||
@apply bg-white dark:bg-gray-800 shadow transition hover:shadow-md;
|
||||
}
|
||||
.dropdown-menu {
|
||||
@apply shadow;
|
||||
}
|
||||
.dropdown-item {
|
||||
@apply bg-white dark:bg-gray-800 hover:bg-yellow-500 dark:hover:bg-red-600 hover:text-gray-50 hover:font-semibold;
|
||||
}
|
||||
}
|
||||
</style>
|
29
frontend-svelte/src/components/input/File.svelte
Normal file
29
frontend-svelte/src/components/input/File.svelte
Normal file
@ -0,0 +1,29 @@
|
||||
<script>
|
||||
import Upload from "../utils/Upload.svelte";
|
||||
import { prettyBytes } from "../utils/helpers";
|
||||
|
||||
export let value, setValue, theme;
|
||||
</script>
|
||||
|
||||
<div class="input-file" {theme}>
|
||||
{#if value === null}
|
||||
<Upload load={setValue} {theme}>
|
||||
Drop File Here
|
||||
<br />- or -<br />
|
||||
Click to Upload
|
||||
</Upload>
|
||||
{:else}
|
||||
<div class="file-preview w-full flex flex-col justify-center items-center relative">
|
||||
<div class="file-name text-4xl p-6 break-all">{value.name}</div>
|
||||
<div class="file-size text-2xl p-2">
|
||||
{prettyBytes(value.size)}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="postcss">
|
||||
.input-file[theme="default"] .file-preview {
|
||||
@apply h-60;
|
||||
}
|
||||
</style>
|
30
frontend-svelte/src/components/input/Image.svelte
Normal file
30
frontend-svelte/src/components/input/Image.svelte
Normal file
@ -0,0 +1,30 @@
|
||||
<script>
|
||||
import Upload from "../utils/Upload.svelte";
|
||||
|
||||
export let value, setValue, theme;
|
||||
export let source;
|
||||
</script>
|
||||
|
||||
<div class="input-image">
|
||||
{#if value === null}
|
||||
{#if source === "upload"}
|
||||
<Upload
|
||||
filetype="image/x-png,image/gif,image/jpeg"
|
||||
load={setValue}
|
||||
include_file_metadata={false}
|
||||
{theme}
|
||||
>
|
||||
Drop Image Here
|
||||
<br />- or -<br />
|
||||
Click to Upload
|
||||
</Upload>
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="image-preview w-full h-60 flex justify-center items-center bg-gray-200 dark:bg-gray-600 relative">
|
||||
<img class="w-full h-full object-contain" src={value} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="postcss">
|
||||
</style>
|
45
frontend-svelte/src/components/input/Video.svelte
Normal file
45
frontend-svelte/src/components/input/Video.svelte
Normal file
@ -0,0 +1,45 @@
|
||||
<script>
|
||||
import Upload from "../utils/Upload.svelte";
|
||||
import { prettyBytes, playable } from "../utils/helpers";
|
||||
|
||||
export let value, setValue, theme;
|
||||
export let source;
|
||||
|
||||
</script>
|
||||
|
||||
<div class="input-video">
|
||||
{#if value === null}
|
||||
{#if source === "upload"}
|
||||
<Upload filetype="video/mp4,video/x-m4v,video/*" load={setValue} {theme}>
|
||||
Drop Video Here
|
||||
<br />- or -<br />
|
||||
Click to Upload
|
||||
</Upload>
|
||||
{/if}
|
||||
{:else}
|
||||
<div
|
||||
class="video-preview w-full h-60 flex justify-center items-center bg-gray-200 dark:bg-gray-600 relative"
|
||||
>
|
||||
{#if playable(value.name)}
|
||||
<video
|
||||
class="video_preview"
|
||||
controls
|
||||
playsInline
|
||||
preload
|
||||
src={value.data}
|
||||
/>
|
||||
{:else}
|
||||
<div class="file-preview h-60 w-full flex flex-col justify-center items-center relative">
|
||||
<div class="file-name text-4xl p-6 break-all">{value.name}</div>
|
||||
<div class="file-size text-2xl p-2">
|
||||
{prettyBytes(value.size)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="postcss">
|
||||
</style>
|
10
frontend-svelte/src/components/output/Audio.svelte
Normal file
10
frontend-svelte/src/components/output/Audio.svelte
Normal file
@ -0,0 +1,10 @@
|
||||
<script>
|
||||
export let value, theme;
|
||||
</script>
|
||||
|
||||
<audio {theme} controls>
|
||||
<source src={value} />
|
||||
</audio>
|
||||
|
||||
<style lang="postcss">
|
||||
</style>
|
112
frontend-svelte/src/components/output/Dataframe.svelte
Normal file
112
frontend-svelte/src/components/output/Dataframe.svelte
Normal file
@ -0,0 +1,112 @@
|
||||
<script>
|
||||
export let value, theme;
|
||||
export let headers, max_rows, max_cols, overflow_row_behaviour;
|
||||
let page = 0;
|
||||
let sort_by = null;
|
||||
let sort_descending = false;
|
||||
|
||||
let table_headers = headers || value.headers;
|
||||
let row_count = value.data.length;
|
||||
let col_count = row_count > 0 ? value.data[0].length : 0;
|
||||
let selected_data = value.data.slice();
|
||||
if (sort_by) {
|
||||
let sort_fn;
|
||||
if (sort_descending) {
|
||||
sort_fn = (a, b) =>
|
||||
a[sort_by] === b[sort_by] ? 0 : a[sort_by] < b[sort_by] ? 1 : -1;
|
||||
} else {
|
||||
sort_fn = (a, b) =>
|
||||
a[sort_by] === b[sort_by] ? 0 : a[sort_by] < b[sort_by] ? -1 : 1;
|
||||
}
|
||||
selected_data.sort(sort_fn);
|
||||
}
|
||||
let visible_pages = null;
|
||||
if (max_rows !== null && row_count > max_rows) {
|
||||
if (overflow_row_behaviour === "paginate") {
|
||||
selected_data = selected_data.slice(page * max_rows, page + 1 * max_rows);
|
||||
let page_count = Math.ceil(row_count / max_rows);
|
||||
visible_pages = [];
|
||||
[0, page, page_count - 1].forEach((anchor) => {
|
||||
for (let i = anchor - 2; i <= anchor + 2; i++) {
|
||||
if (i >= 0 && i < page_count && !visible_pages.includes(i)) {
|
||||
if (
|
||||
visible_pages.length > 0 &&
|
||||
i - visible_pages[visible_pages.length - 1] > 1
|
||||
) {
|
||||
visible_pages.push(null);
|
||||
}
|
||||
visible_pages.push(i);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
selected_data = selected_data
|
||||
.slice(0, Math.ceil(max_rows / 2))
|
||||
.concat(
|
||||
[Array(col_count).fill("...")],
|
||||
selected_data.slice(row_count - Math.floor(max_rows / 2))
|
||||
);
|
||||
}
|
||||
}
|
||||
if (max_cols !== null && col_count > max_cols) {
|
||||
let [hidden_col_start, hidden_col_end] = [
|
||||
Math.ceil(max_cols / 2),
|
||||
col_count - Math.floor(max_cols / 2) - 1,
|
||||
];
|
||||
table_headers =
|
||||
table_headers.slice(0, hidden_col_start) +
|
||||
["..."] +
|
||||
table_headers.slice(hidden_col_end);
|
||||
selected_data = selected_data.map(
|
||||
(row) =>
|
||||
row.slice(0, hidden_col_start) + ["..."] + row.slice(hidden_col_end)
|
||||
);
|
||||
}
|
||||
|
||||
const sort_table = (col_index) => {
|
||||
if (sort_by === col_index) {
|
||||
sort_descending = !sort_descending;
|
||||
} else {
|
||||
sort_by = col_index;
|
||||
sort_descending = false;
|
||||
}
|
||||
page = 0;
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="output-dataframe" {theme}>
|
||||
<table>
|
||||
{#if table_headers}
|
||||
<thead class="font-bold border-gray-200 border-b-2">
|
||||
{#each table_headers as header, i}
|
||||
<th class="px-4 transition cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-600" key={i} on:click={() => sort_table(i)}>
|
||||
{header}
|
||||
{#if sort_by === i}
|
||||
<svg
|
||||
class="caret h-3 inline-block ml-1 mb-0.5 fill-current"
|
||||
viewBox="0 0 20 20"
|
||||
transform={sort_descending ? "scale(1, -1)" : ""}
|
||||
>
|
||||
<path
|
||||
d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z"
|
||||
/>{" "}
|
||||
</svg>
|
||||
{/if}
|
||||
</th>
|
||||
{/each}
|
||||
</thead>
|
||||
{/if}
|
||||
<tbody>
|
||||
{#each selected_data as row, i}
|
||||
<tr key={i}>
|
||||
{#each row as cell, j}
|
||||
<td class="px-4" key={j}>{cell}</td>
|
||||
{/each}
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<style lang="postcss">
|
||||
</style>
|
23
frontend-svelte/src/components/output/File.svelte
Normal file
23
frontend-svelte/src/components/output/File.svelte
Normal file
@ -0,0 +1,23 @@
|
||||
<script>
|
||||
import { prettyBytes } from "../utils/helpers";
|
||||
|
||||
export let value, theme;
|
||||
</script>
|
||||
|
||||
<a
|
||||
class="output-file w-full h-full flex flex-col justify-center items-center relative"
|
||||
href={value.data}
|
||||
download={value.name}
|
||||
{theme}
|
||||
>
|
||||
<div class="file-name text-4xl p-6 break-all">{value.name}</div>
|
||||
<div class="text-2xl p-2">
|
||||
{isNaN(value.size) ? "" : prettyBytes(value.size)}
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<style lang="postcss">
|
||||
.output-file[theme="default"] {
|
||||
@apply h-60 hover:text-gray-500;
|
||||
}
|
||||
</style>
|
10
frontend-svelte/src/components/output/Html.svelte
Normal file
10
frontend-svelte/src/components/output/Html.svelte
Normal file
@ -0,0 +1,10 @@
|
||||
<script>
|
||||
export let value, theme;
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="output-html"
|
||||
{theme}
|
||||
>
|
||||
{@html value}
|
||||
</div>
|
10
frontend-svelte/src/components/output/Image.svelte
Normal file
10
frontend-svelte/src/components/output/Image.svelte
Normal file
@ -0,0 +1,10 @@
|
||||
<script>
|
||||
export let value, theme;
|
||||
</script>
|
||||
|
||||
<div class="output-image w-full h-60 flex justify-center items-center bg-gray-200 dark:bg-gray-600 relative" {theme}>
|
||||
<img class="w-full h-full object-contain" src={value} />
|
||||
</div>
|
||||
|
||||
<style lang="postcss">
|
||||
</style>
|
15
frontend-svelte/src/components/output/Json.svelte
Normal file
15
frontend-svelte/src/components/output/Json.svelte
Normal file
@ -0,0 +1,15 @@
|
||||
<script>
|
||||
import JsonNode from "./JsonNode.svelte";
|
||||
|
||||
export let value, theme;
|
||||
</script>
|
||||
|
||||
<div class="output-json font-mono leading-relaxed" {theme}>
|
||||
<JsonNode value={value} depth={0} theme={theme} />
|
||||
</div>
|
||||
|
||||
<style lang="postcss">
|
||||
.output-text[theme="default"] {
|
||||
@apply shadow transition hover:shadow-md dark:bg-gray-800;
|
||||
}
|
||||
</style>
|
78
frontend-svelte/src/components/output/JsonNode.svelte
Normal file
78
frontend-svelte/src/components/output/JsonNode.svelte
Normal file
@ -0,0 +1,78 @@
|
||||
<script>
|
||||
export let value, theme;
|
||||
export let depth;
|
||||
export let collapsed = depth > 4;
|
||||
</script>
|
||||
|
||||
<div class="json-node inline" {theme}>
|
||||
{#if value instanceof Array}
|
||||
{#if collapsed}
|
||||
<button
|
||||
on:click={() => {
|
||||
collapsed = false;
|
||||
}}
|
||||
>
|
||||
[+{value.length} children]
|
||||
</button>
|
||||
{:else}
|
||||
[
|
||||
<div class="json-children pl-4">
|
||||
{#each value as node, i}
|
||||
<div class="json-item">
|
||||
{i}: <svelte:self
|
||||
value={node}
|
||||
depth={depth + 1}
|
||||
{theme}
|
||||
/>,
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
]
|
||||
{/if}
|
||||
{:else if value instanceof Object}
|
||||
{#if collapsed}
|
||||
<button
|
||||
on:click={() => {
|
||||
collapsed = false;
|
||||
}}
|
||||
>
|
||||
{+{Object.keys(value).length} children}
|
||||
</button>
|
||||
{:else}
|
||||
{
|
||||
<div class="json-children pl-4">
|
||||
{#each Object.entries(value) as node}
|
||||
<div class="json-item">
|
||||
{node[0]}: <svelte:self
|
||||
value={node[1]}
|
||||
depth={depth + 1}
|
||||
{theme}
|
||||
/>,
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
}
|
||||
{/if}
|
||||
{:else if value === null}
|
||||
<div class="json-item inline text-gray-500 dark:text-gray-400" item-type="null">null</div>
|
||||
{:else if typeof value === "string"}
|
||||
<div class="json-item inline text-green-500" item-type="string">
|
||||
"{value}"
|
||||
</div>
|
||||
{:else if typeof value === "boolean"}
|
||||
<div class="json-item inline text-red-500" item-type="boolean">
|
||||
{value.toLocaleString()}
|
||||
</div>
|
||||
{:else if typeof value === "number"}
|
||||
<div class="json-item inline text-blue-500" item-type="number">
|
||||
{value}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="json-item inline" item-type="other">
|
||||
{value}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="postcss">
|
||||
</style>
|
30
frontend-svelte/src/components/output/Video.svelte
Normal file
30
frontend-svelte/src/components/output/Video.svelte
Normal file
@ -0,0 +1,30 @@
|
||||
<script>
|
||||
import { prettyBytes, playable } from "../utils/helpers";
|
||||
|
||||
export let value, theme;
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="output-video w-full h-60 flex justify-center items-center bg-gray-200 dark:bg-gray-600 relative"
|
||||
>
|
||||
{#if playable(value.name)}
|
||||
<video
|
||||
class="video_preview"
|
||||
controls
|
||||
playsInline
|
||||
preload
|
||||
src={value.data}
|
||||
/>
|
||||
{:else}
|
||||
<a
|
||||
href={value.data}
|
||||
download={value.name}
|
||||
class="file-preview h-60 w-full flex flex-col justify-center items-center relative"
|
||||
>
|
||||
<div class="file-name text-4xl p-6 break-all">{value.name}</div>
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="postcss">
|
||||
</style>
|
71
frontend-svelte/src/components/utils/Upload.svelte
Normal file
71
frontend-svelte/src/components/utils/Upload.svelte
Normal file
@ -0,0 +1,71 @@
|
||||
<script>
|
||||
export let load, filetype, theme;
|
||||
export let single_file = true;
|
||||
export let include_file_metadata = true;
|
||||
let hidden_upload;
|
||||
|
||||
const openFileUpload = () => {
|
||||
hidden_upload.click();
|
||||
};
|
||||
const loadFiles = (files) => {
|
||||
if (!files.length || !window.FileReader) {
|
||||
return;
|
||||
}
|
||||
if (single_file) {
|
||||
files = [files[0]];
|
||||
}
|
||||
var all_file_data = [];
|
||||
files.forEach((file, i) => {
|
||||
let ReaderObj = new FileReader();
|
||||
ReaderObj.readAsDataURL(file);
|
||||
ReaderObj.onloadend = function (e) {
|
||||
all_file_data[i] = include_file_metadata
|
||||
? {
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
data: this.result,
|
||||
is_example: false,
|
||||
}
|
||||
: this.result;
|
||||
if (Object.keys(all_file_data).length === files.length) {
|
||||
load(single_file ? all_file_data[0] : all_file_data);
|
||||
}
|
||||
};
|
||||
});
|
||||
};
|
||||
const loadFilesFromUpload = (e) => {
|
||||
loadFiles(e.target.files);
|
||||
};
|
||||
const loadFilesFromDrop = (e) => {
|
||||
loadFiles(e.dataTransfer.files);
|
||||
};
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="upload h-60 border-gray-300 text-gray-400 dark:text-gray-500 dark:border-gray-500 border-8 border-dashed w-full flex justify-center items-center text-3xl text-center cursor-pointer leading-10"
|
||||
{theme}
|
||||
on:drag|preventDefault|stopPropagation
|
||||
on:dragstart|preventDefault|stopPropagation
|
||||
on:dragend|preventDefault|stopPropagation
|
||||
on:dragover|preventDefault|stopPropagation
|
||||
on:dragenter|preventDefault|stopPropagation
|
||||
on:dragleave|preventDefault|stopPropagation
|
||||
on:drop|preventDefault|stopPropagation
|
||||
on:click={openFileUpload}
|
||||
on:drop={loadFilesFromDrop}
|
||||
>
|
||||
<slot />
|
||||
<input
|
||||
class="hidden-upload hidden"
|
||||
type="file"
|
||||
bind:this={hidden_upload}
|
||||
on:change={loadFilesFromUpload}
|
||||
accept={filetype}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<style lang="postcss">
|
||||
.upload[theme="default"] {
|
||||
@apply transition hover:border-gray-400 hover:text-gray-500 dark:hover:border-gray-300 dark:hover:text-gray-300;
|
||||
}
|
||||
</style>
|
20
frontend-svelte/src/components/utils/helpers.js
Normal file
20
frontend-svelte/src/components/utils/helpers.js
Normal file
@ -0,0 +1,20 @@
|
||||
// import mime from "mime-types";
|
||||
|
||||
export const playable = (filename) => {
|
||||
// let video_element = document.createElement("video");
|
||||
// let mime_type = mime.lookup(filename);
|
||||
// return video_element.canPlayType(mime_type) != "";
|
||||
return true; // FIX BEFORE COMMIT - mime import causing issues
|
||||
};
|
||||
|
||||
export const prettyBytes = (bytes) => {
|
||||
let units = ["B", "KB", "MB", "GB", "PB"];
|
||||
let i = 0;
|
||||
while (bytes > 1024) {
|
||||
bytes /= 1024;
|
||||
i++;
|
||||
}
|
||||
let unit = units[i];
|
||||
return bytes.toFixed(1) + " " + unit;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user