Files
fnx_web/svelte/src/filesystem/ShareDialog.svelte

189 lines
4.6 KiB
Svelte
Raw Normal View History

2025-06-05 21:29:07 +02:00
<script lang="ts">
import type { FSNavigator } from "./FSNavigator";
import { fs_check_is_error, fs_node_icon, fs_share_hotlink_url, fs_share_url, fs_update, type FSNode, type FSPermissions } from "lib/FilesystemAPI.svelte";
2025-06-05 21:29:07 +02:00
import CopyButton from "layout/CopyButton.svelte";
import Dialog from "layout/Dialog.svelte";
2025-06-12 11:32:56 +02:00
import { fade } from "svelte/transition";
import { get_user } from "lib/NovaAPI";
import Button from "layout/Button.svelte";
2025-06-05 21:29:07 +02:00
2025-10-13 16:05:50 +02:00
let { nav }: {
nav: FSNavigator;
} = $props();
2025-06-05 21:29:07 +02:00
let path: FSNode[]
2025-10-13 16:05:50 +02:00
let base: FSNode = $state()
let share_url = $state("")
let direct_share_url = $state("")
let parent_node: FSNode = $state()
2025-06-05 21:29:07 +02:00
2025-10-13 16:05:50 +02:00
let dialog: Dialog = $state()
let dialog_not_allowed: Dialog = $state()
2025-06-05 21:29:07 +02:00
export const open = async (e: MouseEvent, p: FSNode[]) => {
path = p
base = path[path.length-1]
const user = await get_user()
if (user.subscription.file_sharing === false && base.created_by === user.id) {
}
2025-06-05 21:29:07 +02:00
share_url = fs_share_url(path)
if (share_url === "") {
// File is not public, make public
try {
await make_public()
} catch (err) {
if (fs_check_is_error(err, "sharing_not_allowed")) {
if (e.target instanceof HTMLButtonElement) {
dialog_not_allowed.open(e.target.getBoundingClientRect())
} else {
dialog_not_allowed.open((e.target as HTMLElement).parentElement.getBoundingClientRect())
}
return
} else {
alert("Error file making file public: "+err)
}
}
2025-06-05 21:29:07 +02:00
}
await share()
if (e.target instanceof HTMLButtonElement) {
dialog.open(e.target.getBoundingClientRect())
} else {
dialog.open((e.target as HTMLElement).parentElement.getBoundingClientRect())
}
}
const make_public = async () => {
if (!base.is_shared()) {
base = await fs_update(
base.path,
{link_permissions: {read: true} as FSPermissions},
)
await nav.reload()
2025-06-05 21:29:07 +02:00
// Insert the new FSNode into the path
path[path.length-1] = base
}
2025-06-05 21:29:07 +02:00
}
let share_parent = $state(false)
let navigator_share = $state(false)
2025-06-05 21:29:07 +02:00
const share = async () => {
// If the base node is not shared then the file is shared through a parent
// node. In that case we ask the user if it was their intention to share the
// parent directory
share_parent = !base.is_shared()
navigator_share = navigator.share !== undefined
if (!base.is_shared()) {
2025-06-05 21:29:07 +02:00
// Walk path backwards looking for the last public ID
for (let i = path.length - 1; i >= 0; i--) {
if (path[i].is_shared()) {
2025-06-05 21:29:07 +02:00
parent_node = path[i]
break
}
}
}
share_url = fs_share_url(path)
direct_share_url = fs_share_hotlink_url(path)
}
2025-06-05 21:29:07 +02:00
const nav_share = async (url: string) => {
await navigator.share({
title: base.name,
text: "I would like to share '" + base.name + "' with you",
url: url,
})
2025-06-05 21:29:07 +02:00
}
</script>
<Dialog bind:this={dialog_not_allowed}>
<div class="dialog_inner">
<div class="highlight_yellow" transition:fade>
Sharing is not allowed on free accounts. Upgrade to premium to
enable this feature
</div>
</div>
</Dialog>
2025-06-05 21:29:07 +02:00
<Dialog bind:this={dialog}>
<div class="dialog_inner">
<div>Sharing link</div>
<div class="link_copy">
<div class="button_container">
<CopyButton text={share_url}>Copy</CopyButton>
{#if navigator_share}
<Button icon="share" label="Share" click={() => {nav_share(share_url)}}/>
{/if}
2025-06-05 21:29:07 +02:00
</div>
<a href="{share_url}">{share_url}</a>
</div>
<div class="separator"></div>
<div>Direct sharing link (hotlink)</div>
<div class="link_copy">
<div class="button_container">
<CopyButton text={direct_share_url}>Copy</CopyButton>
{#if navigator_share}
<Button icon="share" label="Share" click={() => {nav_share(direct_share_url)}}/>
{/if}
2025-06-05 21:29:07 +02:00
</div>
<a href="{direct_share_url}">{direct_share_url}</a>
</div>
2025-06-12 11:32:56 +02:00
{#if share_parent}
2025-06-12 11:32:56 +02:00
<div class="separator"></div>
<div>
This link also gives access to
<img src={fs_node_icon(parent_node, 64, 64)} class="node_icon" alt="icon"/>
{parent_node.name}
<br/>
2025-10-13 16:05:50 +02:00
<button onclick={async e => {await make_public(); await share()}} style="display: inline;">
2025-06-12 11:32:56 +02:00
Only share
<img src={fs_node_icon(base, 64, 64)} class="node_icon" alt="icon"/>
{base.name}
</button>
</div>
{/if}
2025-06-05 21:29:07 +02:00
</div>
</Dialog>
<style>
.dialog_inner {
display: flex;
flex-direction: column;
text-align: center;
2025-06-12 11:32:56 +02:00
max-width: 40em;
2025-06-05 21:29:07 +02:00
}
.link_copy {
display: flex;
flex-direction: row;
align-items: center;
gap: 0.5em;
}
.link_copy > .button_container {
flex: 0 0 auto;
}
.link_copy > a {
flex: 1 1 auto;
text-overflow: ellipsis;
white-space: nowrap;
overflow-x: hidden;
}
.node_icon {
width: 1.5em;
height: 1.5em;
vertical-align: middle;
}
.separator {
height: 1px;
border: none;
background-color: var(--separator);
2025-06-12 11:32:56 +02:00
margin-top: 0.5em;
margin-bottom: 0.5em;
2025-06-05 21:29:07 +02:00
}
</style>