You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

348 lines
15 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<script lang="ts">
import Button from "$lib/header/Button.svelte";
import { onMount } from "svelte";
import words from "$lib/en-lang.json";
let total = 0;
let error = null;
let lang = words["calculator"];
let types = lang["types"];
interface Commission {
type: string,
name: string,
price: number,
example: string,
questions?: any[],
answers?: any[],
}
let commissions: Commission[] = [];
let number: number;
$: number = commissions.length + 1;
async function setup() {
let prefill = true;
const urlParams = new URLSearchParams(window.location.search);
urlParams.forEach((value, key) => {
if(key == "commissions") {
try {
prefill = false;
commissions = JSON.parse(value);
commissions.forEach(value => {
types.forEach(element => {
if(element["name"] == value.type) {
value['questions'] = element["questions"];
}
});
update_price(value);
update_example(value);
});
} catch(msg) {
prefill = true;
error = "The selected preset link failed to load. It may be from an old version of the commission picker. It has been replaced with the default preset below."
}
}
});
if(prefill) {
base();
}
}
function update_example(commission: Commission) {
let lastQuestion = commission.questions[commission.questions.length - 1];
let lastAnswer = commission.answers[commission.answers.length - 1];
let example = "";
commission.example = "";
let typeFound = types.filter(value => {
return value['name'] == commission.type;
});
let type = typeFound[0];
let count = 0;
commission.questions.forEach(value => {
if(type['examples_from'] == value['name']) {
lastQuestion = commission.questions[count];
lastAnswer = commission.answers[count];
}
count++;
})
lastQuestion.options.forEach(value => {
if(value['name'] == lastAnswer['option']) {
example = value['example'];
}
});
type['examples'].forEach(value => {
if(value['name'] == example) {
commission.example = value['url'];
}
});
}
function base() {
let commission = {
"type": types[0]["name"],
"name": "Commission " + number,
"example": types[0]["example"],
"price": 10,
};
commissions.push(commission);
update_commission_type(commission);
update_example(commission);
update_price(commission);
commissions = commissions;
}
function save() {
let data = [];
commissions.forEach(value => {
data.push({
"type": value['type'],
"name": value["name"],
"answers": value["answers"]
})
});
const urlParams = new URLSearchParams(window.location.search);
urlParams.set("commissions", JSON.stringify(data));
let url = window.location.origin + window.location.pathname + "?" + urlParams.toString();
window.history.replaceState( {} , document.title, url);
}
function save_clipboard() {
save();
const urlParams = new URLSearchParams(window.location.search);
let url = window.location.origin + window.location.pathname + "?" + urlParams.toString();
navigator.clipboard.writeText(url);
}
function update_commission_type(commission: Commission) {
types.forEach(element => {
if(element["name"] == commission.type) {
commission.questions = element["questions"];
}
});
commission.answers = [];
commission.questions.forEach(value => {
commission.answers.push({'name': value.name, 'option': value.options[0]['name']});
});
update_price(commission);
update_example(commission);
}
function update_price(commission: Commission) {
commission.price = 0;
for (let index = 0; index < commission.answers.length; index++) {
const answer = commission.answers[index];
const question = commission.questions.filter(value => {
return value['name'] == answer['name'];
})[0];
question['options'].forEach(value => {
if(value['name'] == answer['option']) {
commission.price += value['price'];
}
});
}
total = 0;
commissions.forEach(value => {
total += value.price;
})
}
async function load() {
let url = await navigator.clipboard.readText();
window.history.replaceState( {} , document.title, url);
const urlParams = new URLSearchParams(window.location.search);
urlParams.forEach((value, key) => {
if(key == "commissions") {
try {
commissions = JSON.parse(value);
commissions.forEach(value => {
types.forEach(element => {
if(element["name"] == value.type) {
value['questions'] = element["questions"];
}
});
update_price(value);
update_example(value);
});
} catch(msg) {
error = "The selected preset link failed to load. It may be from an old version of the commission picker."
}
}
});
}
function createNew() {
base();
save();
}
function copy(commission: Commission) {
let newCommission = { ...commission };
newCommission.name = "Commission " + number;
commissions.push(newCommission);
commissions = commissions;
update_price(newCommission);
update_example(newCommission);
save();
}
function remove(name: string) {
commissions = commissions.filter(value => {
return value.name != name;
});
update_price(commissions[0]);
save();
}
function clear() {
commissions = [];
total = 0;
save();
}
onMount(() => {
setup();
});
</script>
<main class="container flex flex-col gap-5">
<section class="container bg-slate-800 rounded-lg shadow-lg p-3 flex flex-col w-full gap-5">
<nav class="flex flex-col lg:flex-row gap-3 justify-between justify-items-stretch items-center">
<Button href="/">⬅️ Back to home</Button>
<Button href="/commissions">🎨 Visit commissions page</Button>
<Button href="/commissions/tos">⚖️ Read Terms of Service</Button>
</nav>
</section>
<section class="container bg-slate-800 rounded-lg shadow-lg p-5 flex flex-col w-full gap-10">
<div class="flex flex-col lg:flex-row gap-5 lg:gap-1 flex-wrap -ml-2 -mr-2">
<span class="flex-grow"><Button added_classes="w-full" on:click={createNew}> Add Commission</Button></span>
<span><Button on:click={save_clipboard}>💾 Save to Clipboard</Button></span>
<span><Button on:click={load}>📋 Load from Clipboard</Button></span>
<span><Button on:click={clear}> Clear</Button></span>
</div>
<div class="flex items-center justify-between">
<div class="flex items-center gap-5">
<h3 class="hidden lg:block text-6xl">🧮</h3>
<div class="flex flex-col gap-2">
<div class="flex gap-3 items-center">
<p class="font-bold bg-green-500 py-1 px-5 rounded-lg text-lg">${total}</p>
<h4 class="text-xl font-bold">Estimated Total</h4>
</div>
<p class="italic text-gray-200 text-sm">This figure is an estimate, the final price may differ.<br/>All commissions are strictly SFW only.</p>
</div>
</div>
</div>
</section>
{#if error}
<section class="bg-slate-800 text-yellow-500 font-bold rounded-lg shadow-lg p-5 flex flex-col gap-5 text-center lg:text-left">
⚠️ {error}
</section>
{/if}
{#if commissions.length == 0}
<section class="bg-slate-800 rounded-lg shadow-lg p-5 flex flex-col lg:flex-row justify-between items-center w-full gap-5">
<div class="flex flex-col text-center lg:text-left">
<p class="text-green-500 font-bold text-xl">It's alone here :'(</p>
<p>You currently have no commissions selected. <span class="hidden lg:block">Add one --></span></p>
</div>
<span><Button on:click={createNew}> Add Commission</Button></span>
</section>
{/if}
{#if commissions.length > 10}
<section class="bg-slate-800 rounded-lg shadow-lg p-5 flex items-end w-full gap-5 text-center lg:text-left">
<p><span class="text-green-500 font-bold text-xl">Calm down Elon Musk!</span>
Your list is becoming quite long. Loading and saving long lists is not supported and may cause considerable lag or result in loss of data.</p>
</section>
{/if}
{#each [...commissions].reverse() as commission}
<section class="flex flex-col lg:flex-row gap-5">
<div class="w-full lg:w-3/5">
<div class="bg-slate-800 rounded-lg shadow-lg p-5 flex flex-col gap-5">
<div class="flex justify-between flex-col lg:flex-row gap-5 lg:gap-0">
<h3 class="text-xl font-bold flex gap-5">{commission.name}<p class="bg-green-500 py-1 text-sm px-5 rounded-lg">${commission.price}</p></h3>
<span>
<Button on:click={() => {copy(commission)}}>⤴️</Button>
<Button on:click={() => {remove(commission.name)}}>🗑️</Button>
</span>
</div>
<form class="flex flex-col gap-10" on:change={() => {update_example(commission)}}>
<div class="flex flex-col gap-1">
<label for={commission.type}>Type of commission</label>
<select class="bg-slate-600 p-2 rounded-lg hover:bg-slate-500 duration-300" bind:value={commission.type} on:change={() => {update_commission_type(commission)}}>
{#each types as question}
<option value={question.name}>{question.name}</option>
{/each}
</select>
</div>
{#each commission.questions as question, key}
{#if question.multiple}
<div class="flex flex-col gap-1">
<label for={commission.answers[key]['option']}>{question.name}</label>
{#each commission.answers.filter(value => { return value['name'] == question.name; }) as answer, key}
<div class="flex gap-1">
<select class="flex-grow bg-slate-600 p-2 rounded-lg hover:bg-slate-500 duration-300" bind:value={answer['option']} on:change={() => {update_price(commission)}}>
{#each question.options as option}
<option value={option.name}>{option.name} | ${option.price}</option>
{/each}
</select>
</div>
{/each}
<div class="flex gap-1 w-full items-stretch">
<button type="none" class="w-full bg-slate-600 p-2 rounded-lg hover:bg-slate-500 duration-300" on:click|preventDefault={() => {commission.answers.push({'name': question['name'], 'option': question.options[0]['name']}); commission.answers = commission.answers;}}>Add</button>
{#if commission.answers.filter(value => { return value['name'] == question.name; }).length > 1}
<button type="none" class="w-full bg-slate-600 p-2 rounded-lg hover:bg-slate-500 duration-300" on:click|preventDefault={() => {commission.answers.pop(); commission.answers = commission.answers; }}>Remove</button>
{/if}
</div>
</div>
{:else}
<div class="flex flex-col gap-1">
<label for={commission.answers[key]['option']}>{question.name}</label>
<select class="bg-slate-600 p-2 rounded-lg hover:bg-slate-500 duration-300" bind:value={commission.answers[key]['option']} on:change={() => {update_price(commission)}}>
{#each question.options as option}
<option value={option.name}>{option.name} | ${option.price}</option>
{/each}
</select>
</div>
{/if}
{/each}
</form>
</div>
</div>
<div class="w-full lg:w-2/5">
{#if commission.example != ""}
<div class="relative bg-black bg-opacity-50 rounded-xl shadow-xl">
<p class="xl:block hidden absolute top-0 right-0 text-right -rotate-12 font-bold text-4xl -mb-40 -mr-40">
🠔 Example!
</p>
<img src={commission.example} alt="example" class="rounded-xl shadow-xl w-full" />
</div>
{:else}
<div class="relative w-full aspect-square bg-black bg-opacity-50 rounded-xl shadow-xl">
<p class="w-full h-full absolute inset-0 flex items-center justify-center text-center opacity-50 -rotate-45 font-bold text-6xl">
NO EXAMPLE AVAILABLE
</p>
</div>
{/if}
</div>
</section>
{/each}
</main>