Add embedding options to filesystem

This commit is contained in:
2024-02-16 21:07:01 +01:00
parent 68ef84b1e7
commit a9d685424f
8 changed files with 246 additions and 94 deletions

View File

@@ -314,7 +314,7 @@ h4,
h5, h5,
h6 { h6 {
line-height: 1; line-height: 1;
margin: 0.5em 0; margin: 0.3em 0;
font-weight: lighter; font-weight: lighter;
font-family: 'Open Sans Light', sans-serif; font-family: 'Open Sans Light', sans-serif;
} }
@@ -365,7 +365,7 @@ a {
} }
p { p {
margin: 1em 0; margin: 0.5em 0;
} }
/* Forms*/ /* Forms*/

View File

@@ -130,7 +130,7 @@ onDestroy(close_socket)
line-height: 0.75em; line-height: 0.75em;
margin-top: 0.5em; margin-top: 0.5em;
} }
@media (max-width: 600px) { @media (max-width: 700px) {
.label { .label {
text-align: center; text-align: center;
padding-left: 0; padding-left: 0;

View File

@@ -55,7 +55,7 @@ const keydown = e => {
if (edit_visible) { if (edit_visible) {
edit_visible = false edit_visible = false
} else { } else {
edit_window.edit(state.base, true) edit_window.edit(state.base, true, "file")
} }
break; break;
case "s": case "s":
@@ -242,7 +242,10 @@ const update_css = path => document.documentElement.style = branding_from_path(p
flex-direction: row; flex-direction: row;
overflow: hidden; overflow: hidden;
} }
@media (max-width: 600px) {
/* This max-width needs to be synced with the .toolbar max-width in
Toolbar.svelte and the .label max-width in FileStats.svelte */
@media (max-width: 700px) {
.viewer_area { .viewer_area {
flex-direction: column-reverse; flex-direction: column-reverse;
} }

View File

@@ -25,7 +25,7 @@ $: share_url = generate_share_url(state.path)
let link_copied = false let link_copied = false
export const copy_link = () => { export const copy_link = () => {
if (share_url === "") { if (share_url === "") {
edit_window.edit(state.base, "share", true) edit_window.edit(state.base, true, "share")
return return
} }
@@ -119,7 +119,7 @@ let expand = e => {
</button> </button>
{#if state.base.id !== "me" && state.permissions.update === true} {#if state.base.id !== "me" && state.permissions.update === true}
<button on:click={() => edit_window.edit(state.base, true)} class:button_highlight={edit_visible}> <button on:click={() => edit_window.edit(state.base, true, "file")} class:button_highlight={edit_visible}>
<i class="icon">edit</i> <i class="icon">edit</i>
<span><u>E</u>dit</span> <span><u>E</u>dit</span>
</button> </button>
@@ -161,7 +161,10 @@ let expand = e => {
.button_expand { .button_expand {
display: none; display: none;
} }
@media (max-width: 600px) {
/* This max-width needs to be synced with the .viewer_area max-width in
Toolbar.svelte and the .label max-width in FileStats.svelte */
@media (max-width: 700px) {
.toolbar { .toolbar {
overflow-y: hidden; overflow-y: hidden;
max-height: 2.5em; max-height: 2.5em;

View File

@@ -1,11 +1,11 @@
<script> <script>
import { fs_delete_all, fs_rename, fs_update } from "../FilesystemAPI"; import { fs_rename, fs_update } from "../FilesystemAPI";
import Modal from "../../util/Modal.svelte"; import Modal from "../../util/Modal.svelte";
import { createEventDispatcher } from "svelte"; import { createEventDispatcher } from "svelte";
import Button from "../../layout/Button.svelte";
import BrandingOptions from "./BrandingOptions.svelte"; import BrandingOptions from "./BrandingOptions.svelte";
import PathLink from "../util/PathLink.svelte";
import { branding_from_node } from "./Branding"; import { branding_from_node } from "./Branding";
import FileOptions from "./FileOptions.svelte";
import SharingOptions from "./SharingOptions.svelte";
let dispatch = createEventDispatcher() let dispatch = createEventDispatcher()
@@ -19,17 +19,24 @@ let file = {
}; };
let custom_css = "" let custom_css = ""
$: is_root_dir = file.path === "/"+file.id
export let visible export let visible
export const edit = (f, oae = false, t = "file") => {
// Open the edit window. Argument 1 is the file to edit, 2 is whether the file
// should be opened after the user finishes editing and 3 is the default tab
// that should be open when the window shows
export const edit = (f, oae = false, open_tab = "") => {
file = f file = f
open_after_edit = oae open_after_edit = oae
tab = t if (open_tab !== "") {
tab = open_tab
}
console.log("Editing file", file) console.log("Editing file", file)
file_name = file.name // We save the name in a separate field because we need both the original
// name and the new name for the rename operation
new_name = file.name
shared = !(file.id === undefined || file.id === "") shared = !(file.id === undefined || file.id === "")
if (file.properties === undefined) { if (file.properties === undefined) {
@@ -49,8 +56,8 @@ export const edit = (f, oae = false, t = "file") => {
let tab = "file" let tab = "file"
let open_after_edit = false let open_after_edit = false
let file_name = ""
let shared = false let shared = false
let new_name = ""
let branding_enabled = false let branding_enabled = false
let branding_colors let branding_colors
@@ -63,14 +70,13 @@ let branding_fields = [
"brand_card_color", "brand_card_color",
"brand_header_image", "brand_header_image",
"brand_header_link", "brand_header_link",
"brand_footer_image",
"brand_footer_link",
"brand_background_image", "brand_background_image",
] ]
const save = async () => { const save = async (keep_editing = false) => {
console.debug("Saving file", file.path) console.debug("Saving file", file.path)
let new_file
try { try {
dispatch("loading", true) dispatch("loading", true)
let opts = {shared: shared} let opts = {shared: shared}
@@ -86,14 +92,17 @@ const save = async () => {
} }
} }
await fs_update(file.path, opts) new_file = await fs_update(file.path, opts)
if (file_name !== file.name) { if (new_name !== file.name) {
let parent = file.path.slice(0, -file.name.length) let parent = file.path.slice(0, -file.name.length)
console.log("Moving", file.path, "to", parent+file_name) console.log("Moving", file.path, "to", parent+new_name)
await fs_rename(file.path, parent+file_name) await fs_rename(file.path, parent+new_name)
file.path = parent+file_name file.path = parent+new_name
new_file.name = new_name
new_file.path = file.path
} }
} catch (err) { } catch (err) {
if (err.message) { if (err.message) {
@@ -112,27 +121,10 @@ const save = async () => {
} else { } else {
fs_navigator.reload() fs_navigator.reload()
} }
}
const delete_file = async e => {
e.preventDefault()
try { if (keep_editing) {
dispatch("loading", true) edit(new_file, open_after_edit)
await fs_delete_all(file.path)
} catch (err) {
console.error(err)
alert(err)
return
} finally {
dispatch("loading", false)
} }
if (open_after_edit) {
fs_navigator.navigate(file.path, false)
} else {
fs_navigator.reload()
}
visible = false
} }
</script> </script>
@@ -152,55 +144,33 @@ const delete_file = async e => {
</button> </button>
</div> </div>
<form id="edit_form" on:submit|preventDefault={save}></form> <form id="edit_form" on:submit|preventDefault={() => save(false)}></form>
{#if tab === "file"} <div class="tab_content">
<div class="tab_content"> {#if tab === "file"}
<h2>File settings</h2> <FileOptions
{#if is_root_dir} fs_navigator={fs_navigator}
<div class="highlight_yellow"> bind:file
Filesystem root cannot be renamed. If this shared directory bind:new_name
is in bind:visible
<PathLink nav={fs_navigator} path="/me">your filesystem</PathLink> bind:open_after_edit
you can rename it from there on:loading
</div> />
{/if} {:else if tab === "share"}
<div class="form_grid"> <SharingOptions
<label for="file_name">Name</label> bind:file
<input form="edit_form" bind:value={file_name} id="file_name" type="text" class="form_input" disabled={is_root_dir}/> bind:shared
</div> on:save={() => save(true)}
<h2>Delete</h2> />
<p> {:else if tab === "branding"}
Delete this file or directory. If this is a directory then all
subfiles will be deleted as well. This action cannot be undone.
</p>
<Button click={delete_file} red icon="delete" label="Delete" style="align-self: flex-start;"/>
</div>
{:else if tab === "share"}
<div class="tab_content">
<h2>Share this file/directory</h2>
<p>
When a file or directory is shared it can be accessed
through a unique link. You can get the URL with the 'Copy
link' button on the toolbar, or share the link with the
'Share' button. If you share a directory all the files
within the directory are also accessible from the link.
</p>
<div>
<input form="edit_form" bind:checked={shared} id="shared" type="checkbox" class="form_input"/>
<label for="shared">Share this file or directory</label>
</div>
</div>
{:else if tab === "branding"}
<div class="tab_content">
<BrandingOptions <BrandingOptions
bind:enabled={branding_enabled} bind:enabled={branding_enabled}
bind:colors={branding_colors} bind:colors={branding_colors}
file={file} bind:file
on:style_change={e => custom_css = branding_from_node(file)} on:style_change={e => custom_css = branding_from_node(file)}
/> />
</div> {/if}
{/if} </div>
</Modal> </Modal>
<style> <style>
@@ -208,13 +178,6 @@ const delete_file = async e => {
border-bottom: 2px solid var(--separator); border-bottom: 2px solid var(--separator);
} }
.tab_content { .tab_content {
display: flex;
flex-direction: column;
padding: 8px; padding: 8px;
} }
.form_grid {
display: grid;
grid-template-columns: 1fr 10fr;
align-items: center;
}
</style> </style>

View File

@@ -0,0 +1,66 @@
<script>
import { createEventDispatcher } from "svelte";
import Button from "../../layout/Button.svelte";
import { fs_delete_all } from "../FilesystemAPI";
import PathLink from "../util/PathLink.svelte";
let dispatch = createEventDispatcher()
export let fs_navigator
export let file = {}
export let new_name
export let visible
export let open_after_edit
$: is_root_dir = file.path === "/"+file.id
const delete_file = async e => {
e.preventDefault()
try {
dispatch("loading", true)
await fs_delete_all(file.path)
} catch (err) {
console.error(err)
alert(err)
return
} finally {
dispatch("loading", false)
}
if (open_after_edit) {
fs_navigator.navigate(file.path, false)
} else {
fs_navigator.reload()
}
visible = false
}
</script>
<h2>File settings</h2>
{#if is_root_dir}
<div class="highlight_yellow">
Filesystem root cannot be renamed. If this shared directory
is in
<PathLink nav={fs_navigator} path="/me">your filesystem</PathLink>
you can rename it from there
</div>
{/if}
<div class="form_grid">
<label for="file_name">Name</label>
<input form="edit_form" bind:value={new_name} id="file_name" type="text" class="form_input" disabled={is_root_dir}/>
</div>
<h2>Delete</h2>
<p>
Delete this file or directory. If this is a directory then all
subfiles will be deleted as well. This action cannot be undone.
</p>
<Button click={delete_file} red icon="delete" label="Delete" style="align-self: flex-start;"/>
<style>
.form_grid {
display: grid;
grid-template-columns: 1fr 10fr;
align-items: center;
}
</style>

View File

@@ -0,0 +1,117 @@
<script>
import { createEventDispatcher } from "svelte";
import { copy_text, domain_url } from "../../util/Util.svelte";
import Button from "../../layout/Button.svelte";
let dispatch = createEventDispatcher()
export let shared
export let file
let embed_html
let preview_area
$: is_shared = file.id !== undefined && file.id !== ""
$: share_link = window.location.protocol+"//"+window.location.host+"/d/"+file.id
$: embed_iframe(file)
let embed_iframe = file => {
if (!is_shared) {
example = false
embed_html = "File is not shared, can't generate embed code"
return
}
let url = domain_url()+"/d/"+file.id
embed_html = `<iframe ` +
`src="${url}" ` +
`style="border: none; width: 800px; max-width: 100%; height: 600px; max-height: 100%; border-radius: 8px;"` +
`></iframe>`
}
let copy_status = "" // empty, success or error
const copy = () => {
if (copy_text(embed_html)) {
copy_status = "success"
} else {
copy_status = "error"
alert("Your browser does not support copying text.")
}
}
let example = false
const toggle_example = () => {
if (is_shared) {
example = !example
if (example) {
preview_area.innerHTML = embed_html
} else {
preview_area.innerHTML = ""
}
}
}
</script>
<h2>Share this file/directory</h2>
<p>
When a file or directory is shared it can be accessed through a
unique link. You can get the URL with the 'Copy link' button on
the toolbar, or share the link with the 'Share' button. If you
share a directory all the files within the directory are also
accessible from the link.
</p>
<div class="form_grid">
<div>
<input form="edit_form" bind:checked={shared} id="shared" type="checkbox" class="form_input"/>
<label for="shared">Share this file or directory</label>
</div>
<button on:click={() => dispatch("save")}><i class="icon">save</i> Save</button>
{#if is_shared}
<span>Your sharing link: <a href={share_link}>{share_link}</a></span>
<Button highlight_on_click icon="content_copy" label="Copy" click={e => copy_text(share_link)}/>
{/if}
</div>
<h2>Embedding</h2>
<p>
If you have a website you can embed pixeldrain directories and files in your
own webpages with the code below. If you embed a directory then all
subdirectories and files will be accessible through the frame. Branding
options will also apply in the frame, but only when applied to this
directory. It will not inherit the style from parent directories.
</p>
<h3>Code</h3>
<p>
Put this code in your website to embed the file or directory.
</p>
<div class="center">
<textarea bind:value={embed_html} style="width: 100%; height: 4em;"></textarea>
<br/>
<button on:click={copy} class:button_highlight={copy_status === "success"} class:button_red={copy_status === "error"}>
<i class="icon">content_copy</i>
{#if copy_status === "success"}
Copied!
{:else if copy_status === "error"}
Error!
{:else}
Copy HTML
{/if}
</button>
<button on:click={toggle_example} class:button_highlight={example} disabled={!is_shared}>
<i class="icon">visibility</i> Show example
</button>
</div>
<div bind:this={preview_area} style="text-align: center;"></div>
<style>
.center {
text-align: center;
}
.form_grid {
display: grid;
grid-template-columns: 10fr auto;
align-items: center;
}
</style>

View File

@@ -71,7 +71,7 @@ const node_select = e => {
state.children[index].fm_selected = !state.children[index].fm_selected state.children[index].fm_selected = !state.children[index].fm_selected
} }
const node_settings = e => edit_window.edit(state.children[e.detail], false) const node_settings = e => edit_window.edit(state.children[e.detail], false, "file")
const node_branding = e => edit_window.edit(state.children[e.detail], false, "branding") const node_branding = e => edit_window.edit(state.children[e.detail], false, "branding")
const navigate_up = () => { const navigate_up = () => {