Empire Modification, Partial Code for Empire Creation

This commit is contained in:
Neshura 2023-09-09 02:39:37 +02:00
parent 00579db8ce
commit 9fdc93be9e
Signed by: Neshura
GPG key ID: B6983AAA6B9A7A6C
12 changed files with 757 additions and 306 deletions

View file

@ -23,7 +23,6 @@
width: var(--size); width: var(--size);
height: var(--size); height: var(--size);
box-sizing: border-box; box-sizing: border-box;
position: relative;
border: 3px solid transparent; border: 3px solid transparent;
border-top-color: var(--color-active-1); border-top-color: var(--color-active-1);
border-radius: 50%; border-radius: 50%;

View file

@ -0,0 +1,75 @@
<script lang="ts">
import type { Circle2Types } from '../types/spinner';
export let size: Circle2Types['size'] = '60';
export let unit: Circle2Types['unit'] = 'px';
export let pause: Circle2Types['pause'] = false;
export let colorOuter: Circle2Types['colorOuter'] = '#FF3E00';
export let colorCenter: Circle2Types['colorCenter'] = '#40B3FF';
export let colorInner: Circle2Types['colorInner'] = '#676778';
export let durationMultiplier: Circle2Types['durationMultiplier'] = 1;
export let durationOuter: Circle2Types['durationOuter'] = `${durationMultiplier * 2}s`;
export let durationInner: Circle2Types['durationInner'] = `${durationMultiplier * 1.5}s`;
export let durationCenter: Circle2Types['durationCenter'] = `${durationMultiplier * 3}s`;
</script>
<div
class="circle"
class:pause-animation={pause}
style="--size: {size}{unit}; --colorInner: {colorInner}; --colorCenter: {colorCenter}; --colorOuter: {colorOuter}; --durationInner: {durationInner}; --durationCenter: {durationCenter}; --durationOuter: {durationOuter};"
/>
<style>
.circle {
width: var(--size);
height: var(--size);
box-sizing: border-box;
position: relative;
border: 3px solid transparent;
border-top-color: var(--color-active-1);
border-radius: 50%;
animation: circleSpin var(--durationOuter) linear infinite;
position: relative;
top: 50%;
margin: auto;
}
.circle::before,
.circle::after {
content: '';
box-sizing: border-box;
position: absolute;
border: 3px solid transparent;
border-radius: 50%;
}
.circle::after {
border-top-color: var(--color-active-2);
top: 9px;
left: 9px;
right: 9px;
bottom: 9px;
animation: circleSpin var(--durationInner) linear infinite;
}
.circle::before {
border-top-color: var(--color-text);
top: 3px;
left: 3px;
right: 3px;
bottom: 3px;
animation: circleSpin var(--durationCenter) linear infinite;
}
.pause-animation,
.pause-animation::after,
.pause-animation::before {
animation-play-state: paused;
}
@keyframes circleSpin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>

View file

@ -1 +1,2 @@
export const apiBaseUrl = 'https://wip.chellaris.net/api'; export const apiBaseUrl = 'https://wip.chellaris.net/api';
export const MACHINE_GROUP_ID = 12;

View file

@ -1,7 +1,9 @@
import { writable, type Writable } from "svelte/store"; import { writable, type Writable } from "svelte/store";
import type { ChellarisInfo } from '../types/chellaris'; import { createBlankChellarisData, type ChellarisData, type ChellarisInfo } from '../types/chellaris';
import { createChellarisInfo } from '../types/chellaris'; import { createChellarisInfo } from '../types/chellaris';
const ChellarisDataStore: Writable<ChellarisInfo> = writable(createChellarisInfo()); const ChellarisDataStore: Writable<ChellarisInfo> = writable(createChellarisInfo());
export default ChellarisDataStore; export default ChellarisDataStore;
export const LeanChellarisDataStore: Writable<ChellarisData> = writable(createBlankChellarisData());

View file

