merge both repos! atempt 1 by making the file system the same!
This commit is contained in:
parent
badb303ea6
commit
2fe58ee6be
128 changed files with 2320 additions and 4285 deletions
2
.env.example
Normal file
2
.env.example
Normal file
|
@ -0,0 +1,2 @@
|
|||
VITE_SUPABASE_URL=https://yourproject.supabase.co
|
||||
VITE_SUPABASE_ANON_KEY=your-service-role-key
|
42
.gitignore
vendored
42
.gitignore
vendored
|
@ -1,22 +1,26 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
# Output
|
||||
.output
|
||||
.vercel
|
||||
.netlify
|
||||
.wrangler
|
||||
/.svelte-kit
|
||||
/build
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
Thumbs.db
|
||||
|
||||
# Env
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
!.env.test
|
||||
|
||||
# Vite
|
||||
vite.config.js.timestamp-*
|
||||
vite.config.ts.timestamp-*
|
||||
|
||||
|
||||
package-lock.json
|
||||
|
|
1
.npmrc
Normal file
1
.npmrc
Normal file
|
@ -0,0 +1 @@
|
|||
engine-strict=true
|
4
.prettierignore
Normal file
4
.prettierignore
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Package Managers
|
||||
package-lock.json
|
||||
pnpm-lock.yaml
|
||||
yarn.lock
|
15
.prettierrc
Normal file
15
.prettierrc
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"useTabs": true,
|
||||
"singleQuote": false,
|
||||
"trailingComma": "all",
|
||||
"printWidth": 100,
|
||||
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.svelte",
|
||||
"options": {
|
||||
"parser": "svelte"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"recommendations": ["svelte.svelte-vscode", "esbenp.prettier-vscode"]
|
||||
}
|
10
.vscode/settings.json
vendored
10
.vscode/settings.json
vendored
|
@ -1,7 +1,9 @@
|
|||
{
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"[svelte]": {
|
||||
"editor.defaultFormatter": "svelte.svelte-vscode"
|
||||
"tailwindCSS.emmetCompletions": true,
|
||||
"editor.inlineSuggest.enabled": true,
|
||||
"editor.quickSuggestions": {
|
||||
"strings": true
|
||||
},
|
||||
"cSpell.words": ["Kahoot", "kokoro"]
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"css.customData": [".vscode/tailwind.json"]
|
||||
}
|
||||
|
|
96
.vscode/tailwind.json
vendored
Normal file
96
.vscode/tailwind.json
vendored
Normal file
|
@ -0,0 +1,96 @@
|
|||
{
|
||||
"version": 1.2,
|
||||
"atDirectives": [
|
||||
{
|
||||
"name": "@theme",
|
||||
"description": "Use the `@theme` directive to define your project's custom design tokens, like fonts, colors, and breakpoints.",
|
||||
"references": [
|
||||
{
|
||||
"name": "Tailwind Documentation",
|
||||
"url": "https://tailwindcss.com/docs/functions-and-directives#theme-directive"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "@source",
|
||||
"description": "Use the `@source` directive to explicitly specify source files that aren't picked up by Tailwind's automatic content detection.",
|
||||
"references": [
|
||||
{
|
||||
"name": "Tailwind Documentation",
|
||||
"url": "https://tailwindcss.com/docs/functions-and-directives#source-directive"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "@utility",
|
||||
"description": "Use the `@utility` directive to add custom utilities to your project that work with variants like `hover`, `focus` and `lg`.",
|
||||
"references": [
|
||||
{
|
||||
"name": "Tailwind Documentation",
|
||||
"url": "https://tailwindcss.com/docs/functions-and-directives#utility-directive"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "@variant",
|
||||
"description": "Use the `@variant` directive to apply a Tailwind variant to styles in your CSS.",
|
||||
"references": [
|
||||
{
|
||||
"name": "Tailwind Documentation",
|
||||
"url": "https://tailwindcss.com/docs/functions-and-directives#variant-directive"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "@custom-variant",
|
||||
"description": "Use the `@custom-variant` directive to add a custom variant in your project.",
|
||||
"references": [
|
||||
{
|
||||
"name": "Tailwind Documentation",
|
||||
"url": "https://tailwindcss.com/docs/functions-and-directives#custom-variant-directive"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "@apply",
|
||||
"description": "Use the `@apply` directive to inline any existing utility classes into your own custom CSS.",
|
||||
"references": [
|
||||
{
|
||||
"name": "Tailwind Documentation",
|
||||
"url": "https://tailwindcss.com/docs/functions-and-directives#apply-directive"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "@reference",
|
||||
"description": "If you want to use `@apply` or `@variant` in the `<style>` block of a Vue or Svelte component, or within CSS modules, you will need to import your theme variables, custom utilities, and custom variants to make those values available in that context.\n\nTo do this without duplicating any CSS in your output, use the `@reference` directive to import your main stylesheet for reference without actually including the styles.",
|
||||
"references": [
|
||||
{
|
||||
"name": "Tailwind Documentation",
|
||||
"url": "https://tailwindcss.com/docs/functions-and-directives#reference-directive"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "@config",
|
||||
"description": "Use the `@config` directive to load a legacy JavaScript-based configuration file.",
|
||||
"references": [
|
||||
{
|
||||
"name": "Tailwind Documentation",
|
||||
"url": "https://tailwindcss.com/docs/functions-and-directives#config-directive"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "@plugin",
|
||||
"description": "Use the `@plugin` directive to load a legacy JavaScript-based plugin.",
|
||||
"references": [
|
||||
{
|
||||
"name": "Tailwind Documentation",
|
||||
"url": "https://tailwindcss.com/docs/functions-and-directives#plugin-directive"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
3
eslint.config.js
Normal file
3
eslint.config.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import prettier from 'eslint-config-prettier';
|
||||
import svelte from 'eslint-plugin-svelte';
|
||||
export default [prettier, ...svelte.configs.prettier];
|
30
index.html
30
index.html
|
@ -1,30 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" style="height: 100%; margin: 0; padding: 0">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@200&family=Sour+Gummy:ital,wght@0,100..900;1,100..900&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<script
|
||||
src="https://drag-drop-touch-js.github.io/dragdroptouch/dist/drag-drop-touch.esm.min.js"
|
||||
type="module"
|
||||
></script>
|
||||
</head>
|
||||
<body style="height: 100%; margin: 0; padding: 0">
|
||||
<div id="app" style="height: 100%"></div>
|
||||
<script type="module">
|
||||
import { mount } from "svelte";
|
||||
import App from "./src/app.svelte";
|
||||
|
||||
const app = mount(App, {
|
||||
target: document.getElementById("app"),
|
||||
});
|
||||
|
||||
export default app;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,35 +1,14 @@
|
|||
{
|
||||
"extends": "./.svelte-kit/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "bundler",
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
/**
|
||||
* svelte-preprocess cannot figure out whether you have
|
||||
* a value or a type, so tell TypeScript to enforce using
|
||||
* `import type` instead of `import` for Types.
|
||||
*/
|
||||
"verbatimModuleSyntax": true,
|
||||
"isolatedModules": true,
|
||||
"resolveJsonModule": true,
|
||||
/**
|
||||
* To have warnings / errors of the Svelte compiler at the
|
||||
* correct position, enable source maps by default.
|
||||
*/
|
||||
"sourceMap": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
/**
|
||||
* Typecheck JS in `.svelte` and `.js` files by default.
|
||||
* Disable this if you'd like to use dynamic types.
|
||||
*/
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"types": ["svelte", "estree"],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"**/node_modules/*",
|
||||
".git",
|
||||
"**/*",
|
||||
"!src/wordle/**/*"
|
||||
]
|
||||
}
|
||||
"moduleResolution": "bundler"
|
||||
},
|
||||
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
|
||||
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
|
||||
//
|
||||
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
|
||||
// from the referenced tsconfig.json - TypeScript does not merge them in
|
||||
"exclude": ["**/node_modules/**", "**/build/**", "**/.svelte-kit/**", "**/out/**", "!src/**"],
|
||||
}
|
||||
|
|
2223
package-lock.json
generated
2223
package-lock.json
generated
File diff suppressed because it is too large
Load diff
47
package.json
47
package.json
|
@ -1,25 +1,42 @@
|
|||
{
|
||||
"name": "package",
|
||||
"name": "kahootclone",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
"preview": "vite preview",
|
||||
"prepare": "svelte-kit sync || echo ''",
|
||||
"format": "prettier --write .",
|
||||
"lint": "prettier --check . && eslint ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
||||
"@types/estree": "^1.0.6",
|
||||
"svelte": "^5.20.2",
|
||||
"vite": "^6.3.4"
|
||||
"@eslint/compat": "^1.2.5",
|
||||
"@eslint/js": "^9.18.0",
|
||||
"@sveltejs/adapter-static": "^3.0.8",
|
||||
"@sveltejs/kit": "^2.16.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^5.0.0",
|
||||
"@tailwindcss/vite": "^4.0.0",
|
||||
"eslint": "^9.18.0",
|
||||
"eslint-config-prettier": "^10.0.1",
|
||||
"eslint-plugin-svelte": "^3.0.0",
|
||||
"globals": "^16.0.0",
|
||||
"prettier": "^3.4.2",
|
||||
"prettier-plugin-svelte": "^3.3.3",
|
||||
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||
"svelte": "^5.0.0",
|
||||
"tailwindcss": "^4.0.0",
|
||||
"vite": "^6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"chart.js": "^4.4.9",
|
||||
"drag-drop-touch": "^1.3.1",
|
||||
"kokoro-js": "^1.2.1",
|
||||
"random-words": "^2.0.1",
|
||||
"svelte-spa-router": "^4.0.1",
|
||||
"word-exists": "^1.0.0"
|
||||
"dependencies": {
|
||||
"@supabase/supabase-js": "^2.49.4",
|
||||
"@sveltejs/adapter-static": "^3.0.8",
|
||||
"chart.js": "^4.4.9",
|
||||
"js-confetti": "^0.12.0",
|
||||
"random-words": "^2.0.1",
|
||||
"svelte-5-french-toast": "^2.0.4",
|
||||
"word-exists": "^1.0.0"
|
||||
|
||||
}
|
||||
}
|
||||
|
|
19
readme.md
19
readme.md
|
@ -1,19 +0,0 @@
|
|||
# ClassRoomStuff
|
||||
|
||||

|
||||
|
||||
A collection of awesome tools, games, and more — made to be used in any classroom!
|
||||
|
||||
A project by [RezHackXYZ](https://rezhack.xyz) for [Neighborhood](https://neighborhood.hackclub.com/)
|
||||
|
||||
[Try Now](https://edu.rezhack.xyz/) • [Repo for Kahhot Clone in the project](https://github.com/RezHackXYZ/KahootClone)
|
||||
|
||||
---
|
||||
|
||||
## The "Stuff" in it
|
||||
|
||||
1. **DaKahootClone** — The best ever kahoot clone (code in [different repo](https://github.com/RezHackXYZ/KahootClone))
|
||||
2. **Timetable** — Clock included!
|
||||
3. **Name selector** — For any class activity!
|
||||
4. **Wordle** — Challenge your vocabulary!
|
||||
5. **Announcer** — To shout from the speakers!
|
316
src/Confetti.js
316
src/Confetti.js
|
@ -1,316 +0,0 @@
|
|||
export function confettiAnimation() {
|
||||
(() => {
|
||||
"use strict";
|
||||
|
||||
// Utility functions grouped into a single object
|
||||
const Utils = {
|
||||
// Parse pixel values to numeric values
|
||||
parsePx: (value) => parseFloat(value.replace(/px/, "")),
|
||||
|
||||
// Generate a random number between two values, optionally with a fixed precision
|
||||
getRandomInRange: (min, max, precision = 0) => {
|
||||
const multiplier = Math.pow(10, precision);
|
||||
const randomValue = Math.random() * (max - min) + min;
|
||||
return Math.floor(randomValue * multiplier) / multiplier;
|
||||
},
|
||||
|
||||
// Pick a random item from an array
|
||||
getRandomItem: (array) =>
|
||||
array[Math.floor(Math.random() * array.length)],
|
||||
|
||||
// Scaling factor based on screen width
|
||||
getScaleFactor: () => Math.log(window.innerWidth) / Math.log(1920),
|
||||
|
||||
// Debounce function to limit event firing frequency
|
||||
debounce: (func, delay) => {
|
||||
let timeout;
|
||||
return (...args) => {
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(() => func(...args), delay);
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
// Precomputed constants
|
||||
const DEG_TO_RAD = Math.PI / 180;
|
||||
|
||||
// Centralized configuration for default values
|
||||
const defaultConfettiConfig = {
|
||||
confettiesNumber: 250,
|
||||
confettiRadius: 6,
|
||||
confettiColors: [
|
||||
"#fcf403",
|
||||
"#62fc03",
|
||||
"#f4fc03",
|
||||
"#03e7fc",
|
||||
"#03fca5",
|
||||
"#a503fc",
|
||||
"#fc03ad",
|
||||
"#fc03c2",
|
||||
],
|
||||
emojies: [],
|
||||
svgIcon: null, // Example SVG link
|
||||
};
|
||||
|
||||
// Confetti class representing individual confetti pieces
|
||||
class Confetti {
|
||||
constructor({
|
||||
initialPosition,
|
||||
direction,
|
||||
radius,
|
||||
colors,
|
||||
emojis,
|
||||
svgIcon,
|
||||
}) {
|
||||
const speedFactor =
|
||||
Utils.getRandomInRange(0.9, 1.7, 3) *
|
||||
Utils.getScaleFactor();
|
||||
this.speed = { x: speedFactor, y: speedFactor };
|
||||
this.finalSpeedX = Utils.getRandomInRange(0.2, 0.6, 3);
|
||||
this.rotationSpeed =
|
||||
emojis.length || svgIcon
|
||||
? 0.01
|
||||
: Utils.getRandomInRange(0.03, 0.07, 3) *
|
||||
Utils.getScaleFactor();
|
||||
this.dragCoefficient = Utils.getRandomInRange(
|
||||
0.0005,
|
||||
0.0009,
|
||||
6
|
||||
);
|
||||
this.radius = { x: radius, y: radius };
|
||||
this.initialRadius = radius;
|
||||
this.rotationAngle =
|
||||
direction === "left"
|
||||
? Utils.getRandomInRange(0, 0.2, 3)
|
||||
: Utils.getRandomInRange(-0.2, 0, 3);
|
||||
this.emojiRotationAngle = Utils.getRandomInRange(
|
||||
0,
|
||||
2 * Math.PI
|
||||
);
|
||||
this.radiusYDirection = "down";
|
||||
|
||||
const angle =
|
||||
direction === "left"
|
||||
? Utils.getRandomInRange(82, 15) * DEG_TO_RAD
|
||||
: Utils.getRandomInRange(-15, -82) * DEG_TO_RAD;
|
||||
this.absCos = Math.abs(Math.cos(angle));
|
||||
this.absSin = Math.abs(Math.sin(angle));
|
||||
|
||||
const offset = Utils.getRandomInRange(-150, 0);
|
||||
const position = {
|
||||
x:
|
||||
initialPosition.x +
|
||||
(direction === "left" ? -offset : offset) * this.absCos,
|
||||
y: initialPosition.y - offset * this.absSin,
|
||||
};
|
||||
|
||||
this.position = { ...position };
|
||||
this.initialPosition = { ...position };
|
||||
this.color =
|
||||
emojis.length || svgIcon
|
||||
? null
|
||||
: Utils.getRandomItem(colors);
|
||||
this.emoji = emojis.length ? Utils.getRandomItem(emojis) : null;
|
||||
this.svgIcon = null;
|
||||
|
||||
// Preload SVG if provided
|
||||
if (svgIcon) {
|
||||
this.svgImage = new Image();
|
||||
this.svgImage.src = svgIcon;
|
||||
this.svgImage.onload = () => {
|
||||
this.svgIcon = this.svgImage; // Mark as ready once loaded
|
||||
};
|
||||
}
|
||||
|
||||
this.createdAt = Date.now();
|
||||
this.direction = direction;
|
||||
}
|
||||
|
||||
draw(context) {
|
||||
const { x, y } = this.position;
|
||||
const { x: radiusX, y: radiusY } = this.radius;
|
||||
const scale = window.devicePixelRatio;
|
||||
|
||||
if (this.svgIcon) {
|
||||
context.save();
|
||||
context.translate(scale * x, scale * y);
|
||||
context.rotate(this.emojiRotationAngle);
|
||||
context.drawImage(
|
||||
this.svgIcon,
|
||||
-radiusX,
|
||||
-radiusY,
|
||||
radiusX * 2,
|
||||
radiusY * 2
|
||||
);
|
||||
context.restore();
|
||||
} else if (this.color) {
|
||||
context.fillStyle = this.color;
|
||||
context.beginPath();
|
||||
context.ellipse(
|
||||
x * scale,
|
||||
y * scale,
|
||||
radiusX * scale,
|
||||
radiusY * scale,
|
||||
this.rotationAngle,
|
||||
0,
|
||||
2 * Math.PI
|
||||
);
|
||||
context.fill();
|
||||
} else if (this.emoji) {
|
||||
context.font = `${radiusX * scale}px serif`;
|
||||
context.save();
|
||||
context.translate(scale * x, scale * y);
|
||||
context.rotate(this.emojiRotationAngle);
|
||||
context.textAlign = "center";
|
||||
context.fillText(this.emoji, 0, radiusY / 2); // Adjust vertical alignment
|
||||
context.restore();
|
||||
}
|
||||
}
|
||||
|
||||
updatePosition(deltaTime, currentTime) {
|
||||
const elapsed = currentTime - this.createdAt;
|
||||
|
||||
if (this.speed.x > this.finalSpeedX) {
|
||||
this.speed.x -= this.dragCoefficient * deltaTime;
|
||||
}
|
||||
|
||||
this.position.x +=
|
||||
this.speed.x *
|
||||
(this.direction === "left" ? -this.absCos : this.absCos) *
|
||||
deltaTime;
|
||||
this.position.y =
|
||||
this.initialPosition.y -
|
||||
this.speed.y * this.absSin * elapsed +
|
||||
(0.00125 * Math.pow(elapsed, 2)) / 2;
|
||||
|
||||
if (!this.emoji && !this.svgIcon) {
|
||||
this.rotationSpeed -= 1e-5 * deltaTime;
|
||||
this.rotationSpeed = Math.max(this.rotationSpeed, 0);
|
||||
|
||||
if (this.radiusYDirection === "down") {
|
||||
this.radius.y -= deltaTime * this.rotationSpeed;
|
||||
if (this.radius.y <= 0) {
|
||||
this.radius.y = 0;
|
||||
this.radiusYDirection = "up";
|
||||
}
|
||||
} else {
|
||||
this.radius.y += deltaTime * this.rotationSpeed;
|
||||
if (this.radius.y >= this.initialRadius) {
|
||||
this.radius.y = this.initialRadius;
|
||||
this.radiusYDirection = "down";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isVisible(canvasHeight) {
|
||||
return this.position.y < canvasHeight + 100;
|
||||
}
|
||||
}
|
||||
|
||||
class ConfettiManager {
|
||||
constructor() {
|
||||
this.canvas = document.createElement("canvas");
|
||||
// @ts-ignore
|
||||
this.canvas.style =
|
||||
"position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 1000; pointer-events: none;";
|
||||
document.body.appendChild(this.canvas);
|
||||
this.context = this.canvas.getContext("2d");
|
||||
this.confetti = [];
|
||||
this.lastUpdated = Date.now();
|
||||
window.addEventListener(
|
||||
"resize",
|
||||
Utils.debounce(() => this.resizeCanvas(), 200)
|
||||
);
|
||||
this.resizeCanvas();
|
||||
requestAnimationFrame(() => this.loop());
|
||||
}
|
||||
|
||||
resizeCanvas() {
|
||||
this.canvas.width = window.innerWidth * window.devicePixelRatio;
|
||||
this.canvas.height =
|
||||
window.innerHeight * window.devicePixelRatio;
|
||||
}
|
||||
|
||||
addConfetti(config = {}) {
|
||||
const {
|
||||
confettiesNumber,
|
||||
confettiRadius,
|
||||
confettiColors,
|
||||
emojies,
|
||||
svgIcon,
|
||||
} = {
|
||||
...defaultConfettiConfig,
|
||||
...config,
|
||||
};
|
||||
|
||||
const baseY = (5 * window.innerHeight) / 7;
|
||||
for (let i = 0; i < confettiesNumber / 2; i++) {
|
||||
this.confetti.push(
|
||||
new Confetti({
|
||||
initialPosition: { x: 0, y: baseY },
|
||||
direction: "right",
|
||||
radius: confettiRadius,
|
||||
colors: confettiColors,
|
||||
emojis: emojies,
|
||||
svgIcon,
|
||||
})
|
||||
);
|
||||
this.confetti.push(
|
||||
new Confetti({
|
||||
initialPosition: { x: window.innerWidth, y: baseY },
|
||||
direction: "left",
|
||||
radius: confettiRadius,
|
||||
colors: confettiColors,
|
||||
emojis: emojies,
|
||||
svgIcon,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
resetAndStart(config = {}) {
|
||||
// Clear existing confetti
|
||||
this.confetti = [];
|
||||
// Add new confetti
|
||||
this.addConfetti(config);
|
||||
}
|
||||
|
||||
loop() {
|
||||
const currentTime = Date.now();
|
||||
const deltaTime = currentTime - this.lastUpdated;
|
||||
this.lastUpdated = currentTime;
|
||||
|
||||
this.context.clearRect(
|
||||
0,
|
||||
0,
|
||||
this.canvas.width,
|
||||
this.canvas.height
|
||||
);
|
||||
|
||||
this.confetti = this.confetti.filter((item) => {
|
||||
item.updatePosition(deltaTime, currentTime);
|
||||
item.draw(this.context);
|
||||
return item.isVisible(this.canvas.height);
|
||||
});
|
||||
|
||||
requestAnimationFrame(() => this.loop());
|
||||
}
|
||||
}
|
||||
|
||||
const manager = new ConfettiManager();
|
||||
manager.addConfetti();
|
||||
|
||||
const triggerButton = document.getElementById("show-again");
|
||||
if (triggerButton) {
|
||||
triggerButton.addEventListener("click", () =>
|
||||
manager.addConfetti()
|
||||
);
|
||||
}
|
||||
|
||||
const resetInput = document.getElementById("reset");
|
||||
if (resetInput) {
|
||||
resetInput.addEventListener("input", () => manager.resetAndStart());
|
||||
}
|
||||
})();
|
||||
}
|
|
@ -1,348 +0,0 @@
|
|||
<script>
|
||||
import { newTable } from "./timeTable.svelte";
|
||||
|
||||
let table = JSON.parse(localStorage.getItem("TimeTable"));
|
||||
|
||||
let TabOpen = false;
|
||||
|
||||
let csv = "";
|
||||
</script>
|
||||
|
||||
<div class="root">
|
||||
<div id="wrap">
|
||||
<div id="left">
|
||||
<div class="Header Row">
|
||||
<span class="DayOfWeek" style="Opacity: 0;"></span>
|
||||
{#each table.Times as time}
|
||||
<input
|
||||
type="text"
|
||||
onchange={() => {
|
||||
newTable(table);
|
||||
}}
|
||||
bind:value={time}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="Row">
|
||||
<span class="DayOfWeek">Monday</span>
|
||||
{#each table.Monday as time}
|
||||
<input
|
||||
type="text"
|
||||
onchange={() => {
|
||||
newTable(table);
|
||||
}}
|
||||
bind:value={time}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="Row">
|
||||
<span class="DayOfWeek">Tuesday</span>
|
||||
{#each table.Tuesday as time}
|
||||
<input
|
||||
type="text"
|
||||
onchange={() => {
|
||||
newTable(table);
|
||||
}}
|
||||
bind:value={time}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="Row">
|
||||
<span class="DayOfWeek">Wednesday</span>
|
||||
{#each table.Wednesday as time}
|
||||
<input
|
||||
type="text"
|
||||
onchange={() => {
|
||||
newTable(table);
|
||||
}}
|
||||
bind:value={time}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="Row">
|
||||
<span class="DayOfWeek">Thursday</span>
|
||||
{#each table.Thursday as time}
|
||||
<input
|
||||
type="text"
|
||||
onchange={() => {
|
||||
newTable(table);
|
||||
}}
|
||||
bind:value={time}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="Row">
|
||||
<span class="DayOfWeek">Friday</span>
|
||||
{#each table.Friday as time}
|
||||
<input
|
||||
type="text"
|
||||
onchange={() => {
|
||||
newTable(table);
|
||||
}}
|
||||
bind:value={time}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
<div id="right">
|
||||
<button
|
||||
onclick={() => {
|
||||
table.Times.push("");
|
||||
table.Monday.push("");
|
||||
table.Tuesday.push("");
|
||||
table.Wednesday.push("");
|
||||
table.Thursday.push("");
|
||||
table.Friday.push("");
|
||||
newTable(table);
|
||||
table = JSON.parse(localStorage.getItem("TimeTable"));
|
||||
}}
|
||||
><svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="24px"
|
||||
viewBox="0 -960 960 960"
|
||||
width="24px"
|
||||
fill="#FFFFFF"
|
||||
><path
|
||||
d="M440-440H200v-80h240v-240h80v240h240v80H520v240h-80v-240Z"
|
||||
/></svg
|
||||
>Add new Period
|
||||
</button>
|
||||
<button
|
||||
onclick={() => {
|
||||
if (
|
||||
confirm(
|
||||
"This will remove the last period, it is not reversible! are you sure?"
|
||||
)
|
||||
) {
|
||||
table.Times.pop();
|
||||
table.Monday.pop();
|
||||
table.Tuesday.pop();
|
||||
table.Wednesday.pop();
|
||||
table.Thursday.pop();
|
||||
table.Friday.pop();
|
||||
newTable(table);
|
||||
table = JSON.parse(localStorage.getItem("TimeTable"));
|
||||
}
|
||||
}}
|
||||
><svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="24px"
|
||||
viewBox="0 -960 960 960"
|
||||
width="24px"
|
||||
fill="#FFFFFF"
|
||||
><path
|
||||
d="M280-120q-33 0-56.5-23.5T200-200v-520h-40v-80h200v-40h240v40h200v80h-40v520q0 33-23.5 56.5T680-120H280Zm400-600H280v520h400v-520ZM360-280h80v-360h-80v360Zm160 0h80v-360h-80v360ZM280-720v520-520Z"
|
||||
/></svg
|
||||
>
|
||||
Delete last Period
|
||||
</button>
|
||||
<button
|
||||
onclick={() => {
|
||||
TabOpen = true;
|
||||
}}
|
||||
><svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="24px"
|
||||
viewBox="0 -960 960 960"
|
||||
width="24px"
|
||||
fill="#FFFFFF"
|
||||
><path
|
||||
d="M230-360h120v-60H250v-120h100v-60H230q-17 0-28.5 11.5T190-560v160q0 17 11.5 28.5T230-360Zm156 0h120q17 0 28.5-11.5T546-400v-60q0-17-11.5-31.5T506-506h-60v-34h100v-60H426q-17 0-28.5 11.5T386-560v60q0 17 11.5 30.5T426-456h60v36H386v60Zm264 0h60l70-240h-60l-40 138-40-138h-60l70 240ZM160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm0-80h640v-480H160v480Zm0 0v-480 480Z"
|
||||
/></svg
|
||||
>
|
||||
Import From CSV
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if TabOpen !== false}
|
||||
<div id="UpperLayer">
|
||||
<div id="wrapClose">
|
||||
<div class="root">
|
||||
<h1>Paste CSV here:</h1>
|
||||
<p></p>
|
||||
<textarea
|
||||
bind:value={csv}
|
||||
id="box"
|
||||
placeholder="Duration 1, Duration 2, Duration 3, Duration 4
|
||||
Subject 01, Subject 02, Subject 03, Subject 04
|
||||
Subject 08, Subject 09, Subject 10, Subject 12
|
||||
Subject 13, Subject 13, Subject 14, Subject 15"
|
||||
></textarea>
|
||||
</div>
|
||||
<div id="options">
|
||||
<button
|
||||
class="close"
|
||||
id="cancel"
|
||||
onclick={() => (TabOpen = false)}
|
||||
aria-label="close">CANCEL</button
|
||||
>
|
||||
<button
|
||||
class="close"
|
||||
id="save"
|
||||
onclick={() => {
|
||||
TabOpen = false;
|
||||
let lines = csv.split("\n");
|
||||
table.Times = lines[0].split(",");
|
||||
table.Monday = lines[1].split(",");
|
||||
table.Tuesday = lines[2].split(",");
|
||||
table.Wednesday = lines[3].split(",");
|
||||
table.Thursday = lines[4].split(",");
|
||||
table.Friday = lines[5].split(",");
|
||||
newTable(table);
|
||||
table = JSON.parse(localStorage.getItem("TimeTable"));
|
||||
}}
|
||||
aria-label="close">SAVE</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.root {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
margin: 10px;
|
||||
justify-content: center;
|
||||
background-color: #303030;
|
||||
padding: 10px;
|
||||
margin: 20px;
|
||||
border-radius: 10px;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
#wrap {
|
||||
display: flex;
|
||||
background-color: #252525;
|
||||
padding: 20px;
|
||||
border-radius: 20px;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.Row {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 15px;
|
||||
color: white;
|
||||
background-color: #3f3f3f;
|
||||
padding: 5px;
|
||||
border-radius: 10px;
|
||||
width: 100px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.DayOfWeek {
|
||||
width: 100px;
|
||||
background-color: #30492e;
|
||||
}
|
||||
|
||||
input {
|
||||
font-size: 15px;
|
||||
color: white;
|
||||
background-color: #3f3f3f;
|
||||
padding: 5px;
|
||||
border-radius: 10px;
|
||||
width: 100px;
|
||||
text-align: center;
|
||||
}
|
||||
.Header > input {
|
||||
background-color: #30492e;
|
||||
}
|
||||
|
||||
#left {
|
||||
gap: 5px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#right {
|
||||
gap: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#right > button {
|
||||
background-color: rgb(63, 63, 63);
|
||||
color: white;
|
||||
border: 2px solid white;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
transition: all 0.1s ease-in-out;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
max-width: 100px;
|
||||
}
|
||||
|
||||
#right > button:hover {
|
||||
transform: scale(1.2);
|
||||
background-color: rgb(50, 50, 50);
|
||||
}
|
||||
|
||||
#UpperLayer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
backdrop-filter: blur(10px);
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#wrapClose {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.close {
|
||||
background-color: #2b2b2b;
|
||||
color: #888;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
align-self: center;
|
||||
}
|
||||
#box {
|
||||
width: 700px;
|
||||
height: 300px;
|
||||
background-color: #121212;
|
||||
color: white;
|
||||
border-radius: 10px;
|
||||
resize: vertical;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
h1,
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#options {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#cancel {
|
||||
background-color: #580000;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
#save {
|
||||
background-color: #004611;
|
||||
color: #ffffff;
|
||||
}
|
||||
</style>
|
|
@ -1,180 +0,0 @@
|
|||
<script module>
|
||||
import Time from "./time.svelte";
|
||||
import TimeTable from "./timeTable.svelte";
|
||||
import EditTimetableDiv from "./EditTimetable.svelte";
|
||||
|
||||
function EditTimetable() {
|
||||
console.log("Edit timetable");
|
||||
TabOpen.v = true;
|
||||
}
|
||||
|
||||
let TabOpen = $state({ v: false });
|
||||
|
||||
export let ShowSeconds = $state({ v: true });
|
||||
</script>
|
||||
|
||||
<div id="wrap">
|
||||
<div id="nav">
|
||||
<a href="#/" aria-label="Back to main menu"
|
||||
><button aria-label="Back to main menu"
|
||||
><span class="front"
|
||||
><svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="24px"
|
||||
viewBox="0 -960 960 960"
|
||||
width="24px"
|
||||
fill="#FFFFFF"
|
||||
><path
|
||||
d="M240-200h120v-240h240v240h120v-360L480-740 240-560v360Zm-80 80v-480l320-240 320 240v480H520v-240h-80v240H160Zm320-350Z"
|
||||
/></svg
|
||||
> GO BACK
|
||||
</span></button
|
||||
></a
|
||||
>
|
||||
<h1>Idle Screen</h1>
|
||||
<div>
|
||||
<button
|
||||
aria-label="Back to main menu"
|
||||
onclick={() => {
|
||||
ShowSeconds.v = !ShowSeconds.v;
|
||||
localStorage.setItem("ShowSeconds", String(ShowSeconds.v));
|
||||
}}
|
||||
><span class="front"
|
||||
>{#if ShowSeconds.v}Disable Seconds{:else}Enable Seconds{/if}</span
|
||||
></button
|
||||
><button
|
||||
aria-label="Back to main menu"
|
||||
onclick={() => EditTimetable()}
|
||||
><span class="front"
|
||||
><svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="24px"
|
||||
viewBox="0 -960 960 960"
|
||||
width="24px"
|
||||
fill="#FFFFFF"
|
||||
><path
|
||||
d="M200-80q-33 0-56.5-23.5T120-160v-560q0-33 23.5-56.5T200-800h40v-80h80v80h320v-80h80v80h40q33 0 56.5 23.5T840-720v200h-80v-40H200v400h280v80H200Zm0-560h560v-80H200v80Zm0 0v-80 80ZM560-80v-123l221-220q9-9 20-13t22-4q12 0 23 4.5t20 13.5l37 37q8 9 12.5 20t4.5 22q0 11-4 22.5T903-300L683-80H560Zm300-263-37-37 37 37ZM620-140h38l121-122-18-19-19-18-122 121v38Zm141-141-19-18 37 37-18-19Z"
|
||||
/></svg
|
||||
> Edit timetable
|
||||
</span></button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="root">
|
||||
<TimeTable /><Time />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if TabOpen.v !== false}
|
||||
<div id="UpperLayer">
|
||||
<div id="wrapClose">
|
||||
<EditTimetableDiv />
|
||||
<button
|
||||
class="close"
|
||||
onclick={() => (TabOpen.v = false)}
|
||||
aria-label="close">CLOSE</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
#wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#root {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
#nav {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: #121212;
|
||||
color: white;
|
||||
}
|
||||
|
||||
button {
|
||||
background: #292929;
|
||||
border-radius: 12px;
|
||||
border: none;
|
||||
margin: 10px;
|
||||
padding: 2px 0px;
|
||||
cursor: pointer;
|
||||
outline-offset: 4px;
|
||||
max-width: 400px;
|
||||
}
|
||||
button:hover .front {
|
||||
transform: translateY(-7px);
|
||||
}
|
||||
|
||||
button:active .front {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.front {
|
||||
display: flex;
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
padding: 5px;
|
||||
border-radius: 12px;
|
||||
|
||||
background: #4d4d4d;
|
||||
color: white;
|
||||
transform: translateY(-4px);
|
||||
transition: all 0.1s ease-in-out;
|
||||
font-family: "JetBrains Mono", monospace;
|
||||
font-size: 25px;
|
||||
}
|
||||
h1 {
|
||||
text-align: center;
|
||||
margin: 5px 0px;
|
||||
text-decoration: underline #444;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 0.5em;
|
||||
text-decoration: none;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
#UpperLayer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
backdrop-filter: blur(5px);
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#wrapClose {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.close {
|
||||
background-color: #2b2b2b;
|
||||
color: #888;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
align-self: center;
|
||||
}
|
||||
</style>
|
|
@ -1,231 +0,0 @@
|
|||
<script>
|
||||
import { ShowSeconds } from "./main.svelte";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
let hour1;
|
||||
let hour2;
|
||||
let min1;
|
||||
let min2;
|
||||
let sec1;
|
||||
let sec2;
|
||||
let AmOrPm;
|
||||
|
||||
function DecideScrool(Object, currentTime, legnth, LastZeroPos) {
|
||||
if (currentTime == 0) {
|
||||
if (Object.scrollTop != 0) {
|
||||
Object.scrollTop = LastZeroPos * legnth;
|
||||
setTimeout(() => {
|
||||
Object.scroll({
|
||||
top: 0,
|
||||
behavior: "instant",
|
||||
});
|
||||
}, 500);
|
||||
}
|
||||
} else {
|
||||
Object.scrollTop = currentTime * legnth;
|
||||
}
|
||||
}
|
||||
|
||||
function updateTime() {
|
||||
const now = new Date();
|
||||
|
||||
let hours = now.getHours().toString().padStart(2, "0");
|
||||
|
||||
if (now.getHours() >= 12) {
|
||||
hours = (now.getHours() - 12).toString().padStart(2, "0");
|
||||
AmOrPm = "PM";
|
||||
} else {
|
||||
AmOrPm = "AM";
|
||||
}
|
||||
|
||||
const minutes = now.getMinutes().toString().padStart(2, "0");
|
||||
const seconds = now.getSeconds().toString().padStart(2, "0");
|
||||
|
||||
DecideScrool(hour1, parseInt(hours[0]), 200, 2);
|
||||
DecideScrool(hour2, parseInt(hours[1]), 200, 10);
|
||||
DecideScrool(min1, parseInt(minutes[0]), 200, 6);
|
||||
DecideScrool(min2, parseInt(minutes[1]), 200, 10);
|
||||
if (ShowSeconds) {
|
||||
DecideScrool(sec1, parseInt(seconds[0]), 75, 6);
|
||||
DecideScrool(sec2, parseInt(seconds[1]), 75, 10);
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
updateTime();
|
||||
setInterval(updateTime, 1000);
|
||||
});
|
||||
|
||||
let TempLocalStorage = localStorage.getItem("ShowSeconds") || "";
|
||||
|
||||
if (TempLocalStorage == "false") {
|
||||
ShowSeconds.v = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div id="root">
|
||||
<div id="wrap">
|
||||
<div id="time">
|
||||
<div class="rowOfNumbers" bind:this={hour1}>
|
||||
<h1>0</h1>
|
||||
<h1>1</h1>
|
||||
<h1>0</h1>
|
||||
</div>
|
||||
<div class="rowOfNumbers" bind:this={hour2}>
|
||||
<h1>0</h1>
|
||||
<h1>1</h1>
|
||||
<h1>2</h1>
|
||||
<h1>3</h1>
|
||||
<h1>4</h1>
|
||||
<h1>5</h1>
|
||||
<h1>6</h1>
|
||||
<h1>7</h1>
|
||||
<h1>8</h1>
|
||||
<h1>9</h1>
|
||||
<h1>0</h1>
|
||||
</div>
|
||||
<h1 id="HourMinDivider">:</h1>
|
||||
<div class="rowOfNumbers" bind:this={min1}>
|
||||
<h1>0</h1>
|
||||
<h1>1</h1>
|
||||
<h1>2</h1>
|
||||
<h1>3</h1>
|
||||
<h1>4</h1>
|
||||
<h1>5</h1>
|
||||
<h1>0</h1>
|
||||
</div>
|
||||
<div class="rowOfNumbers" bind:this={min2}>
|
||||
<h1>0</h1>
|
||||
<h1>1</h1>
|
||||
<h1>2</h1>
|
||||
<h1>3</h1>
|
||||
<h1>4</h1>
|
||||
<h1>5</h1>
|
||||
<h1>6</h1>
|
||||
<h1>7</h1>
|
||||
<h1>8</h1>
|
||||
<h1>9</h1>
|
||||
<h1>0</h1>
|
||||
</div>
|
||||
{#if ShowSeconds.v}
|
||||
<h1 id="MinSecDivider">.</h1>
|
||||
<div class="rowOfNumbersSec" bind:this={sec1}>
|
||||
<h1>0</h1>
|
||||
<h1>1</h1>
|
||||
<h1>2</h1>
|
||||
<h1>3</h1>
|
||||
<h1>4</h1>
|
||||
<h1>5</h1>
|
||||
<h1>0</h1>
|
||||
</div>
|
||||
<div class="rowOfNumbersSec" bind:this={sec2}>
|
||||
<h1>0</h1>
|
||||
<h1>1</h1>
|
||||
<h1>2</h1>
|
||||
<h1>3</h1>
|
||||
<h1>4</h1>
|
||||
<h1>5</h1>
|
||||
<h1>6</h1>
|
||||
<h1>7</h1>
|
||||
<h1>8</h1>
|
||||
<h1>9</h1>
|
||||
<h1>0</h1>
|
||||
</div>{/if}
|
||||
<h1 id="AmOrPm">{AmOrPm}</h1>
|
||||
</div>
|
||||
<div id="date">
|
||||
<h2>
|
||||
{new Date().toLocaleString("en-US", { weekday: "short" })}
|
||||
{new Date().getDate()},
|
||||
{new Date().toLocaleString("en-US", { month: "short" })}
|
||||
{new Date().getFullYear()}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
#root {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
#wrap {
|
||||
background-color: #252525;
|
||||
padding: 20px 70px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
#time {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: baseline;
|
||||
margin: -30px;
|
||||
}
|
||||
|
||||
#HourMinDivider {
|
||||
font-size: 200px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#MinSecDivider {
|
||||
font-size: 75px;
|
||||
margin: 0;
|
||||
color: #585858;
|
||||
}
|
||||
|
||||
.rowOfNumbers {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 200px;
|
||||
overflow-y: hidden;
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
.rowOfNumbers h1 {
|
||||
height: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.rowOfNumbers > h1 {
|
||||
font-size: 200px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.rowOfNumbersSec {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 75px;
|
||||
overflow-y: hidden;
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
.rowOfNumbersSec > h1 {
|
||||
height: 75px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.rowOfNumbersSec > h1 {
|
||||
font-size: 75px;
|
||||
margin: 0;
|
||||
color: #585858;
|
||||
}
|
||||
|
||||
#AmOrPm {
|
||||
font-size: 75px;
|
||||
margin: 0;
|
||||
margin-left: 30px;
|
||||
color: #585858;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
font-size: 40px;
|
||||
color: #888;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
|
@ -1,198 +0,0 @@
|
|||
<script module>
|
||||
export function newTable(timetable) {
|
||||
localStorage.setItem("TimeTable", JSON.stringify(timetable));
|
||||
table = timetable;
|
||||
}
|
||||
|
||||
let TemplateTable = {
|
||||
Times: [
|
||||
"07:50 - 08:50",
|
||||
"08:50 - 09:40",
|
||||
"09:40 - 10:30 ",
|
||||
"10:30 - 11:00",
|
||||
"11:00 - 12:00",
|
||||
"12:00 - 01:00",
|
||||
"01:00 - 02:00",
|
||||
],
|
||||
Monday: [
|
||||
"English",
|
||||
"Sanskrit",
|
||||
"Math",
|
||||
"Lunch",
|
||||
"Hindi",
|
||||
"Social Science",
|
||||
"Science",
|
||||
],
|
||||
Tuesday: [
|
||||
"English",
|
||||
"Art & Craft",
|
||||
"Math",
|
||||
"Lunch",
|
||||
"Hindi",
|
||||
"Social Science",
|
||||
"Science",
|
||||
],
|
||||
Wednesday: [
|
||||
"English",
|
||||
"GK",
|
||||
"Math",
|
||||
"Lunch",
|
||||
"Hindi",
|
||||
"Social Science",
|
||||
"Science",
|
||||
],
|
||||
Thursday: [
|
||||
"English",
|
||||
"Sanskrit",
|
||||
"Math",
|
||||
"Lunch",
|
||||
"Hindi",
|
||||
"Social Science",
|
||||
"Science",
|
||||
],
|
||||
Friday: [
|
||||
"English",
|
||||
"Computers",
|
||||
"Math",
|
||||
"Lunch",
|
||||
"Hindi",
|
||||
"Social Science",
|
||||
"Science",
|
||||
],
|
||||
};
|
||||
|
||||
let table = $state();
|
||||
|
||||
let TempTimeTable = localStorage.getItem("TimeTable") || "";
|
||||
|
||||
if (TempTimeTable != "") {
|
||||
table = JSON.parse(TempTimeTable);
|
||||
} else {
|
||||
newTable($state.snapshot(TemplateTable));
|
||||
}
|
||||
</script>
|
||||
|
||||
<div id="root">
|
||||
<div id="wrap">
|
||||
<div class="Header Row">
|
||||
<span class="DayOfWeek" style="Opacity: 0;"></span>
|
||||
{#each table.Times as time}
|
||||
<span>{time}</span>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="Row">
|
||||
{#if new Date().getDay() == 1}
|
||||
<span class="DayOfWeek NavHighlight">Monday</span>
|
||||
{:else}
|
||||
<span class="DayOfWeek">Monday</span>
|
||||
{/if}
|
||||
{#each table.Monday as time}
|
||||
{#if new Date().getDay() == 1}
|
||||
<span class="highlight">{time}</span>
|
||||
{:else}
|
||||
<span>{time}</span>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
<div class="Row">
|
||||
{#if new Date().getDay() == 2}
|
||||
<span class="DayOfWeek NavHighlight">Tuesday</span>
|
||||
{:else}
|
||||
<span class="DayOfWeek">Tuesday</span>
|
||||
{/if}
|
||||
{#each table.Tuesday as time}
|
||||
{#if new Date().getDay() == 2}
|
||||
<span class="highlight">{time}</span>
|
||||
{:else}
|
||||
<span>{time}</span>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
<div class="Row">
|
||||
{#if new Date().getDay() == 3}
|
||||
<span class="DayOfWeek NavHighlight">Wednesday</span>
|
||||
{:else}
|
||||
<span class="DayOfWeek">Wednesday</span>
|
||||
{/if}
|
||||
{#each table.Wednesday as time}
|
||||
{#if new Date().getDay() == 3}
|
||||
<span class="highlight">{time}</span>
|
||||
{:else}
|
||||
<span>{time}</span>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
<div class="Row">
|
||||
{#if new Date().getDay() == 4}
|
||||
<span class="DayOfWeek NavHighlight">Thursday</span>
|
||||
{:else}
|
||||
<span class="DayOfWeek">Thursday</span>
|
||||
{/if}
|
||||
{#each table.Thursday as time}
|
||||
{#if new Date().getDay() == 4}
|
||||
<span class="highlight">{time}</span>
|
||||
{:else}
|
||||
<span>{time}</span>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
<div class="Row">
|
||||
{#if new Date().getDay() == 5}
|
||||
<span class="DayOfWeek NavHighlight">Friday</span>
|
||||
{:else}
|
||||
<span class="DayOfWeek">Friday</span>
|
||||
{/if}
|
||||
{#each table.Friday as time}
|
||||
{#if new Date().getDay() == 5}
|
||||
<span class="highlight">{time}</span>
|
||||
{:else}
|
||||
<span>{time}</span>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
#root {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
#wrap {
|
||||
display: flex;
|
||||
background-color: #252525;
|
||||
padding: 20px;
|
||||
border-radius: 20px;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
.Row {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
}
|
||||
span {
|
||||
font-size: 20px;
|
||||
color: white;
|
||||
background-color: #3f3f3f;
|
||||
padding: 5px;
|
||||
border-radius: 10px;
|
||||
width: 140px;
|
||||
text-align: center;
|
||||
}
|
||||
.Header > span {
|
||||
background-color: #30492e;
|
||||
}
|
||||
.DayOfWeek {
|
||||
width: 120px;
|
||||
background-color: #30492e;
|
||||
}
|
||||
.highlight {
|
||||
background-color: #707070;
|
||||
display: block;
|
||||
}
|
||||
.NavHighlight {
|
||||
background-color: #3b8235;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
|
@ -1,249 +0,0 @@
|
|||
<div id="root">
|
||||
<img
|
||||
src="https://hc-cdn.hel1.your-objectstorage.com/s/v3/77e7a04f27807b4e0c16bcda09ea222f9e091616_group_18.svg" id="logo"
|
||||
/>
|
||||
<h2>
|
||||
A collection of awesome tools, games, and more — made to be used in any
|
||||
classroom!
|
||||
</h2>
|
||||
<h3>MAIN</h3>
|
||||
|
||||
<div id="items2">
|
||||
<a href="https://kahoot-clone-rezhackxyz.vercel.app/">
|
||||
<button class="button2">
|
||||
<span class="front2">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="70px"
|
||||
viewBox="0 -960 960 960"
|
||||
width="70px"
|
||||
fill="#e3e3e3"
|
||||
><path
|
||||
d="M560-360q17 0 29.5-12.5T602-402q0-17-12.5-29.5T560-444q-17 0-29.5 12.5T518-402q0 17 12.5 29.5T560-360Zm-30-128h60q0-29 6-42.5t28-35.5q30-30 40-48.5t10-43.5q0-45-31.5-73.5T560-760q-41 0-71.5 23T446-676l54 22q9-25 24.5-37.5T560-704q24 0 39 13.5t15 36.5q0 14-8 26.5T578-596q-33 29-40.5 45.5T530-488ZM320-240q-33 0-56.5-23.5T240-320v-480q0-33 23.5-56.5T320-880h480q33 0 56.5 23.5T880-800v480q0 33-23.5 56.5T800-240H320Zm0-80h480v-480H320v480ZM160-80q-33 0-56.5-23.5T80-160v-560h80v560h560v80H160Zm160-720v480-480Z"
|
||||
/></svg
|
||||
>
|
||||
DaKahootClone
|
||||
<p>The best ever kahoot clone.</p></span
|
||||
>
|
||||
</button></a
|
||||
>
|
||||
</div>
|
||||
<h3>OTHERS</h3>
|
||||
<div id="items">
|
||||
<a href="#/IdleScreen">
|
||||
<button>
|
||||
<span class="front">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="30px"
|
||||
viewBox="0 -960 960 960"
|
||||
width="30px"
|
||||
fill="#FFFFFF"
|
||||
><path
|
||||
d="m612-292 56-56-148-148v-184h-80v216l172 172ZM480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-400Zm0 320q133 0 226.5-93.5T800-480q0-133-93.5-226.5T480-800q-133 0-226.5 93.5T160-480q0 133 93.5 226.5T480-160Z"
|
||||
/></svg
|
||||
>
|
||||
Timetable
|
||||
<p>Clock included!</p></span
|
||||
>
|
||||
</button></a
|
||||
>
|
||||
<a href="#/RandomName">
|
||||
<button>
|
||||
<span class="front">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="30px"
|
||||
viewBox="0 -960 960 960"
|
||||
width="30px"
|
||||
fill="#FFFFFF"
|
||||
><path
|
||||
d="M0-240v-63q0-43 44-70t116-27q13 0 25 .5t23 2.5q-14 21-21 44t-7 48v65H0Zm240 0v-65q0-32 17.5-58.5T307-410q32-20 76.5-30t96.5-10q53 0 97.5 10t76.5 30q32 20 49 46.5t17 58.5v65H240Zm540 0v-65q0-26-6.5-49T754-397q11-2 22.5-2.5t23.5-.5q72 0 116 26.5t44 70.5v63H780Zm-455-80h311q-10-20-55.5-35T480-370q-55 0-100.5 15T325-320ZM160-440q-33 0-56.5-23.5T80-520q0-34 23.5-57t56.5-23q34 0 57 23t23 57q0 33-23 56.5T160-440Zm640 0q-33 0-56.5-23.5T720-520q0-34 23.5-57t56.5-23q34 0 57 23t23 57q0 33-23 56.5T800-440Zm-320-40q-50 0-85-35t-35-85q0-51 35-85.5t85-34.5q51 0 85.5 34.5T600-600q0 50-34.5 85T480-480Zm0-80q17 0 28.5-11.5T520-600q0-17-11.5-28.5T480-640q-17 0-28.5 11.5T440-600q0 17 11.5 28.5T480-560Zm1 240Zm-1-280Z"
|
||||
/></svg
|
||||
>
|
||||
Name selector
|
||||
<p>for any class activity!</p></span
|
||||
>
|
||||
</button></a
|
||||
>
|
||||
<a href="#/Wordle">
|
||||
<button>
|
||||
<span class="front">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="30px"
|
||||
viewBox="0 -960 960 960"
|
||||
width="30px"
|
||||
fill="#FFFFFF"
|
||||
><path
|
||||
d="M182-200q-51 0-79-35.5T82-322l42-300q9-60 53.5-99T282-760h396q60 0 104.5 39t53.5 99l42 300q7 51-21 86.5T778-200q-21 0-39-7.5T706-230l-90-90H344l-90 90q-15 15-33 22.5t-39 7.5Zm16-86 114-114h336l114 114q2 2 16 6 11 0 17.5-6.5T800-304l-44-308q-4-29-26-48.5T678-680H282q-30 0-52 19.5T204-612l-44 308q-2 11 4.5 17.5T182-280q2 0 16-6Zm482-154q17 0 28.5-11.5T720-480q0-17-11.5-28.5T680-520q-17 0-28.5 11.5T640-480q0 17 11.5 28.5T680-440Zm-80-120q17 0 28.5-11.5T640-600q0-17-11.5-28.5T600-640q-17 0-28.5 11.5T560-600q0 17 11.5 28.5T600-560ZM310-440h60v-70h70v-60h-70v-70h-60v70h-70v60h70v70Zm170-40Z"
|
||||
/></svg
|
||||
>
|
||||
Wordle
|
||||
<p>Challenge your vocabulary!</p></span
|
||||
>
|
||||
</button></a
|
||||
>
|
||||
|
||||
<a href="#/announcer">
|
||||
<button>
|
||||
<span class="front">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="30px"
|
||||
viewBox="0 -960 960 960"
|
||||
width="30px"
|
||||
fill="#FFFFFF"
|
||||
><path
|
||||
d="M720-440v-80h160v80H720Zm48 280-128-96 48-64 128 96-48 64Zm-80-480-48-64 128-96 48 64-128 96ZM200-200v-160h-40q-33 0-56.5-23.5T80-440v-80q0-33 23.5-56.5T160-600h160l200-120v480L320-360h-40v160h-80Zm240-182v-196l-98 58H160v80h182l98 58Zm120 36v-268q27 24 43.5 58.5T620-480q0 41-16.5 75.5T560-346ZM300-480Z"
|
||||
/></svg
|
||||
>
|
||||
Announcer
|
||||
<p>to shout from the speakers!</p></span
|
||||
>
|
||||
</button></a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="BottomBadge">
|
||||
Made by <a href="https://rezhack.xyz" target="_blank">RezHackXYZ</a> for
|
||||
<a href="https://neighborhood.hackclub.com/" target="_blank">Neighborhood</a
|
||||
>!
|
||||
<a href="https://github.com/RezHackXYZ/ClassRoomStuff" target="_blank"
|
||||
>Contribute here</a
|
||||
> if you want.
|
||||
</div>
|
||||
|
||||
<style>
|
||||
#root {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
font-size: 60px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
color: #797979;
|
||||
font-size: 30px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
#items2 {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#items {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
button {
|
||||
background: #292929;
|
||||
border-radius: 12px;
|
||||
border: none;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
outline-offset: 4px;
|
||||
}
|
||||
|
||||
.front {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
padding: 5px 15px;
|
||||
border-radius: 12px;
|
||||
font-size: 1.25rem;
|
||||
background: #4d4d4d;
|
||||
color: white;
|
||||
transform: translateY(-7px);
|
||||
transition: all 0.1s ease-in-out;
|
||||
font-family: "JetBrains Mono", monospace;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
.front2 {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
padding: 3px 30px;
|
||||
border-radius: 12px;
|
||||
background: #4d4d4d;
|
||||
color: white;
|
||||
transform: translateY(-7px);
|
||||
transition: all 0.1s ease-in-out;
|
||||
font-family: "JetBrains Mono", monospace;
|
||||
font-size: 50px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 12px;
|
||||
color: #aaaaaa;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.front2 > p {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
button:hover .front {
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
|
||||
button:active .front {
|
||||
transform: translateY(-3px);
|
||||
}
|
||||
|
||||
#BottomBadge {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
background-color: #242424;
|
||||
color: #aaaaaa;
|
||||
margin-bottom: 10px;
|
||||
width: fit-content;
|
||||
align-self: center;
|
||||
padding: 5px;
|
||||
font-size: 20px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #aaaaaa;
|
||||
}
|
||||
|
||||
h3 {
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
color: #aaaaaa;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
#logo {
|
||||
width: 500px;
|
||||
margin-bottom: 20px;
|
||||
align-self: center;
|
||||
}
|
||||
</style>
|
|
@ -1,182 +0,0 @@
|
|||
<script>
|
||||
let text = $state("");
|
||||
|
||||
function speak() {
|
||||
window.speechSynthesis.speak(
|
||||
Object.assign(new SpeechSynthesisUtterance(text), {
|
||||
rate: 0.5,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
let TempelateCommonAnounce = $state(["Please be quiet"]);
|
||||
|
||||
let CommonAnounce = $state([]);
|
||||
|
||||
export function newNames(Names) {
|
||||
localStorage.setItem("CommonAnounce", JSON.stringify(Names));
|
||||
}
|
||||
|
||||
let TempCommonAnounce = localStorage.getItem("CommonAnounce") || "";
|
||||
|
||||
if (TempCommonAnounce != "") {
|
||||
CommonAnounce = JSON.parse(TempCommonAnounce);
|
||||
} else {
|
||||
CommonAnounce = $state.snapshot(TempelateCommonAnounce);
|
||||
localStorage.setItem("CommonAnounce", JSON.stringify(CommonAnounce));
|
||||
}
|
||||
</script>
|
||||
|
||||
<div id="root">
|
||||
<div id="wrap">
|
||||
<h1>Most Announced announcements</h1>
|
||||
|
||||
<div id="mostanouncedanounements">
|
||||
{#each CommonAnounce as anouncement, i}
|
||||
<div>
|
||||
<button
|
||||
class="anuncement"
|
||||
onclick={() => {
|
||||
text = anouncement;
|
||||
speak();
|
||||
}}
|
||||
>
|
||||
{anouncement}
|
||||
</button>
|
||||
<button
|
||||
aria-label="Delete anouncement"
|
||||
onclick={() => {
|
||||
if (
|
||||
confirm(
|
||||
"Are you sure you want to delete this anouncement?"
|
||||
)
|
||||
) {
|
||||
CommonAnounce.splice(i, 1);
|
||||
localStorage.setItem(
|
||||
"CommonAnounce",
|
||||
JSON.stringify(CommonAnounce)
|
||||
);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="15px"
|
||||
viewBox="0 -960 960 960"
|
||||
width="15px"
|
||||
fill="#FFFFFF"
|
||||
><path
|
||||
d="M280-120q-33 0-56.5-23.5T200-200v-520h-40v-80h200v-40h240v40h200v80h-40v520q0 33-23.5 56.5T680-120H280Zm400-600H280v520h400v-520ZM360-280h80v-360h-80v360Zm160 0h80v-360h-80v360ZM280-720v520-520Z"
|
||||
/></svg
|
||||
></button
|
||||
>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<h1>Or announce something else</h1>
|
||||
<div>
|
||||
<input
|
||||
bind:value={text}
|
||||
placeholder="Type in here what you want to announce"
|
||||
/>
|
||||
<button onclick={speak}>Play</button>
|
||||
</div>
|
||||
{#if text}
|
||||
<button
|
||||
id="new"
|
||||
onclick={() => {
|
||||
CommonAnounce.push(text);
|
||||
text = "";
|
||||
localStorage.setItem(
|
||||
"CommonAnounce",
|
||||
JSON.stringify(CommonAnounce)
|
||||
);
|
||||
}}>Add "{text}" to "Most Announced announcements"</button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<style>
|
||||
#root {
|
||||
height: 100%;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
#wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
padding: 20px;
|
||||
border-radius: 20px;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
input {
|
||||
font-size: 20px;
|
||||
padding: 10px;
|
||||
border-radius: 12px;
|
||||
border: none;
|
||||
background-color: #292929;
|
||||
color: white;
|
||||
width: 400px;
|
||||
}
|
||||
button {
|
||||
font-size: 20px;
|
||||
padding: 10px;
|
||||
border-radius: 12px;
|
||||
border: none;
|
||||
background-color: #292929;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
transition: all 0.1s ease-in-out;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: #414141;
|
||||
transform: rotateZ(-15deg) scale(1.2);
|
||||
}
|
||||
|
||||
hr {
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background-color: #292929;
|
||||
border: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
#mostanouncedanounements {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
}
|
||||
.anuncement:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
.anuncement {
|
||||
width: calc(100% - 40px);
|
||||
}
|
||||
|
||||
#new {
|
||||
width: fit-content;
|
||||
align-self: center;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
#new:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
</style>
|
|
@ -1,100 +0,0 @@
|
|||
<script>
|
||||
import ActualAnnouncer from "./ActualAnnouncer.svelte";
|
||||
</script>
|
||||
|
||||
<div id="wrap">
|
||||
<div id="nav">
|
||||
<a href="#/" aria-label="Back to main menu"
|
||||
><button aria-label="Back to main menu"
|
||||
><span class="front"
|
||||
><svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="24px"
|
||||
viewBox="0 -960 960 960"
|
||||
width="24px"
|
||||
fill="#FFFFFF"
|
||||
><path
|
||||
d="M240-200h120v-240h240v240h120v-360L480-740 240-560v360Zm-80 80v-480l320-240 320 240v480H520v-240h-80v240H160Zm320-350Z"
|
||||
/></svg
|
||||
> GO BACK
|
||||
</span></button
|
||||
></a
|
||||
>
|
||||
<h1>Announcer</h1>
|
||||
</div>
|
||||
<div id="root">
|
||||
<ActualAnnouncer />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
#wrap {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#nav {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: #121212;
|
||||
color: white;
|
||||
}
|
||||
|
||||
button {
|
||||
background: #292929;
|
||||
border-radius: 12px;
|
||||
border: none;
|
||||
margin: 10px;
|
||||
padding: 2px 0px;
|
||||
cursor: pointer;
|
||||
outline-offset: 4px;
|
||||
max-width: 400px;
|
||||
}
|
||||
button:hover .front {
|
||||
transform: translateY(-7px);
|
||||
}
|
||||
|
||||
button:active .front {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.front {
|
||||
display: flex;
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
padding: 5px;
|
||||
border-radius: 12px;
|
||||
|
||||
background: #4d4d4d;
|
||||
color: white;
|
||||
transform: translateY(-4px);
|
||||
transition: all 0.1s ease-in-out;
|
||||
font-family: "JetBrains Mono", monospace;
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
#root {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
margin: 5px 0px;
|
||||
text-decoration: underline #444;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 0.5em;
|
||||
text-decoration: none;
|
||||
color: #444;
|
||||
}
|
||||
</style>
|
15
src/app.html
Normal file
15
src/app.html
Normal file
|
@ -0,0 +1,15 @@
|
|||
<!doctype html>
|
||||
<html lang="en" style="height: 100%; margin: 0">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link
|
||||
rel="icon"
|
||||
href="https://hc-cdn.hel1.your-objectstorage.com/s/v3/4a82e0c815624c7786ca2a5addbcc74487da8940_group_8__2_.svg"
|
||||
/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover" style="height: 100%; margin: 0">
|
||||
<div style="display: contents; height: 100%">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,79 +0,0 @@
|
|||
<script module>
|
||||
import Router from "svelte-spa-router";
|
||||
import Wordle from "./wordle/game.svelte";
|
||||
import TypeSelector from "./SelectionMenue/TypeSelector.svelte";
|
||||
import IdleScreen from "./IdleScreen/main.svelte";
|
||||
import RandomName from "./RandomName/main.svelte";
|
||||
import Announcer from "./announcer/main.svelte";
|
||||
import { confettiAnimation } from "./Confetti.js";
|
||||
|
||||
let routes = {
|
||||
"/": TypeSelector,
|
||||
"/Wordle": Wordle,
|
||||
"/IdleScreen": IdleScreen,
|
||||
"/RandomName": RandomName,
|
||||
"/announcer": Announcer,
|
||||
};
|
||||
let ShowAlertDiv = $state(false);
|
||||
let ShowAlertText = $state("this Code is bad");
|
||||
let ShowAlertType = $state("Error");
|
||||
|
||||
export function ShowAlert(text, type) {
|
||||
ShowAlertDiv = true;
|
||||
ShowAlertType = type;
|
||||
|
||||
ShowAlertText = text;
|
||||
setTimeout(() => {
|
||||
ShowAlertDiv = false;
|
||||
}, 1500);
|
||||
|
||||
if (type == "success") {
|
||||
confettiAnimation();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div id="root">
|
||||
<Router {routes} />
|
||||
</div>
|
||||
{#if ShowAlertDiv == true}
|
||||
<div id="alert">
|
||||
<h1 class={ShowAlertType}>{ShowAlertText}</h1>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
:root {
|
||||
background-color: #121212;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#root {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
font-family: "Sour Gummy", sans-serif;
|
||||
}
|
||||
|
||||
#alert {
|
||||
position: fixed;
|
||||
top: 10px;
|
||||
color: white;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
h1 {
|
||||
margin: 0;
|
||||
padding: 10px 20px;
|
||||
border-radius: 20px;
|
||||
font-family: "Sour Gummy", sans-serif;
|
||||
}
|
||||
.error {
|
||||
background-color: #830000;
|
||||
}
|
||||
.warning {
|
||||
background-color: #975b00;
|
||||
}
|
||||
.success {
|
||||
background-color: #006b00;
|
||||
}
|
||||
}
|
||||
</style>
|
133
src/lib/config.js
Normal file
133
src/lib/config.js
Normal file
|
@ -0,0 +1,133 @@
|
|||
export let AnswersSymbolAndColorScheme = [
|
||||
{
|
||||
color: "#6E0000",
|
||||
selectedColor: "#AA2222",
|
||||
hoverBorderColor: "#FF5D5D",
|
||||
selectedBorderColor: "#FF0000",
|
||||
symbol: "nf-md-triangle",
|
||||
},
|
||||
{
|
||||
color: "#00316E",
|
||||
selectedColor: "#2255AA",
|
||||
hoverBorderColor: "#5D9CFF",
|
||||
selectedBorderColor: "#0000FF",
|
||||
symbol: "nf-fa-square",
|
||||
},
|
||||
{
|
||||
color: "#6E6E00",
|
||||
selectedColor: "#AAAA22",
|
||||
hoverBorderColor: "#FFFF5D",
|
||||
selectedBorderColor: "#DDFF00",
|
||||
symbol: "nf-fa-circle",
|
||||
},
|
||||
{
|
||||
color: "#006E00",
|
||||
selectedColor: "#22AA22",
|
||||
hoverBorderColor: "#5DFF5D",
|
||||
selectedBorderColor: "#00FF00",
|
||||
symbol: "nf-fa-diamond",
|
||||
},
|
||||
{
|
||||
color: "#4B0082",
|
||||
selectedColor: "#7F33B5",
|
||||
hoverBorderColor: "#B066FF",
|
||||
selectedBorderColor: "#9932CC",
|
||||
symbol: "nf-md-star",
|
||||
},
|
||||
{
|
||||
color: "#FF8C00",
|
||||
selectedColor: "#FFB347",
|
||||
hoverBorderColor: "#FFD580",
|
||||
selectedBorderColor: "#FFA500",
|
||||
symbol: "nf-md-hexagon",
|
||||
},
|
||||
{
|
||||
color: "#008B8B",
|
||||
selectedColor: "#33CCCC",
|
||||
hoverBorderColor: "#66FFFF",
|
||||
selectedBorderColor: "#00CED1",
|
||||
symbol: "nf-md-octagon",
|
||||
},
|
||||
{
|
||||
color: "#8B4513",
|
||||
selectedColor: "#CD853F",
|
||||
hoverBorderColor: "#DEB887",
|
||||
selectedBorderColor: "#A0522D",
|
||||
symbol: "nf-md-heart",
|
||||
},
|
||||
];
|
||||
|
||||
export let DefaultQuestions = [
|
||||
{
|
||||
name: "What should you do when you're free?",
|
||||
answers: ["Do something in real life!", "Play video games", "Code!", "Touch grass!"],
|
||||
correctAnswer: 2,
|
||||
},
|
||||
{
|
||||
name: "Is RezHackXYZ the best programmer in the world?",
|
||||
answers: ["Yes :)", "No :("],
|
||||
correctAnswer: 0,
|
||||
},
|
||||
{
|
||||
name: "Best place in the world?",
|
||||
answers: [
|
||||
"Google",
|
||||
"Microsoft",
|
||||
"Apple",
|
||||
"Samsung",
|
||||
"Hack Club!! :D",
|
||||
"Amazon",
|
||||
"Facebook",
|
||||
"Twitter",
|
||||
],
|
||||
correctAnswer: 4,
|
||||
},
|
||||
];
|
||||
|
||||
export let AiPrompts = {
|
||||
GenerateQuestionsUsingAI: `
|
||||
You are the AI of a quiz game.
|
||||
Generate a list of quiz questions with possible answers and the correct answer index.
|
||||
Each question must have:
|
||||
- A "name" (question text)
|
||||
- An "answers" array (minimum 2, maximum 8 options)
|
||||
- A "correctAnswer" (index starting from 0)
|
||||
Ensure the questions are diverse.
|
||||
Example format:
|
||||
{
|
||||
"name": "What is the capital of France?",
|
||||
"answers": [
|
||||
"Paris",
|
||||
"London",
|
||||
"Berlin",
|
||||
"Madrid"
|
||||
],
|
||||
"correctAnswer": 0
|
||||
}
|
||||
JUST PROVIDE THE JSON AND NOTHING ELSE.
|
||||
|
||||
The user's topic of interest is:
|
||||
[topic]`,
|
||||
GenerateOptionsUsingAI: `
|
||||
You are the AI of a quiz game.
|
||||
Generate a list of answers relevant to the Question the correct answer index.
|
||||
generate 2 things for the question:
|
||||
- An "answers" array (minimum 2, maximum 8 options)
|
||||
- A "correctAnswer" (index starting from 0)
|
||||
Ensure the questions are diverse.
|
||||
Example format if the question is "What is the capital of France?":
|
||||
{
|
||||
"answers": [
|
||||
"Paris",
|
||||
"London",
|
||||
"Berlin",
|
||||
"Madrid"
|
||||
],
|
||||
"correctAnswer": 0
|
||||
}
|
||||
JUST PROVIDE THE JSON AND NOTHING ELSE.
|
||||
|
||||
The user's Question that they want to generate options for is:
|
||||
[question]
|
||||
`
|
||||
};
|
2
src/lib/showAlert.js
Normal file
2
src/lib/showAlert.js
Normal file
|
@ -0,0 +1,2 @@
|
|||
import JSConfetti from "js-confetti";
|
||||
const jsConfetti = new JSConfetti();
|
6
src/lib/supabase.js
Normal file
6
src/lib/supabase.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
import { createClient } from '@supabase/supabase-js';
|
||||
|
||||
export const supabase = createClient(
|
||||
import.meta.env.VITE_SUPABASE_URL,
|
||||
import.meta.env.VITE_SUPABASE_ANON_KEY
|
||||
);
|
28
src/routes/+HomePage/Galery.svelte
Normal file
28
src/routes/+HomePage/Galery.svelte
Normal file
|
@ -0,0 +1,28 @@
|
|||
<script>
|
||||
import tools from "./tools.json"
|
||||
</script>
|
||||
|
||||
<div class="flex items-center justify-center p-3">
|
||||
<div
|
||||
class="flex flex-wrap justify-center gap-5"
|
||||
>
|
||||
{#each tools as tool}
|
||||
<a href={tool.link} class="flex justify-center">
|
||||
<div class="card flex w-full max-w-xs flex-col items-center text-center">
|
||||
<img
|
||||
class="mb-2 w-full rounded border-2 border-white"
|
||||
src={tool.image}
|
||||
alt="how the tool {tool.name} looks like"
|
||||
/>
|
||||
<div
|
||||
class="flex items-center justify-center text-2xl whitespace-nowrap md:text-3xl lg:text-4xl"
|
||||
>
|
||||
<i class="nf {tool.icon}"></i>
|
||||
<span class="ml-2">{tool.name}</span>
|
||||
</div>
|
||||
<p>{@html tool.description}</p>
|
||||
</div>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
87
src/routes/+HomePage/ascii.svelte
Normal file
87
src/routes/+HomePage/ascii.svelte
Normal file
|
@ -0,0 +1,87 @@
|
|||
<pre class="w-full text-center font-mono text-[4.5px] leading-[0.6] text-gray-500">
|
||||
##########%#% ############%#
|
||||
#%#################% %###################%#%%
|
||||
%%###################### ###########################%
|
||||
########################## %###########################%#
|
||||
%###########################% %#############################%#
|
||||
##############################% ######%##########################
|
||||
%%###############%##%############ %#################################%
|
||||
###############*+=-----=+*%#######% #######+--=+**#####################%
|
||||
%%###########+=-------------*######% %######=--------=-----=*############%
|
||||
############+----------------.######% #######------------------=*###########
|
||||
##########+------------------.######% %#######% ######*----------------::::=##########%
|
||||
%#########=-----------------::.######%############%% %######+--------------::::::-=##########
|
||||
########*-----------------:::.:######################% %######=------------::::::-====*#########
|
||||
%#######*:---------------:::::.-######################## %######=----------::::::-=======*########
|
||||
#######*:::------------::::::-:=########################% #######---------::::::-======+++=########%
|
||||
########=::::----------:::::-==.+#########################% ######*-------::::::-======++++++=#######%
|
||||
#######+==:::::------::...:--==.*#########################% %######+-----:::::.:-=====++++++++=+######%
|
||||
%#######+===-:::::-::...:===--:.:################%########## %######=---::::::=.-==-=+++++++++++-#######%
|
||||
#######*++====::::::. =#######################+++++*######## %%%% %% #%%% #######=-::::::===.####++++++++++++-*####### #%#%###%% #%%####%# %%#%####%%#
|
||||
#######++++====::::..*#######################*++++++==############## #%#####%% %###############::::::====-.#####*++++++++++==##################% %#%############%% %%%%%###############
|
||||
#######+++++=====-..*#######################%**+++++-:##################% %############ #################*::::======--######+++++++++++-###################%% #################### %%%######################%%
|
||||
######*+++++++====.=##############%##########****+++--#####################%%################################+::=======+-=######+++++++++++:######################%#################################################
|
||||
######*++++++++==-.##########################*****++:=#######################################################========+++:+######++++++++**+:#########################################################################
|
||||
######*++++++++++--##########################******+:+#######################################################+=====+++++.######*+++++*****+:##########################################################################
|
||||
######*++++++++++=-##########################*******.*#######################################################====+++++++.######++++*******=-##########################################################################%
|
||||
######*++++++++++==########################%#*******.########################################################==+++++++++=*###*+++*********-=##########***#############################################**+**#############
|
||||
######***++++++++=-########################%#******+.#####*++++++*###############*++++*#########*+===#######*++++++++++++++++++***********.*########*********############********##################*++++++++++##########
|
||||
######****++++++++:#################*+######*******+:####+++++++++++**########%*++++++-#######*+++==-+######*++++++++++++++++************=.#######************#########***********+#######%#+++++=======+++++++*########%
|
||||
#######****+++++++:################***+#####*******=-###++++++++++++++++++####+++++++++=#####++++++++-######*++++++++++++++*************+.+#####**************+*######***********+++*##%**+++=============+++++++########
|
||||
#######*****++++++=+##############****+*####++++***-=##**+++++++++++++++++:##++++++++++-####++++++++++-#####+++++++++++++***************::#####****************=#####*********++++++=*##++==================++++=*#######%
|
||||
#######*******+++++=#############******+*###+++++**:+##***++++++++++++++++.#********+=:.=##+++++++++-: #####+++++++++++****************::######*******+=+*******=###******+++++++++++-##+=========-----=======+++-########
|
||||
#######********+++++=###########******++=###++++++*.*##****+++=-=********=-#********+.=####++++++++::*######+++++++++*****************=.######*+*****-.:==******-###***++++-.:-=+++====#*=====-----------:======+=+#######
|
||||
%######**********+++*+*#######*******++++=##==+++++.##*******-.=*+*******:+#*********-#####++++++++-*######*+++++++***=+************+++-######++++++=.*###******==##++++++:.*###======:#*==---------------+=======-#######%
|
||||
########***************************++++++-=*====++=.##******+.*###*******.###**********####+++++++++=######*+++++*****.==-=*******+++++:######++++++:=####*++++++-#*++++++.*####======:*#------::--------:#=--====:########%
|
||||
#######*************************+++++++=.=+=====+=:##******=-####******+:###**********+####**++++++++*####++++******* ###*=****+++++++-+#####++++++:*####*+++++=:#*+++++=.#####+===--:+#--------#-------.#+----==-*#######%
|
||||
%#######**********************+++++++==::#+======--##******==####******=-####+*********+###+***++++++++###++********+:#####**+++++++===-#####=====+-*####*+++++=:#*++====:#####=-----:+#=------:#+------.**-------=########
|
||||
%#######********************+++++++===- *#=----==:=##+******=####******:+#####+*********=###+*****++++=*##**********=-#####*++++++=====:#####========####++++++:-#*======:####+------.+#=-----:.#*:::---:+#--------########
|
||||
########+****************+++++++====:.+##------=:+##++*****+*##*******:*######+********-####********++-##**********:=######++++=======:#####+========*+=======.*##======--**+-------.*#+--::::.*#:::::::=#=--------#######
|
||||
%########+**************++++++=====:.*###-------.*###++***************:*#######********-+####*********.#***********.*######++=======--:+####*--==============::###===--------------::##*::::::.+#:::::::-##--------.######
|
||||
########%=***********++++++======:.*###*-------.####+++**************=*######++++*****.*####********=:##********** ########======------#####=----------====-.*####---------------:.+###:::::::=#-::::::.##+------.-######
|
||||
##########=+*******+++++++=====-.:#####+-------.#####=++++++++++++++++-####+++++++++*-.###*********+.+##*********=:########====-------:######--------------.=#####+------------::.-####::::::::#=::::::.##%+:---.:#######
|
||||
%#########*=+***+++++++=====-:.=######+::----::######=+++++++++++++++:+###+++++++++-.*###********+.-###-=+****++--#########=---------.######*-----------:.=#######+-------::::..-#####-::::::.#+::::::.*%##*-:..########
|
||||
%##########=-+++++++=====-:.:*#######=::::--:-#######=-=+++++=+++++-.####*+++++++:.*####*******=.=####*+-::--=+:=#########=---------.#######*::-------..+#########*::-:::::...=######=::::::.#*:::::..=#####*+#########
|
||||
############=--======-:..-*##########=:..::.=########*-::::.:=====.+#####====-:.:#######***+=..+###########*=--##########*------::..#########=::::...-#############+:.....:+########+::::::.*#=...--+################
|
||||
%#############+=--::-=*#################*+=##################===.-#######-:..=#########*-:.-+############################----:..:=############*==+*################################*::....:*##*#####################
|
||||
#############################################################*-:#########+*############*+################################:..:=*####################################################*:=+*##########################
|
||||
########################################################################################################################**####################################################################################%
|
||||
#######################%@%##############################################################+++*#######################################*#######################################################################%
|
||||
###################%@@@@@%##############################################**+++########*++++++++###############################+=-::=###############*+-:::*########################################%%###%%
|
||||
################%@@@@@@@@%##################++++*############**+==---------:#######++++++==-:#########################*+=:::::::.=#########*+=-:::::::.######%%%%%#################%%%%#######%
|
||||
##############%@@@@%#%@@@@@%############*+---------###*+=------------------:+######========-:#########*##########*+=-::::::::::::-#####+=-::::::::::::.######%@@@@@@%###########%@@@@@@#######%
|
||||
############%@@@@%%####%@@@@%##########------------.##=------:::::---------:=######========:=########+::-+*#####:::::::::::::::::.###=::::::::::::::::.+#####%@@@@@@@@%#######%@@@@@@@@########
|
||||
##########%@@@@@%########%@@@@%#######::::---::::::.##=:::::::::::::-------:=#####*-======-.+########-::::::-*##:::::::::::::::::.###=:::::::::::::::::=#####%@@@@@@@@@@%###%@@@@@@@@@@#######%
|
||||
#########@@@@@%############%@@@@%####-:::::::::::::.*#=::::::::::::::::----:-#####+-------- #########:::::::::*#:::::::::::::::::.+##+::::::::::::::::::#####%@@%**%@@@@@%#%@@@@@#**@@@########
|
||||
#########%@@@@@%##########%@@@@@@###*::::::::::::::.*#+::::::::::::::::::--::#####=--------.########*::::::::.=#=:::::::::::::::::=##*:::::::::::::::::.#####%@@%****%@@@@@@@@@#****@@@#######%
|
||||
%##########%@@@@@%######%@@@@@@@@###=::::::::::::::.*#*:::::::::::::::::::::.#####--------:-########+::::::::.*#+::::.........:::.:###::::::::::::::::..*####%@@%******%@@@@@%******@@@########
|
||||
%###########@@@@@%###%@@@@@%#@@@###-::::::::::::::.*#*:::::::::::::::......-#####--------.=########-:::::::: ##*::...............+###::::::::::::.....:#####%@@%*******#@@@%*******@@@#######%
|
||||
############@@@@@@@%@@@@%@@%#@@@###:::::::::::..:::*##:::::::::::::::.=+**######+-------:.*########::::::::.:###...........:-=*######=...........:=+*#######%@@%********%@@#*******@@@#######%
|
||||
%##########@@#*%@@@@@%#*@@%#@@@###-:::::::::.=#######+....::::::::::.##########=:----:::.########*::::::::.=###:........=###########+........:#############%@@%********#@@#*******@@@#######%
|
||||
%#########@@#***%@@#***@@%#@@@###-::::::::.:#########**###+::::::::.*#########-:::::::.:########=::::::::.*###=........=#*+=-+#####*.........##*+==#######%@@%********#@@#*******@@@########
|
||||
%########@@#***#@#****@@%#@@@###+:::::::::-##############+::::::::.*#########::::::::.=########-:::::::. ####+........:......+#####:........:.....:######%@@%********%@@#*******@@@#######%
|
||||
########@@@#**#@#***%@@%#@@@####.::::::::-##############*::::::::.+########*::::::::.+########::::::...:####*...::::::::....-#####-.............:.*#####%@@%********%@@#*******@@@%#######
|
||||
########@@@@%*#@#*#@@@@%#%%%####-.:::::::.###############::::::::.=########+:::::::: ########*::::.....=#####::::::::::::::::#####=..........::::.*#####%@@@@%#*****%@@#****%%@@@@#######
|
||||
#########%@@@@%@#@@@@%##########+..::::::.*##############.....::::-########=:::::::::########=::.......*#####=::::::::::::::.#####*:::::..::::::::+#####%@@@@@@@%#**%@@#*#%@@@@@@@#######
|
||||
%##########%@@@@@@@@%############.........-##############:......:::########-:::::::.-########:........ ######+:::--:::::::::.######:::::::::::::::=#####%@@@@@@@@@%*%@@#%@@@@@@@@@#######
|
||||
#########%#%%@@@@%##############-.........##############-........:########::::::::.=#######*.........:######*:------------:.*#####-:::::::::::----#########%%@@@@@@@@@@@@@@@%%##########
|
||||
%############%@%################=.........=#############-.........########::::::::.=#######=.........=#######--------------.+#####=::::::::-----::#############%@@@@@@@@@%##############
|
||||
%##############################=.........-#############=.........########:::::::::=#######:......::.*#######---------...:-=######+--------:...:-*##############%%@@@@@%###############
|
||||
#######################%######:..........#############+.........*#######-:::::::::######-.....::::.########+-------:-###########*--------.*#####################%@@@%################
|
||||
###########################*-::.........#############*:::......+#######=:::::::..:###+-....:::::.=########+---------############--------.########################%#################
|
||||
#%###################%=----:::::::::::.####%########*::::::...+#######*.................::::::: *########*--------:############=-------:+######################################%%
|
||||
%%##################=-----:::::::::::##############::::::::.=########:..............:::::::-:-##########--------.############+-------:=###########%%####################%#%
|
||||
#%########%%######=------::::::::.=##############-::::::::-########*............:::::::--- *##########=-------:+###########*--------:########% #%#################%
|
||||
#%% #######=-------:::::::.###############=---::::::#########-.........:::::::----.-###########+-------:=############--------.#######% ###############%
|
||||
%######=------------:.+###############=-----::::##########:......:::::::-----:.*###########*--------:############--------.*######% %##########%
|
||||
#######+-----------:.+################=--------.###########-...:::::::------:.*#############--------.############=-------:=###### #%####%#
|
||||
%######+---------:.-##################+--------.############=:::::::------:.:*##############--------:*###########+---------######
|
||||
%#######+::::...:=*########## ######*-----::: ##############-:::------:..+################=-------.+###########*-------::######
|
||||
##########*+*#############% #######+..:--=+*################=::::...:=##################+--::..:-#############--::..:-*#####%
|
||||
########################## %###################%#############***#######################=:-+*#################:-=*#########
|
||||
%######################% ###################% %###########################% #########################################%
|
||||
###################### #################%% %#########################%% ####################%##################%
|
||||
#%################# ###############% %######################## %##################% %################%
|
||||
############### %############# ####################%% ################% %###############
|
||||
#%##%%%#% %#######%## %%%###########%%% #############% ###########%%
|
||||
</pre>
|
11
src/routes/+HomePage/footer.svelte
Normal file
11
src/routes/+HomePage/footer.svelte
Normal file
|
@ -0,0 +1,11 @@
|
|||
<div class="mt-5 bg-gray-700 p-3 text-center text-2xl">
|
||||
<div>
|
||||
Made By <a href="https://rezhack.xyz" class="text-blue-400 underline">RezHackXYZ</a> for
|
||||
<a href="https://neighborhood.hackclub.com/" class="text-blue-400 underline">Neighborhood</a>. •
|
||||
Source code available
|
||||
<a href="https://neighborhood.hackclub.com/" class="text-blue-400 underline">here</a>.
|
||||
</div>
|
||||
<div class="text-sm">
|
||||
and the "<a href="?ascii" class="text-blue-400 underline">?ascii</a>" flag for a surprise!
|
||||
</div>
|
||||
</div>
|
42
src/routes/+HomePage/landingPage.svelte
Normal file
42
src/routes/+HomePage/landingPage.svelte
Normal file
|
@ -0,0 +1,42 @@
|
|||
<script>
|
||||
import { onMount } from "svelte";
|
||||
import Ascii from "./ascii.svelte";
|
||||
import RightCards from "./rightCards.svelte";
|
||||
|
||||
let FlagAscii = false;
|
||||
onMount(() => {
|
||||
FlagAscii = new URLSearchParams(window.location.search).has("ascii");
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col h-full justify-between items-center">
|
||||
<div class="flex h-full items-center justify-around w-full">
|
||||
<div class="flex w-[600px] flex-col items-baseline gap-3">
|
||||
{#if FlagAscii == true}
|
||||
<Ascii />
|
||||
{:else}
|
||||
<img
|
||||
src="https://hc-cdn.hel1.your-objectstorage.com/s/v3/77e7a04f27807b4e0c16bcda09ea222f9e091616_group_18.svg"
|
||||
alt="ClassRoomStuff Logo"
|
||||
class="w-[600px]"
|
||||
/>
|
||||
{/if}
|
||||
<h1 class="text-center text-5xl">
|
||||
The
|
||||
<span class="rounded-full bg-blue-800 px-3 py-1 text-3xl">
|
||||
<i class="nf nf-cod-sparkle"></i> ultimate <i class="nf nf-cod-sparkle"></i>
|
||||
</span>
|
||||
classroom
|
||||
<span class="rounded-full bg-green-800 px-3 py-1 text-3xl">
|
||||
<i class="nf nf-cod-tools"></i> toolkit <i class="nf nf-cod-tools"></i>
|
||||
</span> for all the teachers and students needs!
|
||||
</h1>
|
||||
</div>
|
||||
<RightCards />
|
||||
</div>
|
||||
<div class="rounded-full bg-gray-900 px-3 py-1 text-xl text-gray-500 w-fit m-3">
|
||||
<i class="nf-fa-angles_down nf"></i>
|
||||
Scroll to see more tools!
|
||||
<i class="nf-fa-angles_down nf"></i>
|
||||
</div>
|
||||
</div>
|
24
src/routes/+HomePage/rightCards.svelte
Normal file
24
src/routes/+HomePage/rightCards.svelte
Normal file
|
@ -0,0 +1,24 @@
|
|||
<script>
|
||||
import tools from "./tools.json";
|
||||
</script>
|
||||
|
||||
<div class="hidden flex-col gap-3 lg:flex">
|
||||
{#each tools as tool, i}
|
||||
{#if i < 3}
|
||||
<div class="card max-w-[320px]">
|
||||
<div class="flex gap-2 text-4xl">
|
||||
<i class="nf {tool.icon}"></i>
|
||||
<h1>{tool.name}</h1>
|
||||
</div>
|
||||
|
||||
<p>{@html tool.description}</p>
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
<div class="card max-w-[320px]">
|
||||
<div class="flex gap-2 text-4xl">
|
||||
<i class="nf nf-fa-angles_down"></i>
|
||||
<h1>and more!</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
37
src/routes/+HomePage/tools.json
Normal file
37
src/routes/+HomePage/tools.json
Normal file
|
@ -0,0 +1,37 @@
|
|||
[
|
||||
{
|
||||
"name": "Kahoot Clone",
|
||||
"description": "A Kahoot clone built from scratch with a Postgres DB, AI integration, and more.",
|
||||
"link": "/kahootclone",
|
||||
"icon": "nf-md-chat_question",
|
||||
"image": "https://placehold.co/1800x1000?text=screenshot+TBA"
|
||||
},
|
||||
{
|
||||
"name": "Wordle",
|
||||
"description": "with unlimited tries, customizable world lengths and more.",
|
||||
"link": "/wordle",
|
||||
"icon": "nf-md-file_word_box",
|
||||
"image": "https://placehold.co/1800x1000?text=screenshot+TBA"
|
||||
},
|
||||
{
|
||||
"name": "Announcer",
|
||||
"description": "To let the have computer <strike>talk</strike> shout on them, if they don't listen to you",
|
||||
"link": "/announcer",
|
||||
"icon": "nf-md-speaker_wireless",
|
||||
"image": "https://placehold.co/1800x1000?text=screenshot+TBA"
|
||||
},
|
||||
{
|
||||
"name": "Name Selecter",
|
||||
"description": "to chose any student randomly, with memory of previous names and more.",
|
||||
"link": "/randomname",
|
||||
"icon": "nf-oct-people",
|
||||
"image": "https://placehold.co/1800x1000?text=screenshot+TBA"
|
||||
},
|
||||
{
|
||||
"name": "Time&Table",
|
||||
"description": "The perfect idle screen when theres no teacher with the timetable, time and date!",
|
||||
"link": "/randomname",
|
||||
"icon": "nf-cod-table",
|
||||
"image": "https://placehold.co/1800x1000?text=screenshot+TBA"
|
||||
}
|
||||
]
|
1
src/routes/+layout.js
Normal file
1
src/routes/+layout.js
Normal file
|
@ -0,0 +1 @@
|
|||
export const prerender = true;
|
9
src/routes/+layout.svelte
Normal file
9
src/routes/+layout.svelte
Normal file
|
@ -0,0 +1,9 @@
|
|||
<script>
|
||||
import "./tailwind.css";
|
||||
|
||||
import { Toaster } from "svelte-5-french-toast";
|
||||
let { children } = $props();
|
||||
</script>
|
||||
|
||||
<Toaster />
|
||||
<div class="h-full font-[Sour_Gummy]">{@render children()}</div>
|
9
src/routes/+page.svelte
Normal file
9
src/routes/+page.svelte
Normal file
|
@ -0,0 +1,9 @@
|
|||
<script>
|
||||
import LandingPage from "./+HomePage/landingPage.svelte";
|
||||
import Galery from "./+HomePage/Galery.svelte";
|
||||
import Footer from "./+HomePage/footer.svelte";
|
||||
</script>
|
||||
|
||||
<LandingPage />
|
||||
<Galery />
|
||||
<Footer />
|
36
src/routes/IdleScreen/+page.svelte
Normal file
36
src/routes/IdleScreen/+page.svelte
Normal file
|
@ -0,0 +1,36 @@
|
|||
<script module>
|
||||
import { Modal, Content, Trigger } from "sv-popup";
|
||||
|
||||
import Time from "./components/time/DisplayCollsOfTime.svelte";
|
||||
import TimeTable from "./components/timetable/DisplayRowsOfTimetable.svelte";
|
||||
import EditTimetableDiv from "./components/timetable/EditTimetable.svelte";
|
||||
import { colseModal } from "./logic/TimeAndTableData.svelte.js";
|
||||
|
||||
export let ShowSeconds = $state({ v: true });
|
||||
</script>
|
||||
|
||||
<div class="flex h-full flex-col">
|
||||
<div>
|
||||
<button
|
||||
class="btn"
|
||||
onclick={() => {
|
||||
ShowSeconds.v = !ShowSeconds.v;
|
||||
localStorage.setItem("ShowSeconds", String(ShowSeconds.v));
|
||||
}}
|
||||
>
|
||||
{#if ShowSeconds.v}Disable Seconds{:else}Enable Seconds{/if}</button
|
||||
>
|
||||
<Modal big={true} close={colseModal.v}>
|
||||
<Content>
|
||||
<EditTimetableDiv />
|
||||
</Content>
|
||||
<Trigger>
|
||||
<button class="btn">Edit timetable </button>
|
||||
</Trigger>
|
||||
</Modal>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-1 flex-col items-center justify-center">
|
||||
<Time /><TimeTable />
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,40 @@
|
|||
<script>
|
||||
import { onMount } from "svelte";
|
||||
import Row from "./row.svelte";
|
||||
|
||||
let ShowSeconds;
|
||||
let ampm;
|
||||
|
||||
onMount(() => {
|
||||
ShowSeconds = localStorage.getItem("ShowSeconds") || "true" == "true" ? true : false;
|
||||
setInterval(() => {
|
||||
ampm = new Date().getHours() >= 12 ? "PM" : "AM";
|
||||
}, 1000);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="m-5 w-fit rounded-lg bg-gray-700 p-3">
|
||||
<div class="flex items-baseline justify-center">
|
||||
<Row type={"hour"} digit={0} />
|
||||
<Row type={"hour"} digit={1} />
|
||||
<h1 class="m-0 text-[200px] leading-[200px]">:</h1>
|
||||
<Row type={"min"} digit={0} />
|
||||
<Row type={"min"} digit={1} />
|
||||
|
||||
{#if ShowSeconds}
|
||||
<h1 class="text-[75px] leading-none text-gray-500">.</h1>
|
||||
|
||||
<Row type={"sec"} digit={0} />
|
||||
<Row type={"sec"} digit={1} />
|
||||
{/if}
|
||||
<h1 class="text-[75px] leading-none text-gray-500 ml-3">{ampm}</h1>
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="text-center text-5xl text-gray-300">
|
||||
{new Date().toLocaleString("en-US", { weekday: "short" })}
|
||||
{new Date().getDate()},
|
||||
{new Date().toLocaleString("en-US", { month: "short" })}
|
||||
{new Date().getFullYear()}
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
11
src/routes/IdleScreen/components/time/digit.svelte
Normal file
11
src/routes/IdleScreen/components/time/digit.svelte
Normal file
|
@ -0,0 +1,11 @@
|
|||
<script>
|
||||
let props = $props();
|
||||
</script>
|
||||
|
||||
{#if props.size == "small"}
|
||||
<h1 class="flex items-center justify-center text-[75px] leading-none m-0 text-gray-500">
|
||||
{props.digit}
|
||||
</h1>
|
||||
{:else if props.size == "large"}
|
||||
<h1 class="flex items-center justify-center text-[200px] leading-none m-0">{props.digit}</h1>
|
||||
{/if}
|
29
src/routes/IdleScreen/components/time/row.svelte
Normal file
29
src/routes/IdleScreen/components/time/row.svelte
Normal file
|
@ -0,0 +1,29 @@
|
|||
<script>
|
||||
import { onMount } from "svelte";
|
||||
import Digit from "./digit.svelte";
|
||||
import { updateTime } from "../../logic/updateTime.js";
|
||||
|
||||
let props = $props();
|
||||
let size = props.type == "sec" ? "small" : "large";
|
||||
let digit = props.digit;
|
||||
let digits = digit == 1 ? 10 : digit == 0 && props.type == "hour" ? 2 : 6;
|
||||
|
||||
let thisRow;
|
||||
|
||||
onMount(() => {
|
||||
setInterval(() => {
|
||||
updateTime(thisRow, digit, props.type);
|
||||
}, 1000);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div
|
||||
style="--height: {size == 'small' ? '75px' : '200px'};"
|
||||
class="flex h-(--height) flex-col overflow-y-hidden scroll-smooth"
|
||||
bind:this={thisRow}
|
||||
>
|
||||
{#each Array(digits) as _, i}
|
||||
<Digit {size} digit={i} />
|
||||
{/each}
|
||||
<Digit {size} digit={0} />
|
||||
</div>
|
|
@ -0,0 +1,37 @@
|
|||
<script>
|
||||
import { onMount } from "svelte";
|
||||
import { timetableData } from "../../logic/TimeAndTableData.svelte";
|
||||
|
||||
let legend = ["", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
|
||||
|
||||
onMount(() => {
|
||||
timetableData.v = JSON.parse(localStorage.getItem("timetableData")) || timetableData.v;
|
||||
});
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="m-5 grid grid-cols-[auto_repeat(var(--NoOfPeriods),_auto)] gap-1 gap-x-1 gap-y-2 rounded-lg bg-gray-800 p-3"
|
||||
style="--NoOfPeriods: {timetableData.v[0].length - 1};"
|
||||
>
|
||||
{#each timetableData.v as row, RowIndex}
|
||||
{#each row as time, timeIndex}
|
||||
{#if RowIndex == 0 && timeIndex == 0}
|
||||
<span class="rounded-xl bg-transparent p-1.5 text-center text-xl"></span>
|
||||
{:else if RowIndex == 0}
|
||||
<span class="rounded-xl bg-blue-800 p-1.5 text-center text-xl">{time}</span>
|
||||
{:else if RowIndex == new Date().getDay() && timeIndex == 0}
|
||||
<span class="rounded-xl bg-green-600 p-1.5 text-center text-xl"
|
||||
>{legend[RowIndex]}</span
|
||||
>
|
||||
{:else if RowIndex == new Date().getDay()}
|
||||
<span class="rounded-xl bg-green-600 p-1.5 text-center text-xl">{time}</span>
|
||||
{:else if timeIndex == 0}
|
||||
<span class="rounded-xl bg-green-900 p-1.5 text-center text-xl"
|
||||
>{legend[RowIndex]}</span
|
||||
>
|
||||
{:else}
|
||||
<span class="rounded-xl bg-gray-700 p-1.5 text-center text-xl">{time}</span>
|
||||
{/if}
|
||||
{/each}
|
||||
{/each}
|
||||
</div>
|
|
@ -0,0 +1,58 @@
|
|||
<script>
|
||||
import { onMount } from "svelte";
|
||||
import { timetableData } from "../../logic/TimeAndTableData.svelte";
|
||||
|
||||
let data = $state.snapshot(timetableData).v;
|
||||
|
||||
let legend = ["", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
|
||||
|
||||
import { colseModal } from "../../logic/TimeAndTableData.svelte.js";
|
||||
|
||||
onMount(() => {
|
||||
colseModal.v = false;
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="m-5 flex flex-col items-center justify-center rounded-lg bg-gray-800 p-3">
|
||||
<div
|
||||
class=" flex flex-col gap-1 gap-x-1 gap-y-2 overflow-x-auto"
|
||||
style="--NoOfPeriods: {timetableData.v[0].length - 1};"
|
||||
>
|
||||
{#each data as row, RowIndex}
|
||||
<div class="flex">
|
||||
{#each row as _, timeIndex}
|
||||
{#if RowIndex == 0 && timeIndex == 0}
|
||||
<input class="rounded-xl bg-transparent p-0.5 text-center" disabled />
|
||||
{:else if timeIndex == 0}
|
||||
<input
|
||||
class="rounded-xl bg-green-900 p-0.5 text-center"
|
||||
bind:value={legend[RowIndex]}
|
||||
disabled
|
||||
/>
|
||||
{:else if RowIndex == 0}
|
||||
<input
|
||||
class="rounded-xl border-2 border-white bg-blue-800 p-0.5 text-center"
|
||||
bind:value={data[RowIndex][timeIndex]}
|
||||
/>
|
||||
{:else}
|
||||
<input
|
||||
class="rounded-xl border-2 border-white bg-gray-700 p-0.5 text-center"
|
||||
bind:value={data[RowIndex][timeIndex]}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button
|
||||
onclick={() => {
|
||||
timetableData.v = data;
|
||||
localStorage.setItem("timetableData", JSON.stringify(data));
|
||||
colseModal.v = true;
|
||||
}}
|
||||
class="btn green mt-3">SAVE</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
20
src/routes/IdleScreen/logic/TimeAndTableData.svelte.js
Normal file
20
src/routes/IdleScreen/logic/TimeAndTableData.svelte.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
export let timetableData = $state({
|
||||
v: [
|
||||
[
|
||||
"07:50 - 08:50",
|
||||
"08:50 - 09:40",
|
||||
"09:40 - 10:30 ",
|
||||
"10:30 - 11:00",
|
||||
"11:00 - 12:00",
|
||||
"12:00 - 01:00",
|
||||
"01:00 - 02:00",
|
||||
],
|
||||
["English", "Sanskrit", "Math", "Lunch", "Hindi", "Social Science", "Science"],
|
||||
["English", "Art & Craft", "Math", "Lunch", "Hindi", "Social Science", "Science"],
|
||||
["English", "GK", "Math", "Lunch", "Hindi", "Social Science", "Science"],
|
||||
["English", "Sanskrit", "Math", "Lunch", "Hindi", "Social Science", "Science"],
|
||||
["English", "Computers", "Math", "Lunch", "Hindi", "Social Science", "Science"],
|
||||
],
|
||||
});
|
||||
|
||||
export let colseModal = $state({ v: false });
|
31
src/routes/IdleScreen/logic/updateTime.js
Normal file
31
src/routes/IdleScreen/logic/updateTime.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
export function updateTime(RowsObject, Digit, type) {
|
||||
let DigitsHeight = parseInt(type == "sec" ? "75" : "200");
|
||||
let LastZeroPos = Digit == 1 ? 10 : Digit == 0 && type == "hour" ? 2 : 6;
|
||||
let currentTime;
|
||||
|
||||
if (type == "hour") {
|
||||
if (new Date().getHours() > 12) {
|
||||
currentTime = parseInt((new Date().getHours() - 12).toString().padStart(2, "0")[Digit]);
|
||||
} else {
|
||||
currentTime = parseInt(new Date().getHours().toString().padStart(2, "0")[Digit]);
|
||||
}
|
||||
} else if (type == "min") {
|
||||
currentTime = parseInt(new Date().getMinutes().toString().padStart(2, "0")[Digit]);
|
||||
} else if (type == "sec") {
|
||||
currentTime = parseInt(new Date().getSeconds().toString().padStart(2, "0")[Digit]);
|
||||
}
|
||||
|
||||
if (currentTime == 0) {
|
||||
if (RowsObject.scrollTop != 0) {
|
||||
RowsObject.scrollTop = LastZeroPos * DigitsHeight;
|
||||
setTimeout(() => {
|
||||
RowsObject.scroll({
|
||||
top: 0,
|
||||
behavior: "instant",
|
||||
});
|
||||
}, 500);
|
||||
}
|
||||
} else {
|
||||
RowsObject.scrollTop = currentTime * DigitsHeight;
|
||||
}
|
||||
}
|
20
src/routes/announcer/+page.svelte
Normal file
20
src/routes/announcer/+page.svelte
Normal file
|
@ -0,0 +1,20 @@
|
|||
<script>
|
||||
import List from "./components/CommonAnounceedTexts/list.svelte";
|
||||
import Add from "./components/CustomText/add.svelte";
|
||||
import CustomText from "./components/CustomText/CustomText.svelte";
|
||||
|
||||
import { onMount } from "svelte";
|
||||
import { LoadMostUsedAnnouncement } from "./logic/LoadMostUsedAnnouncement.js";
|
||||
onMount(() => LoadMostUsedAnnouncement());
|
||||
</script>
|
||||
|
||||
<div class="flex h-full flex-col items-center justify-center gap-5 p-5">
|
||||
<div class="w-fit rounded-2xl bg-gray-900 p-3">
|
||||
<h1 class="text-center text-4xl">Most Announced announcements</h1>
|
||||
<List />
|
||||
<hr class="my-5 w-full border-gray-600" />
|
||||
<h1 class="text-center text-4xl">Or announce something else</h1>
|
||||
<CustomText />
|
||||
<Add />
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,14 @@
|
|||
<script>
|
||||
import { DeleteMostUsedAnnouncement } from "../../logic/AddAndDeleteMostUsedAnnouncements.js";
|
||||
|
||||
let props = $props();
|
||||
let announcementID = props.announcementID;
|
||||
</script>
|
||||
|
||||
<button
|
||||
class="cursor-pointer rounded-2xl bg-gray-800 p-2.5 text-2xl transition-all hover:scale-120 hover:-rotate-15 hover:bg-gray-600"
|
||||
aria-label="Delete announcement"
|
||||
onclick={() => DeleteMostUsedAnnouncement(announcementID)}
|
||||
>
|
||||
<i class="nf nf-md-trash_can_outline"></i></button
|
||||
>
|
|
@ -0,0 +1,12 @@
|
|||
<script>
|
||||
import { MostUsedAnnouncements } from "../../logic/announcerData.svelte.js";
|
||||
import Delete from "./delete.svelte";
|
||||
import Text from "./text.svelte";
|
||||
</script>
|
||||
|
||||
{#each MostUsedAnnouncements.v as announcementText, announcementID}
|
||||
<div class="flex w-full gap-2 mt-2">
|
||||
<Text {announcementText} />
|
||||
<Delete {announcementID} />
|
||||
</div>
|
||||
{/each}
|
|
@ -0,0 +1,13 @@
|
|||
<script>
|
||||
import { AnnounceUsingTTS } from "../../logic/AnnounceUsingTTS.js";
|
||||
|
||||
let props = $props();
|
||||
let announcementText = props.announcementText;
|
||||
</script>
|
||||
|
||||
<button
|
||||
class="w-full cursor-pointer rounded-2xl bg-gray-800 p-2.5 text-2xl transition-all hover:scale-105 hover:bg-gray-600"
|
||||
onclick={() => AnnounceUsingTTS(announcementText)}
|
||||
>
|
||||
{announcementText}
|
||||
</button>
|
|
@ -0,0 +1,9 @@
|
|||
<script>
|
||||
import Input from "./input.svelte";
|
||||
import Play from "./play.svelte";
|
||||
</script>
|
||||
|
||||
<div class="mt-2 flex gap-2">
|
||||
<Input />
|
||||
<Play />
|
||||
</div>
|
16
src/routes/announcer/components/CustomText/add.svelte
Normal file
16
src/routes/announcer/components/CustomText/add.svelte
Normal file
|
@ -0,0 +1,16 @@
|
|||
<script>
|
||||
import { AddMostUsedAnnouncement } from "../../logic/AddAndDeleteMostUsedAnnouncements.js";
|
||||
import { CurrentText } from "../../logic/announcerData.svelte.js";
|
||||
</script>
|
||||
|
||||
{#if CurrentText.v}
|
||||
<div class="flex w-full justify-center mt-2">
|
||||
<button
|
||||
class="text-1xl w-fit cursor-pointer self-center rounded-2xl bg-gray-800 p-2.5 transition-all hover:scale-110 hover:bg-gray-600"
|
||||
onclick={() => {
|
||||
AddMostUsedAnnouncement(CurrentText.v);
|
||||
CurrentText.v = "";
|
||||
}}>Add "{CurrentText.v}" to "Most Announced announcements"</button
|
||||
>
|
||||
</div>
|
||||
{/if}
|
9
src/routes/announcer/components/CustomText/input.svelte
Normal file
9
src/routes/announcer/components/CustomText/input.svelte
Normal file
|
@ -0,0 +1,9 @@
|
|||
<script>
|
||||
import { CurrentText } from "../../logic/announcerData.svelte.js";
|
||||
</script>
|
||||
|
||||
<input
|
||||
bind:value={CurrentText.v}
|
||||
placeholder="Type in here what you want to announce"
|
||||
class="flex-1 rounded-2xl bg-gray-800 p-2.5 text-2xl"
|
||||
/>
|
11
src/routes/announcer/components/CustomText/play.svelte
Normal file
11
src/routes/announcer/components/CustomText/play.svelte
Normal file
|
@ -0,0 +1,11 @@
|
|||
<script>
|
||||
import { AnnounceUsingTTS } from "../../logic/AnnounceUsingTTS.js";
|
||||
import { CurrentText } from "../../logic/announcerData.svelte.js";
|
||||
</script>
|
||||
|
||||
<button
|
||||
class="cursor-pointer rounded-2xl bg-gray-800 p-2.5 text-2xl transition-all hover:scale-120 hover:-rotate-15 hover:bg-gray-600"
|
||||
onclick={() => AnnounceUsingTTS(CurrentText.v)}
|
||||
>
|
||||
📢</button
|
||||
>
|
|
@ -0,0 +1,13 @@
|
|||
import { MostUsedAnnouncements } from "./announcerData.svelte.js";
|
||||
|
||||
export function AddMostUsedAnnouncement(announcementText) {
|
||||
MostUsedAnnouncements.v.push(announcementText);
|
||||
localStorage.setItem("MostUsedAnnouncements", JSON.stringify(MostUsedAnnouncements.v));
|
||||
}
|
||||
|
||||
export function DeleteMostUsedAnnouncement(announcementID) {
|
||||
if (confirm("Are you sure you want to delete this announcement?")) {
|
||||
MostUsedAnnouncements.v.splice(announcementID, 1);
|
||||
localStorage.setItem("MostUsedAnnouncements", JSON.stringify(MostUsedAnnouncements.v));
|
||||
}
|
||||
}
|
7
src/routes/announcer/logic/AnnounceUsingTTS.js
Normal file
7
src/routes/announcer/logic/AnnounceUsingTTS.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
export function AnnounceUsingTTS(text) {
|
||||
window.speechSynthesis.speak(
|
||||
Object.assign(new SpeechSynthesisUtterance(text), {
|
||||
rate: 0.5,
|
||||
}),
|
||||
);
|
||||
}
|
12
src/routes/announcer/logic/LoadMostUsedAnnouncement.js
Normal file
12
src/routes/announcer/logic/LoadMostUsedAnnouncement.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { MostUsedAnnouncements } from "./announcerData.svelte.js";
|
||||
|
||||
export function LoadMostUsedAnnouncement() {
|
||||
let TempMostUsedAnnouncements = JSON.parse(localStorage.getItem("MostUsedAnnouncements")) || "";
|
||||
|
||||
if (TempMostUsedAnnouncements == "") {
|
||||
MostUsedAnnouncements.v = ["Please be quiet"];
|
||||
localStorage.setItem("MostUsedAnnouncements", JSON.stringify(MostUsedAnnouncements.v));
|
||||
} else {
|
||||
MostUsedAnnouncements.v = TempMostUsedAnnouncements;
|
||||
}
|
||||
}
|
2
src/routes/announcer/logic/announcerData.svelte.js
Normal file
2
src/routes/announcer/logic/announcerData.svelte.js
Normal file
|
@ -0,0 +1,2 @@
|
|||
export let CurrentText = $state({ v: "" });
|
||||
export let MostUsedAnnouncements = $state({ v: [] });
|
18
src/routes/kahootclone/+page.svelte
Normal file
18
src/routes/kahootclone/+page.svelte
Normal file
|
@ -0,0 +1,18 @@
|
|||
<div class="bg-grey-900 flex h-full items-center justify-center">
|
||||
<div class="flex flex-col items-center justify-center gap-1 rounded-lg bg-gray-900 p-8 shadow-lg">
|
||||
<h1 class="m-[0] text-6xl">DaKahootClone</h1>
|
||||
<p class="m-[0] mb-2 text-lg text-gray-400">The best ever kahoot clone.</p>
|
||||
<a href="./kahootclone/join">
|
||||
<button
|
||||
class="cursor-pointer rounded-full bg-green-700 p-2 transition-all hover:scale-110 hover:-rotate-10"
|
||||
>Join a game</button
|
||||
></a
|
||||
>
|
||||
<a href="./kahootclone/create">
|
||||
<button
|
||||
class="cursor-pointer rounded-full bg-blue-700 p-2 transition-all hover:scale-110 hover:-rotate-10"
|
||||
>Create and Host a game</button
|
||||
>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
28
src/routes/kahootclone/create/+page.svelte
Normal file
28
src/routes/kahootclone/create/+page.svelte
Normal file
|
@ -0,0 +1,28 @@
|
|||
<script>
|
||||
import UseDemoQuestions from "./components/buttons/UseDemoQuestions.svelte";
|
||||
import NewQuestion from "./components/buttons/NewQuestion.svelte";
|
||||
import StartGame from "./components/buttons/StartGame.svelte";
|
||||
import Question from "./components/Questions/question.svelte";
|
||||
import { questions, Wait } from "./logic/GameCreateData.svelte.js";
|
||||
import WaitStartGame from "./components/buttons/WaitStartGame.svelte";
|
||||
import GenerateQuetionsUsingAi from "./components/buttons/GenerateQuetionsUsingAI.svelte";
|
||||
</script>
|
||||
|
||||
<div class="bg-grey-900 flex justify-center p-5">
|
||||
<div
|
||||
class="flex flex-col items-center justify-center gap-1 rounded-lg bg-gray-900 p-8 shadow-lg"
|
||||
>
|
||||
<div class="flex gap-3"><UseDemoQuestions /> <GenerateQuetionsUsingAi /></div>
|
||||
{#each questions.v as question, index}
|
||||
<Question {index} />
|
||||
{/each}
|
||||
<div class="flex gap-3">
|
||||
<NewQuestion />
|
||||
{#if Wait.v == false}
|
||||
<StartGame />
|
||||
{:else}
|
||||
<WaitStartGame />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,23 @@
|
|||
<script>
|
||||
import { questions } from '../../logic/GameCreateData.svelte.js';
|
||||
|
||||
let props = $props();
|
||||
let questionsIndex = props.questionsIndex;
|
||||
let index = props.answersIndex;
|
||||
</script>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<input
|
||||
type="radio"
|
||||
value={index}
|
||||
name={index.toString()}
|
||||
bind:group={questions.v[questionsIndex].correctAnswer}
|
||||
class="input"
|
||||
/>
|
||||
|
||||
<input
|
||||
placeholder="Option {index + 1}"
|
||||
bind:value={questions.v[questionsIndex].answers[index]}
|
||||
class="w-[500px] rounded-lg bg-gray-800 p-1 text-center text-white"
|
||||
/>
|
||||
</div>
|
|
@ -0,0 +1,54 @@
|
|||
<script>
|
||||
import DeleteQuestion from "../buttons/DeleteQuestion.svelte";
|
||||
import GenerateOptionsUsingAI from "../buttons/GenerateOptionsUsingAI.svelte";
|
||||
import Answers from "./answers.svelte";
|
||||
import { questions } from "../../logic/GameCreateData.svelte.js";
|
||||
|
||||
let props = $props();
|
||||
let index = props.index;
|
||||
</script>
|
||||
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="mb-3 flex flex-col items-center justify-center gap-1 rounded-2xl bg-gray-600 p-2">
|
||||
<div class="flex h-fit items-center gap-3">
|
||||
<h1 class="mt-2 mb-3 text-2xl">Q{index + 1}.</h1>
|
||||
<input
|
||||
type="text"
|
||||
bind:value={questions.v[index].name}
|
||||
placeholder="Question {index + 1}"
|
||||
class="h-fit w-[500px] rounded-xl bg-gray-800 p-1 text-center text-2xl text-white"
|
||||
/>
|
||||
<select
|
||||
bind:value={questions.v[index].answers.length}
|
||||
onchange={(e) => {
|
||||
const newLength = questions.v[index].answers.length;
|
||||
const currentAnswers = questions.v[index].answers;
|
||||
|
||||
if (newLength > currentAnswers.length) {
|
||||
// Add more answers
|
||||
while (questions.v[index].answers.length < newLength) {
|
||||
questions.v[index].answers.push("");
|
||||
}
|
||||
} else if (newLength < currentAnswers.length) {
|
||||
// Remove excess answers
|
||||
questions.v[index].answers = currentAnswers.slice(0, newLength);
|
||||
}
|
||||
}}
|
||||
class="h-fit rounded-xl bg-gray-800 p-1 text-center text-white"
|
||||
>
|
||||
<option disabled selected>Options</option>
|
||||
{#each Array(7) as _, i}
|
||||
<option value={i + 2}>{i + 2}</option>
|
||||
{/each}
|
||||
</select>
|
||||
<DeleteQuestion {index} />
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-2">
|
||||
{#each questions.v[index].answers as _, answersIndex}
|
||||
<Answers questionsIndex={index} {answersIndex} />
|
||||
{/each}
|
||||
</div>
|
||||
<GenerateOptionsUsingAI {index} />
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,20 @@
|
|||
<script>
|
||||
import { DeleteQuestion } from '../../logic/GameCreateData.svelte.js';
|
||||
|
||||
let props = $props();
|
||||
</script>
|
||||
|
||||
<button
|
||||
onclick={() => DeleteQuestion(props.index)}
|
||||
class="flex h-fit cursor-pointer items-center justify-center rounded-xl bg-red-700 p-2 transition-all hover:scale-110 hover:-rotate-10"
|
||||
><svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="24px"
|
||||
viewBox="0 -960 960 960"
|
||||
width="24px"
|
||||
fill="#FFFFFF"
|
||||
><path
|
||||
d="M280-120q-33 0-56.5-23.5T200-200v-520h-40v-80h200v-40h240v40h200v80h-40v520q0 33-23.5 56.5T680-120H280Zm400-600H280v520h400v-520ZM360-280h80v-360h-80v360Zm160 0h80v-360h-80v360ZM280-720v520-520Z"
|
||||
/></svg
|
||||
>Delete question</button
|
||||
>
|
|
@ -0,0 +1,19 @@
|
|||
<script>
|
||||
import { GenerateOptionsUsingAI } from "../../logic/GenerateOptionsUsingAI.js";
|
||||
import { questions } from "../../logic/GameCreateData.svelte.js";
|
||||
|
||||
let props = $props();
|
||||
let index = props.index;
|
||||
</script>
|
||||
|
||||
{#if questions.v[index].answers.every((answer) => answer === "")}
|
||||
<button
|
||||
onclick={() => {
|
||||
GenerateOptionsUsingAI(index);
|
||||
}}
|
||||
class="mt-1 mb-1 flex h-fit cursor-pointer items-center justify-center gap-2 rounded-xl bg-blue-700 p-2 transition-all hover:scale-110 hover:-rotate-5"
|
||||
>
|
||||
<i class="nf nf-cod-sparkle"></i>
|
||||
Generate Options using AI
|
||||
</button>
|
||||
{/if}
|
|
@ -0,0 +1,14 @@
|
|||
<script>
|
||||
import { GenerateQuestionsUsingAI } from "../../logic/GenerateQuestionsUsingAI.js";
|
||||
import { questions } from "../../logic/GameCreateData.svelte.js";
|
||||
</script>
|
||||
|
||||
{#if questions.v.length === 0 || (questions.v.length === 1 && questions.v[0].name === "" && questions.v[0].answers.every((answer) => answer === "") && questions.v[0].correctAnswer === undefined)}
|
||||
<button
|
||||
onclick={GenerateQuestionsUsingAI}
|
||||
class="-mt-5 mb-3 flex h-fit cursor-pointer items-center justify-center gap-2 rounded-xl bg-blue-700 p-2 transition-all hover:scale-110 hover:-rotate-5"
|
||||
>
|
||||
<i class="nf nf-cod-sparkle"></i>
|
||||
Generate questions using AI
|
||||
</button>
|
||||
{/if}
|
|
@ -0,0 +1,15 @@
|
|||
<script>
|
||||
import { AddQuestion } from '../../logic/GameCreateData.svelte.js';
|
||||
</script>
|
||||
|
||||
<button
|
||||
onclick={() => AddQuestion()}
|
||||
class="flex h-fit cursor-pointer items-center justify-center rounded-xl bg-green-700 p-2 transition-all hover:scale-110 hover:-rotate-10"
|
||||
><svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="24px"
|
||||
viewBox="0 -960 960 960"
|
||||
width="24px"
|
||||
fill="#FFFFFF"><path d="M440-440H200v-80h240v-240h80v240h240v80H520v240h-80v-240Z" /></svg
|
||||
>New question</button
|
||||
>
|
|
@ -0,0 +1,18 @@
|
|||
<script>
|
||||
import { startGame } from '../../logic/StartGame.js';
|
||||
</script>
|
||||
|
||||
<button
|
||||
onclick={startGame}
|
||||
class="flex h-fit cursor-pointer items-center justify-center gap-1 rounded-xl bg-green-700 p-2 transition-all hover:scale-110 hover:-rotate-10"
|
||||
><svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="24px"
|
||||
viewBox="0 -960 960 960"
|
||||
width="24px"
|
||||
fill="#FFFFFF"
|
||||
><path
|
||||
d="M560-360q17 0 29.5-12.5T602-402q0-17-12.5-29.5T560-444q-17 0-29.5 12.5T518-402q0 17 12.5 29.5T560-360Zm-30-128h60q0-29 6-42.5t28-35.5q30-30 40-48.5t10-43.5q0-45-31.5-73.5T560-760q-41 0-71.5 23T446-676l54 22q9-25 24.5-37.5T560-704q24 0 39 13.5t15 36.5q0 14-8 26.5T578-596q-33 29-40.5 45.5T530-488ZM320-240q-33 0-56.5-23.5T240-320v-480q0-33 23.5-56.5T320-880h480q33 0 56.5 23.5T880-800v480q0 33-23.5 56.5T800-240H320Zm0-80h480v-480H320v480ZM160-80q-33 0-56.5-23.5T80-160v-560h80v560h560v80H160Zm160-720v480-480Z"
|
||||
/></svg
|
||||
>Start Quiz</button
|
||||
>
|
|
@ -0,0 +1,15 @@
|
|||
<script>
|
||||
import { SetQuestionsToDemoQuestions } from '../../logic/GameCreateData.svelte.js';
|
||||
</script>
|
||||
|
||||
<button
|
||||
onclick={() => SetQuestionsToDemoQuestions()}
|
||||
class="-mt-5 mb-3 flex h-fit cursor-pointer items-center justify-center rounded-xl bg-green-700 p-2 transition-all hover:scale-110 hover:-rotate-10"
|
||||
><svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="24px"
|
||||
viewBox="0 -960 960 960"
|
||||
width="24px"
|
||||
fill="#FFFFFF"><path d="M440-440H200v-80h240v-240h80v240h240v80H520v240h-80v-240Z" /></svg
|
||||
>Use demo questions</button
|
||||
>
|
|
@ -0,0 +1,18 @@
|
|||
<script>
|
||||
import { startGame } from "../../logic/StartGame.js";
|
||||
</script>
|
||||
|
||||
<button
|
||||
onclick={startGame}
|
||||
class="flex h-fit cursor-pointer items-center justify-center gap-1 rounded-xl bg-gray-700 p-2 transition-all hover:scale-110"
|
||||
><svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="24px"
|
||||
viewBox="0 -960 960 960"
|
||||
width="24px"
|
||||
fill="#FFFFFF"
|
||||
><path
|
||||
d="M560-360q17 0 29.5-12.5T602-402q0-17-12.5-29.5T560-444q-17 0-29.5 12.5T518-402q0 17 12.5 29.5T560-360Zm-30-128h60q0-29 6-42.5t28-35.5q30-30 40-48.5t10-43.5q0-45-31.5-73.5T560-760q-41 0-71.5 23T446-676l54 22q9-25 24.5-37.5T560-704q24 0 39 13.5t15 36.5q0 14-8 26.5T578-596q-33 29-40.5 45.5T530-488ZM320-240q-33 0-56.5-23.5T240-320v-480q0-33 23.5-56.5T320-880h480q33 0 56.5 23.5T880-800v480q0 33-23.5 56.5T800-240H320Zm0-80h480v-480H320v480ZM160-80q-33 0-56.5-23.5T80-160v-560h80v560h560v80H160Zm160-720v480-480Z"
|
||||
/></svg
|
||||
>Wait for game to be created</button
|
||||
>
|
36
src/routes/kahootclone/create/logic/GameCreateData.svelte.js
Normal file
36
src/routes/kahootclone/create/logic/GameCreateData.svelte.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
import { DefaultQuestions } from "$lib/config.js";
|
||||
|
||||
export let Wait = $state({
|
||||
v: false,
|
||||
});
|
||||
export let questions = $state({
|
||||
v: [
|
||||
{
|
||||
name: "",
|
||||
answers: ["", "", "", ""],
|
||||
correctAnswer: undefined,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
export function SetQuestionsToDemoQuestions() {
|
||||
questions.v = DefaultQuestions;
|
||||
}
|
||||
|
||||
export function AddQuestion() {
|
||||
questions.v.push({
|
||||
name: "",
|
||||
answers: ["", "", "", ""],
|
||||
correctAnswer: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
export function DeleteQuestion(index) {
|
||||
if (questions.v.length > 1) {
|
||||
if (confirm("Are you sure you want to delete this question? You cant undo this.")) {
|
||||
questions.v.splice(index, 1);
|
||||
}
|
||||
} else {
|
||||
alert("You need at least one question.");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
import { questions } from "./GameCreateData.svelte.js";
|
||||
import { AiPrompts } from "$lib/config.js";
|
||||
|
||||
export function GenerateOptionsUsingAI(index) {
|
||||
fetch("https://ai.hackclub.com/chat/completions", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: AiPrompts.GenerateOptionsUsingAI.replace(
|
||||
"[question]",
|
||||
questions.v[index].name,
|
||||
),
|
||||
},
|
||||
],
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
let question = questions.v[index].name;
|
||||
questions.v[index] = JSON.parse(data.choices[0].message.content);
|
||||
questions.v[index].name = question;
|
||||
})
|
||||
.catch((error) => {
|
||||
alert("Error:" + error);
|
||||
return;
|
||||
});
|
||||
|
||||
alert("added!");
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
import { questions } from "./GameCreateData.svelte.js";
|
||||
import { AiPrompts } from "$lib/config.js";
|
||||
|
||||
export function GenerateQuestionsUsingAI() {
|
||||
let topic = window.prompt(
|
||||
"What is the topic of the questions?\nand the number of questions in the topic?",
|
||||
);
|
||||
|
||||
if (!topic) {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch("https://ai.hackclub.com/chat/completions", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: AiPrompts.GenerateQuestionsUsingAI.replace("[topic]", topic),
|
||||
},
|
||||
],
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
console.log(data);
|
||||
questions.v = JSON.parse(data.choices[0].message.content);
|
||||
})
|
||||
.catch((error) => {
|
||||
alert("Error:" + error);
|
||||
return;
|
||||
});
|
||||
|
||||
alert("added!");
|
||||
}
|
51
src/routes/kahootclone/create/logic/InsertGameInDB.js
Normal file
51
src/routes/kahootclone/create/logic/InsertGameInDB.js
Normal file
|
@ -0,0 +1,51 @@
|
|||
import { supabase } from "$lib/supabase";
|
||||
|
||||
export async function createGame(questions, gamePin) {
|
||||
const { data: gameData, error: gameError } = await supabase.from("games").insert({
|
||||
creator: "anonymous",
|
||||
creationdate: new Date().toISOString(),
|
||||
status: "lobby",
|
||||
gamepin: gamePin,
|
||||
});
|
||||
|
||||
if (gameError) {
|
||||
alert("Failed to create game: " + gameError.message + "\n\nPlease try again.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare questions and answers for batch insertion
|
||||
const questionsData = questions.map((q, index) => ({
|
||||
gameid: gamePin,
|
||||
questionstext: q.name,
|
||||
correctanswer: q.correctAnswer,
|
||||
}));
|
||||
|
||||
const { data: questionsResult, error: questionsError } = await supabase
|
||||
.from("questions")
|
||||
.insert(questionsData)
|
||||
.select("id");
|
||||
|
||||
if (questionsError) {
|
||||
alert("Failed to insert questions: " + questionsError.message + "\n\nPlease try again.");
|
||||
return;
|
||||
}
|
||||
|
||||
const answersData = [];
|
||||
questionsResult.forEach((question, index) => {
|
||||
questions[index].answers.forEach((answer, answerIndex) => {
|
||||
answersData.push({
|
||||
questionid: question.id,
|
||||
content: answer,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const { error: answersError } = await supabase.from("answers").insert(answersData);
|
||||
|
||||
if (answersError) {
|
||||
alert("Failed to insert answers: " + answersError.message + "\n\nPlease try again.");
|
||||
return;
|
||||
}
|
||||
|
||||
window.location.href = `/host?gamepin=${gamePin}` ;
|
||||
}
|
16
src/routes/kahootclone/create/logic/StartGame.js
Normal file
16
src/routes/kahootclone/create/logic/StartGame.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { createGame } from "./InsertGameInDB.js";
|
||||
import { questions,Wait } from "./GameCreateData.svelte.js";
|
||||
|
||||
export async function startGame() {
|
||||
if (questions.v.some((q) => q.name === "")) return alert("Please fill all questions");
|
||||
if (questions.v.some((q) => q.answers.some((a) => a === ""))) return alert("Fill all options");
|
||||
if (questions.v.some((q) => q.correctAnswer === undefined))
|
||||
return alert("Select correct answers");
|
||||
|
||||
const gamePin = Math.floor(Math.random() * 1000000)
|
||||
.toString()
|
||||
.padStart(6, "0");
|
||||
|
||||
Wait.v = true;
|
||||
|
||||
await createGame(questions.v, gamePin);}
|
30
src/routes/kahootclone/host/+page.svelte
Normal file
30
src/routes/kahootclone/host/+page.svelte
Normal file
|
@ -0,0 +1,30 @@
|
|||
<script>
|
||||
import PlayingDisplay from "./components/DuringGame/display.svelte";
|
||||
|
||||
import LobbyDisplay from "./components/lobby/display.svelte";
|
||||
import { Status } from "./logic/HostsData.svelte.js";
|
||||
import { AutoUpdatePlayersList } from "./logic/UpdatePlayersList.js";
|
||||
import { GetCurrentPlayers } from "./logic/GetCurrentPlayers.js";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
let gamePin;
|
||||
|
||||
onMount(() => {
|
||||
gamePin = new URLSearchParams(new URL(window.location.href).search).get("gamepin");
|
||||
|
||||
GetCurrentPlayers(gamePin);
|
||||
AutoUpdatePlayersList(gamePin);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="bg-grey-900 flex h-full items-center justify-center">
|
||||
<div
|
||||
class="flex max-w-[700px] flex-col items-center justify-center gap-1 rounded-lg bg-gray-900 p-8 shadow-lg"
|
||||
>
|
||||
{#if Status.v == "lobby"}
|
||||
<LobbyDisplay {gamePin} />
|
||||
{:else if Status.v == "started"}
|
||||
<PlayingDisplay />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,13 @@
|
|||
<script>
|
||||
import { PeopleAwnseredQ, Totalplayers } from "./../../logic/HostsData.svelte.js";
|
||||
</script>
|
||||
|
||||
<div class="mt-2 mb-3 flex w-full flex-col rounded-2xl border-2 border-green-400 p-2">
|
||||
<h3>{PeopleAwnseredQ.v} out of {Totalplayers.v} have answered the question</h3>
|
||||
<div class="flex-1 rounded-full border-2 border-gray-600">
|
||||
<div
|
||||
class="h-4 rounded-full bg-green-600 transition-all duration-500"
|
||||
style="width: {(PeopleAwnseredQ.v / Totalplayers.v) * 100}%;"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,24 @@
|
|||
<script>
|
||||
import { CurrentQuestionDetails } from "../../../logic/HostsData.svelte.js";
|
||||
|
||||
import { AnswersSymbolAndColorScheme } from "$lib/config.js";
|
||||
</script>
|
||||
|
||||
<div class="mt-5 grid grid-cols-2 gap-5 gap-x-3">
|
||||
{#each CurrentQuestionDetails.v.answers as answer, index}
|
||||
<div class="flex">
|
||||
<input type="radio" name="question" class="sr-only" />
|
||||
<label
|
||||
for="O{index}"
|
||||
style="
|
||||
--border-color: {AnswersSymbolAndColorScheme[index].Color};
|
||||
--bg-color: {AnswersSymbolAndColorScheme[index].Color};
|
||||
"
|
||||
class="w-full rounded-lg border-[5px] border-[var(--border-color)] bg-[var(--bg-color)] pt-1 pr-2 pb-1 pl-2 text-center text-3xl transition-all"
|
||||
>
|
||||
<i class="nf {AnswersSymbolAndColorScheme[index].Symbol}"></i>
|
||||
{answer}
|
||||
</label>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
|
@ -0,0 +1,13 @@
|
|||
<script>
|
||||
import { currentQuestion, totalQuetions } from "./../../../logic/HostsData.svelte.js";
|
||||
</script>
|
||||
|
||||
<div class="mt-5 mb-2 flex w-full items-center justify-center gap-3">
|
||||
<h3>Question {currentQuestion.v + 1} of {totalQuetions.v}</h3>
|
||||
<div class="flex-1 rounded-full border-2 border-gray-600">
|
||||
<div
|
||||
class="h-4 rounded-full bg-green-600 transition-all duration-700"
|
||||
style="width: {(currentQuestion.v / totalQuetions.v) * 100}%;"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,9 @@
|
|||
<script>
|
||||
import Question from "./text/Quetion.svelte";
|
||||
import Awnsers from "./Awnsers.svelte";
|
||||
import ProgressBar from "./ProgressBar.svelte";
|
||||
</script>
|
||||
|
||||
<ProgressBar />
|
||||
<Question />
|
||||
<Awnsers />
|
|
@ -0,0 +1,7 @@
|
|||
<script>
|
||||
import { currentQuestion, CurrentQuestionDetails } from "../../../../logic/HostsData.svelte.js";
|
||||
</script>
|
||||
|
||||
<h1 class="m-[0] text-center text-5xl">
|
||||
Q{currentQuestion.v + 1}. {CurrentQuestionDetails.v.question}
|
||||
</h1>
|
|
@ -0,0 +1,8 @@
|
|||
<script>
|
||||
import PeopleAwnsered from "./PeopleAwnsered.svelte";
|
||||
import Display from "./awnseringQuetions/display.svelte";
|
||||
</script>
|
||||
|
||||
<h1 class="m-[0] text-7xl">HOSTING</h1>
|
||||
<Display />
|
||||
<PeopleAwnsered />
|
|
@ -0,0 +1,6 @@
|
|||
<script>
|
||||
let props = $props();
|
||||
let playerName = props.playerName;
|
||||
</script>
|
||||
|
||||
<span class="m-[0] rounded-xl bg-gray-700 pt-1 pr-2 pb-0 pl-2 font-mono text-3xl">{playerName}</span>
|
|
@ -0,0 +1,12 @@
|
|||
<script>
|
||||
import { players } from "../../../logic/HostsData.svelte.js";
|
||||
import PlayerBadge from "./playerBadge.svelte";
|
||||
</script>
|
||||
|
||||
<h1 class="m-[0] mt-10 text-6xl">Players Joined:</h1>
|
||||
<h1 class="m-[0] text-4xl text-gray-400">(Total Players: {players.v.length})</h1>
|
||||
<div class="mt-2 flex flex-wrap justify-center gap-2">
|
||||
{#each players.v as playerName}
|
||||
<PlayerBadge {playerName} />
|
||||
{/each}
|
||||
</div>
|
|
@ -0,0 +1,12 @@
|
|||
<script>
|
||||
import { startGame } from "../../../logic/startGame.js";
|
||||
|
||||
let props = $props();
|
||||
</script>
|
||||
|
||||
<button
|
||||
class="mt-5 cursor-pointer rounded-2xl bg-green-700 p-2 text-4xl transition-all hover:scale-110 hover:-rotate-10"
|
||||
onclick={() => {
|
||||
startGame(props.gamePin);
|
||||
}}>Start the game</button
|
||||
>
|
15
src/routes/kahootclone/host/components/lobby/display.svelte
Normal file
15
src/routes/kahootclone/host/components/lobby/display.svelte
Normal file
|
@ -0,0 +1,15 @@
|
|||
<script>
|
||||
import StartGame from "./buttons/startGame.svelte";
|
||||
import Players from "./PlayersGUI/players.svelte";
|
||||
|
||||
let props = $props();
|
||||
let gamePin = props.gamePin;
|
||||
</script>
|
||||
|
||||
<h1 class="m-[0] text-9xl">HOSTING</h1>
|
||||
<h1 class="m-[0] text-7xl">Game Pin:</h1>
|
||||
<h1 class="m-[0] rounded-2xl bg-gray-700 pt-1.5 pr-2 pb-0 pl-2 font-mono text-5xl">
|
||||
{gamePin}
|
||||
</h1>
|
||||
<Players />
|
||||
<StartGame {gamePin} />
|
7
src/routes/kahootclone/host/logic/GameOver.js
Normal file
7
src/routes/kahootclone/host/logic/GameOver.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { supabase } from "$lib/supabase.js";
|
||||
|
||||
export async function GameOver(GamePin) {
|
||||
await supabase.from("games").update({ status: `completed` }).eq("gamepin", GamePin);
|
||||
|
||||
window.location.replace("/results?gamepin=" + GamePin + "&playerID=host-null");
|
||||
}
|
18
src/routes/kahootclone/host/logic/GetCurrentPlayers.js
Normal file
18
src/routes/kahootclone/host/logic/GetCurrentPlayers.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { supabase } from "$lib/supabase.js";
|
||||
import { players } from "./HostsData.svelte.js";
|
||||
|
||||
export async function GetCurrentPlayers(gamePin) {
|
||||
const { data, error } = await supabase
|
||||
.from("players")
|
||||
.select("playername")
|
||||
.eq("gameid", Number(gamePin));
|
||||
|
||||
console.log("Current players data:", JSON.stringify(data));
|
||||
|
||||
if (error) {
|
||||
console.error("Error fetching players:", error);
|
||||
return;
|
||||
}
|
||||
|
||||
players.v = data ? data.map(player => player.playername) : [];
|
||||
}
|
10
src/routes/kahootclone/host/logic/HostsData.svelte.js
Normal file
10
src/routes/kahootclone/host/logic/HostsData.svelte.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
export let players = $state({ v: [] });
|
||||
export let Status = $state({ v: "lobby" });
|
||||
export let questions = { v: {} };
|
||||
|
||||
export let currentQuestion = $state({ v: 0 });
|
||||
export let totalQuetions = $state({ v: 3 });
|
||||
export let PeopleAwnseredQ = $state({ v: 0 });
|
||||
export let Totalplayers = $state({ v: 3 });
|
||||
|
||||
export let CurrentQuestionDetails = $state({ v: {} });
|
26
src/routes/kahootclone/host/logic/UpdatePlayersList.js
Normal file
26
src/routes/kahootclone/host/logic/UpdatePlayersList.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
import { supabase } from "$lib/supabase.js";
|
||||
import { players } from "./HostsData.svelte.js";
|
||||
|
||||
export let LobbyConnection;
|
||||
|
||||
function onNewPlayer(Newplayers) {
|
||||
players.v.push(Newplayers.playername);
|
||||
}
|
||||
|
||||
export async function AutoUpdatePlayersList(gamePin) {
|
||||
LobbyConnection = supabase
|
||||
.channel("players-realtime")
|
||||
.on(
|
||||
"postgres_changes",
|
||||
{
|
||||
event: "INSERT",
|
||||
schema: "public",
|
||||
table: "players",
|
||||
filter: `gameid=eq.${gamePin}`,
|
||||
},
|
||||
(payload) => {
|
||||
onNewPlayer(payload.new);
|
||||
},
|
||||
)
|
||||
.subscribe();
|
||||
}
|
51
src/routes/kahootclone/host/logic/WaitForAwnser.js
Normal file
51
src/routes/kahootclone/host/logic/WaitForAwnser.js
Normal file
|
@ -0,0 +1,51 @@
|
|||
import { supabase } from "$lib/supabase.js";
|
||||
import { onNewPlayerAwnsered } from "./onNewPlayerAwnsered.js";
|
||||
import { currentQuestion, questions, CurrentQuestionDetails } from "./HostsData.svelte.js";
|
||||
|
||||
let WaitingForAwnserConection;
|
||||
|
||||
export async function WaitForAwnser(questionid, gamePin) {
|
||||
if (questionid != 0) {
|
||||
await supabase.removeChannel(WaitingForAwnserConection);
|
||||
}
|
||||
|
||||
await supabase
|
||||
.from("games")
|
||||
.update({ status: `question-${currentQuestion.v}` })
|
||||
.eq("gamepin", gamePin);
|
||||
|
||||
WaitingForAwnserConection = supabase
|
||||
.channel("answeredby-realtime")
|
||||
.on(
|
||||
"postgres_changes",
|
||||
{
|
||||
event: "INSERT",
|
||||
schema: "public",
|
||||
table: "answeredby",
|
||||
filter: `questionid=eq.${questions.v[questionid].id}`,
|
||||
},
|
||||
(payload) => {
|
||||
onNewPlayerAwnsered(gamePin);
|
||||
},
|
||||
)
|
||||
.subscribe();
|
||||
|
||||
const { data: questionsData } = await supabase
|
||||
.from("questions")
|
||||
.select("id,questionstext,correctanswer")
|
||||
.eq("gameid", Number(gamePin))
|
||||
.order("id", { ascending: true });
|
||||
|
||||
const { data: answers } = await supabase
|
||||
.from("answers")
|
||||
.select("content")
|
||||
.eq("questionid", Number(questionsData[currentQuestion.v].id))
|
||||
.order("id", { ascending: true });
|
||||
|
||||
CurrentQuestionDetails.v = {
|
||||
question: questionsData[currentQuestion.v].questionstext,
|
||||
correctAnswer: questionsData[currentQuestion.v].correctanswer,
|
||||
answers: answers.map((answer) => answer.content),
|
||||
questionid: questionsData[currentQuestion.v].id,
|
||||
};
|
||||
}
|
23
src/routes/kahootclone/host/logic/onNewPlayerAwnsered.js
Normal file
23
src/routes/kahootclone/host/logic/onNewPlayerAwnsered.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
import {
|
||||
Totalplayers,
|
||||
PeopleAwnseredQ,
|
||||
currentQuestion,
|
||||
totalQuetions,
|
||||
} from "./HostsData.svelte.js";
|
||||
import { GameOver } from "./GameOver.js";
|
||||
import { WaitForAwnser } from "./WaitForAwnser.js";
|
||||
|
||||
export async function onNewPlayerAwnsered(GamePin) {
|
||||
PeopleAwnseredQ.v++;
|
||||
|
||||
if (PeopleAwnseredQ.v == Totalplayers.v) {
|
||||
currentQuestion.v++;
|
||||
if (currentQuestion.v == totalQuetions.v) {
|
||||
GameOver(GamePin);
|
||||
return;
|
||||
}
|
||||
PeopleAwnseredQ.v = 0;
|
||||
|
||||
WaitForAwnser(currentQuestion.v, GamePin);
|
||||
}
|
||||
}
|
41
src/routes/kahootclone/host/logic/startGame.js
Normal file
41
src/routes/kahootclone/host/logic/startGame.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
import { supabase } from "$lib/supabase.js";
|
||||
import { LobbyConnection } from "./UpdatePlayersList.js";
|
||||
import {
|
||||
questions,
|
||||
Status,
|
||||
Totalplayers,
|
||||
totalQuetions,
|
||||
players,
|
||||
} from "./HostsData.svelte.js";
|
||||
import { WaitForAwnser } from "./WaitForAwnser.js";
|
||||
|
||||
export async function startGame(gamePin) {
|
||||
if (players.v.length == 0) {
|
||||
alert("you need at least 1 person to start the game!");
|
||||
return;
|
||||
}
|
||||
|
||||
await supabase.removeChannel(LobbyConnection);
|
||||
|
||||
Status.v = "started";
|
||||
|
||||
const { data } = await supabase
|
||||
.from("questions")
|
||||
.select("*")
|
||||
.eq("gameid", Number(gamePin))
|
||||
.order("id", { ascending: true });
|
||||
|
||||
questions.v = data;
|
||||
|
||||
totalQuetions.v = data.length;
|
||||
|
||||
const { data: playersData } = await supabase
|
||||
.from("players")
|
||||
.select("id")
|
||||
.eq("gameid", Number(gamePin))
|
||||
.order("id", { ascending: true });
|
||||
|
||||
Totalplayers.v = playersData.length;
|
||||
|
||||
WaitForAwnser(0, gamePin);
|
||||
}
|
47
src/routes/kahootclone/join/+page.svelte
Normal file
47
src/routes/kahootclone/join/+page.svelte
Normal file
|
@ -0,0 +1,47 @@
|
|||
<script>
|
||||
import { joinGame } from "./logic/joinGame.js";
|
||||
import { Checking } from "./logic/JoinGameData.svelte.js";
|
||||
|
||||
let pin;
|
||||
let name;
|
||||
</script>
|
||||
|
||||
<div class="bg-grey-900 flex h-full items-center justify-center">
|
||||
<div
|
||||
class="flex flex-col items-center justify-center gap-1 rounded-lg bg-gray-900 p-7 shadow-lg"
|
||||
>
|
||||
<h1 class="m-[0] mb-3 text-5xl">Join a game here</h1>
|
||||
|
||||
<input
|
||||
placeholder="Enter game pin"
|
||||
class="rounded-lg bg-gray-800 p-2 text-center text-white"
|
||||
bind:value={pin}
|
||||
/>
|
||||
|
||||
<input
|
||||
placeholder="Enter your name"
|
||||
bind:value={name}
|
||||
class="rounded-lg bg-gray-800 p-2 text-center text-white"
|
||||
/>
|
||||
|
||||
{#if Checking.v}
|
||||
<button
|
||||
class="mt-2 cursor-pointer rounded-full bg-gray-700 p-2 transition-all hover:scale-110 hover:-rotate-10"
|
||||
>
|
||||
Checking if pin is valid...
|
||||
</button>
|
||||
{:else}
|
||||
<button
|
||||
class="mt-2 cursor-pointer rounded-full bg-green-700 p-2 transition-all hover:scale-110 hover:-rotate-10"
|
||||
on:click={() => {
|
||||
if (!pin || !name) {
|
||||
alert("Please fill in the game pin and your name.");
|
||||
} else {
|
||||
joinGame(pin, name);
|
||||
}
|
||||
}}
|
||||
>
|
||||
Join game
|
||||
</button>{/if}
|
||||
</div>
|
||||
</div>
|
19
src/routes/kahootclone/join/logic/InsertPlayerInDB.js
Normal file
19
src/routes/kahootclone/join/logic/InsertPlayerInDB.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { supabase } from "$lib/supabase";
|
||||
|
||||
export async function addPlayer(name, gamePin) {
|
||||
const { data, error } = await supabase
|
||||
.from("players")
|
||||
.insert({
|
||||
gameid: gamePin,
|
||||
score: 0,
|
||||
playername: name,
|
||||
})
|
||||
.select("id");
|
||||
|
||||
if (error) {
|
||||
alert("Failed to join game: " + error.message + "\n\nPlease try again.");
|
||||
return;
|
||||
}
|
||||
|
||||
return data[0].id;
|
||||
}
|
3
src/routes/kahootclone/join/logic/JoinGameData.svelte.js
Normal file
3
src/routes/kahootclone/join/logic/JoinGameData.svelte.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
export let Checking = $state({
|
||||
v: false,
|
||||
});
|
19
src/routes/kahootclone/join/logic/joinGame.js
Normal file
19
src/routes/kahootclone/join/logic/joinGame.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { addPlayer } from "./InsertPlayerInDB.js";
|
||||
import { validateGamePin } from "./validateGamePin.js";
|
||||
import { Checking } from "./JoinGameData.svelte.js";
|
||||
|
||||
export async function joinGame(pin, name) {
|
||||
Checking.v = true;
|
||||
|
||||
if (!(await validateGamePin(pin))) {
|
||||
alert("Invalid game pin. Please try again.");
|
||||
Checking.v = false;
|
||||
return;
|
||||
}
|
||||
|
||||
let id = await addPlayer(name, pin);
|
||||
|
||||
Checking.v = false;
|
||||
|
||||
window.location.href = `./play?gamepin=${pin}&name=${name}&playerid=${id}`;
|
||||
}
|
11
src/routes/kahootclone/join/logic/validateGamePin.js
Normal file
11
src/routes/kahootclone/join/logic/validateGamePin.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { supabase } from '$lib/supabase';
|
||||
|
||||
export async function validateGamePin(pin) {
|
||||
const { data, error } = await supabase
|
||||
.from('games')
|
||||
.select('gamepin')
|
||||
.eq('gamepin', Number(pin))
|
||||
.maybeSingle();
|
||||
|
||||
return data !== null && !error;
|
||||
}
|
34
src/routes/kahootclone/play/+page.svelte
Normal file
34
src/routes/kahootclone/play/+page.svelte
Normal file
|
@ -0,0 +1,34 @@
|
|||
<script>
|
||||
import AwnserQuetion from "./components/awnseringQuetions/display.svelte";
|
||||
import LobbyDisplay from "./components/lobby/display.svelte";
|
||||
import { Status } from "./logic/HostsData.svelte.js";
|
||||
import { AutoUpdatePlayersList } from "./logic/UpdatePlayersList.js";
|
||||
import { GetCurrentPlayers } from "./logic/GetCurrentPlayers.js";
|
||||
import { IntializeGameStart } from "./logic/IntializeGameStart.js";
|
||||
import { onMount } from "svelte";
|
||||
import { name,playerid } from "./logic/HostsData.svelte.js";
|
||||
|
||||
let gamePin;
|
||||
|
||||
onMount(() => {
|
||||
name.v = new URLSearchParams(new URL(window.location.href).search).get("name");
|
||||
playerid.v = new URLSearchParams(new URL(window.location.href).search).get("playerid");
|
||||
gamePin = new URLSearchParams(new URL(window.location.href).search).get("gamepin");
|
||||
|
||||
GetCurrentPlayers(gamePin);
|
||||
AutoUpdatePlayersList(gamePin);
|
||||
IntializeGameStart(gamePin);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="bg-grey-900 flex h-full items-center justify-center">
|
||||
<div
|
||||
class="flex max-w-[700px] flex-col items-center justify-center gap-1 rounded-lg bg-gray-900 p-8 shadow-lg"
|
||||
>
|
||||
{#if Status.v == "lobby"}
|
||||
<LobbyDisplay {gamePin} />
|
||||
{:else if Status.v == "started"}
|
||||
<AwnserQuetion />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,36 @@
|
|||
<script>
|
||||
import { questions, Selected } from "../../logic/HostsData.svelte.js";
|
||||
import { AnswersSymbolAndColorScheme } from "$lib/config.js";
|
||||
</script>
|
||||
|
||||
<div class="mt-5 grid grid-cols-2 gap-5 gap-x-3">
|
||||
{#each questions.v.answers as answer, index}
|
||||
<div class="flex">
|
||||
<input
|
||||
type="radio"
|
||||
id="O{index}"
|
||||
name="question"
|
||||
class="peer sr-only"
|
||||
value={index}
|
||||
bind:group={Selected.v}
|
||||
/>
|
||||
|
||||
<label
|
||||
for="O{index}"
|
||||
style="
|
||||
--border-color: {AnswersSymbolAndColorScheme[index].Color};
|
||||
--bg-color: {AnswersSymbolAndColorScheme[index].Color};
|
||||
--border-color-checked: {AnswersSymbolAndColorScheme[index].SelectedColor};
|
||||
--bg-color-checked: {AnswersSymbolAndColorScheme[index].SelectedColor};
|
||||
--border-color-hover: {AnswersSymbolAndColorScheme[index].HoverBorderColor};
|
||||
--border-color-checked: {AnswersSymbolAndColorScheme[index].SelectedBorderColor};
|
||||
--border-color-hover: {AnswersSymbolAndColorScheme[index].HoverBorderColor};
|
||||
"
|
||||
class="w-full cursor-pointer rounded-lg border-[5px] border-[var(--border-color)] bg-[var(--bg-color)] pt-1 pr-2 pb-1 pl-2 text-center text-3xl transition-all peer-checked:border-[var(--border-color-checked)] peer-checked:border-[var(--border-color-checked)] peer-checked:bg-[var(--bg-color-checked)] hover:border-[var(--border-color-hover)]"
|
||||
>
|
||||
<i class="nf {AnswersSymbolAndColorScheme[index].Symbol}"></i>
|
||||
{answer}
|
||||
</label>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
|
@ -0,0 +1,13 @@
|
|||
<script>
|
||||
import { CurrentQuestion, TotalQuestions } from "../../logic/HostsData.svelte.js";
|
||||
</script>
|
||||
|
||||
<div class="mb-5 flex w-full items-center justify-center gap-3">
|
||||
<h3>Question {CurrentQuestion.v + 1} of {TotalQuestions.v}</h3>
|
||||
<div class="flex-1 rounded-full border-2 border-gray-600">
|
||||
<div
|
||||
class="h-4 rounded-full bg-green-600 transition-all duration-700"
|
||||
style="width: {(CurrentQuestion.v / TotalQuestions.v) * 100}%;"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,13 @@
|
|||
<div class="group relative">
|
||||
<button
|
||||
class="mt-4 cursor-not-allowed gap-0 rounded-lg bg-gray-500 p-2 text-3xl text-gray-300 transition-all"
|
||||
disabled
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
<div
|
||||
class="invisible absolute bottom-full left-1/2 mb-2 w-40 -translate-x-1/2 rounded-md bg-black px-3 py-1 text-center text-sm text-white opacity-0 transition-all group-hover:visible group-hover:opacity-100"
|
||||
>
|
||||
Select an option to submit
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,9 @@
|
|||
<script>
|
||||
import { SubmitAnswer } from "../../../logic/SubmitAnswer.js";
|
||||
</script>
|
||||
|
||||
<button
|
||||
class="mt-4 cursor-pointer gap-0 rounded-lg bg-green-700 p-2 text-3xl transition-all hover:scale-110 hover:-rotate-10"
|
||||
onclick={SubmitAnswer}
|
||||
>Submit
|
||||
</button>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue