light app

This commit is contained in:
Miki 2024-01-10 16:21:12 +01:00
parent 4f18d6448f
commit 09b5a101de
23 changed files with 2549 additions and 0 deletions

8
backend.light/main.go Normal file
View file

@ -0,0 +1,8 @@
package main
func main() {
app := InitHttp()
app.Run()
}

View file

@ -0,0 +1,13 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock

View file

@ -0,0 +1,15 @@
/** @type { import("eslint").Linter.Config } */
module.exports = {
root: true,
extends: ['eslint:recommended', 'plugin:svelte/recommended', 'prettier'],
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020,
extraFileExtensions: ['.svelte']
},
env: {
browser: true,
es2017: true,
node: true
}
};

10
frontend.light/.gitignore vendored Normal file
View file

@ -0,0 +1,10 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*

1
frontend.light/.npmrc Normal file
View file

@ -0,0 +1 @@
engine-strict=true

View file

@ -0,0 +1,4 @@
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock

View file

@ -0,0 +1,8 @@
{
"useTabs": true,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100,
"plugins": ["prettier-plugin-svelte"],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
}

38
frontend.light/README.md Normal file
View file

@ -0,0 +1,38 @@
# create-svelte
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).
## Creating a project
If you're seeing this, you've probably already done this step. Congrats!
```bash
# create a new project in the current directory
npm create svelte@latest
# create a new project in my-app
npm create svelte@latest my-app
```
## Developing
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```bash
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
```
## Building
To create a production version of your app:
```bash
npm run build
```
You can preview the production build with `npm run preview`.
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.

View file

@ -0,0 +1,27 @@
{
"name": "frontend.light",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "vite dev --host",
"build": "vite build",
"preview": "vite preview",
"lint": "prettier --check . && eslint .",
"format": "prettier --write ."
},
"devDependencies": {
"@sveltejs/adapter-auto": "^3.0.0",
"@sveltejs/adapter-static": "^3.0.1",
"@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"@types/eslint": "8.56.0",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.35.1",
"prettier": "^3.1.1",
"prettier-plugin-svelte": "^3.1.2",
"svelte": "^4.2.7",
"vite": "^5.0.3"
},
"type": "module"
}

1622
frontend.light/pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>

View file

@ -0,0 +1 @@
// place files you want to import through the `$lib` alias in this folder.

View file

@ -0,0 +1,11 @@
import { readable } from "svelte/store"
export const colors = readable([
"black",
"blue",
"red",
"green",
"yellow",
"pink",
"white",
]);

View file

@ -0,0 +1,29 @@
import { writable } from 'svelte/store';
function createSurfers() {
const { subscribe, set, update } = writable([
{ color: 'lightgray', priority: '', name: '' },
{ color: 'lightgray', priority: '', name: '' },
{ color: 'lightgray', priority: '', name: '' },
{ color: 'lightgray', priority: '', name: '' },
{ color: 'lightgray', priority: '', name: '' },
{ color: 'lightgray', priority: '', name: '' },
])
return {
subscribe,
set,
update,
reset: () => set([
{ color: 'lightgray', priority: '', name: '' },
{ color: 'lightgray', priority: '', name: '' },
{ color: 'lightgray', priority: '', name: '' },
{ color: 'lightgray', priority: '', name: '' },
{ color: 'lightgray', priority: '', name: '' },
{ color: 'lightgray', priority: '', name: '' },
]),
}
}
export const surfers = createSurfers()
export const surfersCount = writable(4)

View file

@ -0,0 +1,3 @@
export const prerender = true;
export const ssr = false;
export const trailingSlash = 'always';

View file

@ -0,0 +1,2 @@
<h1>Welcome to SvelteKit</h1>
<p>Visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to read the documentation</p>

View file

