Converted to turborepo. Added socker server

This commit is contained in:
Thomas Cole 2023-03-13 14:57:13 -04:00
parent d6fc733167
commit 35f470d6e2
34 changed files with 11509 additions and 190 deletions

10
.eslintrc.js Normal file
View File

@ -0,0 +1,10 @@
module.exports = {
root: true,
// This tells ESLint to load the config from the package `eslint-config-custom`
extends: ["custom"],
settings: {
next: {
rootDir: ["apps/*/"],
},
},
};

28
apps/quippy/index.html Normal file
View File

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Quippy</title>
</head>
<body>
<script>
let theme = 'light';
if(window.matchMedia('(prefers-color-scheme: dark)').matches){
theme = 'dark';
}
document.body.classList.add(theme);
//Force light theme when printing. Then set it back after
window.addEventListener('beforeprint', () => {
document.body.classList.replace(theme, "light");
})
window.addEventListener('afterprint', ()=>{
document.body.classList.replace("light", theme);
})
</script>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

3355
apps/quippy/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

29
apps/quippy/package.json Normal file
View File

@ -0,0 +1,29 @@
{
"name": "quippy",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-check --tsconfig ./tsconfig.json"
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^2.0.2",
"@tsconfig/svelte": "^3.0.0",
"socket.io-client":"^4.6.1",
"svelte": "^3.55.1",
"svelte-check": "^2.10.3",
"tslib": "^2.5.0",
"typescript": "^4.9.3",
"vite": "^4.1.0"
},
"dependencies": {
"@dicebear/collection": "^5.3.4",
"@dicebear/core": "^5.3.4",
"beercss": "^3.0.8",
"pocketbase": "^0.12.0",
"svelte-spa-router": "^3.3.0"
}
}

View File

@ -0,0 +1 @@
https://unsplash.com/photos/Rbs7VW98G9A?utm_source=unsplash&utm_medium=referral&utm_content=creditShareLink

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,15 @@
<script lang="ts">
import Router from 'svelte-spa-router';
import {replace, location} from 'svelte-spa-router';
import routes from './lib/routes';
import { onMount } from 'svelte';
import {pb} from './lib/pocketbase';
onMount(()=>{
if(!pb.authStore.isValid && $location !== '/signup'){
replace('/login');
}
})
</script>
<Router {routes}/>

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1,8 @@
<script>
import Nav from "../lib/Nav.svelte";
</script>
<Nav />
<main class="responsive">
<slot />
</main>

View File

@ -0,0 +1,6 @@
<script>
</script>
<main class="responsive">
<slot />
</main>

View File

@ -0,0 +1,11 @@
<header>
<nav>
<button class="circle transparent">
<i>arrow_backward</i>
</button>
<h5 class="max">Title</h5>
<button class="circle transparent">
<i>more_vert</i>
</button>
</nav>
</header>

View File

