Add header image to branding options
This commit is contained in:
@@ -4,9 +4,10 @@ import { formatDataVolume, formatDate, formatThousands } from "../util/Formattin
|
|||||||
import Modal from "../util/Modal.svelte";
|
import Modal from "../util/Modal.svelte";
|
||||||
import { fs_timeseries } from "./FilesystemAPI";
|
import { fs_timeseries } from "./FilesystemAPI";
|
||||||
import { fs_path_url } from "./FilesystemUtil";
|
import { fs_path_url } from "./FilesystemUtil";
|
||||||
import { generate_share_url } from "./Sharebar.svelte";
|
import { generate_share_path, generate_share_url } from "./Sharebar.svelte";
|
||||||
import { color_by_name } from "../util/Util.svelte";
|
import { color_by_name, copy_text } from "../util/Util.svelte";
|
||||||
import { tick } from "svelte";
|
import { tick } from "svelte";
|
||||||
|
import Button from "../layout/Button.svelte";
|
||||||
|
|
||||||
export let state
|
export let state
|
||||||
export let visible = false
|
export let visible = false
|
||||||
@@ -21,6 +22,7 @@ const visibility_change = visible => {
|
|||||||
|
|
||||||
$: direct_url = window.location.origin+fs_path_url(state.base.path)
|
$: direct_url = window.location.origin+fs_path_url(state.base.path)
|
||||||
$: share_url = generate_share_url(state.path)
|
$: share_url = generate_share_url(state.path)
|
||||||
|
$: direct_share_url = window.location.origin+fs_path_url(generate_share_path(state.path))
|
||||||
|
|
||||||
let chart
|
let chart
|
||||||
let chart_timespan = 0
|
let chart_timespan = 0
|
||||||
@@ -171,9 +173,28 @@ let update_chart = async (base, timespan, interval) => {
|
|||||||
</tr>
|
</tr>
|
||||||
<tr><td>SHA256 sum</td><td>{state.base.sha256_sum}</td></tr>
|
<tr><td>SHA256 sum</td><td>{state.base.sha256_sum}</td></tr>
|
||||||
{/if}
|
{/if}
|
||||||
<tr><td>Direct URL</td><td><a href="{direct_url}">{direct_url}</a></td></tr>
|
<tr>
|
||||||
|
<td>Direct link</td>
|
||||||
|
<td>
|
||||||
|
<Button highlight_on_click icon="content_copy" label="Copy" click={e => copy_text(direct_url)}/>
|
||||||
|
<a href="{direct_url}">{direct_url}</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
{#if share_url !== ""}
|
{#if share_url !== ""}
|
||||||
<tr><td>Share URL</td><td><a href="{share_url}">{share_url}</a></td></tr>
|
<tr>
|
||||||
|
<td>Sharing link</td>
|
||||||
|
<td>
|
||||||
|
<Button highlight_on_click icon="content_copy" label="Copy" click={e => copy_text(share_url)}/>
|
||||||
|
<a href="{share_url}">{share_url}</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Direct sharing link</td>
|
||||||
|
<td>
|
||||||
|
<Button highlight_on_click icon="content_copy" label="Copy" click={e => copy_text(direct_share_url)}/>
|
||||||
|
<a href="{direct_share_url}">{direct_share_url}</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
{/if}
|
{/if}
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import LoadingIndicator from '../util/LoadingIndicator.svelte';
|
import LoadingIndicator from '../util/LoadingIndicator.svelte';
|
||||||
import EditWindow from './EditWindow.svelte';
|
import EditWindow from './edit_window/EditWindow.svelte';
|
||||||
import Toolbar from './Toolbar.svelte';
|
import Toolbar from './Toolbar.svelte';
|
||||||
import Breadcrumbs from './Breadcrumbs.svelte';
|
import Breadcrumbs from './Breadcrumbs.svelte';
|
||||||
import DetailsWindow from './DetailsWindow.svelte';
|
import DetailsWindow from './DetailsWindow.svelte';
|
||||||
@@ -10,8 +10,8 @@ import FilePreview from './viewers/FilePreview.svelte';
|
|||||||
import SearchView from './SearchView.svelte';
|
import SearchView from './SearchView.svelte';
|
||||||
import UploadWidget from './upload_widget/UploadWidget.svelte';
|
import UploadWidget from './upload_widget/UploadWidget.svelte';
|
||||||
import HomeButton from '../file_viewer/HomeButton.svelte';
|
import HomeButton from '../file_viewer/HomeButton.svelte';
|
||||||
import { fs_path_url } from './FilesystemUtil';
|
import { fs_path_url } from './FilesystemUtil.js';
|
||||||
import { branding_from_node, branding_from_path } from './BrandingOptions.svelte';
|
import { branding_from_path } from './edit_window/Branding.js'
|
||||||
|
|
||||||
let loading = true
|
let loading = true
|
||||||
let toolbar
|
let toolbar
|
||||||
@@ -179,7 +179,6 @@ const update_css = path => document.documentElement.style = branding_from_path(p
|
|||||||
bind:visible={edit_visible}
|
bind:visible={edit_visible}
|
||||||
fs_navigator={fs_navigator}
|
fs_navigator={fs_navigator}
|
||||||
on:loading={loading_evt}
|
on:loading={loading_evt}
|
||||||
on:style_change={e => document.documentElement.style = branding_from_node(e.detail)}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<UploadWidget
|
<UploadWidget
|
||||||
|
@@ -13,6 +13,9 @@ export const fs_encode_path = path => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const fs_path_url = path => {
|
export const fs_path_url = path => {
|
||||||
|
if (path[0] !== "/") {
|
||||||
|
path = "/" + path
|
||||||
|
}
|
||||||
return window.api_endpoint + "/filesystem" + fs_encode_path(path)
|
return window.api_endpoint + "/filesystem" + fs_encode_path(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,5 +1,12 @@
|
|||||||
<script context="module">
|
<script context="module">
|
||||||
export const generate_share_url = path => {
|
export const generate_share_url = path => {
|
||||||
|
let share_path = generate_share_path(path)
|
||||||
|
if (share_path !== "") {
|
||||||
|
share_path = window.location.protocol+"//"+window.location.host+"/d/"+share_path
|
||||||
|
}
|
||||||
|
return share_path
|
||||||
|
}
|
||||||
|
export const generate_share_path = path => {
|
||||||
let share_url = ""
|
let share_url = ""
|
||||||
let bucket_idx = -1
|
let bucket_idx = -1
|
||||||
|
|
||||||
@@ -11,9 +18,7 @@ export const generate_share_url = path => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bucket_idx !== -1) {
|
if (bucket_idx !== -1) {
|
||||||
share_url = window.location.protocol+"//"+
|
share_url = path[bucket_idx].id
|
||||||
window.location.host+"/d/"+
|
|
||||||
path[bucket_idx].id
|
|
||||||
|
|
||||||
// Construct the path starting from the bucket
|
// Construct the path starting from the bucket
|
||||||
for (let i = bucket_idx+1; i < path.length; i++) {
|
for (let i = bucket_idx+1; i < path.length; i++) {
|
||||||
|
@@ -106,10 +106,12 @@ let expand = e => {
|
|||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<button on:click={share}>
|
{#if state.base.id !== "me"}
|
||||||
<i class="icon">share</i>
|
<button on:click={share}>
|
||||||
<span>Share</span>
|
<i class="icon">share</i>
|
||||||
</button>
|
<span>Share</span>
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<button on:click={() => details_visible = !details_visible} class:button_highlight={details_visible}>
|
<button on:click={() => details_visible = !details_visible} class:button_highlight={details_visible}>
|
||||||
<i class="icon">help</i>
|
<i class="icon">help</i>
|
||||||
|
101
svelte/src/filesystem/edit_window/Branding.js
Normal file
101
svelte/src/filesystem/edit_window/Branding.js
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
import parse from "pure-color/parse"
|
||||||
|
import rgb2hsl from "pure-color/convert/rgb2hsl";
|
||||||
|
import hsl2rgb from "pure-color/convert/hsl2rgb";
|
||||||
|
import rgb2hex from "pure-color/convert/rgb2hex";
|
||||||
|
|
||||||
|
// Generate a branding style from a file's properties map
|
||||||
|
export const branding_from_path = path => {
|
||||||
|
let style = {}
|
||||||
|
for (let node of path) {
|
||||||
|
add_styles(style, node.properties)
|
||||||
|
}
|
||||||
|
last_generated_style = style
|
||||||
|
return gen_css(style)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The last style which was generated is cached, when we don't have a complete
|
||||||
|
// path to generate the style with we will use the cached style as a basis
|
||||||
|
let last_generated_style = {}
|
||||||
|
export const branding_from_node = node => {
|
||||||
|
add_styles(last_generated_style, node.properties)
|
||||||
|
return gen_css(last_generated_style)
|
||||||
|
}
|
||||||
|
|
||||||
|
const gen_css = style => {
|
||||||
|
return Object.entries(style).map(([key, value]) => `--${key}:${value}`).join(';');
|
||||||
|
}
|
||||||
|
|
||||||
|
// add_styles adds the styles configured in the properties struct to the
|
||||||
|
// existing style which is passed as the first argument. When navigating to a
|
||||||
|
// path this function is executed on every member of the path so all the styles
|
||||||
|
// get combined
|
||||||
|
const add_styles = (style, properties) => {
|
||||||
|
if (!properties || !properties.branding_enabled || properties.branding_enabled !== "true") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (properties.brand_input_color) {
|
||||||
|
style.input_background = properties.brand_input_color
|
||||||
|
style.input_hover_background = properties.brand_input_color
|
||||||
|
style.input_text = add_light(properties.brand_input_color, 70)
|
||||||
|
}
|
||||||
|
if (properties.brand_highlight_color) {
|
||||||
|
style.highlight_color = properties.brand_highlight_color
|
||||||
|
style.highlight_background = properties.brand_highlight_color
|
||||||
|
style.highlight_text_color = add_light(properties.brand_highlight_color, 70)
|
||||||
|
style.link_color = properties.brand_highlight_color
|
||||||
|
}
|
||||||
|
if (properties.brand_danger_color) {
|
||||||
|
style.danger_color = properties.brand_danger_color
|
||||||
|
style.danger_text_color = add_light(properties.brand_danger_color, 70)
|
||||||
|
}
|
||||||
|
if (properties.brand_background_color) {
|
||||||
|
style.background_color = properties.brand_background_color
|
||||||
|
style.background = properties.brand_background_color
|
||||||
|
style.background_text_color = add_light(properties.brand_background_color, 70)
|
||||||
|
style.background_pattern_color = properties.brand_background_color
|
||||||
|
}
|
||||||
|
if (properties.brand_body_color) {
|
||||||
|
style.body_color = properties.brand_body_color
|
||||||
|
style.body_background = properties.brand_body_color
|
||||||
|
style.body_text_color = add_light(properties.brand_body_color, 70)
|
||||||
|
style.shaded_background = set_alpha(properties.brand_body_color, 0.8)
|
||||||
|
style.separator = add_light(properties.brand_body_color, 5)
|
||||||
|
style.shadow_color = darken(properties.brand_body_color, 0.8)
|
||||||
|
}
|
||||||
|
if (properties.brand_card_color) {
|
||||||
|
style.card_color = properties.brand_card_color
|
||||||
|
}
|
||||||
|
if (properties.brand_background_image) {
|
||||||
|
style.background_image = "url('/api/filesystem/" + properties.brand_background_image + "')"
|
||||||
|
style.background_image_size = "cover"
|
||||||
|
style.background_image_position = "center"
|
||||||
|
style.background_image_repeat = "no-repeat"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const add_light = (color, amt) => {
|
||||||
|
let hsl = rgb2hsl(parse(color)) // Convert hex to hsl
|
||||||
|
// If the lightness is less than 40 it is considered a dark colour. This
|
||||||
|
// threshold is 40 instead of 50 because overall dark text is more legible
|
||||||
|
if (hsl[2] < 40) {
|
||||||
|
hsl[2] = hsl[2] + amt // Dark color, add lightness
|
||||||
|
} else {
|
||||||
|
hsl[2] = hsl[2] - amt // Light color, remove lightness
|
||||||
|
}
|
||||||
|
return rgb2hex(hsl2rgb(hsl)) // Convert back to hex
|
||||||
|
}
|
||||||
|
|
||||||
|
// Darken and desaturate. Only used for shadows
|
||||||
|
const darken = (color, percent) => {
|
||||||
|
let hsl = rgb2hsl(parse(color)) // Convert hex to hsl
|
||||||
|
hsl[1] = hsl[1] * percent
|
||||||
|
hsl[2] = hsl[2] * percent
|
||||||
|
return rgb2hex(hsl2rgb(hsl)) // Convert back to hex
|
||||||
|
}
|
||||||
|
|
||||||
|
const set_alpha = (color, amt) => {
|
||||||
|
let rgb = parse(color)
|
||||||
|
rgb.push(amt)
|
||||||
|
return "rgba(" + rgb.join(", ") + ")"
|
||||||
|
}
|
@@ -1,124 +1,21 @@
|
|||||||
<script context="module">
|
|
||||||
import parse from "pure-color/parse"
|
|
||||||
import rgb2hsl from "pure-color/convert/rgb2hsl";
|
|
||||||
import hsl2rgb from "pure-color/convert/hsl2rgb";
|
|
||||||
import rgb2hex from "pure-color/convert/rgb2hex";
|
|
||||||
|
|
||||||
// Generate a branding style from a file's properties map
|
|
||||||
export const branding_from_path = path => {
|
|
||||||
let style = {}
|
|
||||||
for (let node of path) {
|
|
||||||
add_styles(style, node.properties)
|
|
||||||
}
|
|
||||||
last_generated_style = style
|
|
||||||
return gen_css(style)
|
|
||||||
}
|
|
||||||
|
|
||||||
// The last style which was generated is cached, when we don't have a complete
|
|
||||||
// path to generate the style with we will use the cached style as a basis
|
|
||||||
let last_generated_style = {}
|
|
||||||
export const branding_from_node = node => {
|
|
||||||
add_styles(last_generated_style, node.properties)
|
|
||||||
return gen_css(last_generated_style)
|
|
||||||
}
|
|
||||||
|
|
||||||
const gen_css = style => {
|
|
||||||
return Object.entries(style).map(([key, value]) => `--${key}:${value}`).join(';');
|
|
||||||
}
|
|
||||||
|
|
||||||
// add_styles adds the styles configured in the properties struct to the
|
|
||||||
// existing style which is passed as the first argument. When navigating to a
|
|
||||||
// path this function is executed on every member of the path so all the styles
|
|
||||||
// get combined
|
|
||||||
const add_styles = (style, properties) => {
|
|
||||||
if (!properties || !properties.branding_enabled || properties.branding_enabled !== "true") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (properties.brand_input_color) {
|
|
||||||
style.input_background = properties.brand_input_color
|
|
||||||
style.input_hover_background = properties.brand_input_color
|
|
||||||
style.input_text = add_light(properties.brand_input_color, 70)
|
|
||||||
}
|
|
||||||
if (properties.brand_highlight_color) {
|
|
||||||
style.highlight_color = properties.brand_highlight_color
|
|
||||||
style.highlight_background = properties.brand_highlight_color
|
|
||||||
style.highlight_text_color = add_light(properties.brand_highlight_color, 70)
|
|
||||||
style.link_color = properties.brand_highlight_color
|
|
||||||
}
|
|
||||||
if (properties.brand_danger_color) {
|
|
||||||
style.danger_color = properties.brand_danger_color
|
|
||||||
style.danger_text_color = add_light(properties.brand_danger_color, 70)
|
|
||||||
}
|
|
||||||
if (properties.brand_background_color) {
|
|
||||||
style.background_color = properties.brand_background_color
|
|
||||||
style.background = properties.brand_background_color
|
|
||||||
style.background_text_color = add_light(properties.brand_background_color, 70)
|
|
||||||
style.background_pattern_color = properties.brand_background_color
|
|
||||||
}
|
|
||||||
if (properties.brand_body_color) {
|
|
||||||
style.body_color = properties.brand_body_color
|
|
||||||
style.body_background = properties.brand_body_color
|
|
||||||
style.body_text_color = add_light(properties.brand_body_color, 70)
|
|
||||||
style.shaded_background = set_alpha(properties.brand_body_color, 0.8)
|
|
||||||
style.separator = add_light(properties.brand_body_color, 5)
|
|
||||||
style.shadow_color = darken(properties.brand_body_color, 0.8)
|
|
||||||
}
|
|
||||||
if (properties.brand_card_color) {
|
|
||||||
style.card_color = properties.brand_card_color
|
|
||||||
}
|
|
||||||
if (properties.brand_background_image) {
|
|
||||||
style.background_image = "url('/api/filesystem/"+properties.brand_background_image+"')"
|
|
||||||
style.background_image_size = "cover"
|
|
||||||
style.background_image_position = "center"
|
|
||||||
style.background_image_repeat = "no-repeat"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const add_light = (color, amt) => {
|
|
||||||
let hsl = rgb2hsl(parse(color)) // Convert hex to hsl
|
|
||||||
// If the lightness is less than 30 it is considered a dark colour. This
|
|
||||||
// threshold is 30 instead of 50 because overall dark text is more legible
|
|
||||||
if (hsl[2] < 30) {
|
|
||||||
hsl[2] = hsl[2]+amt // Dark color, add lightness
|
|
||||||
} else {
|
|
||||||
hsl[2] = hsl[2]-amt // Light color, remove lightness
|
|
||||||
}
|
|
||||||
return rgb2hex(hsl2rgb(hsl)) // Convert back to hex
|
|
||||||
}
|
|
||||||
|
|
||||||
// Darken and desaturate. Only used for shadows
|
|
||||||
const darken = (color, percent) => {
|
|
||||||
let hsl = rgb2hsl(parse(color)) // Convert hex to hsl
|
|
||||||
hsl[1] = hsl[1]*percent
|
|
||||||
hsl[2] = hsl[2]*percent
|
|
||||||
return rgb2hex(hsl2rgb(hsl)) // Convert back to hex
|
|
||||||
}
|
|
||||||
|
|
||||||
const set_alpha = (color, amt) => {
|
|
||||||
let rgb = parse(color)
|
|
||||||
rgb.push(amt)
|
|
||||||
return "rgba("+rgb.join(", ")+")"
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
import FilePicker from "./filemanager/FilePicker.svelte";
|
import FilePicker from "../filemanager/FilePicker.svelte";
|
||||||
import { fs_update } from "./FilesystemAPI";
|
import { fs_update } from "../FilesystemAPI";
|
||||||
import { fs_node_type } from "./FilesystemUtil";
|
import { fs_node_type } from "../FilesystemUtil";
|
||||||
|
import CustomBanner from "../viewers/CustomBanner.svelte";
|
||||||
|
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
|
|
||||||
export let file = {
|
export let file = {
|
||||||
properties: {
|
properties: {
|
||||||
branding_enabled: "false",
|
branding_enabled: "",
|
||||||
brand_input_color: "#2d2d2d",
|
brand_input_color: "",
|
||||||
brand_highlight_color: "#75b72d",
|
brand_highlight_color: "",
|
||||||
brand_danger_color: "#bd5f69",
|
brand_danger_color: "",
|
||||||
brand_background_color: "#141414",
|
brand_background_color: "",
|
||||||
brand_body_color: "#1e1e1e",
|
brand_body_color: "",
|
||||||
brand_card_color: "#282828",
|
brand_card_color: "",
|
||||||
brand_header_image: "",
|
brand_header_image: "",
|
||||||
brand_header_link: "",
|
brand_header_link: "",
|
||||||
brand_footer_image: "",
|
brand_footer_image: "",
|
||||||
@@ -133,7 +30,7 @@ $: update_colors(file)
|
|||||||
const update_colors = file => {
|
const update_colors = file => {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
file.properties.branding_enabled = "true"
|
file.properties.branding_enabled = "true"
|
||||||
dispatch("style_change", file)
|
dispatch("style_change")
|
||||||
} else {
|
} else {
|
||||||
file.properties.branding_enabled = ""
|
file.properties.branding_enabled = ""
|
||||||
}
|
}
|
||||||
@@ -208,15 +105,13 @@ const handle_picker = async e => {
|
|||||||
<div>Card</div>
|
<div>Card</div>
|
||||||
<input type="color" bind:value={file.properties.brand_card_color}/>
|
<input type="color" bind:value={file.properties.brand_card_color}/>
|
||||||
<input type="text" bind:value={file.properties.brand_card_color}/>
|
<input type="text" bind:value={file.properties.brand_card_color}/>
|
||||||
<div class="span3">
|
<p class="span3">
|
||||||
<hr/>
|
|
||||||
|
|
||||||
You can choose an image to show above or behind the files in this
|
You can choose an image to show above or behind the files in this
|
||||||
directory. The image will be picked from your filesystem. The image will
|
directory. The image will be picked from your filesystem. The image will
|
||||||
get a shared file link. You can move and rename the file like normal,
|
get a shared file link. You can move and rename the file like normal,
|
||||||
but if you remove the shared file property your branding will stop
|
but if you remove the shared file property your branding will stop
|
||||||
working.
|
working. Recommended dimensions for the header image are 1000x90 px.
|
||||||
</div>
|
</p>
|
||||||
<div>Header image ID</div>
|
<div>Header image ID</div>
|
||||||
<button on:click={() => pick_image("brand_header_image")}>
|
<button on:click={() => pick_image("brand_header_image")}>
|
||||||
<i class="icon">folder_open</i>
|
<i class="icon">folder_open</i>
|
||||||
@@ -243,7 +138,9 @@ const handle_picker = async e => {
|
|||||||
|
|
||||||
<div class="example example_body">
|
<div class="example example_body">
|
||||||
<div>The content body. <a href="/">A link</a>!</div>
|
<div>The content body. <a href="/">A link</a>!</div>
|
||||||
|
<hr/>
|
||||||
|
<div>Below is your custom header image, if you chose one.</div>
|
||||||
|
<CustomBanner path={[file]}/>
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
<div class="example_button_row">
|
<div class="example_button_row">
|
@@ -1,10 +1,11 @@
|
|||||||
<script>
|
<script>
|
||||||
import { fs_delete_all, fs_rename, fs_update } from "./FilesystemAPI";
|
import { fs_delete_all, 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 Button from "../../layout/Button.svelte";
|
||||||
import BrandingOptions from "./BrandingOptions.svelte";
|
import BrandingOptions from "./BrandingOptions.svelte";
|
||||||
import PathLink from "./util/PathLink.svelte";
|
import PathLink from "../util/PathLink.svelte";
|
||||||
|
import { branding_from_node } from "./Branding";
|
||||||
|
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
|
|
||||||
@@ -17,6 +18,7 @@ let file = {
|
|||||||
properties: {},
|
properties: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let custom_css = ""
|
||||||
$: is_root_dir = file.path === "/"+file.id
|
$: is_root_dir = file.path === "/"+file.id
|
||||||
|
|
||||||
export let visible
|
export let visible
|
||||||
@@ -33,7 +35,14 @@ export const edit = (f, oae = false, t = "file") => {
|
|||||||
if (file.properties === undefined) {
|
if (file.properties === undefined) {
|
||||||
file.properties = {}
|
file.properties = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
branding_enabled = file.properties.branding_enabled === "true"
|
branding_enabled = file.properties.branding_enabled === "true"
|
||||||
|
if (branding_enabled) {
|
||||||
|
custom_css = branding_from_node(file)
|
||||||
|
} else {
|
||||||
|
custom_css = ""
|
||||||
|
}
|
||||||
|
|
||||||
visible = true
|
visible = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,7 +136,7 @@ const delete_file = async e => {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Modal bind:visible={visible} title="Edit {file.name}" width="700px" form="edit_form">
|
<Modal bind:visible={visible} title="Edit {file.name}" width="700px" form="edit_form" style="color: var(--body_text_color); {custom_css}">
|
||||||
<div class="tab_bar">
|
<div class="tab_bar">
|
||||||
<button class:button_highlight={tab === "file"} on:click={() => tab = "file"}>
|
<button class:button_highlight={tab === "file"} on:click={() => tab = "file"}>
|
||||||
<i class="icon">edit</i>
|
<i class="icon">edit</i>
|
||||||
@@ -184,7 +193,12 @@ const delete_file = async e => {
|
|||||||
</div>
|
</div>
|
||||||
{:else if tab === "branding"}
|
{:else if tab === "branding"}
|
||||||
<div class="tab_content">
|
<div class="tab_content">
|
||||||
<BrandingOptions bind:enabled={branding_enabled} bind:colors={branding_colors} file={file} on:style_change/>
|
<BrandingOptions
|
||||||
|
bind:enabled={branding_enabled}
|
||||||
|
bind:colors={branding_colors}
|
||||||
|
file={file}
|
||||||
|
on:style_change={e => custom_css = branding_from_node(file)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</Modal>
|
</Modal>
|
@@ -71,9 +71,9 @@ 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 => {
|
const node_settings = e => edit_window.edit(state.children[e.detail], false)
|
||||||
edit_window.edit(state.children[e.detail], false)
|
const node_branding = e => edit_window.edit(state.children[e.detail], false, "branding")
|
||||||
}
|
|
||||||
const navigate_up = () => {
|
const navigate_up = () => {
|
||||||
creating_dir = false
|
creating_dir = false
|
||||||
|
|
||||||
@@ -352,6 +352,8 @@ onMount(() => {
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<slot></slot>
|
||||||
|
|
||||||
{#if directory_view === "list"}
|
{#if directory_view === "list"}
|
||||||
<ListView
|
<ListView
|
||||||
state={state}
|
state={state}
|
||||||
@@ -361,6 +363,7 @@ onMount(() => {
|
|||||||
on:node_context={node_context}
|
on:node_context={node_context}
|
||||||
on:node_share_click={node_share_click}
|
on:node_share_click={node_share_click}
|
||||||
on:node_settings={node_settings}
|
on:node_settings={node_settings}
|
||||||
|
on:node_branding={node_branding}
|
||||||
on:node_select={node_select}
|
on:node_select={node_select}
|
||||||
/>
|
/>
|
||||||
{:else if directory_view === "gallery"}
|
{:else if directory_view === "gallery"}
|
||||||
|
@@ -5,6 +5,7 @@ import GalleryView from './GalleryView.svelte'
|
|||||||
import Modal from '../../util/Modal.svelte';
|
import Modal from '../../util/Modal.svelte';
|
||||||
import Navigator from '../Navigator.svelte';
|
import Navigator from '../Navigator.svelte';
|
||||||
import LoadingIndicator from '../../util/LoadingIndicator.svelte';
|
import LoadingIndicator from '../../util/LoadingIndicator.svelte';
|
||||||
|
import Breadcrumbs from '../Breadcrumbs.svelte'
|
||||||
|
|
||||||
let fs_navigator
|
let fs_navigator
|
||||||
let state
|
let state
|
||||||
@@ -172,6 +173,9 @@ onMount(() => {
|
|||||||
<i class="icon">done</i> Pick
|
<i class="icon">done</i> Pick
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Breadcrumbs state={state} fs_navigator={fs_navigator}/>
|
||||||
|
|
||||||
{#if directory_view === "list"}
|
{#if directory_view === "list"}
|
||||||
<ListView
|
<ListView
|
||||||
state={state}
|
state={state}
|
||||||
|
@@ -47,8 +47,13 @@ export let large_icons = false
|
|||||||
<i class="icon" title="This file / directory is shared. Click to open public link">share</i>
|
<i class="icon" title="This file / directory is shared. Click to open public link">share</i>
|
||||||
</a>
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if child.properties && child.properties.branding_enabled}
|
||||||
|
<button class="action_button" on:click|preventDefault|stopPropagation={() => dispatch("node_branding", index)}>
|
||||||
|
<i class="icon">palette</i>
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
{#if state.permissions.update}
|
{#if state.permissions.update}
|
||||||
<button class="action_button" on:click|preventDefault|stopPropagation={() => {dispatch("node_settings", index)}}>
|
<button class="action_button" on:click|preventDefault|stopPropagation={() => dispatch("node_settings", index)}>
|
||||||
<i class="icon">edit</i>
|
<i class="icon">edit</i>
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { createEventDispatcher, onMount } from 'svelte'
|
import { createEventDispatcher, onMount } from 'svelte'
|
||||||
import { fs_path_url } from '../FilesystemUtil';
|
import { fs_path_url } from '../FilesystemUtil';
|
||||||
|
import FileTitle from '../../file_viewer/viewers/FileTitle.svelte';
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
|
|
||||||
export let state
|
export let state
|
||||||
@@ -37,7 +38,9 @@ onMount(() => {
|
|||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<slot></slot>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
<FileTitle title={state.base.name}/>
|
||||||
<button on:click={() => dispatch("open_sibling", -1) }><i class="icon">skip_previous</i></button>
|
<button on:click={() => dispatch("open_sibling", -1) }><i class="icon">skip_previous</i></button>
|
||||||
<button on:click={() => player.currentTime -= 10 }><i class="icon">replay_10</i></button>
|
<button on:click={() => player.currentTime -= 10 }><i class="icon">replay_10</i></button>
|
||||||
<button on:click={toggle_play}>
|
<button on:click={toggle_play}>
|
||||||
@@ -65,7 +68,6 @@ onMount(() => {
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
.container {
|
.container {
|
||||||
margin: 50px 0 0 0;
|
|
||||||
padding: 0;
|
padding: 0;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
50
svelte/src/filesystem/viewers/CustomBanner.svelte
Normal file
50
svelte/src/filesystem/viewers/CustomBanner.svelte
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<script>
|
||||||
|
export let path = []
|
||||||
|
|
||||||
|
let image_uri
|
||||||
|
let image_link
|
||||||
|
$: update_links(path)
|
||||||
|
const update_links = (path) => {
|
||||||
|
image_uri = null
|
||||||
|
image_link = null
|
||||||
|
for (let node of path) {
|
||||||
|
if (node.properties && node.properties.branding_enabled === "true") {
|
||||||
|
if (node.properties.brand_header_image) {
|
||||||
|
image_uri = "/api/filesystem/"+node.properties.brand_header_image
|
||||||
|
}
|
||||||
|
if (node.properties.brand_header_link) {
|
||||||
|
image_link = node.properties.brand_header_link
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if image_uri}
|
||||||
|
<div class="container">
|
||||||
|
{#if image_link}
|
||||||
|
<a class="link" href={image_link} target="_blank" rel="noreferrer">
|
||||||
|
<img class="image" src="{image_uri}" alt="User-provided banner"/>
|
||||||
|
</a>
|
||||||
|
{:else}
|
||||||
|
<img class="image" src="{image_uri}" alt="User-provided banner"/>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.container {
|
||||||
|
margin: 6px 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.link {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.image {
|
||||||
|
display: inline-block;
|
||||||
|
margin: auto;
|
||||||
|
max-height: 90px;
|
||||||
|
max-width: 100%;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -7,6 +7,8 @@ let dispatch = createEventDispatcher()
|
|||||||
export let state
|
export let state
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<slot></slot>
|
||||||
|
|
||||||
<h1>{state.base.name}</h1>
|
<h1>{state.base.name}</h1>
|
||||||
|
|
||||||
<IconBlock icon_href={fs_thumbnail_url(state.base.path, 256, 256)}>
|
<IconBlock icon_href={fs_thumbnail_url(state.base.path, 256, 256)}>
|
||||||
|
@@ -11,6 +11,7 @@ import Text from "./Text.svelte";
|
|||||||
import Video from "./Video.svelte";
|
import Video from "./Video.svelte";
|
||||||
import Torrent from "./Torrent.svelte";
|
import Torrent from "./Torrent.svelte";
|
||||||
import Zip from "./Zip.svelte";
|
import Zip from "./Zip.svelte";
|
||||||
|
import CustomBanner from "./CustomBanner.svelte";
|
||||||
|
|
||||||
export let fs_navigator
|
export let fs_navigator
|
||||||
export let edit_window
|
export let edit_window
|
||||||
@@ -51,9 +52,13 @@ const state_update = async (base) => {
|
|||||||
edit_window={edit_window}
|
edit_window={edit_window}
|
||||||
on:loading
|
on:loading
|
||||||
on:upload_picker
|
on:upload_picker
|
||||||
/>
|
>
|
||||||
|
<CustomBanner path={state.path}/>
|
||||||
|
</FileManager>
|
||||||
{:else if viewer_type === "audio"}
|
{:else if viewer_type === "audio"}
|
||||||
<Audio state={state} on:open_sibling/>
|
<Audio state={state} on:open_sibling>
|
||||||
|
<CustomBanner path={state.path}/>
|
||||||
|
</Audio>
|
||||||
{:else if viewer_type === "image"}
|
{:else if viewer_type === "image"}
|
||||||
<Image state={state} on:open_sibling/>
|
<Image state={state} on:open_sibling/>
|
||||||
{:else if viewer_type === "video"}
|
{:else if viewer_type === "video"}
|
||||||
@@ -61,13 +66,21 @@ const state_update = async (base) => {
|
|||||||
{:else if viewer_type === "pdf"}
|
{:else if viewer_type === "pdf"}
|
||||||
<Pdf state={state}/>
|
<Pdf state={state}/>
|
||||||
{:else if viewer_type === "text"}
|
{:else if viewer_type === "text"}
|
||||||
<Text state={state}/>
|
<Text state={state}>
|
||||||
|
<CustomBanner path={state.path}/>
|
||||||
|
</Text>
|
||||||
{:else if viewer_type === "torrent"}
|
{:else if viewer_type === "torrent"}
|
||||||
<Torrent state={state} bind:this={viewer} on:loading on:download/>
|
<Torrent state={state} bind:this={viewer} on:loading on:download>
|
||||||
|
<CustomBanner path={state.path}/>
|
||||||
|
</Torrent>
|
||||||
{:else if viewer_type === "zip"}
|
{:else if viewer_type === "zip"}
|
||||||
<Zip state={state} bind:this={viewer} on:loading on:download />
|
<Zip state={state} bind:this={viewer} on:loading on:download>
|
||||||
|
<CustomBanner path={state.path}/>
|
||||||
|
</Zip>
|
||||||
{:else}
|
{:else}
|
||||||
<File state={state} on:download/>
|
<File state={state} on:download>
|
||||||
|
<CustomBanner path={state.path}/>
|
||||||
|
</File>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@@ -75,6 +75,7 @@ const mouseup = (e) => {
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
box-shadow: 1px 1px 4px 0px var(--shadow_color);
|
||||||
}
|
}
|
||||||
.image.zoom {
|
.image.zoom {
|
||||||
max-width: none;
|
max-width: none;
|
||||||
|
@@ -27,6 +27,7 @@ export const set_file = file => {
|
|||||||
|
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
<slot></slot>
|
||||||
<pre bind:this={text_pre}>
|
<pre bind:this={text_pre}>
|
||||||
Loading...
|
Loading...
|
||||||
</pre>
|
</pre>
|
||||||
|
@@ -73,6 +73,8 @@ const copy_magnet = () => {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<slot></slot>
|
||||||
|
|
||||||
<h1>{state.base.name}</h1>
|
<h1>{state.base.name}</h1>
|
||||||
|
|
||||||
<IconBlock icon_href={fs_node_icon(state.base, 256, 256)}>
|
<IconBlock icon_href={fs_node_icon(state.base, 256, 256)}>
|
||||||
|
@@ -59,6 +59,8 @@ const recursive_size = (file) => {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<slot></slot>
|
||||||
|
|
||||||
<h1>{state.base.name}</h1>
|
<h1>{state.base.name}</h1>
|
||||||
|
|
||||||
<IconBlock icon_href={fs_node_icon(state.base, 256, 256)}>
|
<IconBlock icon_href={fs_node_icon(state.base, 256, 256)}>
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
export let highlight = false;
|
export let highlight = false;
|
||||||
|
export let highlight_on_click = false
|
||||||
export let red = false;
|
export let red = false;
|
||||||
export let round = false;
|
export let round = false;
|
||||||
export let flat = false;
|
export let flat = false;
|
||||||
@@ -14,11 +15,25 @@ export let click = e => {}
|
|||||||
export let style = ""
|
export let style = ""
|
||||||
export let type = ""
|
export let type = ""
|
||||||
export let form = ""
|
export let form = ""
|
||||||
|
|
||||||
|
let click_int = e => {
|
||||||
|
if (highlight_on_click) {
|
||||||
|
try {
|
||||||
|
click(e)
|
||||||
|
highlight = true
|
||||||
|
} catch (err) {
|
||||||
|
red = true
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
click(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if link_target === ""}
|
{#if link_target === ""}
|
||||||
<button
|
<button
|
||||||
on:click={click}
|
on:click={click_int}
|
||||||
class="button"
|
class="button"
|
||||||
class:button_highlight={highlight}
|
class:button_highlight={highlight}
|
||||||
class:button_red={red}
|
class:button_red={red}
|
||||||
|
@@ -18,6 +18,7 @@ export let width = "800px";
|
|||||||
export let height = "auto";
|
export let height = "auto";
|
||||||
export let padding = false;
|
export let padding = false;
|
||||||
export let visible = false;
|
export let visible = false;
|
||||||
|
export let style = "";
|
||||||
|
|
||||||
const load_bg = background => {
|
const load_bg = background => {
|
||||||
background.style.zIndex = global_index.valueOf();
|
background.style.zIndex = global_index.valueOf();
|
||||||
@@ -53,6 +54,7 @@ const keydown = e => {
|
|||||||
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
||||||
<div
|
<div
|
||||||
class="background"
|
class="background"
|
||||||
|
style={style}
|
||||||
use:load_bg
|
use:load_bg
|
||||||
on:click={hide}
|
on:click={hide}
|
||||||
transition:fade={{duration: 200}}
|
transition:fade={{duration: 200}}
|
||||||
|
Reference in New Issue
Block a user