This commit is contained in:
Miki 2023-12-20 16:49:33 +01:00
parent d9a1837f3b
commit ebd2f05ae2
69 changed files with 2335 additions and 451 deletions

View file

@ -1,10 +1,2 @@
<script>
import TopScorer from "$lib/img/topscorer_logo_web.png";
</script>
<div style="background-color: black;">
<img src={TopScorer} alt="TopScorer">
</div>
<h1>Welcome to SvelteKit</h1>
<p>Visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to read the documentation</p>

View file

@ -1,240 +0,0 @@
<script>
// import { page } from '$app/stores';
import { onDestroy, onMount } from 'svelte';
import { dev } from '$app/environment';
if (dev) {
console.log('Dev mode');
} else {
console.log('Not dev mode');
}
let surfers = [
{ name: 'Kanoa Igarashi', color: 'red', score: '4.50', priority: '3' },
{ name: 'Griffin Colapinto', color: 'white', score: '5.60', priority: 'P' },
{ name: 'Jack Robinson', color: 'blue', score: '6.10', priority: '5' },
{ name: 'Gabriel Medina', color: 'green', score: '4.30', priority: '2' },
{ name: 'Italo Ferreira', color: 'black', score: '6.50', priority: '4' }
];
let width;
// $: activeUrl = $page.url.pathname;
let event = 'Semifinal';
let category = 'U16 man';
let heat = 'Heat 1';
const pad2 = (number) => `00${number}`.slice(-2);
$: min = 10;
$: sec = 25;
let end = false;
function updateRemainingTime() {
if ((min === 0) & (sec === 0)) {
clearInterval(timer);
end = true;
} else if (sec === 0) {
min -= 1;
sec = 59;
} else {
sec -= 1;
}
}
updateRemainingTime();
const timer = setInterval(updateRemainingTime, 1000);
function Subscribe() {
const sse = new EventSource(`/api/sse`);
console.log('subscribe');
sse.onmessage = (e) => {
let Msg = JSON.parse(e.data);
console.log(`received: ${JSON.stringify(Msg)}`);
if (Msg.mode === 'priority') {
console.log(`priority: ${Msg.priority}`);
for (let i in surfers) {
surfers[i].priority = Msg.priority[i];
}
}
};
return () => {
sse.close();
console.log(`sse closing ${Date.now()}`);
};
}
onMount(() => {
const unsub = Subscribe();
return unsub;
});
onDestroy(() => {
clearInterval(timer); // Pulisci il timer quando il componente viene distrutto
});
</script>
<svelte:window bind:innerWidth={width} />
<div class="header">
{#if !end}
<div class="timer">{pad2(min)}:{pad2(sec)}</div>
{:else}
<div class="timer" style="color: red">{pad2(min)}:{pad2(sec)}</div>
{/if}
</div>
<div class="container">
{#each surfers as surfer, id}
<div class="box">
<div class="square" style="background-color: {surfer.color};">
{#if surfer.priority != ''}
{#if surfer.priority === 'P'}
{#if surfer.color === 'white'}
<span class="priority_white">{surfer.priority}</span>
{:else}
<span class="priority">{surfer.priority}</span>
{/if}
{:else}
<span class="priority_small">{surfer.priority}</span>
{/if}
{/if}
</div>
<div class="score">{surfer.score}</div>
</div>
{/each}
</div>
<style>
:root {
--backColor: #334;
--textColor: white;
--maxWidth: (100% - 15px);
}
.header {
/* padding: 15px; */
height: 10vh;
background-color: var(--backColor);
padding-left: 10px;
padding-right: 10px;
padding-top: 6px;
padding-bottom: 6px;
margin-top: 2px;
margin-bottom: 2px;
width: calc(var(--maxWidth));
color: var(--textColor);
display: flex;
justify-content: space-between;
}
.header .timer {
font-size: 13vh;
padding-left: 10px;
padding-right: 20px;
font-weight: bold;
flex: 2 2 auto;
align-self: center;
text-align: center;
}
.container {
height: 85vh;
background-color: var(--backColor);
padding-left: 10px;
padding-right: 10px;
padding-top: 4px;
width: calc(var(--maxWidth));
color: var(--textColor);
}
.box {
width: 100%;
display: flex;
align-items: center;
padding: 1px;
margin-bottom: 1px;
}
.priority {
width: 15%;
height: 100%;
border-radius: 20%;
font-size: 8vh;
animation: blink 2s 3;
margin-right: auto;
background-color: white;
color: black;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
}
.priority_white {
width: 15%;
height: 100%;
border-radius: 20%;
font-size: 8vh;
animation: blink_white 2s 3;
margin-right: auto;
background-color: black;
color: white;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
padding-bottom: 4px;
}
.priority_small {
width: 10%;
height: 80%;
border-radius: 20%;
font-size: 8vh;
/* animation: blink 2s infinite; */
margin-right: auto;
margin-left: 30px;
background-color: #bbb;
color: black;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
}
.square {
width: 100%;
height: 16vh;
border-radius: 5px;
margin-right: 15px;
display: flex;
align-items: center;
justify-content: center;
padding-bottom: 2px;
margin-bottom: 2px;
}
.score {
padding-right: 20px;
width: 20%;
font-size: 12vh;
float: right;
text-align: center;
font-weight: bold;
}
@keyframes blink {
0% {
background-color: white;
}
50% {
background-color: rgba(255, 255, 255, 0.6);
}
100% {
background-color: white;
}
}
</style>

View file

@ -1,256 +0,0 @@
<script>
// import { page } from '$app/stores';
import { onDestroy, onMount } from 'svelte';
import { dev } from '$app/environment';
if (dev) {
console.log('Dev mode');
} else {
console.log('Not dev mode');
}
let surfers = [
// { name: 'Kanoa Igarashi', color: 'red', score: '4.50', priority: '3' },
// { name: 'Griffin Colapinto', color: 'white', score: '5.60', priority: 'P' },
// { name: 'Jack Robinson', color: 'blue', score: '6.10', priority: '5' },
// { name: 'Gabriel Medina', color: 'green', score: '4.30', priority: '2' },
// { name: 'Italo Ferreira', color: 'black', score: '6.50', priority: '4' }
];
let width;
// $: activeUrl = $page.url.pathname;
let heat = {};
const pad2 = (number) => `00${number}`.slice(-2);
$: min = 0;
$: sec = 0;
let end = false;
loadRunning();
async function loadRunning() {
const res = await fetch(`/api/runningheat`);
const data = await res.json();
heat = data;
console.log(`retval: ${JSON.stringify(heat)}`);
if (heat != null) {
console.log(`heat: ${JSON.stringify(heat)}`);
min = heat.timer;
surfers = heat.surfers;
}
}
// function updateRemainingTime() {
// if ((min === 0) & (sec === 0)) {
// clearInterval(timer);
// end = true;
// } else if (sec === 0) {
// min -= 1;
// sec = 59;
// } else {
// sec -= 1;
// }
// }
// updateRemainingTime();
// const timer = setInterval(updateRemainingTime, 1000);
function Subscribe() {
const sse = new EventSource(`/api/sse`);
console.log('subscribe');
sse.onmessage = (e) => {
let Msg = JSON.parse(e.data);
console.log(`received: ${JSON.stringify(Msg)}`);
if (Msg.mode === 'priority') {
console.log(`priority: ${Msg.priority}`);
for (let i in surfers) {
surfers[i].priority = Msg.priority[i];
}
} else if (Msg.mode === 'time') {
// console.log(`duration: ${Msg.duration}`);
let min_sec = Msg.duration.split(":");
min = min_sec[0];
sec = min_sec[1];
// console.log(`min & sec = ${min} & ${sec}`);
if (!start) {
start = true;
}
} else if (Msg.mode === 'stop') {
console.log(`stop duration: ${Msg.duration}`);
end = true;
start = false;
}
};
return () => {
sse.close();
console.log(`sse closing ${Date.now()}`);
};
}
onMount(() => {
if (!dev) {
const unsub = Subscribe();
return unsub;
}
});
onDestroy(() => {
clearInterval(timer); // Pulisci il timer quando il componente viene distrutto
});
</script>
<svelte:window bind:innerWidth={width} />
<div class="header">
{#if !end}
<div class="timer">{pad2(min)}:{pad2(sec)}</div>
{:else}
<div class="timer" style="color: red">{pad2(min)}:{pad2(sec)}</div>
{/if}
</div>
<div class="container">
{#each surfers as surfer, id}
<div class="box">
<div class="square" style="background-color: {surfer.color};">
{#if surfer.priority != ''}
{#if surfer.priority === 'P'}
{#if surfer.color === 'white'}
<span class="priority_white">{surfer.priority}</span>
{:else}
<span class="priority">{surfer.priority}</span>
{/if}
{:else}
<span class="priority_small">{surfer.priority}</span>
{/if}
{/if}
</div>
<div class="score">{surfer.score}</div>
</div>
{/each}
</div>
<style>
:root {
--backColor: #334;
--textColor: white;
--maxWidth: (100% - 15px);
}
.header {
/* padding: 15px; */
height: 10vh;
background-color: var(--backColor);
padding-left: 10px;
padding-right: 10px;
padding-top: 6px;
padding-bottom: 6px;
margin-top: 2px;
margin-bottom: 2px;
width: calc(var(--maxWidth));
color: var(--textColor);
display: flex;
justify-content: space-between;
}
.header .timer {
font-size: 13vh;
padding-left: 10px;
padding-right: 20px;
font-weight: bold;
flex: 2 2 auto;
align-self: center;
text-align: center;
}
.container {
height: 85vh;
background-color: var(--backColor);
padding-left: 10px;
padding-right: 10px;
padding-top: 4px;
width: calc(var(--maxWidth));
color: var(--textColor);
}
.priority {
width: 90%;
height: 20%;
border-radius: 20%;
font-size: 8vh;
animation: blink 2s 3;
margin-top: 50%;
background-color: white;
color: black;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
}
.priority_white {
width: 90%;
height: 20%;
border-radius: 20%;
font-size: 8vh;
animation: blink_white 2s 3;
margin-top: 50%;
background-color: black;
color: white;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
font-weight: bold;
padding-bottom: 4px;
}
.priority_small {
width: 80%;
height: 15%;
border-radius: 20%;
font-size: 8vh;
/* animation: blink 2s infinite; */
margin-top: 60%;
margin-left: 20px;
background-color: #bbb;
color: black;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
}
.score {
padding-right: 20px;
width: 20%;
font-size: 12vh;
float: right;
text-align: center;
font-weight: bold;
}
.box {
height: 100%;
width: 19%;
float: left;
margin-left: 1px;
margin-right: 1px;
}
.square {
height: 100%;
width: 100%;
float: left;
align-items: center;
justify-content: center;
text-align: center;
}
</style>

View file

@ -1,96 +0,0 @@
<script>
import Logo from "$lib/img/topscorer_logo_web.png"
$: heats = [];
loadHeats();
async function loadHeats() {
const res = await fetch(`/api/loadheats`);
const data = await res.json();
for (let i in data) {
heats = [...heats, data[i]];
console.log(`${i} retval: ${JSON.stringify(data[i])}`);
}
}
</script>
<div class="header">
<img class="img" src={Logo} alt="logo">
<span class="title" style="color: aliceblue;">Heat Draws</span>
</div>
<hr>
{#each heats as heat}
<table>
<tr>
{#if heat.status === 'running'}
<th colspan="2" class="running">
{heat.name} ({heat.number}) {heat.category}
</th>
{:else if heat.status === 'ended'}
<th colspan="2" class="ended">
{heat.name} ({heat.number}) {heat.category}
</th>
{:else}
<th colspan="2">
{heat.name} ({heat.number}) {heat.category}
</th>
{/if}
</tr>
{#each heat.surfers as surfer }
<tr>
<td>
{surfer.name}
</td>
<td style="background-color: {surfer.color};">
{surfer.color}
</td>
</tr>
{/each}
</table>
<hr>
{/each}
<style>
.header {
background-color: black;
display: flex;
width: 100%;
justify-content: space-between;
text-align: center;
align-items: center;
}
.header .img {
height: 3rem;
}
.header .title {
font-size: 3rem;
margin: 0 auto;
}
table, th, td {
border: 1px solid black;
border-collapse: collapse;
}
th.running {
background-color: green;
animation: blinker 2s linear infinite;
}
th.ended {
background-color: lightcoral;
text-decoration: line-through 1px lightyellow;
}
@keyframes blinker {
50% {
opacity: 0.5;
}
}
</style>

View file

@ -1,353 +0,0 @@
<script>
// import { page } from '$app/stores';
import { onDestroy, onMount } from 'svelte';
import { dev } from '$app/environment';
if (dev) {
console.log('Dev mode');
} else {
console.log('Not dev mode');
}
let surfers = [
{ name: 'Kanoa Igarashi', color: 'red', score: '4.50', priority: '3' },
{ name: 'Griffin Colapinto', color: 'white', score: '5.60', priority: 'P' },
{ name: 'Jack Robinson', color: 'blue', score: '6.10', priority: '5' },
{ name: 'Gabriel Medina', color: 'green', score: '4.30', priority: '2' },
{ name: 'Italo Ferreira', color: 'black', score: '6.50', priority: '4' }
];
let width;
// $: activeUrl = $page.url.pathname;
let event = 'Semifinal';
let category = 'U16 man';
let heat = 'Heat 1';
const pad2 = (number) => `00${number}`.slice(-2);
$: min = 10;
$: sec = 25;
let end = false;
function updateRemainingTime() {
if ((min === 0) & (sec === 0)) {
clearInterval(timer);
end = true;
} else if (sec === 0) {
min -= 1;
sec = 59;
} else {
sec -= 1;
}
}
updateRemainingTime();
const timer = setInterval(updateRemainingTime, 1000);
function Subscribe() {
const sse = new EventSource(`/api/sse`);
console.log('subscribe');
sse.onmessage = (e) => {
let Msg = JSON.parse(e.data);
console.log(`received: ${JSON.stringify(Msg)}`);
if (Msg.mode === 'priority') {
console.log(`priority: ${Msg.priority}`);
for (let i in surfers) {
surfers[i].priority = Msg.priority[i];
}
}
};
return () => {
sse.close();
console.log(`sse closing ${Date.now()}`);
};
}
onMount(() => {
const unsub = Subscribe();
return unsub;
});
onDestroy(() => {
clearInterval(timer); // Pulisci il timer quando il componente viene distrutto
});
</script>
<svelte:window bind:innerWidth={width} />
<div class="header">
<span class="title">{event}</span>
<span class="title">{category}</span>
{#if !end}
<span class="timer">{pad2(min)}:{pad2(sec)}</span>
{:else}
<span class="timer" style="color: red">{pad2(min)}:{pad2(sec)}</span>
{/if}
<span class="heat">{heat}</span>
</div>
<div class="container">
{#each surfers as surfer, id}
<div class="box">
<div class="square" style="background-color: {surfer.color};">
{#if surfer.priority != ''}
<span class="priority">{surfer.priority}</span>
{/if}
</div>
<div class="text">{surfer.name}</div>
<div class="score">{surfer.score}</div>
</div>
{/each}
</div>
{#if width < 768}
<div class="footer">
<div>waiting for scores</div>
<!-- <div class="score">6.00</div>
<div class="score">6.00</div>
<div class="score">6.00</div>
<div class="score">6.00</div>
<div class="score">6.00</div> -->
</div>
{/if}
<style>
:root {
--backColor: #334;
--textColor: white;
--maxWidth: (100% - 15px);
}
.header {
background-color: var(--backColor);
padding-left: 10px;
padding-right: 10px;
padding-top: 6px;
padding-bottom: 6px;
margin-top: 2px;
margin-bottom: 2px;
width: calc(var(--maxWidth));
color: var(--textColor);
display: flex;
justify-content: space-between;
}
.header .title {
font-size: 2vh;
padding-left: 10px;
padding-right: 10px;
font-weight: bold;
flex: 1 1 0;
align-self: center;
}
.header .heat {
font-size: 2vh;
padding-left: 0px;
padding-right: 10px;
font-weight: bold;
flex: 1 1 auto;
align-self: center;
text-align: right;
}
.header .timer {
font-size: 5vh;
padding-left: 10px;
padding-right: 10px;
font-weight: bold;
flex: 2 2 auto;
align-self: center;
text-align: center;
}
.container {
background-color: var(--backColor);
padding: 10px;
width: calc(var(--maxWidth));
color: var(--textColor);
}
.box {
width: 100%;
display: flex;
align-items: center;
padding: 4px;
margin-bottom: 2px;
}
.priority {
width: 60%;
height: 60%;
background-color: white;
color: black;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.8rem;
font-weight: bold;
}
.square {
width: 60px;
height: 60px;
border-radius: 5px;
margin-right: 20px;
display: flex;
align-items: center;
justify-content: center;
position: relative; /* Per il posizionamento del testo */
}
.text {
flex: 1;
font-size: 1.5rem;
font-weight: lighter;
}
.score {
float: right;
padding-right: 10px;
text-align: center;
width: 20%;
font-size: 2.5rem;
font-weight: bold;
}
.footer {
background-color: var(--backColor);
padding: 10px;
width: calc(var(--maxWidth));
color: var(--textColor);
display: flex;
font-size: larger;
font-weight: bold;
align-items: center;
justify-content: space-around;
align-content: center;
margin-top: 2px;
}
/* .footer .score {
float: right;
padding-right: 10px;
text-align: center;
width: 20%;
font-size: 1.5rem;
font-weight: lighter;
} */
/* @media screen and (min-width: 768px) {
.container {
height: 85vh;
}
.priority {
width: 15%;
height: 100%;
border-radius: 20%;
font-size: 8vh;
animation: blink 2s infinite;
margin-right: auto;
}
@keyframes blink {
0% {
background-color: white;
}
50% {
background-color: rgba(255, 255, 255, 0.6);
}
100% {
background-color: white;
}
}
.square {
width: 100%;
height: 15vh;
margin-right: 20px;
}
.score {
padding-right: 40px;
width: 20%;
font-size: 14vh;
}
.text {
flex: 0;
font-size: 0;
}
.header {
padding: 15px;
margin-bottom: 2px;
height: 10vh;
width: calc(100% - 15px);
}
.header .timer {
font-size: 6rem;
padding-left: 10px;
padding-right: 20px;
}
} */
/* @media screen and (min-width: 1280px) {
.priority {
width: 120px;
height: 90%;
font-size: 6rem;
}
.square {
width: 100%;
height: 125px;
margin-right: 20px;
}
.score {
float: right;
padding-right: 40px;
width: 20%;
font-size: 6rem;
}
.header .timer {
font-size: 6rem;
padding-left: 10px;
padding-right: 20px;
}
}
@media screen and (min-width: 1920px) {
.priority {
width: 200px;
font-size: 10rem;
}
.square {
width: 100%;
height: 205px;
border-radius: 5px;
margin-right: 20px;
}
.score {
padding-right: 40px;
width: 20%;
font-size: 11rem;
}
.header .timer {
font-size: 8rem;
padding-left: 10px;
padding-right: 20px;
}
} */
</style>

View file

@ -1,399 +0,0 @@
<script>
// import { page } from '$app/stores';
import { onDestroy, onMount } from 'svelte';
import { dev } from '$app/environment';
if (dev) {
console.log('Dev mode');
} else {
console.log('Not dev mode');
}
let heat_number;
let heats = [];
$: surfers = [];
// { name: 'Kanoa Igarashi', color: 'red', score: '4.50', priority: '3' },
// { name: 'Griffin Colapinto', color: 'white', score: '5.60', priority: 'P' },
// { name: 'Jack Robinson', color: 'blue', score: '6.10', priority: '5' },
// { name: 'Gabriel Medina', color: 'green', score: '4.30', priority: '2' },
// { name: 'Italo Ferreira', color: 'black', score: '6.50', priority: '4' }
// ];
let width;
// $: activeUrl = $page.url.pathname;
const pad2 = (number) => `00${number}`.slice(-2);
$: min = 0;
$: sec = 0;
let end = false;
let start = false;
loadHeats();
function Subscribe() {
const sse = new EventSource(`/api/sse`);
console.log('subscribe');
sse.onmessage = (e) => {
let Msg = JSON.parse(e.data);
console.log(`received: ${JSON.stringify(Msg)}`);
if (Msg.mode === 'priority') {
console.log(`priority: ${Msg.priority}`);
for (let i in surfers) {
surfers[i].priority = Msg.priority[i];
}
} else if (Msg.mode === 'time') {
// console.log(`duration: ${Msg.duration}`);
let min_sec = Msg.duration.split(":");
min = min_sec[0];
sec = min_sec[1];
// console.log(`min & sec = ${min} & ${sec}`);
if (!start) {
start = true;
}
} else if (Msg.mode === 'stop') {
console.log(`stop duration: ${Msg.duration}`);
end = true;
start = false;
}
};
return () => {
sse.close();
console.log(`sse closing ${Date.now()}`);
};
}
async function dblclick(id) {
console.log(`dblclick = ${surfers[id]}`);
if (surfers[id] === 'P') {
console.log('pressed P');
} else {
console.log(`pressed: [${id}] ${surfers[id].priority}`);
}
const res = await fetch(`/api/stopheat`);
const data = await res.json();
console.log(`stop: ${JSON.stringify(data)}`);
}
async function startHeat() {
const res = await fetch(`/api/startheat`, {
method: 'POST',
body: JSON.stringify({
duration: min+"m",
mode: 'time'
}),
headers: {
'Content-Type': 'application/json'
}
});
console.log(`retval: ${JSON.stringify(res)}`);
start = true;
end = false;
}
async function loadHeats() {
const res = await fetch(`/api/loadheats`);
const data = await res.json();
for (let i in data) {
heats[i] = data[i];
console.log(`${i} retval: ${JSON.stringify(data[i])}`);
}
}
function setHeat(id) {
console.log(`setHeat: ${id}`);
if (id === "99") {
min = 0;
surfers = []
return;
}
min = heats[id].timer;
surfers = heats[id].surfers;
}
async function click(id) {
let max = surfers.length;
console.log(surfers[id]);
if (surfers[id].priority === 'P') {
for (let i in surfers) {
if (i != id) {
let pos = parseInt(surfers[i].priority) - 1;
if (pos === 1) {
surfers[i].priority = 'P';
} else {
surfers[i].priority = pos.toString();
}
}
}
surfers[id].priority = max.toString();
} else if (surfers[id].priority === '') {
console.log(`priority empty; pressed: [${id}] ${surfers[id].priority}`);
for (let i in surfers) {
console.log(`looping(${id}): ${i} - ${surfers[i].priority}`);
if (i != id) {
if (surfers[i].priority === '') {
console.log(`empty: [${i}] ${surfers[i].priority}`);
continue;
} else {
console.log(`not empty: [${i}] ${surfers[i].priority}`);
let pos = parseInt(surfers[i].priority) - 1;
if (pos === 1) {
surfers[i].priority = 'P';
} else {
surfers[i].priority = pos.toString();
}
}
}
}
surfers[id].priority = max.toString();
} else {
console.log(`pressed: [${id}] ${surfers[id].priority}`);
let oldpos = parseInt(surfers[id].priority);
for (let i in surfers) {
if (i != id) {
console.log(`pos: [${i}] ${surfers[i].priority} ${surfers[i].priority > oldpos}`);
if (surfers[i].priority != 'P' && surfers[i].priority > oldpos) {
let pos = parseInt(surfers[i].priority);
if (pos > oldpos) {
surfers[i].priority = (pos - 1).toString();
console.log(`newpos: ${surfers[i].priority}`);
}
}
} else {
surfers[i].priority = max.toString();
console.log(`last: [${i}] ${surfers[i].priority}`);
}
}
}
const res = await fetch(`/api/priority`, {
method: 'POST',
body: JSON.stringify({
priority: surfers.map((obj) => obj.priority),
mode: 'priority'
}),
headers: {
'Content-Type': 'application/json'
}
});
console.log(
JSON.stringify({
priority: surfers.map((obj) => obj.priority),
mode: 'priority'
})
);
console.log(`retval: ${JSON.stringify(res)}`);
}
onMount(() => {
const unsub = Subscribe();
return unsub;
});
// onDestroy(() => {
// clearInterval(timer); // Pulisci il timer quando il componente viene distrutto
// });
</script>
<svelte:window bind:innerWidth={width} />
<div class="header">
<!-- <button class="button" on:click={() => loadHeats()} disabled={start}>Load</button> -->
<select name="heats" id="heats" bind:value={heat_number} on:change={() => setHeat(heat_number)}>
<option value="99">Select Heat</option>
{#each heats as heat, id}
<option value={id}>{heat.name} {heat.number} {heat.category}</option>
{/each}
</select>
{#if !end}
<div class="timer">{pad2(min)}:{pad2(sec)}</div>
{:else}
<div class="timer" style="color: red">{pad2(min)}:{pad2(sec)}</div>
{/if}
<button class="button" on:click={() => startHeat()} disabled={start}>Start</button>
</div>
<div class="container">
{#each surfers as surfer, id}
<div class="box">
<div
class="square"
{id}
style="background-color: {surfer.color};"
on:click={() => click(id)}
on:contextmenu={(e) => {
e.preventDefault();
dblclick(id);
}}
on:keypress={console.log('keypress')}
role="button"
tabindex={id}
>
{#if surfer.priority != ''}
{#if surfer.priority === 'P'}
{#if surfer.color === 'white'}
<span class="priority_white">{surfer.priority}</span>
{:else}
<span class="priority">{surfer.priority}</span>
{/if}
{:else}
<span class="priority_small">{surfer.priority}</span>
{/if}
{/if}
</div>
<div class="score">{surfer.score}</div>
</div>
{/each}
</div>
<style>
:root {
--backColor: #334;
--textColor: white;
--maxWidth: (100% - 15px);
}
.header {
/* padding: 15px; */
height: 10vh;
background-color: var(--backColor);
padding-left: 10px;
padding-right: 10px;
padding-top: 6px;
padding-bottom: 6px;
margin-top: 2px;
margin-bottom: 2px;
width: calc(var(--maxWidth));
color: var(--textColor);
display: flex;
justify-content: space-between;
align-items: center;
}
.header .timer {
font-size: 13vh;
padding-left: 10px;
padding-right: 20px;
font-weight: bold;
flex: 2 2 auto;
align-self: center;
text-align: center;
}
.header .button {
height: 60%;
align-items: center;
background-color: yellow;
border-radius: 10%;
}
.container {
height: 85vh;
background-color: var(--backColor);
padding-left: 10px;
padding-right: 10px;
padding-top: 4px;
width: calc(var(--maxWidth));
color: var(--textColor);
}
.box {
width: 100%;
display: flex;
align-items: center;
padding: 1px;
margin-bottom: 1px;
}
.priority {
width: 15%;
height: 100%;
border-radius: 20%;
font-size: 8vh;
/* animation: blink 2s 2; */
margin-right: auto;
background-color: white;
color: black;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
}
.priority_white {
width: 15%;
height: 100%;
border-radius: 20%;
font-size: 8vh;
/* animation: blink_white 2s 3; */
margin-right: auto;
background-color: black;
color: white;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
padding-bottom: 4px;
}
.priority_small {
width: 13%;
height: 85%;
border-radius: 20%;
font-size: 8vh;
/* animation: blink 2s 3; */
margin-right: auto;
margin-left: 30px;
background-color: #ccc;
color: black;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
}
.square {
width: 100%;
height: 16vh;
border-radius: 5px;
margin-right: 15px;
display: flex;
align-items: center;
justify-content: center;
padding-bottom: 2px;
margin-bottom: 2px;
}
.score {
padding-right: 20px;
width: 20%;
font-size: 12vh;
float: right;
text-align: center;
font-weight: bold;
}
@keyframes blink {
0% {
background-color: white;
}
50% {
background-color: rgba(255, 255, 255, 0.6);
}
100% {
background-color: white;
}
}
@keyframes blink_white {
0% {
background-color: black;
}
50% {
background-color: rgba(0, 0, 0, 0.6);
}
100% {
background-color: black;
}
}
</style>

View file

@ -1,376 +0,0 @@
<script>
import { onMount } from 'svelte';
import Logo from "$lib/img/topscorer_logo_web.png"
let colors = [
"black",
"blue",
"red",
"green",
"yellow",
"pink",
"white",
];
let rounds = [
"Qualifying",
"Opening",
"Elimination",
"Round of 48",
"Round of 32",
"Round of 16",
"Quarterfinal",
"Semifinal",
"Final",
];
let categories = [
"Under 12 Women",
"Under 12 Men",
"Under 14 Women",
"Under 14 Men",
"Under 16 Women",
"Under 16 Men",
"Under 18 Women",
"Under 18 Men",
];
$: surfers = 2;
$: heats = [];
let surfer_list = [];
$: heat = {};
resetHeat();
loadHeats();
function resetHeat() {
surfers = 2;
surfer_list = new Array();
surfer_list.push({
name: '',
color: '',
score: '',
priority: ''
});
surfer_list.push({
name: '',
color: '',
score: '',
priority: ''
});
heat = {
number: 1,
name: '',
category: '',
timer: 20,
surfers: surfer_list
}
}
async function loadHeats() {
const res = await fetch(`/api/loadheats`);
const data = await res.json();
for (let i in data) {
heats[i] = data[i];
console.log(`${i} retval: ${JSON.stringify(data[i])}`);
}
}
async function deleteHeat(id) {
const res = await fetch(`/api/deleteheat`, {
method: 'POST',
body: JSON.stringify(heats[id]),
headers: {
'Content-Type': 'application/json'
}
});
console.log(`retval: ${JSON.stringify(res)}`);
console.log(JSON.stringify(heats[id]));
resetHeat();
loadHeats();
}
function setHeat(id) {
resetHeat();
console.log(`setHeat: ${id}`);
console.log(heats[id]);
heat.number = heats[id].number;
heat.name = heats[id].name;
heat.category = heats[id].category;
heat.timer = heats[id].timer;
surfer_list = heats[id].surfers;
surfers = surfer_list.length;
}
function addSurfers() {
surfers++;
surfer_list.push({
name: '',
color: '',
score: '',
priority: ''
});
}
function removeSurfers() {
surfers--;
if (surfers < 2) surfers = 2;
surfer_list.pop();
}
async function save() {
if(hasDuplicateColors(surfer_list)) {
alert('Colors must be unique');
return;
}
if(surfer_list.length < 2) {
alert('Must have at least 2 surfers');
return;
}
if(heat.name === '') {
alert('Must have a name');
return;
}
if(heat.category === '') {
alert('Must have a category');
return;
}
if(heat.number === '') {
alert('Must have a number');
return;
}
if(heat.timer === '') {
alert('Must have a timer');
return;
}
heat.surfers = surfer_list;
const res = await fetch(`/api/saveheat`, {
method: 'POST',
body: JSON.stringify(heat),
headers: {
'Content-Type': 'application/json'
}
});
console.log(`retval: ${JSON.stringify(res)}`);
console.log(JSON.stringify(heat));
resetHeat();
loadHeats();
}
function hasDuplicateColors(arr) {
const colors = [];
console.log(JSON.stringify(arr));
for(let i = 0; i < arr.length; i++) {
const color = arr[i].color;
if(colors.includes(color)) {
console.log(`duplicate color: ${color}`);
return true;
}
colors.push(color);
}
return false;
}
function capitalize(element, elementName) {
element[elementName] = element[elementName].charAt(0).toUpperCase() + element[elementName].slice(1);
console.log(`element: ${element[elementName]}`);
}
onMount(() => {
resetHeat();
loadHeats();
});
</script>
<div class="header">
<img class="img" src={Logo} alt="logo">
<span class="title" style="color: aliceblue;">Heat setup</span>
</div>
<div class="container">
<div class="heat">
<label class="label" for="heat">Heat</label>
<select name="heat" id="heat" bind:value={heat.name}>
{#each rounds as round}
<option value={round}>{round}</option>
{/each}
</select>
<!-- <input bind:value={heat.name} on:change={capitalize(heat, "name")} id="name" type="text"> -->
<label class="label" for="number">Number</label>
<input bind:value={heat.number} id="number" type="number" min="1" max="20">
<label class="label" for="category">Category</label>
<select name="category" id="category" bind:value={heat.category}>
{#each categories as category}
<option value={category}>{category}</option>
{/each}
</select>
<!-- <input bind:value={heat.category} on:change={capitalize(heat, "category")} id="category" type="text"> -->
<label class="label" for="timer">Duration</label>
<input bind:value={heat.timer} id="timer" type="number" min="5" max="60" step="5"> <!-- on:keydown={(event) => {event.preventDefault()}} -->
</div>
<hr>
<button class="plus" on:click={() => {addSurfers();}}>+</button>
<span class="surfers">{surfers}</span>
<button class="plus" on:click={() => {removeSurfers();}}>-</button>
{#each Array(surfers) as _, surfer}
<div class="surfer">
<label class="label" for="name{surfer}">Name</label>
<input bind:value={surfer_list[surfer].name} on:change={capitalize(surfer_list[surfer], "name")} id="name{surfer}" type="text">
<label class="label" for="color{surfer}">Color</label>
<select name="color" id="color{surfer}" bind:value={surfer_list[surfer].color} style="background-color: {surfer_list[surfer].color};">
{#each colors as color}
<option value={color} style="background-color: {color};">{color}</option>
{/each}
<!-- <option value="red" style="background-color: red;">Select color</option> -->
<!-- <option value="red" style="background-color: red;">Red</option>
<option value="blue" style="background-color: blue;">Blue</option>
<option value="green" style="background-color: green;">Green</option>
<option value="yellow" style="background-color: yellow;">Yellow</option>
<option value="orange" style="background-color: orange;">Orange</option>
<option value="violet" style="background-color: violet;">Violet</option> -->
</select>
<!-- <input bind:value={surfer_list[surfer].color} type="color" id="color{surfer}"> -->
</div>
{/each}
</div>
<button class="plus" on:click={() => {save();}}>SAVE</button>
<button class="plus" on:click={() => {resetHeat();}}>RESET</button>
<hr>
{#each heats as h, id}
<div class="surfer">
<button on:click={() => {setHeat(id);}}>{h.name} {h.number} {h.category}</button>
<button class="plus" on:click={() => {deleteHeat(id);}}>X</button>
</div>
{/each}
<!-- <hr> -->
<!-- <h2>{JSON.stringify(surfer_list)}</h2> -->
<style>
.container {
display: block;
}
.header {
background-color: black;
display: flex;
width: 100%;
justify-content: space-between;
text-align: center;
align-items: center;
}
.header .img {
height: 3rem;
}
.header .title {
font-size: 3rem;
margin: 0 auto;
}
.label {
border: 2px solid #555;
background-color: gray;
border-radius: 8px;
padding: 2px;
}
.heat {
font-size: 1.3rem;
margin-top: 8px;
margin-bottom: 2px;
width: 100%;
margin-left: auto;
margin-right: auto;
/* color: lightcyan; */
display: inline-block;
}
.heat input {
font-size: 1.2rem;
border-radius: 6px;
margin-left: 0.1rem;
margin-right: 0.1rem;
padding-top: 2px;
padding-bottom: 2px;
}
.heat select {
font-size: 1.2rem;
border-radius: 6px;
margin-left: 0.1rem;
margin-right: 0.1rem;
padding-top: 2px;
padding-bottom: 2px;
}
.surfer {
font-size: 1.3rem;
margin-top: 2px;
margin-bottom: 2px;
/* color: lightcyan; */
display: inline-flex;
width: 100%;
margin-left: auto;
margin-right: auto;
border-radius: 8px;
}
.surfer input {
font-size: 1.2rem;
border-radius: 6px;
margin-left: 0.1rem;
margin-right: 0.1rem;
padding-top: 2px;
padding-bottom: 2px;
}
.surfer select {
font-size: 1.2rem;
}
.plus {
border-radius: 8px;
margin-left: 0.2rem;
margin-right: 0.2rem;
margin-bottom: 8px;
margin-top: 8px;
}
.surfers {
border: 1px solid #111;
background-color: yellow;
border-radius: 8px;
padding: 5px;
}
</style>