Add file viewer branding options
This commit is contained in:
2
go.mod
2
go.mod
@@ -2,6 +2,8 @@ module fornaxian.tech/pixeldrain_web
|
|||||||
|
|
||||||
go 1.17
|
go 1.17
|
||||||
|
|
||||||
|
replace fornaxian.tech/pixeldrain_api_client => ../pixeldrain_api_client
|
||||||
|
|
||||||
require (
|
require (
|
||||||
fornaxian.tech/config v0.0.0-20211108212237-6133aed90586
|
fornaxian.tech/config v0.0.0-20211108212237-6133aed90586
|
||||||
fornaxian.tech/log v0.0.0-20211102185326-552e9b1f8640
|
fornaxian.tech/log v0.0.0-20211102185326-552e9b1f8640
|
||||||
|
2
go.sum
2
go.sum
@@ -3,8 +3,6 @@ fornaxian.tech/config v0.0.0-20211108212237-6133aed90586/go.mod h1:ULIXF4J1DbBw4
|
|||||||
fornaxian.tech/log v0.0.0-20190617093801-1c7ce9a7c9b3/go.mod h1:OyWUNsNPlo5AmlOHvJ4s6WcStQw+9rQyBMwmTz0buEM=
|
fornaxian.tech/log v0.0.0-20190617093801-1c7ce9a7c9b3/go.mod h1:OyWUNsNPlo5AmlOHvJ4s6WcStQw+9rQyBMwmTz0buEM=
|
||||||
fornaxian.tech/log v0.0.0-20211102185326-552e9b1f8640 h1:UPDxJwLRCfh/cv80UMSanzmZ0jIcfS1mcd0Y06HYuLw=
|
fornaxian.tech/log v0.0.0-20211102185326-552e9b1f8640 h1:UPDxJwLRCfh/cv80UMSanzmZ0jIcfS1mcd0Y06HYuLw=
|
||||||
fornaxian.tech/log v0.0.0-20211102185326-552e9b1f8640/go.mod h1:sN82qMToeHhP2u3ehvrcE8y1IudRZJAZO9yG5OBYblo=
|
fornaxian.tech/log v0.0.0-20211102185326-552e9b1f8640/go.mod h1:sN82qMToeHhP2u3ehvrcE8y1IudRZJAZO9yG5OBYblo=
|
||||||
fornaxian.tech/pixeldrain_api_client v0.0.0-20220127185304-6a60644d957e h1:/PLg0AMCPx6Uft5oPb70ogK127/oWrRGadPU0kvqRv8=
|
|
||||||
fornaxian.tech/pixeldrain_api_client v0.0.0-20220127185304-6a60644d957e/go.mod h1:uajB2ofEsefUtxjvs4m7SDyPVRlfrI3qzCSWcud47hY=
|
|
||||||
fornaxian.tech/util v0.0.0-20211102152345-9a486dee9787 h1:9ujI8Qi6+FTL/YW6xQAS9DmWDMerHBe8foQvVD/G/i0=
|
fornaxian.tech/util v0.0.0-20211102152345-9a486dee9787 h1:9ujI8Qi6+FTL/YW6xQAS9DmWDMerHBe8foQvVD/G/i0=
|
||||||
fornaxian.tech/util v0.0.0-20211102152345-9a486dee9787/go.mod h1:FqVgfghmxTGR3l9Zx4MOMeZ9KHjiEFl3s3C0BSTvBwk=
|
fornaxian.tech/util v0.0.0-20211102152345-9a486dee9787/go.mod h1:FqVgfghmxTGR3l9Zx4MOMeZ9KHjiEFl3s3C0BSTvBwk=
|
||||||
github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||||
|
@@ -105,7 +105,7 @@ footer {
|
|||||||
.page_navigation {
|
.page_navigation {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
backface-visibility: hidden;
|
backface-visibility: hidden;
|
||||||
width: 18em;
|
width: 17em;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
left: 0;
|
left: 0;
|
||||||
float: left;
|
float: left;
|
||||||
@@ -119,7 +119,7 @@ footer {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
height: auto;
|
height: auto;
|
||||||
left: 18em;
|
left: 17em;
|
||||||
min-width: 300px;
|
min-width: 300px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
text-align: center; /* Center the header and body */
|
text-align: center; /* Center the header and body */
|
||||||
@@ -131,7 +131,7 @@ footer {
|
|||||||
padding: 8px;
|
padding: 8px;
|
||||||
transition: left 0.5s;
|
transition: left 0.5s;
|
||||||
}
|
}
|
||||||
@media (max-width: 1000px) {
|
@media (max-width: 1200px) {
|
||||||
.page_navigation {
|
.page_navigation {
|
||||||
left: -18em;
|
left: -18em;
|
||||||
}
|
}
|
||||||
@@ -467,7 +467,9 @@ select:disabled , select.disabled {
|
|||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
button > i,
|
button > i,
|
||||||
.button > i {
|
.button > i,
|
||||||
|
button > svg,
|
||||||
|
.button > svg {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
BIN
res/static/misc/amogus.opus
Normal file
BIN
res/static/misc/amogus.opus
Normal file
Binary file not shown.
@@ -60,9 +60,9 @@
|
|||||||
background-position: center;
|
background-position: center;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-size: 1.1em;
|
font-size: 1.2em;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
text-shadow: 1px 1px 4px #000000;
|
text-shadow: 1px 1px 3px #000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.feat_table > div > div.round_tl { border-top-left-radius: 0.5em; }
|
.feat_table > div > div.round_tl { border-top-left-radius: 0.5em; }
|
||||||
@@ -298,10 +298,10 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="feat_pro features_cell round_tr">
|
<div class="feat_pro features_cell round_tr">
|
||||||
<div><span class="text_highlight">20 GB</span> max file size<br/></div>
|
<div><span class="text_highlight">20 GB</span> max file size</div>
|
||||||
<div><span class="text_highlight">180 days</span> file expiry</div>
|
<div><span class="text_highlight">180 days</span> file expiry</div>
|
||||||
<div><span class="text_highlight">2 TB</span> transfer limit<br/></div>
|
<div><span class="text_highlight">2 TB</span> transfer limit</div>
|
||||||
<div><span class="text_highlight">2 TB</span> storage space<br/></div>
|
<div><span class="text_highlight">2 TB</span> storage space</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -315,10 +315,16 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="feat_pro features_cell">
|
<div class="feat_pro features_cell">
|
||||||
<div><span class="text_highlight">20 GB</span> max file size<br/></div>
|
<div><span class="text_highlight">20 GB</span> max file size</div>
|
||||||
<div><span class="text_highlight">360 days</span> file expiry</div>
|
<div><span class="text_highlight">360 days</span> file expiry</div>
|
||||||
<div><span class="text_highlight">4 TB</span> transfer limit<br/></div>
|
<div><span class="text_highlight">4 TB</span> transfer limit</div>
|
||||||
<div><span class="text_highlight">4 TB</span> storage space<br/></div>
|
<div><span class="text_highlight">4 TB</span> storage space</div>
|
||||||
|
<div>
|
||||||
|
<span class="text_highlight">File viewer
|
||||||
|
branding</span>: Set a custom theme and header,
|
||||||
|
footer and background images on the download pages
|
||||||
|
for your files
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -332,10 +338,11 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="feat_pro features_cell">
|
<div class="feat_pro features_cell">
|
||||||
<div><span class="text_highlight">20 GB</span> max file size<br/></div>
|
<div><span class="text_highlight">20 GB</span> max file size</div>
|
||||||
<div><span class="text_highlight">Files never expire</span></div>
|
<div><span class="text_highlight">Files never expire</span></div>
|
||||||
<div><span class="text_highlight">8 TB</span> transfer limit<br/></div>
|
<div><span class="text_highlight">8 TB</span> transfer limit</div>
|
||||||
<div><span class="text_highlight">8 TB</span> storage space<br/></div>
|
<div><span class="text_highlight">8 TB</span> storage space</div>
|
||||||
|
<div><span class="text_highlight">File viewer branding</span></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -349,10 +356,11 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="feat_pro features_cell">
|
<div class="feat_pro features_cell">
|
||||||
<div><span class="text_highlight">20 GB</span> max file size<br/></div>
|
<div><span class="text_highlight">20 GB</span> max file size</div>
|
||||||
<div><span class="text_highlight">Files never expire</span></div>
|
<div><span class="text_highlight">Files never expire</span></div>
|
||||||
<div><span class="text_highlight">16 TB</span> transfer limit<br/></div>
|
<div><span class="text_highlight">16 TB</span> transfer limit</div>
|
||||||
<div><span class="text_highlight">16 TB</span> storage space<br/></div>
|
<div><span class="text_highlight">16 TB</span> storage space</div>
|
||||||
|
<div><span class="text_highlight">File viewer branding</span></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -366,10 +374,11 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="feat_pro features_cell">
|
<div class="feat_pro features_cell">
|
||||||
<div><span class="text_highlight">20 GB</span> max file size<br/></div>
|
<div><span class="text_highlight">20 GB</span> max file size</div>
|
||||||
<div><span class="text_highlight">Files never expire</span></div>
|
<div><span class="text_highlight">Files never expire</span></div>
|
||||||
<div><span class="text_highlight">32 TB</span> transfer limit<br/></div>
|
<div><span class="text_highlight">32 TB</span> transfer limit</div>
|
||||||
<div><span class="text_highlight">32 TB</span> storage space<br/></div>
|
<div><span class="text_highlight">32 TB</span> storage space</div>
|
||||||
|
<div><span class="text_highlight">File viewer branding</span></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -385,10 +394,11 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="feat_pro features_cell">
|
<div class="feat_pro features_cell">
|
||||||
<div><span class="text_highlight">20 GB</span> max file size<br/></div>
|
<div><span class="text_highlight">20 GB</span> max file size</div>
|
||||||
<div><span class="text_highlight">Files never expire</span></div>
|
<div><span class="text_highlight">Files never expire</span></div>
|
||||||
<div><span class="text_highlight">48 TB</span> transfer limit<br/></div>
|
<div><span class="text_highlight">48 TB</span> transfer limit</div>
|
||||||
<div><span class="text_highlight">48 TB</span> storage space<br/></div>
|
<div><span class="text_highlight">48 TB</span> storage space</div>
|
||||||
|
<div><span class="text_highlight">File viewer branding</span></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -404,10 +414,11 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="feat_pro features_cell">
|
<div class="feat_pro features_cell">
|
||||||
<div><span class="text_highlight">20 GB</span> max file size<br/></div>
|
<div><span class="text_highlight">20 GB</span> max file size</div>
|
||||||
<div><span class="text_highlight">Files never expire</span></div>
|
<div><span class="text_highlight">Files never expire</span></div>
|
||||||
<div><span class="text_highlight">64 TB</span> transfer limit<br/></div>
|
<div><span class="text_highlight">64 TB</span> transfer limit</div>
|
||||||
<div><span class="text_highlight">64 TB</span> storage space<br/></div>
|
<div><span class="text_highlight">64 TB</span> storage space</div>
|
||||||
|
<div><span class="text_highlight">File viewer branding</span></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -423,10 +434,11 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="feat_pro features_cell">
|
<div class="feat_pro features_cell">
|
||||||
<div><span class="text_highlight">20 GB</span> max file size<br/></div>
|
<div><span class="text_highlight">20 GB</span> max file size</div>
|
||||||
<div><span class="text_highlight">Files never expire</span></div>
|
<div><span class="text_highlight">Files never expire</span></div>
|
||||||
<div><span class="text_highlight">96 TB</span> transfer limit<br/></div>
|
<div><span class="text_highlight">96 TB</span> transfer limit</div>
|
||||||
<div><span class="text_highlight">96 TB</span> storage space<br/></div>
|
<div><span class="text_highlight">96 TB</span> storage space</div>
|
||||||
|
<div><span class="text_highlight">File viewer branding</span></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -442,10 +454,11 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="feat_pro features_cell round_br">
|
<div class="feat_pro features_cell round_br">
|
||||||
<div><span class="text_highlight">20 GB</span> max file size<br/></div>
|
<div><span class="text_highlight">20 GB</span> max file size</div>
|
||||||
<div><span class="text_highlight">Files never expire</span></div>
|
<div><span class="text_highlight">Files never expire</span></div>
|
||||||
<div><span class="text_highlight">128 TB</span> transfer limit<br/></div>
|
<div><span class="text_highlight">128 TB</span> transfer limit</div>
|
||||||
<div><span class="text_highlight">128 TB</span> storage space<br/></div>
|
<div><span class="text_highlight">128 TB</span> storage space</div>
|
||||||
|
<div><span class="text_highlight">File viewer branding</span></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
22
svelte/src/file_viewer/CustomBanner.svelte
Normal file
22
svelte/src/file_viewer/CustomBanner.svelte
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<script>
|
||||||
|
export let src = ""
|
||||||
|
export let border_top = false;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if src}
|
||||||
|
<div class:border_top>
|
||||||
|
<img class="image" src="{src}" alt="User-provided banner"/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.border_top {
|
||||||
|
border-top: solid 1px var(--layer_2_color_border);
|
||||||
|
}
|
||||||
|
.image {
|
||||||
|
display: block;
|
||||||
|
margin: auto;
|
||||||
|
max-height: 100px;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -1,4 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
|
import ThemePicker from "../util/ThemePicker.svelte";
|
||||||
import { copy_text, domain_url } from "../util/Util.svelte";
|
import { copy_text, domain_url } from "../util/Util.svelte";
|
||||||
import { file_type } from "./FileUtilities.svelte";
|
import { file_type } from "./FileUtilities.svelte";
|
||||||
|
|
||||||
@@ -33,6 +34,7 @@ let style = ""
|
|||||||
let set_style = s => {
|
let set_style = s => {
|
||||||
style = s
|
style = s
|
||||||
embed_iframe()
|
embed_iframe()
|
||||||
|
update_example()
|
||||||
}
|
}
|
||||||
|
|
||||||
let embed_iframe = () => {
|
let embed_iframe = () => {
|
||||||
@@ -95,8 +97,17 @@ const copy = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const example = () => {
|
let example = false
|
||||||
|
const toggle_example = () => {
|
||||||
|
example = !example
|
||||||
|
update_example()
|
||||||
|
}
|
||||||
|
const update_example = () => {
|
||||||
|
if (example) {
|
||||||
preview_area.innerHTML = embed_html
|
preview_area.innerHTML = embed_html
|
||||||
|
} else {
|
||||||
|
preview_area.innerHTML = ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -142,38 +153,8 @@ const example = () => {
|
|||||||
You can change the pixeldrain theme for your embedded file. Try the
|
You can change the pixeldrain theme for your embedded file. Try the
|
||||||
available themes <a href="/appearance">here</a>.
|
available themes <a href="/appearance">here</a>.
|
||||||
</p>
|
</p>
|
||||||
<div class="center">
|
|
||||||
<button class:button_highlight={style===""} on:click={() => {set_style("")}}>
|
<ThemePicker on:theme_change={e => set_style(e.detail)}></ThemePicker>
|
||||||
Default
|
|
||||||
</button>
|
|
||||||
<button class:button_highlight={style==="classic"} on:click={() => {set_style("classic")}}>
|
|
||||||
Classic
|
|
||||||
</button>
|
|
||||||
<button class:button_highlight={style==="solarized_dark"} on:click={() => {set_style("solarized_dark")}}>
|
|
||||||
Solarized
|
|
||||||
</button>
|
|
||||||
<button class:button_highlight={style==="maroon"} on:click={() => {set_style("maroon")}}>
|
|
||||||
Maroon
|
|
||||||
</button>
|
|
||||||
<button class:button_highlight={style==="hacker"} on:click={() => {set_style("hacker")}}>
|
|
||||||
Hacker
|
|
||||||
</button>
|
|
||||||
<button class:button_highlight={style==="canta"} on:click={() => {set_style("canta")}}>
|
|
||||||
Canta
|
|
||||||
</button>
|
|
||||||
<button class:button_highlight={style==="nord"} on:click={() => {set_style("nord")}}>
|
|
||||||
Nord
|
|
||||||
</button>
|
|
||||||
<button class:button_highlight={style==="snowstorm"} on:click={() => {set_style("snowstorm")}}>
|
|
||||||
Snowstorm
|
|
||||||
</button>
|
|
||||||
<button class:button_highlight={style==="deepsea"} on:click={() => {set_style("deepsea")}}>
|
|
||||||
Deep sea
|
|
||||||
</button>
|
|
||||||
<button class:button_highlight={style==="skeuos"} on:click={() => {set_style("skeuos")}}>
|
|
||||||
Skeuos
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{:else}
|
{:else}
|
||||||
<h3>Direct link</h3>
|
<h3>Direct link</h3>
|
||||||
<p>
|
<p>
|
||||||
@@ -201,7 +182,7 @@ const example = () => {
|
|||||||
Copy HTML
|
Copy HTML
|
||||||
{/if}
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
<button on:click={example}>
|
<button on:click={toggle_example} class:button_highlight={example}>
|
||||||
<i class="icon">visibility</i> Show example
|
<i class="icon">visibility</i> Show example
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -5,6 +5,7 @@ import DirectoryElement from "../user_file_manager/DirectoryElement.svelte";
|
|||||||
import Modal from "../util/Modal.svelte";
|
import Modal from "../util/Modal.svelte";
|
||||||
let dispatch = createEventDispatcher()
|
let dispatch = createEventDispatcher()
|
||||||
|
|
||||||
|
export let multi_select = true
|
||||||
let modal;
|
let modal;
|
||||||
let directory_element;
|
let directory_element;
|
||||||
let input_search;
|
let input_search;
|
||||||
@@ -92,7 +93,7 @@ const keydown = (e) => {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="dir_container">
|
<div class="dir_container">
|
||||||
<DirectoryElement bind:this={directory_element}></DirectoryElement>
|
<DirectoryElement bind:this={directory_element} multi_select={multi_select}></DirectoryElement>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
|
@@ -19,6 +19,7 @@ import Sharebar from "./Sharebar.svelte";
|
|||||||
import GalleryView from "./GalleryView.svelte";
|
import GalleryView from "./GalleryView.svelte";
|
||||||
import Spinner from "../util/Spinner.svelte";
|
import Spinner from "../util/Spinner.svelte";
|
||||||
import Downloader from "./Downloader.svelte";
|
import Downloader from "./Downloader.svelte";
|
||||||
|
import CustomBanner from "./CustomBanner.svelte";
|
||||||
|
|
||||||
let loading = true
|
let loading = true
|
||||||
let embedded = false
|
let embedded = false
|
||||||
@@ -145,6 +146,10 @@ const open_list = l => {
|
|||||||
// correct file is opened
|
// correct file is opened
|
||||||
is_list = true
|
is_list = true
|
||||||
|
|
||||||
|
if (l.files.length !== 0) {
|
||||||
|
apply_customizations(l.files[0])
|
||||||
|
}
|
||||||
|
|
||||||
hash_change()
|
hash_change()
|
||||||
}
|
}
|
||||||
const hash_change = () => {
|
const hash_change = () => {
|
||||||
@@ -200,6 +205,8 @@ const open_file_index = async index => {
|
|||||||
document.title = file.name+" ~ pixeldrain"
|
document.title = file.name+" ~ pixeldrain"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apply_customizations(file)
|
||||||
|
|
||||||
// Register a file view
|
// Register a file view
|
||||||
fetch(window.api_endpoint + "/file/" + file.id + "/view", {
|
fetch(window.api_endpoint + "/file/" + file.id + "/view", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@@ -215,6 +222,30 @@ const toggle_gallery = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Premium page customizations. In the gallery view we will use the
|
||||||
|
// customizations for the first file in the list, else we simply use the
|
||||||
|
// selected file. In most cases they are all the same so the user won't notice
|
||||||
|
// any change
|
||||||
|
let file_preview_background
|
||||||
|
let custom_header = ""
|
||||||
|
let custom_background = ""
|
||||||
|
let custom_footer = ""
|
||||||
|
const apply_customizations = file => {
|
||||||
|
if (file.custom_header) {
|
||||||
|
custom_header = window.api_endpoint+"/file/"+file.custom_header
|
||||||
|
}
|
||||||
|
if (file.custom_footer) {
|
||||||
|
custom_footer = window.api_endpoint+"/file/"+file.custom_footer
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file.custom_background) {
|
||||||
|
custom_background = window.api_endpoint+"/file/"+file.custom_background
|
||||||
|
file_preview_background.style.backgroundImage = "url('"+custom_background+"')"
|
||||||
|
} else {
|
||||||
|
file_preview_background.style.backgroundImage = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let supports_fullscreen = !!document.documentElement.requestFullscreen
|
let supports_fullscreen = !!document.documentElement.requestFullscreen
|
||||||
let fullscreen = false
|
let fullscreen = false
|
||||||
const toggle_fullscreen = () => {
|
const toggle_fullscreen = () => {
|
||||||
@@ -378,6 +409,8 @@ const keyboard_event = evt => {
|
|||||||
</ListNavigator>
|
</ListNavigator>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
<CustomBanner src={custom_header} border_top={true}></CustomBanner>
|
||||||
|
|
||||||
<div id="file_preview_window" class="file_preview_window">
|
<div id="file_preview_window" class="file_preview_window">
|
||||||
<div id="toolbar" class="toolbar" class:toolbar_visible><div><div>
|
<div id="toolbar" class="toolbar" class:toolbar_visible><div><div>
|
||||||
{#if view === "file"}
|
{#if view === "file"}
|
||||||
@@ -523,7 +556,13 @@ const keyboard_event = evt => {
|
|||||||
<br/>
|
<br/>
|
||||||
</div></div></div>
|
</div></div></div>
|
||||||
|
|
||||||
<div id="file_preview" class="file_preview checkers" class:toolbar_visible class:skyscraper_visible>
|
<div bind:this={file_preview_background}
|
||||||
|
class="file_preview_container"
|
||||||
|
class:checkers={!custom_background}
|
||||||
|
class:custom_background={!!custom_background}
|
||||||
|
class:toolbar_visible
|
||||||
|
class:skyscraper_visible
|
||||||
|
>
|
||||||
{#if view === "file"}
|
{#if view === "file"}
|
||||||
<FilePreview
|
<FilePreview
|
||||||
bind:this={file_preview}
|
bind:this={file_preview}
|
||||||
@@ -550,6 +589,8 @@ const keyboard_event = evt => {
|
|||||||
|
|
||||||
{#if ads_enabled}
|
{#if ads_enabled}
|
||||||
<AdLeaderboard></AdLeaderboard>
|
<AdLeaderboard></AdLeaderboard>
|
||||||
|
{:else if custom_footer}
|
||||||
|
<CustomBanner src={custom_footer}></CustomBanner>
|
||||||
{:else if !window.viewer_data.user_ads_enabled && !embedded}
|
{:else if !window.viewer_data.user_ads_enabled && !embedded}
|
||||||
<div style="text-align: center; line-height: 1.3em; font-size: 13px;">
|
<div style="text-align: center; line-height: 1.3em; font-size: 13px;">
|
||||||
Thank you for supporting pixeldrain!
|
Thank you for supporting pixeldrain!
|
||||||
@@ -660,7 +701,7 @@ const keyboard_event = evt => {
|
|||||||
height: auto;
|
height: auto;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
.file_preview {
|
.file_preview_container {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
@@ -676,6 +717,12 @@ const keyboard_event = evt => {
|
|||||||
box-shadow: inset 2px 2px 10px 2px var(--shadow_color);
|
box-shadow: inset 2px 2px 10px 2px var(--shadow_color);
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
}
|
}
|
||||||
|
.file_preview_container.toolbar_visible { left: 8em; }
|
||||||
|
.file_preview_container.skyscraper_visible { right: 160px; }
|
||||||
|
.file_preview_container.custom_background {
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
|
||||||
/* Toolbars */
|
/* Toolbars */
|
||||||
.toolbar {
|
.toolbar {
|
||||||
@@ -692,8 +739,6 @@ const keyboard_event = evt => {
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
.toolbar.toolbar_visible { left: 0; }
|
.toolbar.toolbar_visible { left: 0; }
|
||||||
.file_preview.toolbar_visible { left: 8em; }
|
|
||||||
.file_preview.skyscraper_visible { right: 160px; }
|
|
||||||
|
|
||||||
/* Workaround to hide the scrollbar in non webkit browsers, it's really ugly' */
|
/* Workaround to hide the scrollbar in non webkit browsers, it's really ugly' */
|
||||||
.toolbar > div {
|
.toolbar > div {
|
||||||
|
@@ -156,7 +156,7 @@ const drop = (e, index) => {
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<FilePicker bind:this={file_picker} on:files={e => {add_files(e.detail)}}></FilePicker>
|
<FilePicker bind:this={file_picker} on:files={e => {add_files(e.detail)}} multi_select={true}></FilePicker>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.gallery{
|
.gallery{
|
||||||
|
@@ -91,7 +91,6 @@ const copy_magnet = () => {
|
|||||||
</a>
|
</a>
|
||||||
<button
|
<button
|
||||||
on:click={copy_magnet}
|
on:click={copy_magnet}
|
||||||
class="button"
|
|
||||||
class:button_highlight={copy_magnet_status === "copied"}
|
class:button_highlight={copy_magnet_status === "copied"}
|
||||||
class:button_red={copy_magnet_status === "error"}
|
class:button_red={copy_magnet_status === "error"}
|
||||||
>
|
>
|
||||||
|
@@ -8,6 +8,7 @@ import Twitter from "../icons/Twitter.svelte"
|
|||||||
import Tumblr from "../icons/Tumblr.svelte"
|
import Tumblr from "../icons/Tumblr.svelte"
|
||||||
import { formatDataVolume, formatDuration } from "../util/Formatting.svelte";
|
import { formatDataVolume, formatDuration } from "../util/Formatting.svelte";
|
||||||
import StorageProgressBar from "../user_home/StorageProgressBar.svelte"
|
import StorageProgressBar from "../user_home/StorageProgressBar.svelte"
|
||||||
|
import Konami from "../util/Konami.svelte"
|
||||||
|
|
||||||
// === UPLOAD LOGIC ===
|
// === UPLOAD LOGIC ===
|
||||||
|
|
||||||
@@ -384,6 +385,8 @@ const keydown = (e) => {
|
|||||||
on:keydown={keydown}
|
on:keydown={keydown}
|
||||||
on:beforeunload={leave_confirmation} />
|
on:beforeunload={leave_confirmation} />
|
||||||
|
|
||||||
|
<Konami></Konami>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<!-- If the user is logged in and has used more than 50% of their storage space we will show a progress bar -->
|
<!-- If the user is logged in and has used more than 50% of their storage space we will show a progress bar -->
|
||||||
{#if window.user.username !== "" && window.user.storage_space_used/window.user.subscription.storage_space > 0.5}
|
{#if window.user.username !== "" && window.user.storage_space_used/window.user.subscription.storage_space > 0.5}
|
||||||
|
@@ -259,10 +259,11 @@ const detect_shift = (e) => {
|
|||||||
shift_pressed = e.type === "keydown"
|
shift_pressed = e.type === "keydown"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export let multi_select = true
|
||||||
let last_selected_node = -1
|
let last_selected_node = -1
|
||||||
const node_click = (index) => {
|
const node_click = (index) => {
|
||||||
if (selectionMode) {
|
if (selectionMode) {
|
||||||
if (shift_pressed && last_selected_node != -1) {
|
if (multi_select && shift_pressed && last_selected_node != -1) {
|
||||||
let id_low = last_selected_node
|
let id_low = last_selected_node
|
||||||
let id_high = last_selected_node
|
let id_high = last_selected_node
|
||||||
if (last_selected_node < index) {
|
if (last_selected_node < index) {
|
||||||
@@ -277,6 +278,14 @@ const node_click = (index) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// If multi select is disabled we deselect all other files before
|
||||||
|
// selecting this one
|
||||||
|
if (!multi_select) {
|
||||||
|
for (let i in allFiles) {
|
||||||
|
allFiles[i].selected = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
allFiles[index].selected = !allFiles[index].selected
|
allFiles[index].selected = !allFiles[index].selected
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,4 +1,8 @@
|
|||||||
<script>
|
<script>
|
||||||
|
import { onMount } from "svelte";
|
||||||
|
import FilePicker from "../file_viewer/FilePicker.svelte";
|
||||||
|
import SuccessMessage from "../util/SuccessMessage.svelte";
|
||||||
|
import ThemePicker from "../util/ThemePicker.svelte";
|
||||||
import Form from "./../util/Form.svelte";
|
import Form from "./../util/Form.svelte";
|
||||||
|
|
||||||
let password_change = {
|
let password_change = {
|
||||||
@@ -6,7 +10,7 @@ let password_change = {
|
|||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: "old_password",
|
name: "old_password",
|
||||||
label: "Old password",
|
label: "Current password",
|
||||||
type: "current_password",
|
type: "current_password",
|
||||||
}, {
|
}, {
|
||||||
name: "new_password",
|
name: "new_password",
|
||||||
@@ -135,26 +139,195 @@ let delete_account = {
|
|||||||
return {success: true, message: "Success! Your account has been scheduled for deletion in 7 days"}
|
return {success: true, message: "Success! Your account has been scheduled for deletion in 7 days"}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
let success_message
|
||||||
|
|
||||||
|
let file_picker
|
||||||
|
let theme = ""
|
||||||
|
let currently_selecting = "" // header, background or footer
|
||||||
|
let header_image_id = ""
|
||||||
|
let background_image_id = ""
|
||||||
|
let footer_image_id = ""
|
||||||
|
let select_file = t => {
|
||||||
|
currently_selecting = t
|
||||||
|
file_picker.open()
|
||||||
|
}
|
||||||
|
let add_file = files => {
|
||||||
|
let type = files[0].type
|
||||||
|
if (type != "image/png" && type != "image/jpeg" && type != "image/gif" && type != "image/webp") {
|
||||||
|
success_message.set(false, "File must be an image type")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (files[0].size > 10e6) {
|
||||||
|
success_message.set(false, "Files larger than 10 MB are not allowed. Recommended size is below 1 MB")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currently_selecting === "header") {
|
||||||
|
header_image_id = files[0].id
|
||||||
|
} else if (currently_selecting === "background") {
|
||||||
|
background_image_id = files[0].id
|
||||||
|
} else if (currently_selecting === "footer") {
|
||||||
|
footer_image_id = files[0].id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let save = async () => {
|
||||||
|
const form = new FormData()
|
||||||
|
form.append("file_theme", theme)
|
||||||
|
form.append("file_header", header_image_id)
|
||||||
|
form.append("file_background", background_image_id)
|
||||||
|
form.append("file_footer", footer_image_id)
|
||||||
|
|
||||||
|
const resp = await fetch(
|
||||||
|
window.api_endpoint+"/user/file_customization",
|
||||||
|
{ method: "PUT", body: form }
|
||||||
|
);
|
||||||
|
if(resp.status >= 400) {
|
||||||
|
let json = await resp.json()
|
||||||
|
console.debug(json)
|
||||||
|
success_message.set(false, json.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
success_message.set(true, "Changes saved")
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
theme = window.user.custom_file_theme
|
||||||
|
header_image_id = window.user.custom_file_header
|
||||||
|
background_image_id = window.user.custom_file_background
|
||||||
|
footer_image_id = window.user.custom_file_footer
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<h2>Change password</h2>
|
<h2>Account settings</h2>
|
||||||
<div class="highlight_dark">
|
<h3>Change password</h3>
|
||||||
<Form config={password_change}></Form>
|
<Form config={password_change}></Form>
|
||||||
</div>
|
|
||||||
|
|
||||||
<h2>Change e-mail address</h2>
|
<h3>Change e-mail address</h3>
|
||||||
<div class="highlight_dark">
|
|
||||||
<Form config={email_change}></Form>
|
<Form config={email_change}></Form>
|
||||||
</div>
|
|
||||||
|
|
||||||
<h2>Change name</h2>
|
<h3>Change name</h3>
|
||||||
<div class="highlight_dark">
|
|
||||||
<Form config={name_change}></Form>
|
<Form config={name_change}></Form>
|
||||||
</div>
|
|
||||||
|
|
||||||
<h2>Delete account</h2>
|
<h3>Delete account</h3>
|
||||||
<div class="highlight_dark">
|
|
||||||
<Form config={delete_account}></Form>
|
<Form config={delete_account}></Form>
|
||||||
|
|
||||||
|
<h2>File viewer branding</h2>
|
||||||
|
{#if !window.user.subscription.file_viewer_branding}
|
||||||
|
<div class="highlight_red">
|
||||||
|
File viewer branding is not available for your account. Subscribe to
|
||||||
|
the Persistence plan or higher to enable this feature.
|
||||||
</div>
|
</div>
|
||||||
|
{:else if !window.user.hotlinking_enabled}
|
||||||
|
<div class="highlight_red">
|
||||||
|
To use the branding feature bandwidth sharing needs to be enabled.
|
||||||
|
Without this the custom images will not be able to load. Enable
|
||||||
|
bandwidth sharing on the
|
||||||
|
<a href="/user/subscription">subscription page</a>.
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<SuccessMessage bind:this={success_message}></SuccessMessage>
|
||||||
|
<p>
|
||||||
|
You can change the appearance of your file viewer pages. The images you
|
||||||
|
choose here will be loaded each time someone visits one of your files.
|
||||||
|
The data usage will also be subtracted from your account's data cap.
|
||||||
|
Keep in mind that large images can take a very long time to load over
|
||||||
|
cellular connections. I recommend keeping the header and footer images
|
||||||
|
below 100 kB, and the background image below 1 MB. Allowed image types
|
||||||
|
are PNG, JPEG, GIF and WebP. If you want to use an animated banner you
|
||||||
|
should use APNG or WebP. Avoid using animated GIFs as they are very slow
|
||||||
|
to load.
|
||||||
|
</p>
|
||||||
|
<h3>Theme</h3>
|
||||||
|
<p>
|
||||||
|
Choose a theme for your download pages. This theme will override the
|
||||||
|
theme preference of the person viewing the file. Set to 'None' to let
|
||||||
|
the viewer choose their own theme.
|
||||||
|
</p>
|
||||||
|
<ThemePicker on:theme_change={e => theme = e.detail}></ThemePicker>
|
||||||
|
|
||||||
|
<h3>Header image</h3>
|
||||||
|
<p>
|
||||||
|
Will be shown above the file. Maximum height is 100px. Will be shrunk if
|
||||||
|
larger.
|
||||||
|
</p>
|
||||||
|
<button on:click={() => {select_file("header")}}>
|
||||||
|
<i class="icon">add_photo_alternate</i>
|
||||||
|
Select header image
|
||||||
|
</button>
|
||||||
|
<button on:click={() => {header_image_id = ""}}>
|
||||||
|
<i class="icon">close</i>
|
||||||
|
Remove
|
||||||
|
</button>
|
||||||
|
{#if header_image_id}
|
||||||
|
<div class="highlight_dark">
|
||||||
|
<img class="banner_preview" src="/api/file/{header_image_id}" alt="Custom file viewer header"/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<h3>Background image</h3>
|
||||||
|
<p>
|
||||||
|
This image will be shown behind the file which is being viewed. I
|
||||||
|
recommend choosing something dark and not too distracting. Try to keep
|
||||||
|
the file below 1 MB to not harm page loading times. Using a JPEG image
|
||||||
|
with a quality value of 60 is usually good enough.
|
||||||
|
</p>
|
||||||
|
<button on:click={() => {select_file("background")}}>
|
||||||
|
<i class="icon">add_photo_alternate</i>
|
||||||
|
Select background image
|
||||||
|
</button>
|
||||||
|
<button on:click={() => {background_image_id = ""}}>
|
||||||
|
<i class="icon">close</i>
|
||||||
|
Remove
|
||||||
|
</button>
|
||||||
|
{#if background_image_id}
|
||||||
|
<div class="highlight_dark">
|
||||||
|
<img class="background_preview" src="/api/file/{background_image_id}" alt="Custom file viewer background"/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<h3>Footer image</h3>
|
||||||
|
<p>
|
||||||
|
Will be shown below the file. Maximum height is 100px. Will be shrunk if
|
||||||
|
larger.
|
||||||
|
</p>
|
||||||
|
<button on:click={() => {select_file("footer")}}>
|
||||||
|
<i class="icon">add_photo_alternate</i>
|
||||||
|
Select footer image
|
||||||
|
</button>
|
||||||
|
<button on:click={() => {footer_image_id = ""}}>
|
||||||
|
<i class="icon">close</i>
|
||||||
|
Remove
|
||||||
|
</button>
|
||||||
|
{#if footer_image_id}
|
||||||
|
<div class="highlight_dark">
|
||||||
|
<img class="banner_preview" src="/api/file/{footer_image_id}" alt="Custom file viewer footer"/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<button on:click={save}>
|
||||||
|
<i class="icon">save</i> Save
|
||||||
|
</button>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<FilePicker bind:this={file_picker} on:files={e => {add_file(e.detail)}} multi_select={false}></FilePicker>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.banner_preview {
|
||||||
|
max-height: 100px;
|
||||||
|
max-width: 100%;
|
||||||
|
display: block;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
.background_preview {
|
||||||
|
max-height: 200px;
|
||||||
|
max-width: 100%;
|
||||||
|
display: block;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
31
svelte/src/util/Konami.svelte
Normal file
31
svelte/src/util/Konami.svelte
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<script>
|
||||||
|
let sequence = [
|
||||||
|
"ArrowUp",
|
||||||
|
"ArrowUp",
|
||||||
|
"ArrowDown",
|
||||||
|
"ArrowDown",
|
||||||
|
"ArrowLeft",
|
||||||
|
"ArrowRight",
|
||||||
|
"ArrowLeft",
|
||||||
|
"ArrowRight",
|
||||||
|
"b",
|
||||||
|
"a",
|
||||||
|
]
|
||||||
|
let index = 0
|
||||||
|
|
||||||
|
const keypress = e => {
|
||||||
|
if (e.key === sequence[index]) {
|
||||||
|
index++
|
||||||
|
} else {
|
||||||
|
index = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index === sequence.length) {
|
||||||
|
index = 0
|
||||||
|
let audio = new Audio("/res/misc/amogus.opus")
|
||||||
|
audio.play()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:window on:keydown={keypress} />
|
18
svelte/src/util/SuccessMessage.svelte
Normal file
18
svelte/src/util/SuccessMessage.svelte
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<script>
|
||||||
|
let s = false
|
||||||
|
let m = ""
|
||||||
|
|
||||||
|
export const set = (success, message) => {
|
||||||
|
s = success
|
||||||
|
m = message
|
||||||
|
}
|
||||||
|
export const clear = () => {
|
||||||
|
m = ""
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if m}
|
||||||
|
<div class:highlight_green={s} class:highlight_red={!s}>
|
||||||
|
{m}
|
||||||
|
</div>
|
||||||
|
{/if}
|
53
svelte/src/util/ThemePicker.svelte
Normal file
53
svelte/src/util/ThemePicker.svelte
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<script>
|
||||||
|
import { createEventDispatcher } from "svelte";
|
||||||
|
let dispatch = createEventDispatcher()
|
||||||
|
|
||||||
|
export let theme = ""
|
||||||
|
let set = s => {
|
||||||
|
theme = s
|
||||||
|
dispatch("theme_change", theme)
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="center">
|
||||||
|
<button class:button_highlight={theme===""} on:click={() => {set("")}}>
|
||||||
|
None
|
||||||
|
</button>
|
||||||
|
<button class:button_highlight={theme==="default"} on:click={() => {set("default")}}>
|
||||||
|
Default (purple)
|
||||||
|
</button>
|
||||||
|
<button class:button_highlight={theme==="classic"} on:click={() => {set("classic")}}>
|
||||||
|
Classic
|
||||||
|
</button>
|
||||||
|
<button class:button_highlight={theme==="solarized_dark"} on:click={() => {set("solarized_dark")}}>
|
||||||
|
Solarized
|
||||||
|
</button>
|
||||||
|
<button class:button_highlight={theme==="maroon"} on:click={() => {set("maroon")}}>
|
||||||
|
Maroon
|
||||||
|
</button>
|
||||||
|
<button class:button_highlight={theme==="hacker"} on:click={() => {set("hacker")}}>
|
||||||
|
Hacker
|
||||||
|
</button>
|
||||||
|
<button class:button_highlight={theme==="canta"} on:click={() => {set("canta")}}>
|
||||||
|
Canta
|
||||||
|
</button>
|
||||||
|
<button class:button_highlight={theme==="nord"} on:click={() => {set("nord")}}>
|
||||||
|
Nord
|
||||||
|
</button>
|
||||||
|
<button class:button_highlight={theme==="snowstorm"} on:click={() => {set("snowstorm")}}>
|
||||||
|
Snowstorm
|
||||||
|
</button>
|
||||||
|
<button class:button_highlight={theme==="deepsea"} on:click={() => {set("deepsea")}}>
|
||||||
|
Deep sea
|
||||||
|
</button>
|
||||||
|
<button class:button_highlight={theme==="skeuos"} on:click={() => {set("skeuos")}}>
|
||||||
|
Skeuos
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -97,6 +97,8 @@ func (wc *WebController) serveFileViewer(w http.ResponseWriter, r *http.Request,
|
|||||||
|
|
||||||
templateData.Other = vd
|
templateData.Other = vd
|
||||||
|
|
||||||
|
fileStyleOverride(templateData, files)
|
||||||
|
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
if file.AbuseType != "" {
|
if file.AbuseType != "" {
|
||||||
w.WriteHeader(http.StatusUnavailableForLegalReasons)
|
w.WriteHeader(http.StatusUnavailableForLegalReasons)
|
||||||
@@ -157,6 +159,8 @@ func (wc *WebController) serveListViewer(w http.ResponseWriter, r *http.Request,
|
|||||||
}
|
}
|
||||||
templateData.Other = vd
|
templateData.Other = vd
|
||||||
|
|
||||||
|
fileStyleOverride(templateData, list.Files)
|
||||||
|
|
||||||
for _, file := range list.Files {
|
for _, file := range list.Files {
|
||||||
if file.AbuseType != "" {
|
if file.AbuseType != "" {
|
||||||
w.WriteHeader(http.StatusUnavailableForLegalReasons)
|
w.WriteHeader(http.StatusUnavailableForLegalReasons)
|
||||||
@@ -175,6 +179,16 @@ func (wc *WebController) serveListViewer(w http.ResponseWriter, r *http.Request,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fileStyleOverride(td *TemplateData, files []pixelapi.ListFile) {
|
||||||
|
if len(files) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if files[0].CustomTheme != "" {
|
||||||
|
td.setStyle(userStyle(files[0].CustomTheme))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ServeFileViewerDemo is a dummy API response that responds with info about a
|
// ServeFileViewerDemo is a dummy API response that responds with info about a
|
||||||
// non-existent demo file. This is required by the a-ads ad network to allow for
|
// non-existent demo file. This is required by the a-ads ad network to allow for
|
||||||
// automatic checking of the presence of the ad unit on this page.
|
// automatic checking of the presence of the ad unit on this page.
|
||||||
|
@@ -21,6 +21,7 @@ import (
|
|||||||
// TemplateData is a struct that every template expects when being rendered. In
|
// TemplateData is a struct that every template expects when being rendered. In
|
||||||
// the field Other you can pass your own template-specific variables.
|
// the field Other you can pass your own template-specific variables.
|
||||||
type TemplateData struct {
|
type TemplateData struct {
|
||||||
|
tpm *TemplateManager
|
||||||
Authenticated bool
|
Authenticated bool
|
||||||
User pixelapi.UserInfo
|
User pixelapi.UserInfo
|
||||||
UserAgent string
|
UserAgent string
|
||||||
@@ -45,14 +46,17 @@ type TemplateData struct {
|
|||||||
Form Form
|
Form Form
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (td *TemplateData) setStyle(style pixeldrainStyleSheet) {
|
||||||
|
td.Style = style
|
||||||
|
td.UserStyle = template.CSS(style.String())
|
||||||
|
td.BackgroundPattern = style.Background(td.tpm.tpl)
|
||||||
|
}
|
||||||
|
|
||||||
func (wc *WebController) newTemplateData(w http.ResponseWriter, r *http.Request) (t *TemplateData) {
|
func (wc *WebController) newTemplateData(w http.ResponseWriter, r *http.Request) (t *TemplateData) {
|
||||||
var style = userStyle(r)
|
|
||||||
t = &TemplateData{
|
t = &TemplateData{
|
||||||
|
tpm: wc.templates,
|
||||||
Authenticated: false,
|
Authenticated: false,
|
||||||
UserAgent: r.UserAgent(),
|
UserAgent: r.UserAgent(),
|
||||||
Style: style,
|
|
||||||
UserStyle: template.CSS(style.String()),
|
|
||||||
BackgroundPattern: style.Background(wc.templates.tpl),
|
|
||||||
APIEndpoint: template.URL(wc.apiURLExternal),
|
APIEndpoint: template.URL(wc.apiURLExternal),
|
||||||
|
|
||||||
// Use the user's IP address for making requests
|
// Use the user's IP address for making requests
|
||||||
@@ -63,6 +67,8 @@ func (wc *WebController) newTemplateData(w http.ResponseWriter, r *http.Request)
|
|||||||
URLQuery: r.URL.Query(),
|
URLQuery: r.URL.Query(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t.setStyle(userStyleFromRequest(r))
|
||||||
|
|
||||||
// If the user is authenticated we'll indentify him and put the user info
|
// If the user is authenticated we'll indentify him and put the user info
|
||||||
// into the templatedata. This is used for putting the username in the menu
|
// into the templatedata. This is used for putting the username in the menu
|
||||||
// and stuff like that
|
// and stuff like that
|
||||||
|
@@ -9,7 +9,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func userStyle(r *http.Request) (s pixeldrainStyleSheet) {
|
func userStyleFromRequest(r *http.Request) (s pixeldrainStyleSheet) {
|
||||||
// Get the chosen style from the URL
|
// Get the chosen style from the URL
|
||||||
var style = r.URL.Query().Get("style")
|
var style = r.URL.Query().Get("style")
|
||||||
|
|
||||||
@@ -20,6 +20,10 @@ func userStyle(r *http.Request) (s pixeldrainStyleSheet) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return userStyle(style)
|
||||||
|
}
|
||||||
|
|
||||||
|
func userStyle(style string) (s pixeldrainStyleSheet) {
|
||||||
switch style {
|
switch style {
|
||||||
case "classic":
|
case "classic":
|
||||||
s = pixeldrainClassicStyle
|
s = pixeldrainClassicStyle
|
||||||
|
Reference in New Issue
Block a user