web/DonateOptionsCard: move all strings to i18n, mobile scaling

This commit is contained in:
wukko 2024-08-09 11:31:44 +06:00
parent e727e3a95b
commit abeacd7534
No known key found for this signature in database
GPG key ID: 3E30B3F26C7B4AA2
2 changed files with 101 additions and 45 deletions

View file

@ -3,5 +3,17 @@
"banner.subtitle": "donate to imput or share the\njoy of cobalt with a friend", "banner.subtitle": "donate to imput or share the\njoy of cobalt with a friend",
"body.motivation": "cobalt helps thousands of producers, educators, and other creative people to do what they love. we created cobalt because we believe that internet doesnt have to be scary. greed and ads have ruined the internet — we are fighting back with friendly and open tools that arent made for profit.", "body.motivation": "cobalt helps thousands of producers, educators, and other creative people to do what they love. we created cobalt because we believe that internet doesnt have to be scary. greed and ads have ruined the internet — we are fighting back with friendly and open tools that arent made for profit.",
"body.keep_going": "you can help us stay motivated & keep creating safe alternatives to unfair and abusive web tools by sharing cobalt with a friend or by donating to us." "body.keep_going": "you can help us stay motivated & keep creating safe alternatives to unfair and abusive web tools by sharing cobalt with a friend or by donating to us.",
"card.once": "one-time donation",
"card.monthly": "monthly donation",
"card.custom": "custom amount (from $2)",
"card.processor.stripe": "processed by stripe",
"card.processor.liberapay": "processed by liberapay",
"card.option.5": "cup of coffee",
"card.option.10": "full size pizza",
"card.option.15": "full lunch",
"card.option.30": "lunch for two"
} }

View file

