mirror of
https://github.com/CharaChorder/DeviceManager.git
synced 2026-01-20 08:52:59 +00:00
layout sharing via url
[deploy]
This commit is contained in:
@@ -2,7 +2,8 @@
|
||||
import {serialPort, syncStatus} from "$lib/serial/connection"
|
||||
import {browser} from "$app/environment"
|
||||
import {page} from "$app/stores"
|
||||
import {slide} from "svelte/transition"
|
||||
import {slide, fly} from "svelte/transition"
|
||||
import {canShare, triggerShare} from "$lib/share"
|
||||
|
||||
const training = [
|
||||
{slug: "cpm", title: "CPM - Characters Per Minute", icon: "music_note"},
|
||||
@@ -29,6 +30,10 @@
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
{#if $canShare}
|
||||
<a transition:fly={{x: -8}} class="icon" on:click={triggerShare}>share</a>
|
||||
<div transition:slide class="separator" />
|
||||
{/if}
|
||||
{#await import("$lib/components/PwaStatus.svelte") then { default: PwaStatus }}
|
||||
<PwaStatus />
|
||||
{/await}
|
||||
@@ -63,7 +68,7 @@
|
||||
>
|
||||
cable
|
||||
</a>
|
||||
<a href="/" title="Statistics" class="icon account">person</a>
|
||||
<a href="/stats/" title="Statistics" class="icon account">person</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@@ -119,6 +124,12 @@
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.separator {
|
||||
width: 1px;
|
||||
height: 24px;
|
||||
background: var(--md-sys-color-outline-variant);
|
||||
}
|
||||
|
||||
nav {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
@@ -143,6 +154,10 @@
|
||||
|
||||
position: relative;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
aspect-ratio: 1;
|
||||
padding: 4px;
|
||||
|
||||
@@ -168,6 +183,9 @@
|
||||
}
|
||||
|
||||
.steps {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
translate: -50% 0;
|
||||
display: flex;
|
||||
|
||||
> a.icon {
|
||||
|
||||
@@ -21,9 +21,7 @@ export async function getSharableUrl(name: string, data: any, baseHref = window.
|
||||
return new Promise(async resolve => {
|
||||
const reader = new FileReader()
|
||||
reader.onloadend = function () {
|
||||
const base64String = (reader.result as string)
|
||||
.replace(/^data:application\/octet-stream;base64,/, "")
|
||||
.replace(/==$/, "")
|
||||
const base64String = (reader.result as string).replace(/^data:application\/octet-stream;base64,/, "")
|
||||
const url = new URL(baseHref)
|
||||
url.searchParams.set(name, base64String)
|
||||
resolve(url)
|
||||
@@ -31,3 +29,15 @@ export async function getSharableUrl(name: string, data: any, baseHref = window.
|
||||
reader.readAsDataURL(await stringifyCompressed(data))
|
||||
})
|
||||
}
|
||||
|
||||
export async function parseSharableUrl<T>(
|
||||
name: string,
|
||||
url: string = window.location.href,
|
||||
): Promise<T | undefined> {
|
||||
const searchParams = new URL(url).searchParams
|
||||
if (!searchParams.has(name)) return
|
||||
|
||||
return await fetch(`data:application/octet-stream;base64,${searchParams.get(name)}`)
|
||||
.then(it => it.blob())
|
||||
.then(it => parseCompressed(it))
|
||||
}
|
||||
|
||||
22
src/lib/share.ts
Normal file
22
src/lib/share.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import type {Action} from "svelte/action"
|
||||
import {readonly, writable} from "svelte/store"
|
||||
|
||||
const setCanShare = writable(false)
|
||||
export const canShare = readonly(setCanShare)
|
||||
|
||||
let shareCallback: ((event: Event) => void) | undefined
|
||||
export function triggerShare(event: Event) {
|
||||
shareCallback?.(event)
|
||||
}
|
||||
|
||||
export const share: Action<Window, (event: Event) => void> = (node, callback: (event: Event) => void) => {
|
||||
setCanShare.set(true)
|
||||
shareCallback = callback
|
||||
|
||||
return {
|
||||
destroy() {
|
||||
setCanShare.set(false)
|
||||
shareCallback = undefined
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user