@ -1,9 +1,19 @@
import type { EmpireEthic, Ethic, Species } from './stellaris'; import type { EmpireEthic, Ethic, Phenotype } from './stellaris';
export type ChellarisInfo = { export type ChellarisInfo = {
games: { [key: number]: ChellarisGame }, // Key is Game Id games: { [key: number]: ChellarisGame }, // Key is Game Id
ethics: { [key: number]: Ethic }, // Key is Ethic Id ethics: { [key: number]: Ethic }, // Key is Ethic Id
species: { [key: number]: Species }, // Key is Species Group Id phenotypes: { [key: number]: Phenotype }, // Key is Species Group Id
}
export const createChellarisInfo = (): ChellarisInfo => {
const newChellarisInfo = {
games: {},
ethics: {},
phenotypes: {},
};
return newChellarisInfo;
} }
export type ChellarisGame = { export type ChellarisGame = {
@ -13,39 +23,6 @@ export type ChellarisGame = {
empires: { [key: number]: ChellarisEmpire }, // Key is Empire Id empires: { [key: number]: ChellarisEmpire }, // Key is Empire Id
} }
export type ChellarisGameGroup = {
id: number,
name: string,
}
export type ChellarisEmpire = {
id: number,
group: number,
game: number,
name: string,
discord_user?: string,
gestalt: boolean,
machine: boolean,
portrait_id: number, // TODO replace with Enum?
portrait_group_id: number, // TODO replace with Enum?
ethics: { [key: number]: EmpireEthic },
}
export type ChellarisGameInfo = {
id: number,
name: string
}
export const createChellarisInfo = (): ChellarisInfo => {
const newChellarisInfo = {
games: [],
ethics: [],
species: [],
};
return newChellarisInfo;
}
export const createChellarisGame = (): ChellarisGame => { export const createChellarisGame = (): ChellarisGame => {
const newChellarisGame = { const newChellarisGame = {
id: 1, id: 1,
@ -57,6 +34,11 @@ export const createChellarisGame = (): ChellarisGame => {
return newChellarisGame; return newChellarisGame;
} }
export type ChellarisGameGroup = {
id: number,
name: string,
}
export const createChellarisGameGroup = (): ChellarisGameGroup => { export const createChellarisGameGroup = (): ChellarisGameGroup => {
const newChellarisGameGroup = { const newChellarisGameGroup = {
id: 1, id: 1,
@ -66,6 +48,19 @@ export const createChellarisGameGroup = (): ChellarisGameGroup => {
return newChellarisGameGroup; return newChellarisGameGroup;
} }
export type ChellarisEmpire = {
id: number,
group: number,
game: number,
name: string,
discord_user?: string,
gestalt: boolean,
machine: boolean,
portrait_id: number, // TODO replace with Enum?
portrait_group_id: number, // TODO replace with Enum?
ethics: { [key: number]: EmpireEthic },
}
export const createChellarisEmpire = ( export const createChellarisEmpire = (
{ {
id, name, discord_user, group_id, game_id, gestalt, portrait_id, portrait_group_id id, name, discord_user, group_id, game_id, gestalt, portrait_id, portrait_group_id
@ -93,4 +88,42 @@ export const createChellarisEmpire = (
}; };
return newChellarisEmpire; return newChellarisEmpire;
} }
export const createBlankEmpire = (
game: number
) => {
const newChellarisEmpire: ChellarisEmpire = {
id: 0,
group: 0,
game: game,
gestalt: false,
machine: false,
portrait_id: 0,
portrait_group_id: 0,
ethics: [],
discord_user: undefined,
name: ""
};
return newChellarisEmpire;
}
export type ChellarisGameInfo = {
id: number,
name: string
}
export type ChellarisData = {
ethics: { [key: number]: Ethic },
phenotypes: { [key: number]: Phenotype }
}
export const createBlankChellarisData = () => {
const newData: ChellarisData = {
ethics: {},
phenotypes: {}
};
return newData;
}

View file

@ -67,21 +67,21 @@ export class EthicsDataLegacy {
export type Ethic = { export type Ethic = {
id: number, id: number,
display: string, display: string,
machine: boolean, gestalt: boolean,
fanatic?: boolean, fanatic?: boolean,
} }
export type EmpireEthic = { export type EmpireEthic = {
ethic_id: number, ethic_id: number,
display: string, display: string,
machine: boolean, gestalt: boolean,
fanatic?: boolean, fanatic?: boolean,
} }
export type Species = { export type Phenotype = {
id: number, id: number,
display: string, display: string,
portraits: { [key: number]: Portrait }, // Key is Portrait Id species: { [key: number]: Portrait }, // Key is Portrait Id
} }
export type Portrait = { export type Portrait = {

View file

@ -1,6 +1,22 @@
<script> <script>
import { apiBaseUrl } from '$lib/components/consts';
import { LeanChellarisDataStore } from '$lib/stores/ChellarisData';
import Header from './Header.svelte'; import Header from './Header.svelte';
import './styles.css'; import './styles.css';
$: {
fetch(apiBaseUrl + '/v3/ethics').then((res) => {
res.json().then((data) => {
$LeanChellarisDataStore.ethics = data.ethics;
})
});
fetch(apiBaseUrl + '/v3/phenotypes').then((res) => {
res.json().then((data) => {
$LeanChellarisDataStore.phenotypes = data.phenotypes;
})
});
}
</script> </script>
<div class="app"> <div class="app">

View file

@ -0,0 +1,15 @@
import { apiBaseUrl } from "$lib/components/consts";
import { redirect } from "@sveltejs/kit";
export async function load({ cookies }) {
const auth = await (await fetch(apiBaseUrl + "/v3/auth", {
headers: {
'Content-Type': 'application/json',
'x-api-key': cookies.get("authToken") || ""
}
})).json();
if (!auth.admin && !auth.moderator) {
throw redirect(303, '/401');
}
}

View file

@ -1,16 +1,22 @@
<script lang="ts"> <script lang="ts">
import { browser } from '$app/environment'; import { browser } from '$app/environment';
import LoadingSpinnerLocal from '$lib/components/LoadingSpinnerLocal.svelte';
import { apiBaseUrl } from '$lib/components/consts'; import { apiBaseUrl } from '$lib/components/consts';
import AuthTokenStore from '$lib/stores/AuthTokenStore'; import AuthTokenStore from '$lib/stores/AuthTokenStore';
import AdminSelectedEmpireStore from '$lib/stores/admin-page/EmpireStore'; import AdminSelectedEmpireStore from '$lib/stores/admin-page/EmpireStore';
import AdminSelectedGameStore from '$lib/stores/admin-page/GameStore'; import AdminSelectedGameStore from '$lib/stores/admin-page/GameStore';
import AdminSelectedGroupStore from '$lib/stores/admin-page/GroupStore'; import AdminSelectedGroupStore from '$lib/stores/admin-page/GroupStore';
import type { ChellarisEmpire, ChellarisGame, ChellarisGameGroup } from '$lib/types/chellaris'; import { createBlankEmpire, type ChellarisEmpire, type ChellarisGame, type ChellarisGameGroup } from '$lib/types/chellaris';
import EmpireDetails from './EmpireDetails.svelte'; import EmpireDetails from './EmpireDetails.svelte';
import List from './List.svelte'; import List from './List.svelte';
function delay(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
export let data; export let data;
let auth = $AuthTokenStore;
// Game Variables // Game Variables
let newGameForm = false; let newGameForm = false;
@ -25,55 +31,62 @@
let newGroupForm = false; let newGroupForm = false;
let addingNewGroup = false; let addingNewGroup = false;
let newGroupName = ''; let newGroupName = '';
let groupList: {[key: number]: ChellarisGameGroup }; let groupList: { [key: number]: ChellarisGameGroup };
$: groupList = {}; $: groupList = {};
// Empire Variables // Empire Variables
let empireList: { [key: number]: ChellarisEmpire } = {}; let empireList: { [key: number]: ChellarisEmpire } = {};
let empireData: ChellarisEmpire; let empireData: ChellarisEmpire;
let addingNewEmpire = false;
$: console.log("adding:", addingNewEmpire);
let loadingEmpireData = true; let loadingEmpireData = true;
const updateGameData = () => { const updateGameData = () => {
fetch(apiBaseUrl + '/v3/game?game_id=' + $AdminSelectedGameStore, { if (auth != '') {
headers: { fetch(apiBaseUrl + '/v3/game?game_id=' + $AdminSelectedGameStore, {
'Content-Type': 'application/json', headers: {
'x-api-key': $AuthTokenStore 'Content-Type': 'application/json',
} 'x-api-key': auth
}).then((res) => { }
res.json().then((data: {groups: { [key: number]: ChellarisGameGroup}, empires: { [key: number]: ChellarisEmpire}}) => { }).then((res) => {
groupList = data.groups; res.json().then((data: { groups: { [key: number]: ChellarisGameGroup }; empires: { [key: number]: ChellarisEmpire } }) => {
empireList = {}; groupList = data.groups;
Object.values(data.empires).forEach((empire: ChellarisEmpire) => { empireList = {};
if ($AdminSelectedGroupStore[$AdminSelectedGameStore] === undefined) { Object.values(data.empires).forEach((empire: ChellarisEmpire) => {
$AdminSelectedGroupStore[$AdminSelectedGameStore] = {}; if ($AdminSelectedGroupStore[$AdminSelectedGameStore] === undefined) {
} $AdminSelectedGroupStore[$AdminSelectedGameStore] = {};
if ($AdminSelectedGroupStore[$AdminSelectedGameStore][empire.group]) { }
empireList[empire.id] = empire; if ($AdminSelectedGroupStore[$AdminSelectedGameStore][empire.group]) {
} empireList[empire.id] = empire;
}); }
});
loadingGameData = false; delay(200).then(() => (loadingGameData = false));
loadEmpireData(); delay(200).then(() => (loaded = true));
loadEmpireData();
});
}); });
}); }
}; };
const loadEmpireData = () => { const loadEmpireData = () => {
fetch(apiBaseUrl + '/v3/empire?game_id=' + $AdminSelectedGameStore + '&empire_id=' + $AdminSelectedEmpireStore[$AdminSelectedGameStore], { fetch(apiBaseUrl + '/v3/empire?game_id=' + $AdminSelectedGameStore + '&empire_id=' + $AdminSelectedEmpireStore[$AdminSelectedGameStore], {
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'x-api-key': $AuthTokenStore 'x-api-key': auth
} }
}).then((res) => { }).then((res) => {
res.json().then((data: ChellarisEmpire) => { res.json().then((data: ChellarisEmpire) => {
empireData = data; empireData = data;
loadingEmpireData = false; delay(200).then(() => {
loadingEmpireData = false;
addingNewEmpire = false;
});
}); });
}); });
} };
$: { $: {
if (typeof localStorage !== 'undefined') { if (typeof localStorage !== 'undefined') {
@ -120,7 +133,7 @@
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'x-api-key': $AuthTokenStore 'x-api-key': auth
}, },
body: JSON.stringify(newGame) body: JSON.stringify(newGame)
}).then((response) => { }).then((response) => {
@ -136,7 +149,7 @@
method: 'DELETE', method: 'DELETE',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'x-api-key': $AuthTokenStore 'x-api-key': auth
} }
}).then(() => { }).then(() => {
getGameList(); getGameList();
@ -171,7 +184,7 @@
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'x-api-key': $AuthTokenStore 'x-api-key': auth
}, },
body: JSON.stringify(newGroup) body: JSON.stringify(newGroup)
}).then((response) => { }).then((response) => {
@ -187,7 +200,7 @@
method: 'DELETE', method: 'DELETE',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'x-api-key': $AuthTokenStore 'x-api-key': auth
} }
}).then(() => { }).then(() => {
updateGameData(); updateGameData();
@ -203,13 +216,21 @@
const setActiveEmpire = (empireId: number) => { const setActiveEmpire = (empireId: number) => {
loadingEmpireData = true; loadingEmpireData = true;
loadEmpireData();
$AdminSelectedEmpireStore[$AdminSelectedGameStore] = empireId; $AdminSelectedEmpireStore[$AdminSelectedGameStore] = empireId;
loadEmpireData();
}; };
const addEmpire = () => { const addEmpire = () => {
$AdminSelectedEmpireStore[$AdminSelectedGameStore] = list2.length; addingNewEmpire = true;
list2.push(list2.length); $AdminSelectedEmpireStore[$AdminSelectedGameStore] = 1000;
empireData = createBlankEmpire($AdminSelectedGameStore);
/* $AdminSelectedEmpireStore[$AdminSelectedGameStore] = list2.length;
list2.push(list2.length); */
};
const finishAddNewEmpire = (event: { detail: { new_id: number; }; }) => {
$AdminSelectedEmpireStore[$AdminSelectedGameStore] = event.detail.new_id;
updateGameData();
}; };
const deleteEmpire = (empire: ChellarisEmpire) => { const deleteEmpire = (empire: ChellarisEmpire) => {
@ -217,7 +238,7 @@
method: 'DELETE', method: 'DELETE',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'x-api-key': $AuthTokenStore 'x-api-key': auth
} }
}).then(() => { }).then(() => {
updateGameData(); updateGameData();
@ -229,10 +250,7 @@
empireList = empireList; empireList = empireList;
}; };
let list2 = new Array(); let loaded = false;
for (let i = 0; i < 100; i++) {
list2.push(i);
}
</script> </script>
<svelte:head> <svelte:head>
@ -241,129 +259,163 @@
</svelte:head> </svelte:head>
<div class="frame"> <div class="frame">
<List area="games" listTitle="Games"> {#if loaded}
{#each Object.values(gameList) as game} <List area="games" listTitle="Games">
<button class="list-card" class:active={game.id == $AdminSelectedGameStore ? 'active' : ''} on:click={() => setActiveGame(game.id)}> {#each Object.values(gameList) as game}
<div class="card-content">{game.name}</div> <button class="list-card" class:active={game.id == $AdminSelectedGameStore ? 'active' : ''} on:click={() => setActiveGame(game.id)}>
<button class="delete-box" on:click={() => deleteGame(game.id)}> <div class="card-content">{game.name}</div>
<svg class="checkmark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <button class="delete-box" on:click={() => deleteGame(game.id)}>
<path fill="none" d="M0 0 24 24 M24 0 0 24" /> <svg class="checkmark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
</svg> <path fill="none" d="M0 0 24 24 M24 0 0 24" />
</button> </svg>
</button> </button>
{/each}
{#if newGameForm}
<div class="list-card active">
<form on:submit={addGame}>
<input bind:value={newGameName} />
<input type="submit" value="Add Game" />
</form>
</div>
{:else if addingNewGame}
<div class="list-card loading">
<div class="card-content">{newGameName}</div>
</div>
{:else}
<button
class="list-card"
on:click={() => {
newGameForm = true;
}}
>
<div class="card-content button">+</div>
</button>
{/if}
</List>
<List area="groups" listTitle="Groups">
{#if loadingGameData}
<div>Loading</div>
{:else}
{#each Object.values(groupList) as group}
<button
class="list-card"
class:active={$AdminSelectedGroupStore[$AdminSelectedGameStore] ? $AdminSelectedGroupStore[$AdminSelectedGameStore][group.id] ? 'active' : '' : ''}
on:click={() => toggleActiveGroup(group.id)}
>
<div class="card-content">{group.name}</div>
{#if group.name !== 'N/A'}
<button class="delete-box" on:click={() => deleteGroup(group.id)}>
<svg class="checkmark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path fill="none" d="M0 0 24 24 M24 0 0 24" />
</svg>
</button>
{/if}
</button> </button>
{/each} {/each}
{#if newGroupForm} {#if newGameForm}
<div class="list-card active"> <div class="list-card active">
<form on:submit={addGroup}> <form on:submit={addGame}>
<input bind:value={newGroupName} /> <input bind:value={newGameName} />
<input type="submit" value="Add Group" /> <input type="submit" value="Add Game" />
</form> </form>
</div> </div>
{:else if addingNewGroup} {:else if addingNewGame}
<div class="list-card loading"> <div class="list-card loading">
<div class="card-content">{newGroupName}</div> <div class="card-content">{newGameName}</div>
</div> </div>
{:else} {:else}
<button <button
class="list-card" class="list-card"
on:click={() => { on:click={() => {
newGroupForm = true; newGameForm = true;
}} }}
> >
<div class="card-content button">+</div> <div class="card-content button">+</div>
</button> </button>
{/if} {/if}
{/if} </List>
</List> <List area="groups" listTitle="Groups">
<List area="empires" listTitle="Empires"> {#if loadingGameData}
<div class="empires-table"> <LoadingSpinnerLocal />
<div class="table-headers"> {:else}
<div class="table-header">Empire Name</div> {#each Object.values(groupList) as group}
<div class="table-header">Discord User</div> <button
</div> class="list-card"
<div class="table-content"> class:active={$AdminSelectedGroupStore[$AdminSelectedGameStore]
{#if loadingGameData} ? $AdminSelectedGroupStore[$AdminSelectedGameStore][group.id]
<button class="list-card"> ? 'active'
<div class="card-content">Loading Empires</div> : ''
</button> : ''}
{:else} on:click={() => toggleActiveGroup(group.id)}
{#each Object.values(empireList) as empire} >
<button <div class="card-content">{group.name}</div>
class="list-card" {#if group.name !== 'N/A'}
class:active={empire.id == $AdminSelectedEmpireStore[$AdminSelectedGameStore] ? 'active' : ''} <button class="delete-box" on:click={() => deleteGroup(group.id)}>
on:click={() => setActiveEmpire(empire.id)}
>
<div class="card-content" class:active={empire.id == $AdminSelectedEmpireStore[$AdminSelectedGameStore] ? 'active' : ''}>{empire.name}</div>
<div class="card-content" class:active={empire.id == $AdminSelectedEmpireStore[$AdminSelectedGameStore] ? 'active' : ''}>
{empire.discord_user}
</div>
<button class="delete-box" on:click={() => deleteEmpire(empire)}>
<svg class="checkmark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <svg class="checkmark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path fill="none" d="M0 0 24 24 M24 0 0 24" /> <path fill="none" d="M0 0 24 24 M24 0 0 24" />
</svg> </svg>
</button> </button>
</button> {/if}
{:else} </button>
<div class="list-card"> {/each}
<div class="card-content">No Empires Present</div> {#if newGroupForm}
<div class="list-card active">
<form on:submit={addGroup}>
<input bind:value={newGroupName} />
<input type="submit" value="Add Group" />
</form>
</div> </div>
{/each} {:else if addingNewGroup}
<button class="list-card" on:click={addEmpire}> <div class="list-card loading">
<div class="card-content">{newGroupName}</div>
</div>
{:else}
<button
class="list-card"
on:click={() => {
newGroupForm = true;
}}
>
<div class="card-content button">+</div> <div class="card-content button">+</div>
</button> </button>
{/if} {/if}
{/if}
</List>
<List area="empires" listTitle="Empires">
<div class="empires-table">
<div class="table-headers">
<div class="table-header">Empire Name</div>
<div class="table-header">Discord User</div>
</div>
<div class="table-content">
{#if loadingGameData}
<LoadingSpinnerLocal />
{:else}
{#each Object.values(empireList) as empire}
<button
class="list-card"
class:active={empire.id == $AdminSelectedEmpireStore[$AdminSelectedGameStore] ? 'active' : ''}
on:click={() => setActiveEmpire(empire.id)}
>
<div class="card-content" class:active={empire.id == $AdminSelectedEmpireStore[$AdminSelectedGameStore] ? 'active' : ''}>{empire.name}</div>
<div class="card-content" class:active={empire.id == $AdminSelectedEmpireStore[$AdminSelectedGameStore] ? 'active' : ''}>
{empire.discord_user || "N/A"}
</div>
<button class="delete-box" on:click={() => deleteEmpire(empire)}>
<svg class="checkmark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path fill="none" d="M0 0 24 24 M24 0 0 24" />
</svg>
</button>
</button>
{:else}
<div class="list-card">
<div class="card-content">No Empires Present</div>
</div>
{/each}
{#if addingNewEmpire}
<div class="list-card loading">
<div class="card-content active">{empireData.name}</div>
<div class="card-content active">
{empireData.discord_user || "N/A"}
</div>
</div>
{:else}
<button class="list-card" on:click={addEmpire}>
<div class="card-content button">+</div>
</button>
{/if}
{/if}
</div>
</div> </div>
</div> </List>
</List> <List area="details" listTitle="Empire Details">
<List area="details" listTitle="Empire Details"> {#if loadingEmpireData || loadingGameData}
{#if loadingEmpireData} <LoadingSpinnerLocal />
Loading... {:else if addingNewEmpire || typeof empireData.group !== 'undefined'}
{:else} <EmpireDetails bind:empire={empireData} groups={groupList} {auth} bind:newEmpire={addingNewEmpire} on:updated={updateGameData} on:created={finishAddNewEmpire}/>
<EmpireDetails empire={empireData} /> {/if}
{/if} </List>
</List> {:else}
<List area="games" listTitle="Games">
<LoadingSpinnerLocal />
</List>
<List area="groups" listTitle="Groups">
<LoadingSpinnerLocal />
</List>
<List area="empires" listTitle="Empires">
<div class="empires-table">
<div class="table-headers">
<div class="table-header">Empire Name</div>
<div class="table-header">Discord User</div>
</div>
<div class="table-content">
<LoadingSpinnerLocal />
</div>
</div>
</List>
<List area="details" listTitle="Empire Details">
<LoadingSpinnerLocal />
</List>
{/if}
</div> </div>
<style> <style>
@ -395,6 +447,7 @@
.list-card { .list-card {
display: flex; display: flex;
margin: 0.5rem; margin: 0.5rem;
padding: 1px;
border: 1px solid darkcyan; border: 1px solid darkcyan;
cursor: pointer; cursor: pointer;
background-color: var(--color-bg); background-color: var(--color-bg);
@ -522,5 +575,6 @@
.card-content:first-child { .card-content:first-child {
border-left: none; border-left: none;
min-width: 50%;
} }
</style> </style>

View file

@ -1,29 +1,10 @@
import { apiBaseUrl } from "$lib/components/consts"; import { apiBaseUrl } from "$lib/components/consts";
import AdminSelectedEmpireStore from "$lib/stores/admin-page/EmpireStore"; import AdminSelectedEmpireStore from "$lib/stores/admin-page/EmpireStore";
import AdminSelectedGameStore from "$lib/stores/admin-page/GameStore"; import AdminSelectedGameStore from "$lib/stores/admin-page/GameStore";
import AuthTokenStore from "$lib/stores/AuthTokenStore";
import type { ChellarisGameInfo } from "$lib/types/chellaris"; import type { ChellarisGameInfo } from "$lib/types/chellaris";
import { redirect } from "@sveltejs/kit";
import AdminSelectedGroupStore from '../../lib/stores/admin-page/GroupStore'; import AdminSelectedGroupStore from '../../lib/stores/admin-page/GroupStore';
export async function load ({ fetch }) { export async function load ({ fetch }) {
let authToken = "";
AuthTokenStore.subscribe(token => {
authToken = token;
});
const auth = await (await fetch(apiBaseUrl + "/v3/auth",{
headers: {
'Content-Type': 'application/json',
'x-api-key': authToken
}
})).json();
if (!auth.admin && !auth.moderator) {
throw redirect(303, '/401');
}
const gameList: { [key: number]: ChellarisGameInfo } = await (await fetch(apiBaseUrl + "/v3/games")).json(); const gameList: { [key: number]: ChellarisGameInfo } = await (await fetch(apiBaseUrl + "/v3/games")).json();
let store: string | null; let store: string | null;
@ -56,5 +37,7 @@ export async function load ({ fetch }) {
} }
} }
return { games: gameList }; return {
games: gameList
};
} }

View file

@ -1,49 +1,329 @@
<script lang="ts"> <script lang="ts">
import type { ChellarisEmpire } from '$lib/types/chellaris'; import DropDown from '$lib/components/DropDown.svelte';
import DropDownElement from '$lib/components/DropDownElement.svelte';
import { MACHINE_GROUP_ID, apiBaseUrl } from '$lib/components/consts';
import { LeanChellarisDataStore } from '$lib/stores/ChellarisData';
import type { ChellarisEmpire, ChellarisGameGroup } from '$lib/types/chellaris';
import { createEventDispatcher } from 'svelte';
export let empire: ChellarisEmpire; export let empire: ChellarisEmpire;
export let groups: { [key: number]: ChellarisGameGroup } = {};
export let newEmpire: boolean = false;
export let auth: string;
let newEmpirePrepared = false;
const dispatch = createEventDispatcher();
$: {
console.log($LeanChellarisDataStore);
console.log(empire);
}
let oldEmpireData = { ...empire };
const updateEmpire = () => {
// Generate Diff:
let diffEmpire: any = {};
if (oldEmpireData.name != empire.name) {
diffEmpire.empire_name = empire.name;
}
if (oldEmpireData.discord_user != empire.discord_user) {
diffEmpire.discord_user = empire.discord_user;
}
if (oldEmpireData.group != empire.group) {
diffEmpire.group_id = empire.group;
}
if (oldEmpireData.gestalt != empire.gestalt) {
diffEmpire.gestalt = empire.gestalt;
}
if (JSON.stringify(oldEmpireData.ethics) != JSON.stringify(empire.ethics)) {
console.log('A', oldEmpireData.ethics);
console.log('B', empire.ethics);
diffEmpire.ethics = empire.ethics;
}
if (oldEmpireData.portrait_id != empire.portrait_id) {
diffEmpire.portrait_id = empire.portrait_id;
}
if (oldEmpireData.portrait_group_id != empire.portrait_group_id) {
diffEmpire.portrait_group_id = empire.portrait_group_id;
}
if (Object.values(diffEmpire).length != 0) {
diffEmpire.empire_id = empire.id;
diffEmpire.game_id = empire.game;
fetch(apiBaseUrl + '/v3/empire', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'x-api-key': auth
},
body: JSON.stringify(diffEmpire)
}).then((response) => {
response.json().then((result) => {
empire = result;
oldEmpireData = { ...empire };
dispatch('updated');
});
});
}
};
const createEmpire = () => {
// Generate Diff:
/* let diffEmpire: any = {};
if (oldEmpireData.name != empire.name) {
diffEmpire.empire_name = empire.name;
}
if (oldEmpireData.discord_user != empire.discord_user) {
diffEmpire.discord_user = empire.discord_user;
}
if (oldEmpireData.group != empire.group) {
diffEmpire.group_id = empire.group;
}
if (oldEmpireData.gestalt != empire.gestalt) {
diffEmpire.gestalt = empire.gestalt;
}
if (JSON.stringify(oldEmpireData.ethics) != JSON.stringify(empire.ethics)) {
console.log('A', oldEmpireData.ethics);
console.log('B', empire.ethics);
diffEmpire.ethics = empire.ethics;
}
if (oldEmpireData.portrait_id != empire.portrait_id) {
diffEmpire.portrait_id = empire.portrait_id;
}
if (oldEmpireData.portrait_group_id != empire.portrait_group_id) {
diffEmpire.portrait_group_id = empire.portrait_group_id;
}
if (Object.values(diffEmpire).length != 0) {
diffEmpire.empire_id = empire.id;
diffEmpire.game_id = empire.game;
fetch(apiBaseUrl + '/v3/empire', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'x-api-key': auth
},
body: JSON.stringify(diffEmpire)
}).then((response) => {
response.json().then((result) => {
empire = result;
oldEmpireData = { ...empire };
dispatch('updated');
});
});
} */
dispatch('created', {
new_id: 32
});
};
// Dropdown UUID to make the Click Event work properly
const groupDropdownId = crypto.randomUUID();
const speciesDropdownId = crypto.randomUUID();
const phenotypeDropdownId = crypto.randomUUID();
const ethicsDropdownId = crypto.randomUUID();
$: {
if (empire.portrait_group_id == MACHINE_GROUP_ID) {
empire.machine = true;
} else {
empire.machine = false;
}
}
$: {
if (newEmpire && !newEmpirePrepared) {
empire.group = Object.values(groups)[0].id;
newEmpirePrepared = true;
}
if (!newEmpire) {
newEmpirePrepared = false;
}
}
</script> </script>
<div> {#if newEmpire && newEmpirePrepared}
{#if empire} <div>
<div> ID: {empire.id}
ID: {empire.id} </div>
</div> <div>
<div> Game ID: {empire.game}
Group ID: {empire.group} </div>
</div> <DropDown dropdownTitle={'Group*: ' + groups[empire.group].name} dropdownId={groupDropdownId}>
<div> {#each Object.values(groups) as group}
Game ID: {empire.game} {#if group}
</div> <DropDownElement dropdownId={groupDropdownId}>
<div> <input id={'checkbox' + group.id} data-dropdown={groupDropdownId} type="radio" bind:group={empire.group} value={group.id} />
Gestalt: {empire.gestalt} <label for={'checkbox' + group.id} data-dropdown={groupDropdownId}>{group.name}</label>
</div> </DropDownElement>
<div>
Machine: {empire.machine}
</div>
<div>
Portrait ID: {empire.portrait_id}
</div>
<div>
Portrait Group ID: {empire.portrait_group_id}
</div>
<div>
Name: {empire.name}
</div>
<div>
Discord User: {empire.discord_user}
</div>
<div>
{#if empire.ethics}
{#each Object.values(empire.ethics) as ethic}
{ethic.ethic_id},
{/each}
{/if} {/if}
</div> {/each}
{:else} </DropDown>
No Empire Selected <br />
{/if} <label for="check-gestalt">Gestalt:</label>
</div> <input id="check-gestalt" type="checkbox" bind:checked={empire.gestalt} />
<br />
<label for="check-gestalt">Machine:</label>
<input id="check-gestalt" type="checkbox" bind:checked={empire.machine} />
<br />
<!--TODO: Add Scrolling to Dropdown Element-->
<DropDown
dropdownTitle={'Species*: ' + $LeanChellarisDataStore.phenotypes[empire.portrait_group_id].species[empire.portrait_id].id}
dropdownId={speciesDropdownId}
>
{#each Object.values($LeanChellarisDataStore.phenotypes[empire.portrait_group_id].species) as species}
{#if species}
<DropDownElement dropdownId={speciesDropdownId}>
<input id={'checkbox' + species.id} data-dropdown={speciesDropdownId} type="radio" bind:group={empire.portrait_id} value={species.id} />
<label for={'checkbox' + species.id} data-dropdown={speciesDropdownId}>{species.id}</label>
</DropDownElement>
{/if}
{/each}
</DropDown>
<br />
<!--TODO: Add Scrolling to Dropdown Element-->
<DropDown dropdownTitle={'Phenotype*: ' + $LeanChellarisDataStore.phenotypes[empire.portrait_group_id].display} dropdownId={phenotypeDropdownId}>
{#each Object.values(Object.values($LeanChellarisDataStore.phenotypes)) as phenotype}
{#if phenotype}
<DropDownElement dropdownId={phenotypeDropdownId}>
<input id={'checkbox' + phenotype.id} data-dropdown={phenotypeDropdownId} type="radio" bind:group={empire.portrait_group_id} value={phenotype.id} />
<label for={'checkbox' + phenotype.id} data-dropdown={phenotypeDropdownId}>{phenotype.display}</label>
</DropDownElement>
{/if}
{/each}
</DropDown>
<br />
<label for="text-name">Empire Name*:</label>
<input id="text-name" type="text" bind:value={empire.name} />
<br />
<label for="text-discord">Discord User:</label>
<input id="text-discord" type="text" bind:value={empire.discord_user} />
<DropDown dropdownTitle={'Ethics*: ' + Object.values(empire.ethics).map((selection) => $LeanChellarisDataStore.ethics[selection.ethic_id].display).join(", ")} dropdownId={ethicsDropdownId}>
{#each Object.values($LeanChellarisDataStore.ethics) as ethic}
{#if ethic}
<DropDownElement dropdownId={ethicsDropdownId}>
<input id={'checkbox' + ethic.id} data-dropdown={ethicsDropdownId} type="radio" bind:group={empire.ethics} value={ethic.id} />
<label for={'checkbox' + ethic.id} data-dropdown={ethicsDropdownId}>{ethic.display}</label>
</DropDownElement>
{/if}
{/each}
</DropDown>
<div>
{#if empire.ethics}
Ethics*:
{#each Object.values(empire.ethics) as ethic}
{ethic.fanatic ? ' Fanatic' : ''} {$LeanChellarisDataStore.ethics[ethic.ethic_id].display},
{/each}
{/if}
</div>
<button on:click={createEmpire}>Save</button>
{:else if !newEmpire}
<div>
{#if empire}
<div>
ID: {empire.id}
</div>
<div>
Game ID: {empire.game}
</div>
<DropDown dropdownTitle={'Group: ' + groups[empire.group].name} dropdownId={groupDropdownId}>
{#each Object.values(groups) as group}
{#if group}
<DropDownElement dropdownId={groupDropdownId}>
<input id={'checkbox' + group.id} data-dropdown={groupDropdownId} type="radio" bind:group={empire.group} value={group.id} />
<label for={'checkbox' + group.id} data-dropdown={groupDropdownId}>{group.name}</label>
</DropDownElement>
{/if}
{/each}
</DropDown>
<br />
<label for="check-gestalt">Gestalt:</label>
<input id="check-gestalt" type="checkbox" bind:checked={empire.gestalt} />
<br />
<label for="check-gestalt">Machine:</label>
<input id="check-gestalt" type="checkbox" bind:checked={empire.machine} />
<br />
<!--TODO: Add Scrolling to Dropdown Element-->
<DropDown
dropdownTitle={'Species: ' + $LeanChellarisDataStore.phenotypes[empire.portrait_group_id].species[empire.portrait_id].id}
dropdownId={speciesDropdownId}
>
{#each Object.values($LeanChellarisDataStore.phenotypes[empire.portrait_group_id].species) as species}
{#if species}
<DropDownElement dropdownId={speciesDropdownId}>
<input id={'checkbox' + species.id} data-dropdown={speciesDropdownId} type="radio" bind:group={empire.portrait_id} value={species.id} />
<label for={'checkbox' + species.id} data-dropdown={speciesDropdownId}>{species.id}</label>
</DropDownElement>
{/if}
{/each}
</DropDown>
<br />
<!--TODO: Add Scrolling to Dropdown Element-->
<DropDown dropdownTitle={'Phenotype: ' + $LeanChellarisDataStore.phenotypes[empire.portrait_group_id].display} dropdownId={phenotypeDropdownId}>
{#each Object.values(Object.values($LeanChellarisDataStore.phenotypes)) as phenotype}
{#if phenotype}
<DropDownElement dropdownId={phenotypeDropdownId}>
<input
id={'checkbox' + phenotype.id}
data-dropdown={phenotypeDropdownId}
type="radio"
bind:group={empire.portrait_group_id}
value={phenotype.id}
/>
<label for={'checkbox' + phenotype.id} data-dropdown={phenotypeDropdownId}>{phenotype.display}</label>
</DropDownElement>
{/if}
{/each}
</DropDown>
<br />
<label for="text-name">Empire Name:</label>
<input id="text-name" type="text" bind:value={empire.name} />
<br />
<label for="text-discord">Discord User:</label>
<input id="text-discord" type="text" bind:value={empire.discord_user} />
<DropDown dropdownTitle={'Ethics*: ' + Object.values(empire.ethics).map((selection) => (selection.fanatic ? "Fanatic " : "") + $LeanChellarisDataStore.ethics[selection.ethic_id].display).join(", ")} dropdownId={ethicsDropdownId}>
{#each Object.values($LeanChellarisDataStore.ethics) as ethic}
{#if ethic}
<DropDownElement dropdownId={ethicsDropdownId}>
<input id={'checkbox' + ethic.id} data-dropdown={ethicsDropdownId} type="radio" bind:group={empire.ethics} value={ethic.id} />
<label for={'checkbox' + ethic.id} data-dropdown={ethicsDropdownId}>{ethic.display}</label>
</DropDownElement>
{/if}
{/each}
</DropDown>
<div>
{#if empire.ethics}
Ethics:
{#each Object.values(empire.ethics) as ethic}
{ethic.fanatic ? ' Fanatic' : ''} {$LeanChellarisDataStore.ethics[ethic.ethic_id].display},
{/each}
{/if}
</div>
{:else}
No Empire Selected
{/if}
</div>
<button on:click={updateEmpire}>Save</button>
{/if}
<style> <style>
</style> </style>

View file

@ -31,7 +31,7 @@
ethicsData: { ethicsData: {
[key: number]: { [key: number]: {
id: number; id: number;
machine: boolean; gestalt: boolean;
display: string; display: string;
regular: number; regular: number;
fanatic: number; fanatic: number;
@ -47,7 +47,7 @@
ethicsData: { ethicsData: {
[key: number]: { [key: number]: {
id: number; id: number;
machine: boolean; gestalt: boolean;
display: string; display: string;
regular: number; regular: number;
fanatic: number; fanatic: number;
@ -67,13 +67,13 @@
Object.values($ChellarisDataStore.ethics).forEach((ethic) => { Object.values($ChellarisDataStore.ethics).forEach((ethic) => {
const newEthicsData: { const newEthicsData: {
id: number; id: number;
machine: boolean; gestalt: boolean;
display: string; display: string;
regular: number; regular: number;
fanatic: number; fanatic: number;
} = { } = {
id: ethic.id, id: ethic.id,
machine: ethic.machine, gestalt: ethic.gestalt,
display: ethic.display, display: ethic.display,
regular: 0, regular: 0,
fanatic: 0 fanatic: 0
@ -84,60 +84,6 @@
Object.values(selectedGame.empires).forEach((empire) => { Object.values(selectedGame.empires).forEach((empire) => {
console.log(empire); //DEBUG console.log(empire); //DEBUG
if (empire.group in selectedGameGroupData.selectedGroups) { if (empire.group in selectedGameGroupData.selectedGroups) {
newPageData.empireCount = newPageData.empireCount + 1;
if (empire.gestalt) {
newPageData.gestaltCount.total = newPageData.gestaltCount.total + 1;
let machine = false;
Object.values(empire.ethics).forEach((ethic) => {
if (ethic.machine) {
machine = true;
}
});
if (machine) {
newPageData.gestaltCount.machines = newPageData.gestaltCount.machines + 1;
}
}
Object.values(empire.ethics).forEach((ethic) => {
const tmpEthicPageData = newPageData.ethicsData[ethic.ethic_id];
if (typeof tmpEthicPageData !== 'undefined') {
tmpEthicPageData.display = ethic.display;
if (!ethic.fanatic) {
tmpEthicPageData.regular = tmpEthicPageData.regular + 1;
} else {
tmpEthicPageData.fanatic = tmpEthicPageData.fanatic + 1;
}
newPageData.ethicsData[ethic.ethic_id] = tmpEthicPageData;
} else {
let newEthicsData: {
id: number;
machine: boolean;
display: string;
regular: number;
fanatic: number;
} = {
id: ethic.ethic_id,
machine: ethic.machine,
display: ethic.display,
regular: 0,
fanatic: 0
};
if (!ethic.fanatic) {
newEthicsData.regular = 1;
} else {
newEthicsData.fanatic = 1;
}
newPageData.ethicsData[ethic.ethic_id] = newEthicsData;
}
});
if (typeof newPageData.takenPortraits[empire.portrait_group_id] === 'undefined') { if (typeof newPageData.takenPortraits[empire.portrait_group_id] === 'undefined') {
newPageData.takenPortraits[empire.portrait_group_id] = []; newPageData.takenPortraits[empire.portrait_group_id] = [];
} }
@ -157,16 +103,63 @@
newPageData.takenPortraits[empire.portrait_group_id] = portraitGroupData; newPageData.takenPortraits[empire.portrait_group_id] = portraitGroupData;
} }
} }
newPageData.empireCount = newPageData.empireCount + 1;
if (empire.gestalt) {
newPageData.gestaltCount.total = newPageData.gestaltCount.total + 1;
}
if (empire.machine) {
newPageData.gestaltCount.machines = newPageData.gestaltCount.machines + 1;
}
Object.values(empire.ethics).forEach((ethic) => {
const tmpEthicPageData = newPageData.ethicsData[ethic.ethic_id];
if (typeof tmpEthicPageData !== 'undefined') {
tmpEthicPageData.display = ethic.display;
if (!ethic.fanatic) {
tmpEthicPageData.regular = tmpEthicPageData.regular + 1;
} else {
tmpEthicPageData.fanatic = tmpEthicPageData.fanatic + 1;
}
newPageData.ethicsData[ethic.ethic_id] = tmpEthicPageData;
} else {
let newEthicsData: {
id: number;
gestalt: boolean;
display: string;
regular: number;
fanatic: number;
} = {
id: ethic.ethic_id,
gestalt: ethic.gestalt,
display: ethic.display,
regular: 0,
fanatic: 0
};
if (!ethic.fanatic) {
newEthicsData.regular = 1;
} else {
newEthicsData.fanatic = 1;
}
newPageData.ethicsData[ethic.ethic_id] = newEthicsData;
}
});
} }
}); });
// Fill undefined Portrait Info with default information. // Fill undefined Portrait Info with default information.
for (let i = 0; i < Object.values($ChellarisDataStore.species).length; i++) { for (let i = 0; i < Object.values($ChellarisDataStore.phenotypes).length; i++) {
if (typeof newPageData.takenPortraits[i] === 'undefined') { if (typeof newPageData.takenPortraits[i] === 'undefined') {
newPageData.takenPortraits[i] = []; newPageData.takenPortraits[i] = [];
} }
for (let ii = 0; ii < Object.values($ChellarisDataStore.species[i].portraits).length; ii++) { for (let ii = 0; ii < Object.values($ChellarisDataStore.phenotypes[i].species).length; ii++) {
if (typeof newPageData.takenPortraits[i][ii] === 'undefined') { if (typeof newPageData.takenPortraits[i][ii] === 'undefined') {
newPageData.takenPortraits[i][ii] = [0, []]; newPageData.takenPortraits[i][ii] = [0, []];
} }
@ -210,7 +203,7 @@
<th># Fanatic</th> <th># Fanatic</th>
</tr> </tr>
{#each Object.values(pageData.ethicsData) as ethicData} {#each Object.values(pageData.ethicsData) as ethicData}
{#if ethicData && !ethicData.machine} {#if ethicData && !ethicData.gestalt}
<tr> <tr>
<td class="table-label">{ethicData.display}</td> <td class="table-label">{ethicData.display}</td>
<td>{ethicData.regular}</td> <td>{ethicData.regular}</td>
@ -226,11 +219,11 @@
<p>> Machines: {pageData.gestaltCount.machines}</p> <p>> Machines: {pageData.gestaltCount.machines}</p>
<table> <table>
<tr> <tr>
<th>Machine Ethic</th> <th>Gestalt Ethic</th>
<th>#</th> <th>#</th>
</tr> </tr>
{#each Object.values(pageData.ethicsData) as ethicData} {#each Object.values(pageData.ethicsData) as ethicData}
{#if ethicData && ethicData.machine} {#if ethicData && ethicData.gestalt}
<tr> <tr>
<td class="table-label">{ethicData.display}</td> <td class="table-label">{ethicData.display}</td>
<td>{ethicData.regular}</td> <td>{ethicData.regular}</td>
@ -249,11 +242,11 @@
<th>{index + 1}</th> <th>{index + 1}</th>
{/each} {/each}
</tr> </tr>
{#each Object.values($ChellarisDataStore.species) ?? false as portraitGroup} {#each Object.values($ChellarisDataStore.phenotypes) ?? false as portraitGroup}
{#if portraitGroup} {#if portraitGroup}
<tr> <tr>
<td>{portraitGroup.display}</td> <td>{portraitGroup.display}</td>
{#each Object.values(portraitGroup.portraits) ?? false as portrait} {#each Object.values(portraitGroup.species) ?? false as portrait}
{#if portrait} {#if portrait}
<td <td
class="image-box" class="image-box"