@ -0,0 +1,110 @@
<script>
import { dev } from '$app/environment';
import { onMount } from 'svelte';
import { surfers, surfersCount } from '$lib/stores/surfers.js';
if (dev) {
console.log('Dev mode');
} else {
console.log('Not dev mode');
}
onMount(async () => {
if (!dev) {
const sse = StartSSE();
return sse;
}
});
function StartSSE() {
let url = '/api/sse?';
for (let e in events) {
url += `event=${events[e]}&`;
}
console.log(`sse url: ${url}`);
const sse = new EventSource(url);
console.log(`subscribe: ${sse}`);
sse.onopen = () => {
console.log(`sse open ${now()}`);
};
sse.addEventListener('priority', (e) => {
let Msg = JSON.parse(e.data);
console.log(JSON.stringify(Msg));
});
return () => {
sse.close();
console.log(`sse closing ${Date.now()}`);
};
}
</script>
<ul>
{#each Array($surfersCount) as _, id}
<li>
{#if $surfers[id].priority == 'P'}
<div class="priority" id="p">{$surfers[id].priority}</div>
{:else}
<div class="priority" id="n">{$surfers[id].priority}</div>
{/if}
<div class="color" style="background-color: {$surfers[id].color}"></div>
</li>
{/each}
</ul>
<style>
:global(body) {
overflow-y: hidden;
overflow-x: hidden;
margin: 0.2vmin;
align-content: center;
justify-content: center;
}
ul {
margin: 0;
padding: 0;
}
li {
display: flex;
flex-direction: row;
/* border: 2px solid black; */
/* min-height: 18.8vh; */
/* width: 99.4vw; */
margin-top: 0.2vh;
margin-bottom: 0.2vh;
overflow: hidden;
}
.priority {
text-align: center;
align-self: center;
min-height: 19vh;
min-width: 19vh;
/* border-right: 2px solid gray; */
margin-right: 0.2vw;
background-color: gray;
}
.priority#p {
font-size: 16vmin;
background-color: lightgray;
height: 100%;
}
.priority#n {
font-size: 14vmin;
height: 100%;
}
.color {
width: 100vw;
}
</style>

View file

@ -0,0 +1,156 @@
<script>
// import { page } from '$app/stores';
import { onMount } from 'svelte';
import { dev } from '$app/environment';
import { surfers, surfersCount } from '$lib/stores/surfers.js';
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;
const pad2 = (number) => `00${number}`.slice(-2);
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;
});
</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>
<ul>
{#each Array($surfersCount) as _, id}
<li>
{#if $surfers[id].priority == 'P'}
<div class="priority" id="p">{$surfers[id].priority}</div>
{:else}
<div class="priority" id="n">{$surfers[id].priority}</div>
{/if}
<div class="color" style="background-color: {$surfers[id].color}"></div>
</li>
{/each}
</ul>
<!-- {#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);
}
:global(body) {
overflow-y: hidden;
overflow-x: hidden;
margin: 0.2vmin;
align-content: center;
justify-content: center;
}
.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;
}
ul {
margin: 0;
padding: 0;
}
li {
display: flex;
flex-direction: row;
margin-top: 0.2vh;
margin-bottom: 0.2vh;
overflow: hidden;
}
.priority {
text-align: center;
align-self: center;
min-height: 19vh;
min-width: 19vh;
margin-right: 0.2vw;
background-color: gray;
}
.priority#p {
font-size: 16vmin;
background-color: lightgray;
height: 100%;
}
.priority#n {
font-size: 14vmin;
height: 100%;
}
.color {
width: 100vw;
}
</style>

View file

@ -0,0 +1,116 @@
<script>
import { dev } from '$app/environment';
import { onMount } from 'svelte';
import { surfers, surfersCount } from '$lib/stores/surfers.js';
if (dev) {
console.log('Dev mode');
} else {
console.log('Not dev mode');
}
onMount(async () => {
if (!dev) {
const sse = StartSSE();
return sse;
}
});
function StartSSE() {
let url = '/api/sse?';
for (let e in events) {
url += `event=${events[e]}&`;
}
console.log(`sse url: ${url}`);
const sse = new EventSource(url);
console.log(`subscribe: ${sse}`);
sse.onopen = () => {
console.log(`sse open ${now()}`);
};
sse.addEventListener('priority', (e) => {
let Msg = JSON.parse(e.data);
console.log(JSON.stringify(Msg));
});
return () => {
sse.close();
console.log(`sse closing ${Date.now()}`);
};
}
</script>
<div class="wall">
{#each Array($surfersCount) as _, id}
<div class="column">
{#if $surfers[id].priority == 'P'}
<div class="priority" id="p">{$surfers[id].priority}</div>
{:else}
<div class="priority" id="n">{$surfers[id].priority}</div>
{/if}
<div class="color" style="background-color: {$surfers[id].color}"></div>
</div>
{/each}
</div>
<style>
:global(body) {
overflow-y: hidden;
}
.wall {
display: flex;
margin: 0;
padding: 0;
}
.column {
display: flex;
flex-direction: column;
flex-grow: 1;
height: 97vh;
margin-right: 0.1vw;
margin-left: 0.1vw;
overflow: hidden;
flex-basis: 0;
/* border: 2px solid black; */
}
.column:first-child {
margin-left: 0;
}
.column:last-child {
margin-right: 0;
}
.priority {
text-align: center;
align-self: center;
line-height: 24vh;
overflow: hidden;
/* border-bottom: 2px solid black; */
}
.priority#p {
font-size: 18vmin;
background-color: lightgray;
width: 100%;
margin-bottom: 0.1vh;
}
.priority#n {
font-size: 14vmin;
background-color: gray;
width: 100%;
margin-bottom: 0.1vh;
}
.color {
flex-grow: 1;
}
</style>

