parent
00fd514da5
commit
e4ce767444
18 changed files with 263 additions and 65 deletions
@ -0,0 +1,13 @@ |
||||
export class Files { |
||||
static toString(f: File | Blob): Promise<string> { |
||||
const reader = new window.FileReader() |
||||
reader.readAsDataURL(f) |
||||
return new Promise((resolve) => { |
||||
reader.onloadend = () => resolve(reader.result as string) |
||||
}) |
||||
} |
||||
|
||||
static fromString(s: string): Promise<Blob> { |
||||
return fetch(s).then((r) => r.blob()) |
||||
} |
||||
} |
@ -0,0 +1,69 @@ |
||||
<script lang="ts"> |
||||
import type { FileDTO } from '$lib/api' |
||||
import { Files } from '$lib/files' |
||||
import { createEventDispatcher } from 'svelte' |
||||
|
||||
export let label: string = '' |
||||
let files: File[] = [] |
||||
|
||||
const dispatch = createEventDispatcher<{ file: string }>() |
||||
|
||||
async function onInput(e: Event) { |
||||
const input = e.target as HTMLInputElement |
||||
if (input.files.length) { |
||||
files = Array.from(input.files) |
||||
const data: FileDTO[] = await Promise.all( |
||||
files.map(async (file) => ({ |
||||
name: file.name, |
||||
type: file.type, |
||||
size: file.size, |
||||
contents: await Files.toString(file), |
||||
})) |
||||
) |
||||
console.debug( |
||||
'files', |
||||
data.map((d) => d.contents.length) |
||||
) |
||||
dispatch('file', JSON.stringify(data)) |
||||
} else { |
||||
dispatch('file', '') |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<label> |
||||
<small> |
||||
{label} |
||||
</small> |
||||
<input type="file" on:change={onInput} multiple /> |
||||
<div class="box"> |
||||
{#if files.length} |
||||
<div> |
||||
<b>Selected Files</b> |
||||
{#each files as file} |
||||
<div class="file"> |
||||
{file.name} |
||||
</div> |
||||
{/each} |
||||
</div> |
||||
{:else} |
||||
<div> |
||||
<b>No Files Selected</b> |
||||
</div> |
||||
{/if} |
||||
</div> |
||||
</label> |
||||
|
||||
<style> |
||||
input { |
||||
display: none; |
||||
} |
||||
|
||||
.box { |
||||
display: flex; |
||||
flex-direction: column; |
||||
justify-content: center; |
||||
align-items: center; |
||||
cursor: pointer; |
||||
} |
||||
</style> |
@ -0,0 +1,69 @@ |
||||
<script lang="ts"> |
||||
import type { FileDTO, NotePublic } from '$lib/api' |
||||
import { Files } from '$lib/files' |
||||
import copy from 'copy-to-clipboard' |
||||
import { saveAs } from 'file-saver' |
||||
import prettyBytes from 'pretty-bytes' |
||||
import Button from './Button.svelte' |
||||
|
||||
export let note: NotePublic |
||||
|
||||
let files: FileDTO[] = [] |
||||
|
||||
$: if (note.meta.type === 'file') { |
||||
files = JSON.parse(note.contents) as FileDTO[] |
||||
} |
||||
|
||||
$: download = () => { |
||||
for (const file of files) { |
||||
downloadFile(file) |
||||
} |
||||
} |
||||
|
||||
async function downloadFile(file: FileDTO) { |
||||
const f = new File([await Files.fromString(file.contents)], file.name, { |
||||
type: file.type, |
||||
}) |
||||
saveAs(f) |
||||
} |
||||
</script> |
||||
|
||||
<p class="error-text">you will <b>not</b> get the chance to see the note again.</p> |
||||
{#if note.meta.type === 'text'} |
||||
<div class="note" data-testid="note-result"> |
||||
{note.contents} |
||||
</div> |
||||
<Button on:click={() => copy(note.contents)}>copy to clipboard</Button> |
||||
{:else} |
||||
{#each files as file} |
||||
<div class="note file" data-testid="note-result"> |
||||
<b on:click={() => downloadFile(file)}>↓ {file.name}</b> |
||||
<small> {file.type} - {prettyBytes(file.size)}</small> |
||||
</div> |
||||
{/each} |
||||
<Button on:click={download}>download all</Button> |
||||
{/if} |
||||
|
||||
<style> |
||||
.note { |
||||
width: 100%; |
||||
margin: 0; |
||||
padding: 0; |
||||
border: 2px solid var(--ui-bg-1); |
||||
outline: none; |
||||
padding: 0.5rem; |
||||
white-space: pre; |
||||
overflow: auto; |
||||
margin-bottom: 0.5rem; |
||||
} |
||||
|
||||
.note b { |
||||
cursor: pointer; |
||||
} |
||||
|
||||
.note.file { |
||||
display: flex; |
||||
justify-content: space-between; |
||||
align-items: center; |
||||
} |
||||
</style> |
Loading…
Reference in new issue