@ -0,0 +1,76 @@
<script>
import { pb, currentUser } from "./pocketbase";
import { replace, location, link } from "svelte-spa-router";
import { createAvatar } from "@dicebear/core";
import { initials } from "@dicebear/collection";
const avatar = createAvatar(initials, {
seed: $currentUser.username,
});
const svg = avatar.toDataUriSync();
function logout() {
pb.authStore.clear();
replace("/login");
}
</script>
<nav class="m l left">
<!-- svelte-ignore a11y-missing-attribute -->
<a class="circle transparent">
{#if $currentUser.avatar}
<img class="circle" src={$currentUser.avatar} alt="avatar" />
{:else}
<img class="circle" src={svg} alt="avatar" />
{/if}
</a>
<!-- svelte-ignore a11y-missing-attribute -->
<a class:active={$location === "/"} href="/" use:link>
<i>home</i>
<span>Home</span>
</a>
<!-- svelte-ignore a11y-missing-attribute -->
<a class:active={$location === "/friends"} href="/" use:link>
<i>group</i>
<span>Friends</span>
</a>
<!-- svelte-ignore a11y-missing-attribute -->
<a class:active={$location === "/settings"} href="/" use:link>
<i>settings</i>
<span>Settings</span>
</a>
<div class="max" />
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-missing-attribute -->
<a on:click={logout}>
<!-- svelte-ignore a11y-missing-attribute -->
<i>logout</i>
<span>Logout</span>
</a>
</nav>
<nav class="s bottom">
<!-- svelte-ignore a11y-missing-attribute -->
<a class:active={$location === "/"} href="/" use:link>
<i>home</i>
<span>Home</span>
</a>
<!-- svelte-ignore a11y-missing-attribute -->
<a class:active={$location === "/friends"} href="/" use:link>
<i>group</i>
<span>Friends</span>
</a>
<!-- svelte-ignore a11y-missing-attribute -->
<a class:active={$location === "/settings"} href="/" use:link>
<i>manage_accounts</i>
<span>Account</span>
</a>
</nav>

View File

@ -4,9 +4,6 @@ import { writable } from 'svelte/store';
export const pb = new PocketBase("https://pb.thomaspcole.com")
export const currentUser = writable(pb.authStore.model);
console.log(pb)
pb.authStore.onChange((auth) => {
console.log('AuthStore Changed', auth);
currentUser.set(pb.authStore.model);
})

View File

@ -0,0 +1,13 @@
import Login from "../pages/Login.svelte";
import Home from "../pages/Home.svelte";
import Signup from "../pages/Signup.svelte";
import Play from '../pages/Play.svelte';
export default {
'/': Home,
'/login': Login,
'/signup': Signup,
'/play/': Play,
'/play/:id/': Play,
'*': Home
}

View File

@ -0,0 +1,10 @@
<script>
import BaseLayout from "../layouts/BaseLayout.svelte";
</script>
<BaseLayout>
<div class="space"></div>
<button class="responsive">New Game</button>
<div class="space"></div>
<button class="responsive">Join Game</button>
</BaseLayout>

View File

@ -0,0 +1,67 @@
<script lang="ts">
import { replace } from "svelte-spa-router";
import { pb } from "../lib/pocketbase";
import { onMount } from "svelte";
let username: string;
let password: string;
async function login() {
await pb.collection("users").authWithPassword(username, password);
replace("/");
}
function signup(){
replace("/signup")
}
onMount(() => {
if (pb.authStore.isValid) {
replace("/");
}
});
</script>
<main class="responsive">
<div class="absolute center middle">
<img
class="responsive small"
src="/vite.svg"
alt=""
style="object-fit: contain;"
/>
<div class="row">
<h3 class="center">Quippy</h3>
</div>
<div class="medium-divider" />
<div class="field label border">
<input type="text" bind:value={username} />
<!-- svelte-ignore a11y-label-has-associated-control -->
<label>Email</label>
</div>
<div class="field label border">
<input type="password" bind:value={password} />
<!-- svelte-ignore a11y-label-has-associated-control -->
<label>Password</label>
</div>
<button class="responsive" on:click={login}>Sign in</button>
<div class="small-divider"></div>
<div class="row" style="padding-top: .5rem;">
<p class="center">New to quippy?</p>
</div>
<div class="space"></div>
<button class="responsive border" on:click={signup}>Create an account</button>
</div>
</main>
<style>
main {
max-width: 95%;
}
div {
min-width: 50%;
}
</style>

View File

@ -0,0 +1,58 @@
<script>
export let params = {};
import { replace } from "svelte-spa-router";
import { onMount } from "svelte";
import GameLayout from "../layouts/GameLayout.svelte";
import { pb, currentUser } from "../lib/pocketbase";
import { createAvatar } from "@dicebear/core";
import { initials } from "@dicebear/collection";
import { io } from "socket.io-client";
const socket = io("ws://localhost:3000");
const avatar = createAvatar(initials, {
seed: $currentUser.username,
});
const svg = avatar.toDataUriSync();
onMount(() => {
if (!params.id) {
console.log("Attempted play without an ID. Returning home.");
replace("/");
}
console.log("Looking for game with id: " + params.id);
});
function makeAvatar(name){
return createAvatar(initials,{seed: name}).toDataUriSync();
}
</script>
<GameLayout>
<header class="round">
<nav>
<button class="circle transparent">
<i>arrow_backward</i>
</button>
<h5 class="max center-align">Quippy Room: {params.id}</h5>
<button class="circle transparent">
<i>more_vert</i>
</button>
</nav>
<h6>Players</h6>
<div class="small-divider"></div>
<div class="row">
{#if $currentUser.avatar}
<img class="circle" src={$currentUser.avatar} alt="avatar" />
{:else}
<img class="circle" src={svg} alt="avatar" />
{/if}
{#each ["foobar", "fizzbuzz", "John Doe"] as player}
<!-- svelte-ignore a11y-missing-attribute -->
<!-- svelte-ignore a11y-missing-content -->
<img class="circle" src={makeAvatar(player)}/>
{/each}
</div>
</header>
</GameLayout>

View File

@ -0,0 +1,128 @@
<script lang="ts">
import { pb } from "../lib/pocketbase";
import { onMount } from "svelte";
import { replace } from "svelte-spa-router";
let username: string;
let email: string;
let password: string;
let passwordConfirm: string;
let passwordField;
let passwordConfirmField;
let usernameField;
let emailField;
async function signup() {
if (password === passwordConfirm) {
try {
const data = {
username,
password,
passwordConfirm,
email,
};
const createdUser = await pb.collection("users").create(data);
await pb.collection("users").authWithPassword(email, password);
replace("/");
} catch (err) {
const errData = err.response.data;
if (errData.email) {
console.log("An account with that email already exists.");
emailField.classList.add("invalid");
}
if (errData.username) {
console.log("Invalid username");
usernameField.classList.add("invalid");
}
}
} else {
console.log("Passwords do not match!");
passwordField.classList.add("invalid");
passwordConfirmField.classList.add("invalid");
}
}
function generateUsername() {
username =
email.split("@")[0].replace(/[.,\/#!$%\^&\*;:{}=\-_`~()]/g, "") +
randomNumberofLength(3);
}
function randomNumberofLength(length) {
return Math.floor(
Math.pow(10, length - 1) +
Math.random() * (Math.pow(10, length) - Math.pow(10, length - 1) - 1)
);
}
onMount(() => {
username = "";
});
</script>
<main class="responsive">
<div class="absolute center middle">
<img
class="responsive small"
src="/vite.svg"
alt=""
style="object-fit: contain;"
/>
<div class="row">
<h3 class="center">Create a Quippy Account</h3>
</div>
<div class="medium-divider" />
<div class="field label border" bind:this={emailField}>
<input type="text" bind:value={email} on:change={generateUsername} />
<!-- svelte-ignore a11y-label-has-associated-control -->
<label>Email</label>
</div>
<div class="field label border suffix" bind:this={usernameField}>
<input
type="text"
bind:value={username}
class:clippath={username != ""}
/>
<!-- svelte-ignore a11y-label-has-associated-control -->
<label class:active={username != ""}>Username</label>
</div>
<div class="field label border" bind:this={passwordField}>
<input type="password" bind:value={password} />
<!-- svelte-ignore a11y-label-has-associated-control -->
<label>Password</label>
</div>
<div class="field label border" bind:this={passwordConfirmField}>
<input type="password" bind:value={passwordConfirm} />
<!-- svelte-ignore a11y-label-has-associated-control -->
<label>Confirm Password</label>
</div>
<button class="responsive" on:click={signup}>Create Account</button>
</div>
</main>
<style>
main {
max-width: 95%;
}
div {
min-width: 40%;
}
.clippath {
clip-path: polygon(
0% 0%,
0.75rem 0%,
0.75rem 0.5rem,
4.625rem 0.5rem,
4.625rem 0%,
100% 0%,
100% 100%,
0% 100%
);
}
</style>

16
apps/server/package.json Normal file
View File

@ -0,0 +1,16 @@
{
"name": "server",
"version": "0.0.1",
"description": "",
"scripts": {
"dev": "nodemon server.js",
"start": "node server.js"
},
"dependencies": {
"express":"^4.18.2",
"socket.io":"^4.6.1"
},
"devDependencies": {
"nodemon":"^2.0.21"
}
}

22
apps/server/server.js Normal file
View File

@ -0,0 +1,22 @@
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server, {
cors: {
origin: "http://localhost:5173"
}
});
app.get('/', (req, res) => {
res.send('<h1>Quippy Server</h1>');
});
io.on('connection', (socket) => {
console.log("SocketIO connected to a user.")
})
server.listen(3000, () => {
console.log('listening on *:3000');
});

View File

@ -1,13 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Svelte + TS</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

7748
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,25 +1,28 @@
{
"name": "quiplashclone",
"private": true,
"version": "0.0.0",
"type": "module",
"private": true,
"workspaces": [
"apps/*",
"packages/*"
],
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-check --tsconfig ./tsconfig.json"
"build": "turbo run build",
"dev": "turbo run dev --parallel",
"lint": "turbo run lint",
"format": "prettier --write \"**/*.{ts,tsx,md}\""
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^2.0.2",
"@tsconfig/svelte": "^3.0.0",
"svelte": "^3.55.1",
"svelte-check": "^2.10.3",
"tslib": "^2.5.0",
"typescript": "^4.9.3",
"vite": "^4.1.0"
"eslint-config-custom": "*",
"prettier": "latest",
"turbo": "latest"
},
"engines": {
"node": ">=14.0.0"
},
"dependencies": {
"beercss": "^3.0.8",
"pocketbase": "^0.12.0"
}
"esbuild": "^0.15.15",
"pocketbase": "^0.7.4"
},
"packageManager": "npm@8.19.2"
}

View File

@ -1,8 +0,0 @@
<script lang="ts">
import Login from './lib/Login.svelte';
</script>
<main>
<Login/>
</main>

View File

@ -1,24 +0,0 @@
<script lang="ts">
import {currentUser, pb} from './pocketbase';
let username: string;
let password: string;
async function login() {
await pb.collection('users').authWithPassword(username, password);
}
function signOut(){
pb.authStore.clear();
}
</script>
{#if $currentUser}
<p>Signed in as {$currentUser.username}</p>
{:else}
<form on:submit|preventDefault>
<input type="text" placeholder="Username" bind:value={username}>
<input type="text" placeholder="Password" bind:value={password}>
<button on:click={login}>Sign in</button>
</form>
{/if}

15
turbo.json Normal file
View File

@ -0,0 +1,15 @@
{
"$schema": "https://turborepo.org/schema.json",
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**"]
},
"lint": {
"outputs": []
},
"dev": {
"cache": false
}
}
}