diff --git a/.gitignore b/.gitignore
index 549e00a..4550a7e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,3 +31,6 @@ build/
### VS Code ###
.vscode/
+
+### css compiled by tailwind ###
+src/main/resources/static/main.css
diff --git a/pom.xml b/pom.xml
index 016617c..e7a27ec 100644
--- a/pom.xml
+++ b/pom.xml
@@ -35,6 +35,13 @@
mysql-connector-j
runtime
+
+
+ org.springframework.boot
+ spring-boot-devtools
+ runtime
+ true
+
org.springframework.boot
spring-boot-starter-test
diff --git a/src/main/java/dev/araozu/eeg_java/controller/IndexController.java b/src/main/java/dev/araozu/eeg_java/controller/IndexController.java
new file mode 100644
index 0000000..b521f84
--- /dev/null
+++ b/src/main/java/dev/araozu/eeg_java/controller/IndexController.java
@@ -0,0 +1,13 @@
+package dev.araozu.eeg_java.controller;
+
+import org.springframework.ui.Model;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+
+@Controller
+public class IndexController {
+ @GetMapping("/")
+ public String index(Model model) {
+ return "index";
+ }
+}
diff --git a/src/main/java/dev/araozu/eeg_java/MainController.java b/src/main/java/dev/araozu/eeg_java/controller/MainController.java
similarity index 87%
rename from src/main/java/dev/araozu/eeg_java/MainController.java
rename to src/main/java/dev/araozu/eeg_java/controller/MainController.java
index f7e1349..6ec0410 100644
--- a/src/main/java/dev/araozu/eeg_java/MainController.java
+++ b/src/main/java/dev/araozu/eeg_java/controller/MainController.java
@@ -1,5 +1,7 @@
-package dev.araozu.eeg_java;
+package dev.araozu.eeg_java.controller;
+import dev.araozu.eeg_java.model.Person;
+import dev.araozu.eeg_java.model.PersonRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
diff --git a/src/main/java/dev/araozu/eeg_java/Person.java b/src/main/java/dev/araozu/eeg_java/model/Person.java
similarity index 98%
rename from src/main/java/dev/araozu/eeg_java/Person.java
rename to src/main/java/dev/araozu/eeg_java/model/Person.java
index 4b04a5a..f02c20e 100644
--- a/src/main/java/dev/araozu/eeg_java/Person.java
+++ b/src/main/java/dev/araozu/eeg_java/model/Person.java
@@ -1,4 +1,4 @@
-package dev.araozu.eeg_java;
+package dev.araozu.eeg_java.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
diff --git a/src/main/java/dev/araozu/eeg_java/PersonRepository.java b/src/main/java/dev/araozu/eeg_java/model/PersonRepository.java
similarity index 79%
rename from src/main/java/dev/araozu/eeg_java/PersonRepository.java
rename to src/main/java/dev/araozu/eeg_java/model/PersonRepository.java
index 2cac57e..a5fee43 100644
--- a/src/main/java/dev/araozu/eeg_java/PersonRepository.java
+++ b/src/main/java/dev/araozu/eeg_java/model/PersonRepository.java
@@ -1,4 +1,4 @@
-package dev.araozu.eeg_java;
+package dev.araozu.eeg_java.model;
import org.springframework.data.repository.CrudRepository;
diff --git a/src/main/resources/frontend/.gitignore b/src/main/resources/frontend/.gitignore
new file mode 100644
index 0000000..b512c09
--- /dev/null
+++ b/src/main/resources/frontend/.gitignore
@@ -0,0 +1 @@
+node_modules
\ No newline at end of file
diff --git a/src/main/resources/frontend/main.css b/src/main/resources/frontend/main.css
new file mode 100644
index 0000000..a505389
--- /dev/null
+++ b/src/main/resources/frontend/main.css
@@ -0,0 +1,53 @@
+:root {
+ --c-error: #ffb4ab;
+ --c-on-error: #690005;
+ --c-error-container: #93000a;
+ --c-on-error-container: #ffdad6;
+
+ --c-outline-50: rgba(143, 144, 154, 0.5);
+}
+
+@media (prefers-color-scheme: light) {
+ :root {
+ --c-error: #ba1a1a;
+ --c-on-error: #ffffff;
+ --c-error-container: #ffdad6;
+ --c-on-error-container: #410002;
+
+ --c-outline-50: rgba(118, 118, 128, 0.5);
+ }
+}
+
+
+body {
+ background-color: var(--c-background);
+ color: var(--c-on-background);
+ font-family: Inter, "Inter Nerd Font", sans-serif;
+}
+
+
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+.progress {
+ animation: progress 1s infinite linear;
+}
+
+.left-right {
+ transform-origin: 0% 50%;
+}
+
+@keyframes progress {
+ 0% {
+ transform: translateX(0) scaleX(0);
+ }
+
+ 40% {
+ transform: translateX(0) scaleX(0.4);
+ }
+
+ 100% {
+ transform: translateX(100%) scaleX(0.5);
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/frontend/package.json b/src/main/resources/frontend/package.json
new file mode 100644
index 0000000..5d3b613
--- /dev/null
+++ b/src/main/resources/frontend/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "frontend",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "dev": "tailwindcss -i ./main.css -o ../static/main.css --watch",
+ "build": "tailwindcss -i ./main.css -o ../static/main.css --minify"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "devDependencies": {
+ "tailwindcss": "^3.3.5"
+ }
+}
diff --git a/src/main/resources/frontend/pnpm-lock.yaml b/src/main/resources/frontend/pnpm-lock.yaml
new file mode 100644
index 0000000..0a6db5b
--- /dev/null
+++ b/src/main/resources/frontend/pnpm-lock.yaml
@@ -0,0 +1,728 @@
+lockfileVersion: '6.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+devDependencies:
+ tailwindcss:
+ specifier: ^3.3.5
+ version: 3.4.1
+
+packages:
+
+ /@alloc/quick-lru@5.2.0:
+ resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /@isaacs/cliui@8.0.2:
+ resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
+ engines: {node: '>=12'}
+ dependencies:
+ string-width: 5.1.2
+ string-width-cjs: /string-width@4.2.3
+ strip-ansi: 7.1.0
+ strip-ansi-cjs: /strip-ansi@6.0.1
+ wrap-ansi: 8.1.0
+ wrap-ansi-cjs: /wrap-ansi@7.0.0
+ dev: true
+
+ /@jridgewell/gen-mapping@0.3.5:
+ resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==}
+ engines: {node: '>=6.0.0'}
+ dependencies:
+ '@jridgewell/set-array': 1.2.1
+ '@jridgewell/sourcemap-codec': 1.4.15
+ '@jridgewell/trace-mapping': 0.3.25
+ dev: true
+
+ /@jridgewell/resolve-uri@3.1.2:
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+ dev: true
+
+ /@jridgewell/set-array@1.2.1:
+ resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
+ engines: {node: '>=6.0.0'}
+ dev: true
+
+ /@jridgewell/sourcemap-codec@1.4.15:
+ resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
+ dev: true
+
+ /@jridgewell/trace-mapping@0.3.25:
+ resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.4.15
+ dev: true
+
+ /@nodelib/fs.scandir@2.1.5:
+ resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
+ engines: {node: '>= 8'}
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ run-parallel: 1.2.0
+ dev: true
+
+ /@nodelib/fs.stat@2.0.5:
+ resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
+ engines: {node: '>= 8'}
+ dev: true
+
+ /@nodelib/fs.walk@1.2.8:
+ resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
+ engines: {node: '>= 8'}
+ dependencies:
+ '@nodelib/fs.scandir': 2.1.5
+ fastq: 1.17.1
+ dev: true
+
+ /@pkgjs/parseargs@0.11.0:
+ resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
+ engines: {node: '>=14'}
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /ansi-regex@5.0.1:
+ resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /ansi-regex@6.0.1:
+ resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /ansi-styles@4.3.0:
+ resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+ engines: {node: '>=8'}
+ dependencies:
+ color-convert: 2.0.1
+ dev: true
+
+ /ansi-styles@6.2.1:
+ resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /any-promise@1.3.0:
+ resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
+ dev: true
+
+ /anymatch@3.1.3:
+ resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
+ engines: {node: '>= 8'}
+ dependencies:
+ normalize-path: 3.0.0
+ picomatch: 2.3.1
+ dev: true
+
+ /arg@5.0.2:
+ resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
+ dev: true
+
+ /balanced-match@1.0.2:
+ resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+ dev: true
+
+ /binary-extensions@2.2.0:
+ resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /brace-expansion@2.0.1:
+ resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
+ dependencies:
+ balanced-match: 1.0.2
+ dev: true
+
+ /braces@3.0.2:
+ resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
+ engines: {node: '>=8'}
+ dependencies:
+ fill-range: 7.0.1
+ dev: true
+
+ /camelcase-css@2.0.1:
+ resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
+ engines: {node: '>= 6'}
+ dev: true
+
+ /chokidar@3.6.0:
+ resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
+ engines: {node: '>= 8.10.0'}
+ dependencies:
+ anymatch: 3.1.3
+ braces: 3.0.2
+ glob-parent: 5.1.2
+ is-binary-path: 2.1.0
+ is-glob: 4.0.3
+ normalize-path: 3.0.0
+ readdirp: 3.6.0
+ optionalDependencies:
+ fsevents: 2.3.3
+ dev: true
+
+ /color-convert@2.0.1:
+ resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+ engines: {node: '>=7.0.0'}
+ dependencies:
+ color-name: 1.1.4
+ dev: true
+
+ /color-name@1.1.4:
+ resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+ dev: true
+
+ /commander@4.1.1:
+ resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
+ engines: {node: '>= 6'}
+ dev: true
+
+ /cross-spawn@7.0.3:
+ resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
+ engines: {node: '>= 8'}
+ dependencies:
+ path-key: 3.1.1
+ shebang-command: 2.0.0
+ which: 2.0.2
+ dev: true
+
+ /cssesc@3.0.0:
+ resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
+ engines: {node: '>=4'}
+ hasBin: true
+ dev: true
+
+ /didyoumean@1.2.2:
+ resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
+ dev: true
+
+ /dlv@1.1.3:
+ resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
+ dev: true
+
+ /eastasianwidth@0.2.0:
+ resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
+ dev: true
+
+ /emoji-regex@8.0.0:
+ resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+ dev: true
+
+ /emoji-regex@9.2.2:
+ resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+ dev: true
+
+ /fast-glob@3.3.2:
+ resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
+ engines: {node: '>=8.6.0'}
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ '@nodelib/fs.walk': 1.2.8
+ glob-parent: 5.1.2
+ merge2: 1.4.1
+ micromatch: 4.0.5
+ dev: true
+
+ /fastq@1.17.1:
+ resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
+ dependencies:
+ reusify: 1.0.4
+ dev: true
+
+ /fill-range@7.0.1:
+ resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ to-regex-range: 5.0.1
+ dev: true
+
+ /foreground-child@3.1.1:
+ resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==}
+ engines: {node: '>=14'}
+ dependencies:
+ cross-spawn: 7.0.3
+ signal-exit: 4.1.0
+ dev: true
+
+ /fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /function-bind@1.1.2:
+ resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+ dev: true
+
+ /glob-parent@5.1.2:
+ resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
+ engines: {node: '>= 6'}
+ dependencies:
+ is-glob: 4.0.3
+ dev: true
+
+ /glob-parent@6.0.2:
+ resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
+ engines: {node: '>=10.13.0'}
+ dependencies:
+ is-glob: 4.0.3
+ dev: true
+
+ /glob@10.3.10:
+ resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ hasBin: true
+ dependencies:
+ foreground-child: 3.1.1
+ jackspeak: 2.3.6
+ minimatch: 9.0.3
+ minipass: 7.0.4
+ path-scurry: 1.10.1
+ dev: true
+
+ /hasown@2.0.2:
+ resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ function-bind: 1.1.2
+ dev: true
+
+ /is-binary-path@2.1.0:
+ resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
+ engines: {node: '>=8'}
+ dependencies:
+ binary-extensions: 2.2.0
+ dev: true
+
+ /is-core-module@2.13.1:
+ resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==}
+ dependencies:
+ hasown: 2.0.2
+ dev: true
+
+ /is-extglob@2.1.1:
+ resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /is-fullwidth-code-point@3.0.0:
+ resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /is-glob@4.0.3:
+ resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-extglob: 2.1.1
+ dev: true
+
+ /is-number@7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+ dev: true
+
+ /isexe@2.0.0:
+ resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+ dev: true
+
+ /jackspeak@2.3.6:
+ resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==}
+ engines: {node: '>=14'}
+ dependencies:
+ '@isaacs/cliui': 8.0.2
+ optionalDependencies:
+ '@pkgjs/parseargs': 0.11.0
+ dev: true
+
+ /jiti@1.21.0:
+ resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==}
+ hasBin: true
+ dev: true
+
+ /lilconfig@2.1.0:
+ resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /lilconfig@3.1.1:
+ resolution: {integrity: sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==}
+ engines: {node: '>=14'}
+ dev: true
+
+ /lines-and-columns@1.2.4:
+ resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
+ dev: true
+
+ /lru-cache@10.2.0:
+ resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==}
+ engines: {node: 14 || >=16.14}
+ dev: true
+
+ /merge2@1.4.1:
+ resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
+ engines: {node: '>= 8'}
+ dev: true
+
+ /micromatch@4.0.5:
+ resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
+ engines: {node: '>=8.6'}
+ dependencies:
+ braces: 3.0.2
+ picomatch: 2.3.1
+ dev: true
+
+ /minimatch@9.0.3:
+ resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ dependencies:
+ brace-expansion: 2.0.1
+ dev: true
+
+ /minipass@7.0.4:
+ resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ dev: true
+
+ /mz@2.7.0:
+ resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
+ dependencies:
+ any-promise: 1.3.0
+ object-assign: 4.1.1
+ thenify-all: 1.6.0
+ dev: true
+
+ /nanoid@3.3.7:
+ resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+ dev: true
+
+ /normalize-path@3.0.0:
+ resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /object-assign@4.1.1:
+ resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /object-hash@3.0.0:
+ resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
+ engines: {node: '>= 6'}
+ dev: true
+
+ /path-key@3.1.1:
+ resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /path-parse@1.0.7:
+ resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+ dev: true
+
+ /path-scurry@1.10.1:
+ resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ dependencies:
+ lru-cache: 10.2.0
+ minipass: 7.0.4
+ dev: true
+
+ /picocolors@1.0.0:
+ resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
+ dev: true
+
+ /picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+ dev: true
+
+ /pify@2.3.0:
+ resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /pirates@4.0.6:
+ resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
+ engines: {node: '>= 6'}
+ dev: true
+
+ /postcss-import@15.1.0(postcss@8.4.35):
+ resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ postcss: ^8.0.0
+ dependencies:
+ postcss: 8.4.35
+ postcss-value-parser: 4.2.0
+ read-cache: 1.0.0
+ resolve: 1.22.8
+ dev: true
+
+ /postcss-js@4.0.1(postcss@8.4.35):
+ resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==}
+ engines: {node: ^12 || ^14 || >= 16}
+ peerDependencies:
+ postcss: ^8.4.21
+ dependencies:
+ camelcase-css: 2.0.1
+ postcss: 8.4.35
+ dev: true
+
+ /postcss-load-config@4.0.2(postcss@8.4.35):
+ resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==}
+ engines: {node: '>= 14'}
+ peerDependencies:
+ postcss: '>=8.0.9'
+ ts-node: '>=9.0.0'
+ peerDependenciesMeta:
+ postcss:
+ optional: true
+ ts-node:
+ optional: true
+ dependencies:
+ lilconfig: 3.1.1
+ postcss: 8.4.35
+ yaml: 2.4.1
+ dev: true
+
+ /postcss-nested@6.0.1(postcss@8.4.35):
+ resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==}
+ engines: {node: '>=12.0'}
+ peerDependencies:
+ postcss: ^8.2.14
+ dependencies:
+ postcss: 8.4.35
+ postcss-selector-parser: 6.0.15
+ dev: true
+
+ /postcss-selector-parser@6.0.15:
+ resolution: {integrity: sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==}
+ engines: {node: '>=4'}
+ dependencies:
+ cssesc: 3.0.0
+ util-deprecate: 1.0.2
+ dev: true
+
+ /postcss-value-parser@4.2.0:
+ resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
+ dev: true
+
+ /postcss@8.4.35:
+ resolution: {integrity: sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==}
+ engines: {node: ^10 || ^12 || >=14}
+ dependencies:
+ nanoid: 3.3.7
+ picocolors: 1.0.0
+ source-map-js: 1.0.2
+ dev: true
+
+ /queue-microtask@1.2.3:
+ resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+ dev: true
+
+ /read-cache@1.0.0:
+ resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
+ dependencies:
+ pify: 2.3.0
+ dev: true
+
+ /readdirp@3.6.0:
+ resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
+ engines: {node: '>=8.10.0'}
+ dependencies:
+ picomatch: 2.3.1
+ dev: true
+
+ /resolve@1.22.8:
+ resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
+ hasBin: true
+ dependencies:
+ is-core-module: 2.13.1
+ path-parse: 1.0.7
+ supports-preserve-symlinks-flag: 1.0.0
+ dev: true
+
+ /reusify@1.0.4:
+ resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
+ engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+ dev: true
+
+ /run-parallel@1.2.0:
+ resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+ dependencies:
+ queue-microtask: 1.2.3
+ dev: true
+
+ /shebang-command@2.0.0:
+ resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+ engines: {node: '>=8'}
+ dependencies:
+ shebang-regex: 3.0.0
+ dev: true
+
+ /shebang-regex@3.0.0:
+ resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /signal-exit@4.1.0:
+ resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
+ engines: {node: '>=14'}
+ dev: true
+
+ /source-map-js@1.0.2:
+ resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /string-width@4.2.3:
+ resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
+ engines: {node: '>=8'}
+ dependencies:
+ emoji-regex: 8.0.0
+ is-fullwidth-code-point: 3.0.0
+ strip-ansi: 6.0.1
+ dev: true
+
+ /string-width@5.1.2:
+ resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
+ engines: {node: '>=12'}
+ dependencies:
+ eastasianwidth: 0.2.0
+ emoji-regex: 9.2.2
+ strip-ansi: 7.1.0
+ dev: true
+
+ /strip-ansi@6.0.1:
+ resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
+ engines: {node: '>=8'}
+ dependencies:
+ ansi-regex: 5.0.1
+ dev: true
+
+ /strip-ansi@7.1.0:
+ resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ ansi-regex: 6.0.1
+ dev: true
+
+ /sucrase@3.35.0:
+ resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ hasBin: true
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.5
+ commander: 4.1.1
+ glob: 10.3.10
+ lines-and-columns: 1.2.4
+ mz: 2.7.0
+ pirates: 4.0.6
+ ts-interface-checker: 0.1.13
+ dev: true
+
+ /supports-preserve-symlinks-flag@1.0.0:
+ resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
+ engines: {node: '>= 0.4'}
+ dev: true
+
+ /tailwindcss@3.4.1:
+ resolution: {integrity: sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==}
+ engines: {node: '>=14.0.0'}
+ hasBin: true
+ dependencies:
+ '@alloc/quick-lru': 5.2.0
+ arg: 5.0.2
+ chokidar: 3.6.0
+ didyoumean: 1.2.2
+ dlv: 1.1.3
+ fast-glob: 3.3.2
+ glob-parent: 6.0.2
+ is-glob: 4.0.3
+ jiti: 1.21.0
+ lilconfig: 2.1.0
+ micromatch: 4.0.5
+ normalize-path: 3.0.0
+ object-hash: 3.0.0
+ picocolors: 1.0.0
+ postcss: 8.4.35
+ postcss-import: 15.1.0(postcss@8.4.35)
+ postcss-js: 4.0.1(postcss@8.4.35)
+ postcss-load-config: 4.0.2(postcss@8.4.35)
+ postcss-nested: 6.0.1(postcss@8.4.35)
+ postcss-selector-parser: 6.0.15
+ resolve: 1.22.8
+ sucrase: 3.35.0
+ transitivePeerDependencies:
+ - ts-node
+ dev: true
+
+ /thenify-all@1.6.0:
+ resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
+ engines: {node: '>=0.8'}
+ dependencies:
+ thenify: 3.3.1
+ dev: true
+
+ /thenify@3.3.1:
+ resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
+ dependencies:
+ any-promise: 1.3.0
+ dev: true
+
+ /to-regex-range@5.0.1:
+ resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+ engines: {node: '>=8.0'}
+ dependencies:
+ is-number: 7.0.0
+ dev: true
+
+ /ts-interface-checker@0.1.13:
+ resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
+ dev: true
+
+ /util-deprecate@1.0.2:
+ resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+ dev: true
+
+ /which@2.0.2:
+ resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+ engines: {node: '>= 8'}
+ hasBin: true
+ dependencies:
+ isexe: 2.0.0
+ dev: true
+
+ /wrap-ansi@7.0.0:
+ resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
+ engines: {node: '>=10'}
+ dependencies:
+ ansi-styles: 4.3.0
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+ dev: true
+
+ /wrap-ansi@8.1.0:
+ resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ ansi-styles: 6.2.1
+ string-width: 5.1.2
+ strip-ansi: 7.1.0
+ dev: true
+
+ /yaml@2.4.1:
+ resolution: {integrity: sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==}
+ engines: {node: '>= 14'}
+ hasBin: true
+ dev: true
diff --git a/src/main/resources/frontend/tailwind.config.js b/src/main/resources/frontend/tailwind.config.js
new file mode 100644
index 0000000..c13d6de
--- /dev/null
+++ b/src/main/resources/frontend/tailwind.config.js
@@ -0,0 +1,52 @@
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: [
+ "../templates/**/*.{html,js}",
+ "../static/**/*.{html,js}",
+ ],
+ theme: {
+ extend: {
+ fontFamily: {
+ "mono": ["Inconsolata", "monospace"],
+ },
+ animation: {
+ progress: "progress 1s infinite linear",
+ },
+ keyframes: {
+ progress: {
+ "0%": { transform: " translateX(0) scaleX(0)" },
+ "40%": { transform: "translateX(0) scaleX(0.4)" },
+ "100%": { transform: "translateX(100%) scaleX(0.5)" },
+ },
+ },
+ transformOrigin: {
+ "left-right": "0% 50%",
+ },
+
+ },
+ colors: {
+ "c-primary": "var(--c-primary)",
+ "c-on-primary": "var(--c-on-primary)",
+ "c-primary-container": "var(--c-primary-container)",
+ "c-on-primary-container": "var(--c-on-primary-container)",
+ "c-error": "var(--c-error)",
+ "c-on-error": "var(--c-on-error)",
+ "c-error-container": "var(--c-error-container)",
+ "c-on-error-container": "var(--c-on-error-container)",
+ "c-background": "var(--c-background)",
+ "c-on-background": "var(--c-on-background)",
+ "c-surface": "var(--c-surface)",
+ "c-on-surface": "var(--c-on-surface)",
+ "c-outline": "var(--c-outline)",
+ "c-outline-50": "var(--c-outline-50)",
+ "c-surface-variant": "var(--c-surface-variant)",
+ "c-on-surface-variant": "var(--c-on-surface-variant)",
+ "c-green": "#006b54",
+ "c-success": "var(--c-success)",
+ "c-on-success": "var(--c-on-success)",
+ "c-transparent": "rgba(0,0,0,0)",
+ },
+ },
+ plugins: [],
+};
+
diff --git a/src/main/resources/static/colorManager.js b/src/main/resources/static/colorManager.js
new file mode 100644
index 0000000..4f91456
--- /dev/null
+++ b/src/main/resources/static/colorManager.js
@@ -0,0 +1,58 @@
+
+const applyColors = (colorName) => {
+ const styleStr = `
+:root {
+ --c-primary: var(--c-${colorName}-primary);
+ --c-on-primary: var(--c-${colorName}-on-primary);
+ --c-primary-container: var(--c-${colorName}-primary-container);
+ --c-on-primary-container: var(--c-${colorName}-on-primary-container);
+ --c-background: var(--c-${colorName}-background);
+ --c-on-background: var(--c-${colorName}-on-background);
+ --c-surface: var(--c-${colorName}-surface);
+ --c-on-surface: var(--c-${colorName}-on-surface);
+ --c-outline: var(--c-${colorName}-outline);
+ --c-surface-variant: var(--c-${colorName}-surface-variant);
+ --c-on-surface-variant: var(--c-${colorName}-on-surface-variant);
+ --c-success: var(--c-${colorName}-success);
+ --c-on-success: var(--c-${colorName}-on-success);
+}
+@media (prefers-color-scheme: light) {
+ :root {
+ --c-primary: var(--c-${colorName}-primary);
+ --c-on-primary: var(--c-${colorName}-on-primary);
+ --c-primary-container: var(--c-${colorName}-primary-container);
+ --c-on-primary-container: var(--c-${colorName}-on-primary-container);
+ --c-background: var(--c-${colorName}-background);
+ --c-on-background: var(--c-${colorName}-on-background);
+ --c-surface: var(--c-${colorName}-surface);
+ --c-on-surface: var(--c-${colorName}-on-surface);
+ --c-outline: var(--c-${colorName}-outline);
+ --c-surface-variant: var(--c-${colorName}-surface-variant);
+ --c-on-surface-variant: var(--c-${colorName}-on-surface-variant);
+ --c-success: var(--c-${colorName}-success);
+ --c-on-success: var(--c-${colorName}-on-success);
+ }
+}
+`;
+
+ // Check for a previous style element in the head
+ let styleEl = document.getElementById("color-scheme-style");
+
+ if (styleEl === null) {
+ styleEl = document.createElement("style");
+ styleEl.id = "color-scheme-style";
+ document.head.appendChild(styleEl);
+ }
+
+ // Apply the new color
+ styleEl.innerHTML = styleStr;
+
+ // Save
+ localStorage.setItem("color-scheme", colorName);
+};
+
+// Applies colors on load
+(() => {
+ const savedColor = localStorage.getItem("color-scheme") ?? "blue";
+ applyColors(savedColor);
+})();
diff --git a/src/main/resources/static/colors.css b/src/main/resources/static/colors.css
new file mode 100644
index 0000000..3e0e335
--- /dev/null
+++ b/src/main/resources/static/colors.css
@@ -0,0 +1,232 @@
+/*
+ Material colors
+*/
+
+/*
+ * GREEN
+ */
+:root {
+ --c-green-primary: #7cdc6d;
+ --c-green-on-primary: #003a02;
+ --c-green-primary-container: #005304;
+ --c-green-on-primary-container: #97f986;
+ --c-green-background: #1a1c18;
+ --c-green-on-background: #e2e3dd;
+ --c-green-surface: #1a1c18;
+ --c-green-on-surface: #e2e3dd;
+ --c-green-outline: #8d9387;
+ --c-green-surface-variant: #43483f;
+ --c-green-on-surface-variant: #c3c8bc;
+
+ --c-green-success: #adc6ff;
+ --c-green-on-success: #002e69;
+}
+@media (prefers-color-scheme: light) {
+ :root {
+ --c-green-primary: #006e08;
+ --c-green-on-primary: #ffffff;
+ --c-green-primary-container: #97f986;
+ --c-green-on-primary-container: #002201;
+ --c-green-background: #fcfdf6;
+ --c-green-on-background: #1a1c18;
+ --c-green-surface: #fcfdf6;
+ --c-green-on-surface: #1a1c18;
+ --c-green-outline: #73796e;
+ --c-green-surface-variant: #dfe4d8;
+ --c-green-on-surface-variant: #43483f;
+
+ --c-green-success: #315da8;
+ --c-green-on-success: #ffffff;
+ }
+}
+
+/*
+ * BLUE
+ */
+:root {
+ --c-blue-primary: #adc6ff;
+ --c-blue-on-primary: #002e69;
+ --c-blue-primary-container: #0e448e;
+ --c-blue-on-primary-container: #d8e2ff;
+ --c-blue-background: #1b1b1f;
+ --c-blue-on-background: #e3e2e6;
+ --c-blue-surface: #1b1b1f;
+ --c-blue-on-surface: #e3e2e6;
+ --c-blue-outline: #8e9099;
+ --c-blue-surface-variant: #44474f;
+ --c-blue-on-surface-variant: #c4c6d0;
+
+ --c-blue-success: #7cdc6d;
+ --c-blue-on-success: #003a02;
+}
+@media (prefers-color-scheme: light) {
+ :root {
+ --c-blue-primary: #315da8;
+ --c-blue-on-primary: #ffffff;
+ --c-blue-primary-container: #d8e2ff;
+ --c-blue-on-primary-container: #001a41;
+ --c-blue-background: #fefbff;
+ --c-blue-on-background: #1b1b1f;
+ --c-blue-surface: #fefbff;
+ --c-blue-on-surface: #1b1b1f;
+ --c-blue-outline: #74777f;
+ --c-blue-surface-variant: #e1e2ec;
+ --c-blue-on-surface-variant: #44474f;
+
+ --c-blue-success: #006e08;
+ --c-blue-on-success: #ffffff;
+ }
+}
+
+/*
+ * YELLOW
+ */
+:root {
+ --c-yellow-primary: #f5bf31;
+ --c-yellow-on-primary: #3f2e00;
+ --c-yellow-primary-container: #5b4300;
+ --c-yellow-on-primary-container: #ffdf9b;
+ --c-yellow-background: #1e1b16;
+ --c-yellow-on-background: #e9e1d9;
+ --c-yellow-surface: #1e1b16;
+ --c-yellow-on-surface: #e9e1d9;
+ --c-yellow-outline: #999080;
+ --c-yellow-surface-variant: #4d4639;
+ --c-yellow-on-surface-variant: #d0c5b4;
+
+ --c-yellow-success: #7cdc6d;
+ --c-yellow-on-success: #003a02;
+}
+@media (prefers-color-scheme: light) {
+ :root {
+ --c-yellow-primary: #785a00;
+ --c-yellow-on-primary: #ffffff;
+ --c-yellow-primary-container: #ffdf9b;
+ --c-yellow-on-primary-container: #251a00;
+ --c-yellow-background: #fffbff;
+ --c-yellow-on-background: #1e1b16;
+ --c-yellow-surface: #fffbff;
+ --c-yellow-on-surface: #1e1b16;
+ --c-yellow-outline: #7f7667;
+ --c-yellow-surface-variant: #ede1cf;
+ --c-yellow-on-surface-variant: #4d4639;
+
+ --c-yellow-success: #006e08;
+ --c-yellow-on-success: #ffffff;
+ }
+}
+
+
+/*
+ * PINK
+ */
+:root {
+ --c-pink-primary: #ffade5;
+ --c-pink-on-primary: #5e0051;
+ --c-pink-primary-container: #80156e;
+ --c-pink-on-primary-container: #ffd7ef;
+ --c-pink-background: #1f1a1d;
+ --c-pink-on-background: #eae0e3;
+ --c-pink-surface: #1f1a1d;
+ --c-pink-on-surface: #eae0e3;
+ --c-pink-outline: #9b8d94;
+ --c-pink-surface-variant: #4f444a;
+ --c-pink-on-surface-variant: #d2c2ca;
+
+ --c-pink-success: #7cdc6d;
+ --c-pink-on-success: #003a02;
+}
+@media (prefers-color-scheme: light) {
+ :root {
+ --c-pink-primary: #9d3288;
+ --c-pink-on-primary: #ffffff;
+ --c-pink-primary-container: #ffd7ef;
+ --c-pink-on-primary-container: #3a0031;
+ --c-pink-background: #fffbff;
+ --c-pink-on-background: #1f1a1d;
+ --c-pink-surface: #fffbff;
+ --c-pink-on-surface: #1f1a1d;
+ --c-pink-outline: #81737a;
+ --c-pink-surface-variant: #efdee6;
+ --c-pink-on-surface-variant: #4f444a;
+
+ --c-pink-success: #006e08;
+ --c-pink-on-success: #ffffff;
+ }
+}
+
+/*
+ * ORANGE
+ */
+:root {
+ --c-orange-primary: #ffb86d;
+ --c-orange-on-primary: #492900;
+ --c-orange-primary-container: #683c00;
+ --c-orange-on-primary-container: #ffdcbd;
+ --c-orange-background: #201b16;
+ --c-orange-on-background: #ebe1d9;
+ --c-orange-surface: #201b16;
+ --c-orange-on-surface: #ebe1d9;
+ --c-orange-outline: #9d8e81;
+ --c-orange-surface-variant: #50453a;
+ --c-orange-on-surface-variant: #d5c3b5;
+
+ --c-orange-success: #7cdc6d;
+ --c-orange-on-success: #003a02;
+}
+@media (prefers-color-scheme: light) {
+ :root {
+ --c-orange-primary: #9e4300;
+ --c-orange-on-primary: #ffffff;
+ --c-orange-primary-container: #ffdbcb;
+ --c-orange-on-primary-container: #341100;
+ --c-orange-background: #fffbff;
+ --c-orange-on-background: #201a18;
+ --c-orange-surface: #fffbff;
+ --c-orange-on-surface: #201a18;
+ --c-orange-outline: #85736c;
+ --c-orange-surface-variant: #f4ded4;
+ --c-orange-on-surface-variant: #52443d;
+
+ --c-orange-success: #006e08;
+ --c-orange-on-success: #ffffff;
+ }
+}
+
+/*
+ * RED
+ */
+:root {
+ --c-red-primary: #ffb4a8;
+ --c-red-on-primary: #690100;
+ --c-red-primary-container: #930100;
+ --c-red-on-primary-container: #ffdad4;
+ --c-red-background: #201a19;
+ --c-red-on-background: #ede0dd;
+ --c-red-surface: #201a19;
+ --c-red-on-surface: #ede0dd;
+ --c-red-outline: #a08c89;
+ --c-red-surface-variant: #534341;
+ --c-red-on-surface-variant: #d8c2be;
+
+ --c-red-success: #7cdc6d;
+ --c-red-on-success: #003a02;
+}
+@media (prefers-color-scheme: light) {
+ :root {
+ --c-red-primary: #c00100;
+ --c-red-on-primary: #ffffff;
+ --c-red-primary-container: #ffdad4;
+ --c-red-on-primary-container: #410000;
+ --c-red-background: #fffbff;
+ --c-red-on-background: #201a19;
+ --c-red-surface: #fffbff;
+ --c-red-on-surface: #201a19;
+ --c-red-outline: #857370;
+ --c-red-surface-variant: #f5ddda;
+ --c-red-on-surface-variant: #534341;
+
+ --c-red-success: #006e08;
+ --c-red-on-success: #ffffff;
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html
new file mode 100644
index 0000000..11cfb99
--- /dev/null
+++ b/src/main/resources/templates/index.html
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+ EEGSAC - Java
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Javaaaaaa!!!!!
+
+
+
+
\ No newline at end of file