Rename FNX to Nova
BIN
res/static/img/header.webp
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
res/static/img/northernlights.webp
Normal file
|
After Width: | Height: | Size: 175 KiB |
BIN
res/static/img/nova.xcf
Normal file
BIN
res/static/img/nova_1024.png
Normal file
|
After Width: | Height: | Size: 559 KiB |
BIN
res/static/img/nova_128.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
res/static/img/nova_256.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
res/static/img/nova_32.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
res/static/img/nova_512.png
Normal file
|
After Width: | Height: | Size: 118 KiB |
BIN
res/static/img/nova_64.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
res/static/img/nova_title.xcf
Normal file
@@ -10,16 +10,17 @@
|
||||
<link id="stylesheet_layout" rel="stylesheet" type="text/css" href="/res/style/layout.css?v{{cacheID}}"/>
|
||||
<link id="stylesheet_theme" rel="stylesheet" type="text/css" href="/theme.css"/>
|
||||
|
||||
<link rel="icon" sizes="32x32" href="/res/img/pixeldrain_32.png" />
|
||||
<link rel="icon" sizes="128x128" href="/res/img/pixeldrain_128.png" />
|
||||
<link rel="icon" sizes="152x152" href="/res/img/pixeldrain_152.png" />
|
||||
<link rel="icon" sizes="180x180" href="/res/img/pixeldrain_180.png" />
|
||||
<link rel="icon" sizes="192x192" href="/res/img/pixeldrain_192.png" />
|
||||
<link rel="icon" sizes="196x196" href="/res/img/pixeldrain_196.png" />
|
||||
<link rel="icon" sizes="256x256" href="/res/img/pixeldrain_256.png" />
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="/res/img/pixeldrain_152.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/res/img/pixeldrain_180.png" />
|
||||
<link rel="shortcut icon" sizes="196x196" href="/res/img/pixeldrain_196.png" />
|
||||
<link rel="icon" sizes="32x32" href="/res/img/nova_32.png" />
|
||||
<link rel="icon" sizes="64x64" href="/res/img/nova_64.png" />
|
||||
<link rel="icon" sizes="128x128" href="/res/img/nova_128.png" />
|
||||
<link rel="icon" sizes="152x152" href="/res/img/nova_152.png" />
|
||||
<link rel="icon" sizes="180x180" href="/res/img/nova_180.png" />
|
||||
<link rel="icon" sizes="192x192" href="/res/img/nova_192.png" />
|
||||
<link rel="icon" sizes="196x196" href="/res/img/nova_196.png" />
|
||||
<link rel="icon" sizes="256x256" href="/res/img/nova_256.png" />
|
||||
<link rel="apple-touch-icon" sizes="128x128" href="/res/img/nova_128.png" />
|
||||
<link rel="apple-touch-icon" sizes="256x256" href="/res/img/nova_256.png" />
|
||||
<link rel="shortcut icon" sizes="256x256" href="/res/img/nova_256.png" />
|
||||
|
||||
{{ template "opengraph" .OGData }}
|
||||
<script>
|
||||
|
||||
@@ -97,7 +97,7 @@ export class FSNavigator {
|
||||
// we still replace the URL with replaceState. This way the user is not
|
||||
// greeted to a 404 page when refreshing after renaming a file
|
||||
if (this.history_enabled) {
|
||||
window.document.title = node.path[node.base_index].name + " / FNX"
|
||||
window.document.title = node.path[node.base_index].name + " / Nova"
|
||||
const url = "/d" + fs_encode_path(node.path[node.base_index].path) + window.location.hash
|
||||
if (push_history) {
|
||||
window.history.pushState({}, window.document.title, url)
|
||||
|
||||
@@ -387,15 +387,7 @@ run(() => {
|
||||
{#if creating_dir}
|
||||
<CreateDirectory nav={nav} />
|
||||
{/if}
|
||||
|
||||
{#if $nav.base.path === "/me"}
|
||||
<div class="highlight_shaded" style="background-color: rgba(255, 255, 0, 0.05); border-radius: 0;">
|
||||
The filesystem is experimental!
|
||||
<a href="/filesystem">Please read the guide</a>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
|
||||
{#if $nav.base.abuse_type !== undefined}
|
||||
<div class="highlight_red">
|
||||
|
||||
@@ -22,7 +22,7 @@ let upload_widget
|
||||
<div class="page_content">
|
||||
<section>
|
||||
<p>
|
||||
FNX.storage is a platform for cost-effective cloud storage and
|
||||
Nova.storage is a platform for cost-effective cloud storage and
|
||||
content delivery. We will store and serve your files at an extremely
|
||||
competitive rate.
|
||||
</p>
|
||||
@@ -36,7 +36,7 @@ let upload_widget
|
||||
<div>€ 1 / TB</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2>What FNX is good at</h2>
|
||||
<h2>What Nova is good at</h2>
|
||||
<ul>
|
||||
<li>
|
||||
Serving large files to millions of people worldwide
|
||||
@@ -147,11 +147,11 @@ header > h1 {
|
||||
.header_image_container {
|
||||
text-align: initial;
|
||||
margin: auto;
|
||||
margin-bottom: 1.5em; /*Offset for menu button*/
|
||||
height: 150px;
|
||||
margin-bottom: 50px;
|
||||
height: 100px;
|
||||
width: 500px;
|
||||
max-width: 100%;
|
||||
background-image: url("/res/img/header_orbitron.webp");
|
||||
background-image: url("/res/img/header.webp");
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
background-position: center;
|
||||
|
||||
@@ -18,7 +18,7 @@ let egress = $state(10) // TB
|
||||
let avg_file_size = $state(1000) // kB
|
||||
|
||||
$effect(() => {
|
||||
// FNX has a minimum file size of 10kB. Calculate the number of files from
|
||||
// Nova has a minimum file size of 10kB. Calculate the number of files from
|
||||
// storage and avg file size, then calculate storage usage based on that.
|
||||
fnx_storage = Math.max(storage * 4, ((storage*10)/avg_file_size)*4)
|
||||
fnx_egress = egress * 1
|
||||
@@ -67,14 +67,14 @@ $effect(() => {
|
||||
<div class="bars">
|
||||
<div>
|
||||
<div>
|
||||
FNX.storage - <Euro amount={fnx_total*1e6}/> / month<br/>
|
||||
Nova.storage - <Euro amount={fnx_total*1e6}/> / month<br/>
|
||||
<Euro amount={fnx_storage*1e6}/> storage,
|
||||
<Euro amount={fnx_egress*1e6}/> egress
|
||||
<ProgressBar used={fnx_total} total={price_max}/>
|
||||
</div>
|
||||
{#if avg_file_size < 10}
|
||||
<div>
|
||||
FNX counts a minimum file size of 10 kB. Files smaller than that
|
||||
Nova counts a minimum file size of 10 kB. Files smaller than that
|
||||
are rounded up to 10 kB.
|
||||
</div>
|
||||
{/if}
|
||||
@@ -105,16 +105,16 @@ $effect(() => {
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Note that while FNX.storage might not seem to be the cheapest option in some
|
||||
Note that while Nova.storage might not seem to be the cheapest option in some
|
||||
cases, most cloud providers have extra hidden costs for API calls and
|
||||
region-specific prices. This makes it very hard to accurately compare the
|
||||
pricing of these platforms. FNX.storage includes no hidden costs, I only
|
||||
pricing of these platforms. Nova.storage includes no hidden costs, I only
|
||||
charge for storage and egress.
|
||||
</p>
|
||||
<p>
|
||||
Large cloud providers like Amazon, Microsoft and Google are excluded from
|
||||
this calculation because their pricing is too complex accurately compare
|
||||
them. Just assume that FNX wil be cheaper.
|
||||
them. Just assume that Nova wil be cheaper.
|
||||
</p>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -88,7 +88,8 @@ const login = async (e?: SubmitEvent) => {
|
||||
{
|
||||
method: "POST",
|
||||
body: fd,
|
||||
credentials: "omit", // Dont send existing session cookies
|
||||
// Allow server to set cookies
|
||||
credentials: "include",
|
||||
},
|
||||
))
|
||||
|
||||
@@ -99,9 +100,6 @@ const login = async (e?: SubmitEvent) => {
|
||||
}
|
||||
}
|
||||
|
||||
// Save the session cookie
|
||||
document.cookie = "pd_auth_key="+resp.auth_key+"; Max-Age=31536000;"
|
||||
|
||||
dispatch("login", {key: resp.auth_key})
|
||||
|
||||
if (typeof login_redirect === "string" && login_redirect.startsWith("/")) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { preventDefault } from 'svelte/legacy';
|
||||
import { loading_finish, loading_start } from "lib/Loading";
|
||||
import { formatDate } from "util/Formatting";
|
||||
import CopyButton from 'layout/CopyButton.svelte';
|
||||
|
||||
let loaded = $state(false)
|
||||
let rows = $state([])
|
||||
@@ -130,12 +131,15 @@ const logout = async (key) => {
|
||||
<tbody>
|
||||
{#each rows as row (row.auth_key)}
|
||||
<tr style="border-bottom: none;">
|
||||
<td>{row.auth_key}</td>
|
||||
<td>
|
||||
<CopyButton text={row.auth_key} small_icon>Copy</CopyButton>
|
||||
{row.auth_key}
|
||||
</td>
|
||||
<td>{formatDate(row.creation_time, true, true, false)}</td>
|
||||
<td>{formatDate(row.last_used_time, true, true, false)}</td>
|
||||
<td>{row.creation_ip_address}</td>
|
||||
<td>
|
||||
<button onclick={preventDefault(() => {logout(row.auth_key)})} class="button button_red round">
|
||||
<button onclick={(e) => {e.preventDefault();logout(row.auth_key)}} class="button button_red round">
|
||||
<i class="icon">delete</i>
|
||||
</button>
|
||||
</td>
|
||||
|
||||
@@ -3,6 +3,7 @@ import { get_endpoint, get_user, type User } from "lib/PixeldrainAPI";
|
||||
import { onMount } from "svelte";
|
||||
import HotlinkProgressBar from "user_home/HotlinkProgressBar.svelte";
|
||||
import StorageProgressBar from "user_home/StorageProgressBar.svelte";
|
||||
import { formatThousands } from "util/Formatting";
|
||||
|
||||
let transfer_cap = $state(0)
|
||||
let transfer_used = $state(0)
|
||||
@@ -53,6 +54,9 @@ onMount(async () => {
|
||||
<StorageProgressBar used={user.storage_space_used} total={storage_limit}/>
|
||||
<br/>
|
||||
|
||||
File count: {formatThousands(user.filesystem_node_count)}
|
||||
<br/><br/>
|
||||
|
||||
Egress used (30 days):
|
||||
(<a href="/user/sharing/bandwidth">set custom limit</a>)
|
||||
<HotlinkProgressBar used={transfer_used} total={transfer_cap}></HotlinkProgressBar>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { formatDataVolume, formatNumber } from "./Formatting";
|
||||
import { formatDataVolume, formatDuration, formatNumber } from "./Formatting";
|
||||
import { color_by_name } from "./Util";
|
||||
import {
|
||||
Chart,
|
||||
@@ -33,12 +33,14 @@ let {
|
||||
legend = true,
|
||||
tooltips = true,
|
||||
ticks = true,
|
||||
animations = true,
|
||||
height = "300px"
|
||||
}: {
|
||||
data_type?: string;
|
||||
legend?: boolean;
|
||||
tooltips?: boolean;
|
||||
ticks?: boolean;
|
||||
animations?: boolean;
|
||||
height?: string;
|
||||
} = $props();
|
||||
|
||||
@@ -85,6 +87,9 @@ onMount(() => {
|
||||
},
|
||||
tooltip: {
|
||||
enabled: tooltips,
|
||||
itemSort: (a, b): number => {
|
||||
return <number>b.raw - <number>a.raw
|
||||
},
|
||||
},
|
||||
},
|
||||
layout: {
|
||||
@@ -102,6 +107,8 @@ onMount(() => {
|
||||
callback: function (value: number, index: number, values: Tick[]) {
|
||||
if (data_type == "bytes") {
|
||||
return formatDataVolume(value, 3);
|
||||
} else if (data_type === "duration") {
|
||||
return formatDuration(value, 2);
|
||||
}
|
||||
return formatNumber(value, 3);
|
||||
},
|
||||
@@ -129,6 +136,11 @@ onMount(() => {
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (!animations) {
|
||||
chart_object.options.animation = false
|
||||
chart_object.options.transitions.active.animation.duration = 0
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -58,11 +58,24 @@ const hour = minute * 60
|
||||
const day = hour * 24
|
||||
|
||||
export const formatDuration = (ms: number, decimals: number) => {
|
||||
let remainingDecimals = decimals
|
||||
let res = ""
|
||||
if (ms >= day) { res += Math.floor(ms / day) + "d " }
|
||||
if (ms >= hour) { res += Math.floor((ms % day) / hour) + "h " }
|
||||
if (ms >= minute) { res += Math.floor((ms % hour) / minute) + "m " }
|
||||
return res + ((ms % minute) / second).toFixed(decimals) + "s"
|
||||
if (ms >= day && remainingDecimals > 0) {
|
||||
res += Math.floor(ms / day) + "d "
|
||||
remainingDecimals--
|
||||
}
|
||||
if (ms >= hour && remainingDecimals > 0) {
|
||||
res += Math.floor((ms % day) / hour) + "h "
|
||||
remainingDecimals--
|
||||
}
|
||||
if (ms >= minute && remainingDecimals > 0) {
|
||||
res += Math.floor((ms % hour) / minute) + "m "
|
||||
remainingDecimals--
|
||||
}
|
||||
if (remainingDecimals > 0) {
|
||||
res += ((ms % minute) / second).toFixed(remainingDecimals) + "s"
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
export const formatDate = (
|
||||
|
||||
@@ -49,7 +49,7 @@ const get_page = () => {
|
||||
}
|
||||
|
||||
title = current_subpage === null ? current_page.title : current_subpage.title
|
||||
window.document.title = title+" / FNX"
|
||||
window.document.title = title+" / Nova"
|
||||
}
|
||||
|
||||
let current_page: Tab = $state(null)
|
||||
|
||||
@@ -98,7 +98,7 @@ const load_page = (pathname: string, history: boolean): boolean => {
|
||||
return load_page("/login", true)
|
||||
}
|
||||
|
||||
window.document.title = current_page.title+" / FNX"
|
||||
window.document.title = current_page.title+" / Nova"
|
||||
|
||||
if(history) {
|
||||
window.history.pushState({}, window.document.title, pathname)
|
||||
|
||||