@ -1,15 +1,17 @@
<script lang="ts"> <script lang="ts">
import IconCalendarRepeat from "@tabler/icons-svelte/IconCalendarRepeat.svelte"; import { donate } from "$lib/env";
import { t } from "$lib/i18n/translations";
import IconCoin from "@tabler/icons-svelte/IconCoin.svelte"; import IconCoin from "@tabler/icons-svelte/IconCoin.svelte";
import IconArrowRight from "@tabler/icons-svelte/IconArrowRight.svelte"; import IconCalendarRepeat from "@tabler/icons-svelte/IconCalendarRepeat.svelte";
import DonationOption from "$components/donate/DonationOption.svelte";
import IconCup from "@tabler/icons-svelte/IconCup.svelte"; import IconCup from "@tabler/icons-svelte/IconCup.svelte";
import IconPizza from "@tabler/icons-svelte/IconPizza.svelte"; import IconPizza from "@tabler/icons-svelte/IconPizza.svelte";
import IconToolsKitchen2 from "@tabler/icons-svelte/IconToolsKitchen2.svelte"; import IconToolsKitchen2 from "@tabler/icons-svelte/IconToolsKitchen2.svelte";
import DonationOption from "$components/donate/DonationOption.svelte"; import IconArrowRight from "@tabler/icons-svelte/IconArrowRight.svelte";
import { donate } from "$lib/env";
let customInput: HTMLInputElement; let customInput: HTMLInputElement;
let customInputValue: number | null; let customInputValue: number | null;
@ -30,12 +32,12 @@
url.searchParams.set("period", "monthly"); url.searchParams.set("period", "monthly");
url.searchParams.set("amount", (amount / 100).toString()); url.searchParams.set("amount", (amount / 100).toString());
window.open(url, "_blank"); window.open(url, "_blank");
} },
}; };
const send = (amount: number) => { const send = (amount: number) => {
return donationMethods[processor](amount); return donationMethods[processor](amount);
} };
const sendCustom = () => { const sendCustom = () => {
if (!customInput.reportValidity()) { if (!customInput.reportValidity()) {
@ -44,7 +46,7 @@
const amount = Number(customInputValue) * 100; const amount = Number(customInputValue) * 100;
send(amount); send(amount);
} };
</script> </script>
<div id="donation-box"> <div id="donation-box">
@ -52,47 +54,46 @@
<button <button
id="donation-type-once" id="donation-type-once"
class="donation-type" class="donation-type"
on:click={() => processor = 'stripe'} on:click={() => (processor = "stripe")}
class:selected={processor === 'stripe'} class:selected={processor === "stripe"}
> >
<div class="donation-type-icon"><IconCoin /></div> <div class="donation-type-icon"><IconCoin /></div>
<div class="donation-title">one-time donation</div> <div class="donation-title">{$t("donate.card.once")}</div>
<div class="donation-subtitle">processed by stripe</div> <div class="donation-subtitle">
{$t("donate.card.processor.stripe")}
</div>
</button> </button>
<button <button
id="donation-type-monthly" id="donation-type-monthly"
class="donation-type" class="donation-type"
on:click={() => processor = 'liberapay'} on:click={() => (processor = "liberapay")}
class:selected={processor === 'liberapay'} class:selected={processor === "liberapay"}
> >
<div class="donation-type-icon"><IconCalendarRepeat /></div> <div class="donation-type-icon"><IconCalendarRepeat /></div>
<div class="donation-title">monthly donation</div> <div class="donation-title">{$t("donate.card.monthly")}</div>
<div class="donation-subtitle">processed by liberapay</div> <div class="donation-subtitle">
{$t("donate.card.processor.liberapay")}
</div>
</button> </button>
</div> </div>
<div id="donation-options"> <div id="donation-options">
<DonationOption price={5} desc="cup of coffee" {send}> <DonationOption price={5} desc={$t("donate.card.option.5")} {send}>
<IconCup /> <IconCup />
</DonationOption> </DonationOption>
<DonationOption price={10} desc="full size pizza" {send}> <DonationOption price={10} desc={$t("donate.card.option.10")} {send}>
<IconPizza /> <IconPizza />
</DonationOption> </DonationOption>
<DonationOption price={15} desc="full lunch" {send}> <DonationOption price={15} desc={$t("donate.card.option.15")} {send}>
<IconToolsKitchen2 /> <IconToolsKitchen2 />
</DonationOption> </DonationOption>
<DonationOption price={30} desc="two lunches" {send}> <DonationOption price={30} desc={$t("donate.card.option.30")} {send}>
<IconToolsKitchen2 /> <IconToolsKitchen2 />
</DonationOption> </DonationOption>
</div> </div>
<div id="donation-custom"> <div id="donation-custom">
<div <div id="input-container" class:focused={customFocused}>
id="input-container"
class:focused={customFocused}
>
{#if customInputValue || customInput?.validity.badInput} {#if customInputValue || customInput?.validity.badInput}
<span id="input-dollar-sign"> <span id="input-dollar-sign">$</span>
$
</span>
{/if} {/if}
<input <input
id="donation-custom-input" id="donation-custom-input"
@ -101,35 +102,38 @@
max="10000" max="10000"
step=".01" step=".01"
required required
placeholder="custom amount (from $2)" placeholder={$t("donate.card.custom")}
bind:this={customInput} bind:this={customInput}
bind:value={customInputValue} bind:value={customInputValue}
on:input ={() => customFocused = true} on:input={() => (customFocused = true)}
on:focus ={() => customFocused = true} on:focus={() => (customFocused = true)}
on:blur ={() => customFocused = false} on:blur={() => (customFocused = false)}
on:keydown={(e) => e.key === 'Enter' && sendCustom()} on:keydown={(e) => e.key === "Enter" && sendCustom()}
/> />
</div> </div>
<button <button id="donation-custom-submit" on:click={sendCustom}>
id="donation-custom-submit"
on:click={sendCustom}
>
<IconArrowRight /> <IconArrowRight />
</button> </button>
</div> </div>
<div class="donation-subtitle processor-mobile">
{$t(`donate.card.processor.${processor}`)}
</div>
</div> </div>
<style> <style>
#donation-box { #donation-box {
--donation-box-main-padding: var(--donate-border-radius);
--donation-box-padding: 12px; --donation-box-padding: 12px;
--donation-box-gray-text: #9a9a9a;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: calc(100% - var(--donate-border-radius) * 2); width: calc(100% - var(--donation-box-main-padding) * 2);
max-width: 480px; max-width: 480px;
padding: var(--donate-border-radius); padding: var(--donation-box-main-padding);
border-radius: var(--donate-border-radius); border-radius: var(--donate-border-radius);
gap: calc(var(--donate-border-radius) / 2); gap: calc(var(--donation-box-main-padding) / 2);
color: white; color: white;
background: linear-gradient( background: linear-gradient(
@ -145,6 +149,7 @@
display: flex; display: flex;
flex-direction: row; flex-direction: row;
gap: var(--donation-box-padding); gap: var(--donation-box-padding);
overflow: scroll;
} }
.donation-type, .donation-type,
@ -163,6 +168,7 @@
.donation-type { .donation-type {
width: 100%; width: 100%;
overflow: hidden;
} }
:global(#donation-box button:not(:focus-visible)) { :global(#donation-box button:not(:focus-visible)) {
@ -213,6 +219,7 @@
#donation-custom { #donation-custom {
display: flex; display: flex;
gap: 6px; gap: 6px;
overflow: scroll;
} }
#input-container { #input-container {
@ -227,16 +234,21 @@
} }
#input-dollar-sign { #input-dollar-sign {
animation: grow-in .05s linear; animation: grow-in 0.05s linear;
display: block; display: block;
} }
@keyframes grow-in { @keyframes grow-in {
from { font-size: 0 } from {
to { font-size: inherit } font-size: 0;
}
to {
font-size: inherit;
}
} }
#input-container, #donation-custom-input { #input-container,
#donation-custom-input {
font-size: 13px; font-size: 13px;
} }
@ -245,6 +257,14 @@
background-color: transparent; background-color: transparent;
color: var(--white); color: var(--white);
border: none; border: none;
padding-block: 0;
padding-inline: 0;
padding: 0;
}
#donation-custom-input::placeholder {
color: var(--donation-box-gray-text);
opacity: 1;
} }
#donation-custom-input:focus-visible { #donation-custom-input:focus-visible {
@ -260,7 +280,7 @@
color: var(--white); color: var(--white);
background-color: rgba(255, 255, 255, 0.1); background-color: rgba(255, 255, 255, 0.1);
aspect-ratio: 1/1; aspect-ratio: 1/1;
padding: 8px; padding: 0px 10px;
} }
#donation-custom-submit :global(svg) { #donation-custom-submit :global(svg) {
@ -273,4 +293,28 @@
-webkit-appearance: none; -webkit-appearance: none;
margin: 0; margin: 0;
} }
.processor-mobile {
display: none;
text-align: center;
font-size: 13px;
}
@media screen and (max-width: 550px) {
#donation-box {
--donation-box-main-padding: 18px;
}
.donation-title {
font-size: 14px;
}
.donation-type .donation-subtitle {
display: none;
}
.processor-mobile {
display: block;
}
}
</style> </style>