Init back project
This commit is contained in:
13
front/src/app.d.ts
vendored
Normal file
13
front/src/app.d.ts
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
// See https://kit.svelte.dev/docs/types#app
|
||||
// for information about these interfaces
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface PageState {}
|
||||
// interface Platform {}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
28
front/src/app.html
Normal file
28
front/src/app.html
Normal file
@@ -0,0 +1,28 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Unluckiest</title>
|
||||
|
||||
<link rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css?family=Afacad+Flux">
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Afacad Flux', serif;
|
||||
font-size: 48px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<link rel="stylesheet" href="%sveltekit.assets%/style/app.css" />
|
||||
<link rel="stylesheet" href="%sveltekit.assets%/style/menu.css" />
|
||||
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
7
front/src/index.test.ts
Normal file
7
front/src/index.test.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
|
||||
describe('sum test', () => {
|
||||
it('adds 1 + 2 to equal 3', () => {
|
||||
expect(1 + 2).toBe(3);
|
||||
});
|
||||
});
|
||||
1
front/src/lib/assets/github-mark-white.svg
Normal file
1
front/src/lib/assets/github-mark-white.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="98" height="96" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 960 B |
1
front/src/lib/assets/twitter-mark-white.svg
Normal file
1
front/src/lib/assets/twitter-mark-white.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg fill="#FFFFFF" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" width="50px" height="50px"><path d="M 50.0625 10.4375 C 48.214844 11.257813 46.234375 11.808594 44.152344 12.058594 C 46.277344 10.785156 47.910156 8.769531 48.675781 6.371094 C 46.691406 7.546875 44.484375 8.402344 42.144531 8.863281 C 40.269531 6.863281 37.597656 5.617188 34.640625 5.617188 C 28.960938 5.617188 24.355469 10.21875 24.355469 15.898438 C 24.355469 16.703125 24.449219 17.488281 24.625 18.242188 C 16.078125 17.8125 8.503906 13.71875 3.429688 7.496094 C 2.542969 9.019531 2.039063 10.785156 2.039063 12.667969 C 2.039063 16.234375 3.851563 19.382813 6.613281 21.230469 C 4.925781 21.175781 3.339844 20.710938 1.953125 19.941406 C 1.953125 19.984375 1.953125 20.027344 1.953125 20.070313 C 1.953125 25.054688 5.5 29.207031 10.199219 30.15625 C 9.339844 30.390625 8.429688 30.515625 7.492188 30.515625 C 6.828125 30.515625 6.183594 30.453125 5.554688 30.328125 C 6.867188 34.410156 10.664063 37.390625 15.160156 37.472656 C 11.644531 40.230469 7.210938 41.871094 2.390625 41.871094 C 1.558594 41.871094 0.742188 41.824219 -0.0585938 41.726563 C 4.488281 44.648438 9.894531 46.347656 15.703125 46.347656 C 34.617188 46.347656 44.960938 30.679688 44.960938 17.09375 C 44.960938 16.648438 44.949219 16.199219 44.933594 15.761719 C 46.941406 14.3125 48.683594 12.5 50.0625 10.4375 Z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
72
front/src/lib/components/LeaderBoard.svelte
Normal file
72
front/src/lib/components/LeaderBoard.svelte
Normal file
@@ -0,0 +1,72 @@
|
||||
<script>
|
||||
|
||||
export let scores = []
|
||||
|
||||
</script>
|
||||
|
||||
<ul class="leaderboard">
|
||||
|
||||
{#each scores as score, i}
|
||||
<li class="item">
|
||||
<div class="name"><img src="" alt=""/> {score.playerName} </div><div class="score"> {score.value} pts.</div>
|
||||
</li>
|
||||
{/each}
|
||||
|
||||
</ul>
|
||||
|
||||
<style>
|
||||
|
||||
.leaderboard
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
width: 60vw;
|
||||
height: 65vh;
|
||||
|
||||
padding: 0 2vw 2vw 2vw;
|
||||
overflow: scroll;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.leaderboard::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
li
|
||||
{
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 1.25vh;
|
||||
margin: 1.5vh;
|
||||
border: 2px solid #A1674A;
|
||||
border-radius: 10px;
|
||||
background-color: #f1ecec;
|
||||
box-shadow: 0 0 10px #343232;
|
||||
}
|
||||
|
||||
li:hover
|
||||
{
|
||||
transform: scale(1.075);
|
||||
background-color: #F5F5F5;
|
||||
}
|
||||
|
||||
.name, .score
|
||||
{
|
||||
color: black;
|
||||
margin-left: 3vh;
|
||||
}
|
||||
|
||||
.name
|
||||
{
|
||||
flex-grow: 100;
|
||||
border-right: 1px solid #A1674A;
|
||||
}
|
||||
|
||||
.score
|
||||
{
|
||||
flex-grow: 20;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
</style>
|
||||
3
front/src/lib/components/ListItem.svelte
Normal file
3
front/src/lib/components/ListItem.svelte
Normal file
@@ -0,0 +1,3 @@
|
||||
<li class="item">
|
||||
<slot></slot>
|
||||
</li>
|
||||
36
front/src/lib/components/NavLink.svelte
Normal file
36
front/src/lib/components/NavLink.svelte
Normal file
@@ -0,0 +1,36 @@
|
||||
<script>
|
||||
|
||||
export let link = ""
|
||||
|
||||
</script>
|
||||
|
||||
<a class="bordered" href={link}>
|
||||
<slot/>
|
||||
</a>
|
||||
|
||||
<style>
|
||||
|
||||
a
|
||||
{
|
||||
color: #f1ecec;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
padding: 1vh 2vh;
|
||||
|
||||
width: var(--width, fit-content);
|
||||
height: var(--height, 3vh);
|
||||
|
||||
text-decoration: var(--text-decoration, none);
|
||||
margin-top: var(--margin-top, 0vh);
|
||||
|
||||
}
|
||||
|
||||
a:hover
|
||||
{
|
||||
transform: scale(1.1);
|
||||
color: #303633;
|
||||
}
|
||||
|
||||
</style>
|
||||
1
front/src/lib/index.ts
Normal file
1
front/src/lib/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
// place files you want to import through the `$lib` alias in this folder.
|
||||
11
front/src/lib/models/score.ts
Normal file
11
front/src/lib/models/score.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export class Score {
|
||||
|
||||
readonly playerName : string;
|
||||
readonly value: number;
|
||||
|
||||
constructor({playerName = "", value = 0}) {
|
||||
this.playerName = playerName;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
}
|
||||
34
front/src/lib/stores/scoreStore.ts
Normal file
34
front/src/lib/stores/scoreStore.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import {writable} from "svelte/store";
|
||||
import {Score} from "../models/score";
|
||||
import {browser} from "$app/environment"
|
||||
|
||||
let localStorageKey = "scores"
|
||||
|
||||
function isBrowser() {
|
||||
return typeof window !== 'undefined' && typeof window.localStorage !== 'undefined';
|
||||
}
|
||||
|
||||
function createStore(){
|
||||
|
||||
const storedValue = isBrowser() ? localStorage.getItem(localStorageKey) : null;
|
||||
|
||||
const { set, update, subscribe } = writable<Score[]>(!storedValue ? [] : JSON.parse(storedValue));
|
||||
|
||||
if (isBrowser()) subscribe(value => localStorage.setItem(localStorageKey, JSON.stringify(value)));
|
||||
|
||||
return {
|
||||
update,
|
||||
subscribe,
|
||||
set : (value : Score[]) => set(!value ? [] : value),
|
||||
reset : () => set([]),
|
||||
add : (playerName : string, value : number) => {
|
||||
update(scores => {
|
||||
let s = [...scores, new Score({playerName : playerName, value : value})];
|
||||
if(s.length >= 2) s.sort((s1 : Score, s2 : Score) => s1.value - s2.value)
|
||||
return s;
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const scoreStore = createStore();
|
||||
53
front/src/routes/+layout.svelte
Normal file
53
front/src/routes/+layout.svelte
Normal file
@@ -0,0 +1,53 @@
|
||||
<script>
|
||||
|
||||
import github_mark from '$lib/assets/github-mark-white.svg';
|
||||
import twitter_mark from '$lib/assets/twitter-mark-white.svg';
|
||||
|
||||
import {onMount} from "svelte";
|
||||
|
||||
onMount(async () => {
|
||||
const jQuery = await import('jquery');
|
||||
const $ = jQuery.default;
|
||||
|
||||
window.$ = $;
|
||||
window.jQuery = $;
|
||||
|
||||
window.$(".menu-collapsed").click(function () {
|
||||
window.$(this).toggleClass("menu-expanded");
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<div class="menu-collapsed">
|
||||
<div class="burger"></div>
|
||||
<nav>
|
||||
|
||||
<a href="/">Leaderboard</a>
|
||||
<a href="/play">Play</a>
|
||||
<a href="/about">About</a>
|
||||
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<slot></slot>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<a href="https://github.com/naaturel">
|
||||
<img
|
||||
src={github_mark}
|
||||
height="30"
|
||||
width="30"
|
||||
alt="Github mark"/>
|
||||
</a>
|
||||
|
||||
<a href="https://twitter.com/naaturel_">
|
||||
<img
|
||||
src="{twitter_mark}"
|
||||
height="30"
|
||||
width="30"
|
||||
alt="Twitter mark"/>
|
||||
</a>
|
||||
</footer>
|
||||
7
front/src/routes/+page.svelte
Normal file
7
front/src/routes/+page.svelte
Normal file
@@ -0,0 +1,7 @@
|
||||
<script>
|
||||
import {scoreStore} from "$lib/stores/scoreStore.ts"
|
||||
import LeaderBoard from "$lib/components/LeaderBoard.svelte";
|
||||
|
||||
</script>
|
||||
|
||||
<LeaderBoard bind:scores={$scoreStore}></LeaderBoard>
|
||||
1
front/src/routes/about/+page.svelte
Normal file
1
front/src/routes/about/+page.svelte
Normal file
@@ -0,0 +1 @@
|
||||
<p>It was revealed to me in a dream</p>
|
||||
116
front/src/routes/play/+page.svelte
Normal file
116
front/src/routes/play/+page.svelte
Normal file
@@ -0,0 +1,116 @@
|
||||
<script>
|
||||
|
||||
import {onMount} from "svelte";
|
||||
import {scoreStore} from "$lib/stores/scoreStore.ts";
|
||||
|
||||
let playerName = undefined;
|
||||
let range = 100;
|
||||
let result = 0;
|
||||
|
||||
onMount(async () => {
|
||||
const jQuery = await import('jquery');
|
||||
const $ = jQuery.default;
|
||||
|
||||
window.$ = $;
|
||||
window.jQuery = $;
|
||||
});
|
||||
|
||||
async function roll() {
|
||||
|
||||
toggleLoading();
|
||||
|
||||
result = Math.floor(Math.random() * (range + 1));
|
||||
|
||||
await new Promise(r => setTimeout(r, 3000));
|
||||
|
||||
toggleLoading();
|
||||
window.$(".result").text(`Result : ${result}/${range}`)
|
||||
|
||||
scoreStore.add(playerName, result)
|
||||
}
|
||||
|
||||
function toggleLoading(){
|
||||
window.$(".loader").toggleClass("disabled");
|
||||
window.$(".player").toggleClass("disabled");
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
<div class="loader disabled">
|
||||
<svg class="circular-loader" viewBox="0 0 30 30">
|
||||
<circle class="loader-path" cx="15" cy="15" r="5" fill="none" stroke="#f1ecec" stroke-width="0.7" />
|
||||
</svg>
|
||||
<div class="info">Rolling a random numbers within range 0-{range}...</div>
|
||||
</div>
|
||||
|
||||
<div class="player">
|
||||
<input class="name" placeholder="Your name" bind:value={playerName}/>
|
||||
<button on:click={roll}>Let's roll !</button>
|
||||
<div class="result"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
.container, .player
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.disabled
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.player
|
||||
{
|
||||
gap: 2vh;
|
||||
}
|
||||
|
||||
.name
|
||||
{
|
||||
width: 17vw;
|
||||
height: 6vh;
|
||||
border: 2px solid #A1674A;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 0 10px #343232;
|
||||
}
|
||||
|
||||
.circular-loader
|
||||
{
|
||||
stroke-dasharray: 100, 125;
|
||||
stroke-dashoffset: -5;
|
||||
animation: rotate 2s ease-in-out infinite;
|
||||
stroke-linecap: round;
|
||||
}
|
||||
|
||||
.loader-path {
|
||||
width: 25vw;
|
||||
height: 25vh;
|
||||
}
|
||||
|
||||
button
|
||||
{
|
||||
color: black;
|
||||
width: 18vw;
|
||||
height: 15vh;
|
||||
border-radius: 10px;
|
||||
background-color: #f1ecec;
|
||||
border: 2px solid #A1674A;
|
||||
box-shadow: 0 0 10px #343232;
|
||||
}
|
||||
|
||||
.name:hover, button:hover{
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
@keyframes rotate {
|
||||
to{transform: rotate(360deg)}
|
||||
}
|
||||
|
||||
</style>
|
||||
Reference in New Issue
Block a user