UI overhaul, import fixes, fix user store

This commit is contained in:
2026-07-30 17:07:46 +02:00
parent 773149169b
commit 4b8bd11a4c
75 changed files with 1106 additions and 744 deletions

View File

@@ -1,4 +1,6 @@
<script>
<script lang="ts">
import { get_endpoint } from "lib/NovaAPI";
import { user } from "lib/UserStore";
import { onMount } from "svelte";
import Expandable from "util/Expandable.svelte";
import { formatDate } from "util/Formatting";
@@ -7,9 +9,9 @@ let result = $state(null);
onMount(async () => {
try {
const resp = await fetch(window.api_endpoint+"/misc/ip_address_reputation");
const resp = await fetch(get_endpoint()+"/misc/ip_address_reputation");
if(resp.status >= 400) {
throw new Error(resp.text());
throw new Error(await resp.text());
}
result = await resp.json()
} catch (err) {
@@ -66,7 +68,7 @@ onMount(async () => {
support@nova.storage. Please do not mail unless you have a
good reason. If you do not provide a valid reason why the ban
should be reversed your e-mail will be ignored. And do not
forget to put your username ({window.user.username}) in the
forget to put your username ({$user === null ? "" : $user.username}) in the
e-mail.
</p>
</Expandable>

View File

@@ -1,7 +1,8 @@
<script>
import Tooltip from "layout/Tooltip.svelte";
import Euro from "util/Euro.svelte";
import OtherPlans from "./OtherPlans.svelte";
import OtherPlans from "./SubscriptionPlans.svelte";
import { user } from "lib/UserStore";
</script>
<section>
@@ -222,7 +223,7 @@ import OtherPlans from "./OtherPlans.svelte";
Free
</div>
<div class="bottom_row pro_feat">
{#if window.user.subscription.id === "patreon_1"}
{#if $user !== null && $user.subscription.id === "patreon_1"}
You have this plan<br/>
Thank you for supporting Nova!
{:else}
@@ -240,7 +241,7 @@ import OtherPlans from "./OtherPlans.svelte";
{/if}
</div>
<div class="bottom_row prepaid_feat">
{#if window.user.username === ""}
{#if $user === null}
<!-- User is not logged in -->
Account required<br/>
<a href="/login?redirect=/user/prepaid/deposit" class="button button_highlight round">
@@ -257,16 +258,16 @@ import OtherPlans from "./OtherPlans.svelte";
No recurring payments
{:else}
<!-- User is logged in -->
{#if window.user.subscription.type === ""}
{#if $user.subscription.type === ""}
<a href="/user/prepaid/deposit#deposit" class="button button_highlight round">
Deposit credit
</a>
to activate Prepaid
{:else if window.user.subscription.type === "patreon"}
{:else if $user.subscription.type === "patreon"}
Patreon subscription active. Prepaid cannot be activated
{:else if window.user.subscription.type === "prepaid"}
{:else if $user.subscription.type === "prepaid"}
Prepaid subscription is active<br/>
Current balance <Euro amount={window.user.balance_micro_eur}/>
Current balance <Euro amount={$user.balance_micro_eur}/>
<br/>
<a href="/user/prepaid/deposit#deposit" class="button button_highlight round">
Top up my credit

View File

@@ -1,28 +1,28 @@
<script>
<script lang="ts">
import Checkout from "layout/checkout/Checkout.svelte";
import { user } from "lib/UserStore";
import LoginRegister from "login/LoginRegister.svelte";
import Euro from "util/Euro.svelte";
</script>
{#if window.user.username !== ""}
{#if $user !== null}
<div class="page_content">
<section>
{#if window.user.subscription.type === "patreon"}
{#if $user.subscription.type === "patreon"}
<p>
You already have a Patreon subscription active. You cannot use
Prepaid while that subscription is active.
</p>
{:else if window.user.subscription.type === "prepaid"}
{:else if $user.subscription.type === "prepaid"}
<p>
You already have a Prepaid subscription active. Your account
balance is <Euro amount={window.user.balance_micro_eur}/>. Use
balance is <Euro amount={$user.balance_micro_eur}/>. Use
the form below to top up your balance.
</p>
<Checkout/>
{:else}
<p>
You are currently logged in as '{window.user.username}'. Use the
You are currently logged in as '{$user.username}'. Use the
form below to activate prepaid on this account.
</p>
<Checkout/>

View File

@@ -3,9 +3,9 @@ import Menu from "filesystem/Menu.svelte";
import Footer from "layout/Footer.svelte";
import { drop_target } from "lib/DropTarget";
import AddressReputation from "./AddressReputation.svelte";
import FeatureTable from "./FeatureTable.svelte";
import GetStarted from "./GetStarted.svelte";
import Pricing from "./Pricing.svelte";
import SubscriptionPlans from "./SubscriptionPlans.svelte";
let upload_widget
</script>
@@ -28,26 +28,6 @@ let upload_widget
content delivery. We will store and serve your files at an extremely
competitive rate.
</p>
<div class="prices">
<div>
<div>Storage pricing</div>
<div>€ 4 / TB / month</div>
</div>
<div>
<div>Egress pricing</div>
<div>€ 1 / TB</div>
</div>
</div>
<h2>What Nova is good at</h2>
<ul>
<li>
Serving large files to millions of people worldwide
</li>
<li>
Storing files for less money than all the competition
</li>
</ul>
<Pricing/>
</section>
</div>
@@ -107,6 +87,11 @@ let upload_widget
</section>
</div>
<header>
<h1>Subscription plans</h1>
</header>
<SubscriptionPlans/>
<header>
<h1>Get started</h1>
</header>

View File

@@ -1,146 +0,0 @@
<div class="feat_table">
<div>
<div class="cell_background" style="background-image: url('/res/img/benefit_2.webp');">
Persistence<br/>
{#if window.user.subscription.id === "patreon_2"}
You have this plan<br/>
Thank you for supporting Nova!
{:else}
<a href="https://www.patreon.com/join/nova/checkout?rid=5291482" class="button button_highlight round">
€ 8
</a>
/ month
{/if}
</div>
<div class="feat_pro features_cell round_tr">
<div><span class="text_highlight">100 GB</span> max file size</div>
<div><span class="text_highlight">Files never expire</span></div>
<div><span class="text_highlight">8 TB</span> transfer limit</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 class="cell_background" style="background-image: url('/res/img/benefit_3.webp');">
Tenacity<br/>
{#if window.user.subscription.id === "patreon_3"}
You have this plan<br/>
Thank you for supporting Nova!
{:else}
<a href="https://www.patreon.com/join/nova/checkout?rid=5291516" class="button button_highlight round">
€ 16
</a>
/ month
{/if}
</div>
<div class="feat_pro features_cell">
<div><span class="text_highlight">100 GB</span> max file size</div>
<div><span class="text_highlight">Files never expire</span></div>
<div><span class="text_highlight">16 TB</span> transfer limit</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 class="cell_background" style="background-image: url('/res/img/benefit_4.webp');">
Eternity<br/>
{#if window.user.subscription.id === "patreon_4"}
You have this plan<br/>
Thank you for supporting Nova!
{:else}
<a href="https://www.patreon.com/join/nova/checkout?rid=5291528" class="button button_highlight round">
€ 32
</a>
/ month
{/if}
</div>
<div class="feat_pro features_cell">
<div><span class="text_highlight">100 GB</span> max file size</div>
<div><span class="text_highlight">Files never expire</span></div>
<div><span class="text_highlight">32 TB</span> transfer limit</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 class="cell_background" style="background-image: url('/res/img/benefit_6.webp');">
Infinity<br/>
{#if window.user.subscription.id === "patreon_6"}
You have this plan<br/>
Thank you for supporting Nova!
{:else}
<a href="https://www.patreon.com/join/nova/checkout?rid=6573749" class="button button_highlight round">
€ 64
</a>
/ month
{/if}
</div>
<div class="feat_pro features_cell round_br">
<div><span class="text_highlight">100 GB</span> max file size</div>
<div><span class="text_highlight">Files never expire</span></div>
<div><span class="text_highlight">64 TB</span> transfer limit</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>
<style>
.feat_table {
display: flex;
flex-direction: column;
}
.feat_table > div {
display: flex;
flex-direction: row;
min-height: 8em;
}
.feat_table > div > div:first-child {
flex: 0 0 20%;
max-width: 20%;
}
.feat_table > div > div {
flex: 1 1 0;
margin: 0.2em;
padding: 0.5em;
text-align: center;
word-wrap: break-word;
hyphens: auto;
}
.feat_table > div > .feat_pro {
background-color: var(--card_color);
border: 1px solid var(--highlight_color);
}
.text_highlight {
font-weight: bold;
}
.feat_table > div > .cell_background {
flex: 0 0 33%;
min-width: 33%;
border-top-left-radius: 0.5em;
border-bottom-left-radius: 0.5em;
background-position: center;
background-size: cover;
text-align: left;
font-size: 1.2em;
color: #ffffff;
text-shadow: 1px 1px 2px #000000;
}
.feat_table > div > div.round_tr { border-top-right-radius: 0.5em; }
.feat_table > div > div.round_br { border-bottom-right-radius: 0.5em; }
.features_cell {
display: flex;
flex-wrap: wrap;
}
.features_cell > div {
flex: 1 1 50%;
min-width: 220px;
}
</style>

View File

@@ -0,0 +1,226 @@
<script lang="ts">
import Euro from "util/Euro.svelte";
import { formatDataVolume } from "util/Formatting";
type Plan = {
title: string
monthly: number
egress: number
storage: number
checkout_cadence_1?: string
checkout_cadence_6?: string
checkout_cadence_12?: string
}
const gb = 1e9
const tb = gb*1000
const euro = 1e6
const plans: Plan[] = [
{
title: "Luna",
monthly: 2*euro,
egress: 2*tb,
storage: 500*gb,
// checkout_cadence_1: "https://example.com",
checkout_cadence_6: "https://www.creem.io/test/payment/prod_4WIbZB54NgOTVSGEe8kwpA",
checkout_cadence_12: "https://www.creem.io/test/payment/prod_4A8depiWgKgJ5h5tJD2Sv7",
}, {
title: "Io",
monthly: 4*euro,
egress: 4*tb,
storage: 1*tb,
// checkout_cadence_1: "https://example.com",
checkout_cadence_6: "https://example.com",
checkout_cadence_12: "https://example.com",
}, {
title: "Callisto",
monthly: 8*euro,
egress: 8*tb,
storage: 2*tb,
checkout_cadence_1: "https://example.com",
checkout_cadence_6: "https://example.com",
checkout_cadence_12: "https://example.com",
}, {
title: "Mercury",
monthly: 16*euro,
egress: 16*tb,
storage: 4*tb,
checkout_cadence_1: "https://example.com",
checkout_cadence_6: "https://example.com",
checkout_cadence_12: "https://example.com",
}, {
title: "Titan",
monthly: 32*euro,
egress: 32*tb,
storage: 8*tb,
checkout_cadence_1: "https://example.com",
checkout_cadence_6: "https://example.com",
checkout_cadence_12: "https://example.com",
}, {
title: "Ganymede",
monthly: 64*euro,
egress: 64*tb,
storage: 16*tb,
checkout_cadence_1: "https://example.com",
checkout_cadence_6: "https://example.com",
checkout_cadence_12: "https://example.com",
}, {
title: "Mars",
monthly: 128*euro,
egress: 128*tb,
storage: 32*tb,
checkout_cadence_1: "https://example.com",
checkout_cadence_6: "https://example.com",
checkout_cadence_12: "https://example.com",
}, {
title: "Venus",
monthly: 256*euro,
egress: 256*tb,
storage: 64*tb,
checkout_cadence_1: "https://example.com",
checkout_cadence_6: "https://example.com",
checkout_cadence_12: "https://example.com",
}, {
title: "Terra",
monthly: 512*euro,
egress: 512*tb,
storage: 128*tb,
checkout_cadence_1: "https://example.com",
checkout_cadence_6: "https://example.com",
checkout_cadence_12: "https://example.com",
}, {
title: "Neptunus",
monthly: 1024*euro,
egress: 1024*tb,
storage: 256*tb,
checkout_cadence_1: "https://example.com",
checkout_cadence_6: "https://example.com",
checkout_cadence_12: "https://example.com",
}, {
title: "Uranus",
monthly: 2048*euro,
egress: 2048*tb,
storage: 512*tb,
checkout_cadence_1: "https://example.com",
checkout_cadence_6: "https://example.com",
checkout_cadence_12: "https://example.com",
}, {
title: "Saturnus",
monthly: 4096*euro,
egress: 4096*tb,
storage: 1024*tb,
checkout_cadence_1: "https://example.com",
checkout_cadence_6: "https://example.com",
checkout_cadence_12: "https://example.com",
}, {
title: "Jupiter",
monthly: 8192*euro,
egress: 8192*tb,
storage: 2048*tb,
checkout_cadence_1: "https://example.com",
checkout_cadence_6: "https://example.com",
checkout_cadence_12: "https://example.com",
}, {
title: "Sol",
monthly: 16384*euro,
egress: 16384*tb,
storage: 4096*tb,
checkout_cadence_1: "https://example.com",
checkout_cadence_6: "https://example.com",
checkout_cadence_12: "https://example.com",
}
]
</script>
<div class="horizontal_scroll">
<div class="feat_table">
{#each plans as plan (plan.title)}
<div class="plan">
<div class="title">
<span class="bold">{plan.title}</span>
<br/>
<Euro amount={plan.monthly}/> / month
</div>
<div class="features">
<div>
<span class="bold">{formatDataVolume(plan.storage, 0)}</span>
storage space
</div>
<div>
<span class="bold">{formatDataVolume(plan.egress, 0)}</span>
egress traffic per month
</div>
</div>
<div class="order">
{#if plan.checkout_cadence_1 !== undefined}
<a href="{plan.checkout_cadence_1}" class="button">
<div class="bold">Monthly</div>
<div><Euro amount={plan.monthly}/> / month</div>
</a>
{:else}
<span>Monthly plan not available</span>
{/if}
{#if plan.checkout_cadence_6 !== undefined}
<a href="{plan.checkout_cadence_6}" class="button">
<div class="bold">Bi-yearly (save 10%)</div>
<div><Euro amount={plan.monthly*6*.9}/> / 6 months</div>
</a>
{:else}
<span>Bi-yearly plan not available</span>
{/if}
{#if plan.checkout_cadence_12 !== undefined}
<a href="{plan.checkout_cadence_12}" class="button">
<div class="bold">Yearly (save 20%)</div>
<div><Euro amount={plan.monthly*12*.8}/> / year</div>
</a>
{:else}
<span>Yearly plan not available</span>
{/if}
</div>
</div>
{/each}
</div>
</div>
<style>
.horizontal_scroll {
overflow-x: scroll;
overflow-y: hidden;
width: 100%;
}
.feat_table {
display: flex;
flex-direction: row;
gap: 8px;
padding: 8px;
}
.plan {
flex: 0 0 18em;
display: flex;
width: 18em;
flex-direction: column;
border: 1px solid var(--highlight_color);
border-radius: 8px;
background-color: var(--body_color);
}
.plan > div {
flex: 1 1 0;
margin: 0.2em;
padding: 0.5em;
text-align: center;
word-wrap: break-word;
hyphens: auto;
}
.plan > .order {
flex: 1 1 auto;
display: flex;
flex-direction: column;
}
.plan > .order > .button {
flex-direction: column;
}
.bold {
font-weight: bold;
}
</style>