View file

@ -0,0 +1,335 @@
<script>
import { onMount } from 'svelte';
import { surfers, surfersCount } from '$lib/stores/surfers.js';
import { colors } from '$lib/stores/colors.js';
import { dev } from '$app/environment';
if (dev) {
console.log('Dev mode');
} else {
console.log('Not dev mode');
}
const events = ['priority'];
$: start = false;
// $: surfers_tot = 6;
let footer_height = 8;
$: setup_height = ((100 - footer_height) / $surfersCount) - (2.2 / $surfersCount);
$: if (start && $surfers) {
window.sessionStorage.setItem('priority', JSON.stringify($surfers));
window.sessionStorage.setItem('surfers', JSON.stringify($surfersCount));
window.sessionStorage.setItem('status', JSON.stringify(start));
console.log(`saved: ${JSON.stringify($surfers)}`);
}
onMount(async () => {
let ses = window.sessionStorage.getItem('priority');
if (ses) {
$surfers = JSON.parse(ses);
$surfersCount = JSON.parse(window.sessionStorage.getItem('surfers'));
start = JSON.parse(window.sessionStorage.getItem('status'));
console.log(`loaded: ${JSON.stringify($surfers)}`);
}
if (!dev) {
const sse = StartSSE();
return sse;
}
});
function hasDuplicateColors() {
const colors = [];
console.log(JSON.stringify($surfers));
for (let i = 0; i < $surfersCount; i++) {
const color = $surfers[i].color;
if (colors.includes(color)) {
console.log(`duplicate color: ${color}`);
return true;
}
colors.push(color);
}
return false;
}
function ResetPriority() {
for (let i = 0; i < $surfersCount; i++) {
$surfers[i].priority = '';
}
}
function StartHeat() {
if (hasDuplicateColors()) {
alert('Duplicate colors');
return;
}
ResetPriority();
start = true;
}
function StopHeat() {
window.sessionStorage.clear();
start = false;
}
function AddSurfer() {
if ($surfersCount < 6) {
$surfersCount += 1;
}
}
function RemSurfer() {
if ($surfersCount > 2) {
$surfersCount -= 1;
}
}
function ResetSurfer() {
window.sessionStorage.clear();
location.reload();
}
async function ChangePriority(id) {
console.log($surfers[id]);
if ($surfers[id].priority === 'P') {
for (let i=0; i<$surfersCount; i++) {
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 = $surfersCount.toString();
} else if ($surfers[id].priority === '') {
console.log(`priority empty; pressed: [${id}] ${$surfers[id].priority}`);
for (let i=0; i<$surfersCount; i++) {
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 = $surfersCount.toString();
}
} else {
console.log(`pressed: [${id}] ${$surfers[id].priority}`);
let oldpos = parseInt($surfers[id].priority);
for (let i=0; i<$surfersCount; i++) {
if (i != id) {
console.log(`pos: [${i}] ${$surfers[i].priority} ${$surfers[i].priority > oldpos}`);
if ($surfers[i].priority != 'P') {
let pos = parseInt($surfers[i].priority);
if (pos > oldpos) {
console.log(`newpos: ${$surfers[i].priority}`);
$surfers[i].priority = (pos - 1).toString();
}
}
} else {
$surfers[i].priority = $surfersCount.toString();
console.log(`last: [${i}] ${$surfers[i].priority}`);
}
}
}
if (!dev) {
const res = await fetch(`/api/priority`, {
method: 'POST',
body: JSON.stringify({
priority: $surfers.map((obj) => obj.priority)
}),
headers: {
'Content-Type': 'application/json'
}
});
console.log(`retval: ${JSON.stringify(res)}`);
}
}
function StartSSE() {
let url = '/api/sse?';
for (let e in events) {
url += `event=${events[e]}&`;
}
console.log(`sse url: ${url}`);
const sse = new EventSource(url);
console.log(`subscribe: ${sse}`);
sse.onopen = () => {
console.log(`sse open ${now()}`);
};
sse.addEventListener('priority', (e) => {
let Msg = JSON.parse(e.data);
console.log(JSON.stringify(Msg));
});
return () => {
sse.close();
console.log(`sse closing ${Date.now()}`);
};
}
</script>
{#if start}
<ul>
{#each Array($surfersCount) as _, id}
<li style="--height:{setup_height}vh">
{#if $surfers[id].priority == 'P'}
<div class="priority" id="p" on:click={() => ChangePriority(id)} on:keypress={() => ChangePriority(id)} role="button" tabindex="-1">{$surfers[id].priority}</div>
{:else}
<div class="priority" id="n" on:click={() => ChangePriority(id)} on:keypress={() => ChangePriority(id)} role="button" tabindex="-1">{$surfers[id].priority}</div>
{/if}
<div class="color" style:background-color={$surfers[id].color}>
</div>
</li>
{/each}
</ul>
<div class="footer" style="--height:{footer_height}vh">
<button class="button" on:click={StopHeat}>STOP</button>
</div>
{:else}
<ul>
{#each Array($surfersCount) as _, id}
<li style="--height:{setup_height}vh">
<div class="priority" id="color">
<select name="color{id}" id="{id}" bind:value={$surfers[id].color} style="background-color: {$surfers[id].color};">
{#each $colors as color}
<option value="{color}" style="background-color: {color}"></option>
{/each}
</select>
</div>
<div class="color" style:background-color={$surfers[id].color}></div>
</li>
{/each}
</ul>
<div class="footer" style="--height:{footer_height}vh">
<div class="control">
<button class="button" on:click={AddSurfer}>+</button>
<button class="display">{$surfersCount}</button>
<button class="button" on:click={RemSurfer}>-</button>
</div>
<button class="button" on:click={StartHeat}>START</button>
<div class="command">
<button class="button" on:click={ResetSurfer}>Reset</button>
</div>
</div>
{/if}
<style>
:global(body) {
overflow-y: hidden;
overflow-x: hidden;
margin: 0.2vmin;
align-content: center;
justify-content: center;
}
ul {
margin: 0;
padding: 0;
}
li {
display: flex;
flex-direction: row;
margin-top: 0.2vh;
margin-bottom: 0.2vh;
overflow: hidden;
height: var(--height);
}
.priority {
text-align: center;
align-self: center;
min-height: var(--height);
min-width: var(--height);
margin-right: 0.2vw;
background-color: gray;
}
.priority#p {
font-size: 16vmin;
background-color: lightgray;
height: 100%;
}
.priority#n {
font-size: 14vmin;
height: 100%;
}
.priority#color {
background-color: lightgrey;
margin: 0 auto;
display: flex;
justify-content: center;
align-items: center;
}
.priority#color select {
width: 100%;
/* margin-top: 40%; */
font-size: 6vmin;
}
.color {
width: 100vw;
}
.footer {
display: inline-flex;
bottom: 0;
background-color: darkgrey;
/* border: 2px solid black; */
width: 100%;
height: var(--height);
justify-content: center;
align-items: center;
}
.control {
margin-left: 0;
margin-right: auto;
}
.command {
margin-left: auto;
margin-right: 0;
}
.display {
margin-left: 1vmin;
margin-right: 1vmin;
font-size: 2.5vmin;
}
.button {
margin-left: 1vmin;
margin-right: 1vmin;
border-radius: 4px;
border-style: inset;
font-size: 2.5vmin;
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -0,0 +1,22 @@
//import adapter from '@sveltejs/adapter-auto';
import adapter from '@sveltejs/adapter-static';
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
adapter: adapter(
{
pages: '../backend.light/static',
assets: '../backend.light/static',
fallback: 'index.html',
precompress: true,
strict: true
}
)
}
};
export default config;

View file

@ -0,0 +1,6 @@
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [sveltekit()]
});