Mono Repo
* moveBackend * added Frontend * added env support for COM port * added frontend into monorepo
18
Frontend/.eslintrc.cjs
Normal file
@@ -0,0 +1,18 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
node: true,
|
||||
},
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
"plugin:vue/vue3-recommended",
|
||||
"prettier"
|
||||
],
|
||||
rules: {
|
||||
// override/add rules settings here, such as:
|
||||
// 'vue/no-unused-vars': 'error'
|
||||
},
|
||||
parser: "vue-eslint-parser",
|
||||
parserOptions: {
|
||||
"parser": "@typescript-eslint/parser"
|
||||
},
|
||||
}
|
||||
26
Frontend/.gitignore
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
.env
|
||||
# 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
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
BIN
Frontend/.prettierrc.json
Normal file
9
Frontend/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# Vue 3 + TypeScript + Vite
|
||||
|
||||
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
||||
|
||||
## Recommended Setup
|
||||
|
||||
- [VS Code](https://code.visualstudio.com/) + [Vue - Official](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (previously Volar) and disable Vetur
|
||||
|
||||
- Use [vue-tsc](https://github.com/vuejs/language-tools/tree/master/packages/tsc) for performing the same type checking from the command line, or for generating d.ts files for SFCs.
|
||||
12
Frontend/index.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>Vite + Vue + TS</title>
|
||||
</head>
|
||||
<body class="bg-zinc-800">
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
3856
Frontend/package-lock.json
generated
Normal file
29
Frontend/package.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "frontend",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vue-tsc && vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.4.21"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/parser": "^7.7.0",
|
||||
"@vitejs/plugin-vue": "^5.0.4",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-vue": "^9.25.0",
|
||||
"postcss": "^8.4.38",
|
||||
"prettier": "3.2.5",
|
||||
"sass": "^1.75.0",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"typescript": "^5.2.2",
|
||||
"vite": "^5.2.0",
|
||||
"vue-tsc": "^2.0.6"
|
||||
}
|
||||
}
|
||||
6
Frontend/postcss.config.js
Normal file
@@ -0,0 +1,6 @@
|
||||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
BIN
Frontend/public/assets/blatt_6.png
Normal file
|
After Width: | Height: | Size: 815 KiB |
BIN
Frontend/public/assets/blatt_7.png
Normal file
|
After Width: | Height: | Size: 859 KiB |
BIN
Frontend/public/assets/blatt_8.png
Normal file
|
After Width: | Height: | Size: 971 KiB |
BIN
Frontend/public/assets/blatt_9.png
Normal file
|
After Width: | Height: | Size: 954 KiB |
BIN
Frontend/public/assets/blatt_a.png
Normal file
|
After Width: | Height: | Size: 797 KiB |
BIN
Frontend/public/assets/blatt_k.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
Frontend/public/assets/blatt_o.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
Frontend/public/assets/blatt_u.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
Frontend/public/assets/blatt_x.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
Frontend/public/assets/card_back.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
Frontend/public/assets/eichel_6.png
Normal file
|
After Width: | Height: | Size: 603 KiB |
BIN
Frontend/public/assets/eichel_7.png
Normal file
|
After Width: | Height: | Size: 646 KiB |
BIN
Frontend/public/assets/eichel_8.png
Normal file
|
After Width: | Height: | Size: 730 KiB |
BIN
Frontend/public/assets/eichel_9.png
Normal file
|
After Width: | Height: | Size: 768 KiB |
BIN
Frontend/public/assets/eichel_a.png
Normal file
|
After Width: | Height: | Size: 905 KiB |
BIN
Frontend/public/assets/eichel_k.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
Frontend/public/assets/eichel_o.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
Frontend/public/assets/eichel_u.png
Normal file
|
After Width: | Height: | Size: 1008 KiB |
BIN
Frontend/public/assets/eichel_x.png
Normal file
|
After Width: | Height: | Size: 870 KiB |
BIN
Frontend/public/assets/herz_6.png
Normal file
|
After Width: | Height: | Size: 412 KiB |
BIN
Frontend/public/assets/herz_7.png
Normal file
|
After Width: | Height: | Size: 470 KiB |
BIN
Frontend/public/assets/herz_8.png
Normal file
|
After Width: | Height: | Size: 498 KiB |
BIN
Frontend/public/assets/herz_9.png
Normal file
|
After Width: | Height: | Size: 626 KiB |
BIN
Frontend/public/assets/herz_a.png
Normal file
|
After Width: | Height: | Size: 957 KiB |
BIN
Frontend/public/assets/herz_k.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
Frontend/public/assets/herz_o.png
Normal file
|
After Width: | Height: | Size: 1010 KiB |
BIN
Frontend/public/assets/herz_u.png
Normal file
|
After Width: | Height: | Size: 959 KiB |
BIN
Frontend/public/assets/herz_x.png
Normal file
|
After Width: | Height: | Size: 686 KiB |
BIN
Frontend/public/assets/schell_6.png
Normal file
|
After Width: | Height: | Size: 600 KiB |
BIN
Frontend/public/assets/schell_7.png
Normal file
|
After Width: | Height: | Size: 704 KiB |
BIN
Frontend/public/assets/schell_8.png
Normal file
|
After Width: | Height: | Size: 741 KiB |
BIN
Frontend/public/assets/schell_9.png
Normal file
|
After Width: | Height: | Size: 881 KiB |
BIN
Frontend/public/assets/schell_a.png
Normal file
|
After Width: | Height: | Size: 1009 KiB |
BIN
Frontend/public/assets/schell_k.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
Frontend/public/assets/schell_o.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
Frontend/public/assets/schell_u.png
Normal file
|
After Width: | Height: | Size: 1015 KiB |
BIN
Frontend/public/assets/schell_x.png
Normal file
|
After Width: | Height: | Size: 958 KiB |
228
Frontend/src/App.vue
Normal file
@@ -0,0 +1,228 @@
|
||||
<script lang="ts" setup>
|
||||
import {onMounted, ref} from 'vue';
|
||||
import CardComp from './components/CardComponent.vue';
|
||||
import {BackendMessage, Card, GamePhase, GameState} from "./BackendMessage";
|
||||
|
||||
const messageFromServer = ref<string[]>([]);
|
||||
|
||||
const gameStateText = ref<string>("Schafkopf");
|
||||
const gameInfoText = ref<string>("");
|
||||
|
||||
const socket = ref<WebSocket | null>();
|
||||
const tableCards = ref<Card[]>([]);
|
||||
const botCards = ref(0);
|
||||
const trickCard = ref<Card>();
|
||||
|
||||
const showGameSelect = ref(true);
|
||||
|
||||
|
||||
function startSimulation(): void {
|
||||
sendMessageToServer("startsimulation");
|
||||
|
||||
}
|
||||
|
||||
function stopSimulation(): void {
|
||||
sendMessageToServer("stopsimulation");
|
||||
}
|
||||
|
||||
function showTrumpf(): void {
|
||||
tableCards.value = [];
|
||||
sendMessageToServer("showtrumpf");
|
||||
}
|
||||
|
||||
function showFarben(): void {
|
||||
tableCards.value = [];
|
||||
sendMessageToServer("showfarben");
|
||||
}
|
||||
|
||||
function setGame(game: string): void {
|
||||
sendMessageToServer(game);
|
||||
}
|
||||
|
||||
|
||||
function sendMessageToServer(message: string) {
|
||||
if (socket.value) {
|
||||
socket.value.send(message);
|
||||
console.log("Sent message to server:", message);
|
||||
}
|
||||
}
|
||||
|
||||
function showGameState(gamestate: GameState) {
|
||||
|
||||
|
||||
switch (gamestate.gamePhase) {
|
||||
case GamePhase.GAME_START:
|
||||
gameStateText.value = "Spiel startet";
|
||||
showGameSelect.value = false;
|
||||
botCards.value = 8;
|
||||
break;
|
||||
case GamePhase.TRICK_START:
|
||||
gameStateText.value = "Runde startet";
|
||||
tableCards.value = [];
|
||||
trickCard.value = undefined
|
||||
gameInfoText.value = "";
|
||||
break;
|
||||
case GamePhase.WAIT_FOR_CARD:
|
||||
gameStateText.value = "Spieler " + gamestate.currentPlayer + " muss eine Karte legen.";
|
||||
break;
|
||||
case GamePhase.PLAYER_CARD:
|
||||
gameStateText.value = "Spieler " + gamestate.currentPlayer + " hat eine Karte gespielt.";
|
||||
if (gamestate.currentPlayer === 0) {
|
||||
botCards.value--
|
||||
}
|
||||
if (gamestate.trumpf) {
|
||||
gameInfoText.value = "TRUMPF";
|
||||
} else {
|
||||
gameInfoText.value = gamestate.color?.toString() ?? "ERROR";
|
||||
}
|
||||
tableCards.value.push(gamestate.card!);
|
||||
|
||||
|
||||
break;
|
||||
case GamePhase.PLAYER_TRICK:
|
||||
gameStateText.value = "Spieler " + gamestate.currentPlayer + " sticht.";
|
||||
trickCard.value = gamestate.card
|
||||
break;
|
||||
case GamePhase.GAME_STOP:
|
||||
showGameSelect.value = true;
|
||||
break;
|
||||
default:
|
||||
gameStateText.value = "Fehler";
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const websocketIp = import.meta.env.VITE_APP_WEBSOCKET_IP;
|
||||
// Open a WebSocket connection when the component is mounted
|
||||
socket.value = new WebSocket("ws://" + websocketIp + ":8080/schafkopf-events/");
|
||||
|
||||
// Handle connection opened
|
||||
socket.value.addEventListener("open", (event) => {
|
||||
console.log("WebSocket connection opened:", event);
|
||||
});
|
||||
|
||||
// Handle messages received from the server
|
||||
socket.value.addEventListener("message", (event) => {
|
||||
const message: BackendMessage = JSON.parse(event.data);
|
||||
console.log(message)
|
||||
if ('gamestate' in message) {
|
||||
console.log(message.gamestate)
|
||||
showGameState(message.gamestate)
|
||||
} else {
|
||||
console.log("Invalid BackendMessage format: ", event);
|
||||
}
|
||||
});
|
||||
|
||||
// Handle connection closed
|
||||
socket.value.addEventListener("close", (event) => {
|
||||
console.log("WebSocket connection closed:", event);
|
||||
});
|
||||
|
||||
// Handle errors
|
||||
socket.value.addEventListener("error", (event) => {
|
||||
console.error("WebSocket error:", event);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<div v-for="message in messageFromServer" :key="message">{{ message }}</div>
|
||||
|
||||
<div v-if="showGameSelect">
|
||||
<div class="flex gap-2 place-content-center">
|
||||
<button @click="setGame('setgame:sauspiel')">Sauspiel</button>
|
||||
|
||||
<button @click="setGame('setgame:herzsolo')">herzsolo</button>
|
||||
<button @click="setGame('setgame:eichelsolo')">eichelsolo</button>
|
||||
<button @click="setGame('setgame:blattsolo')">blattsolo</button>
|
||||
<button @click="setGame('setgame:schellsolo')">schellsolo</button>
|
||||
|
||||
<button @click="setGame('setgame:eichelwenz')">eichelwenz</button>
|
||||
<button @click="setGame('setgame:blattwenz')">blattwenz</button>
|
||||
<button @click="setGame('setgame:herzwenz')">herzwenz</button>
|
||||
<button @click="setGame('setgame:schellwenz')">schellwenz</button>
|
||||
|
||||
<button @click="setGame('setgame:eichelgeier')">eichelgeier</button>
|
||||
<button @click="setGame('setgame:blattgeier')">blattgeier</button>
|
||||
<button @click="setGame('setgame:herzgeier')">herzgeier</button>
|
||||
<button @click="setGame('setgame:schellgeier')">schellgeier</button>
|
||||
|
||||
<button @click="setGame('setgame:geier')">Geier</button>
|
||||
<button @click="setGame('setgame:wenz')">Wenz</button>
|
||||
</div>
|
||||
<div class="flex gap-2 place-content-center">
|
||||
<button @click="showFarben">Zeige alle Farben</button>
|
||||
<button @click="showTrumpf">Zeige alle Trumpfkarten</button>
|
||||
</div>
|
||||
<div class="flex gap-2 place-content-center">
|
||||
<button class="v-button" @click="startSimulation">Starten</button>
|
||||
<button class="v-button" @click="stopSimulation">Stoppen</button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="flex gap-2 place-content-center">
|
||||
<button class="v-button" @click="stopSimulation">Stoppen</button>
|
||||
</div>
|
||||
<h1 class=" top-52 text-white font-bold text-6xl absolute text-center w-full">{{ gameInfoText }}</h1>
|
||||
<h1 class=" top-64 text-white font-bold text-6xl absolute text-center w-full">{{ gameStateText }}</h1>
|
||||
<div v-if="tableCards.length > 0">
|
||||
<!-- <div class="grid grid-cols-4 place-content-center">-->
|
||||
<!-- <CardComp v-for="card in tableCards" :card="card" class="md" />-->
|
||||
<!-- </div>-->
|
||||
<CardComp v-if="tableCards.length > 0" :card="tableCards[0]" class="absolute card1 md"/>
|
||||
<CardComp v-if="tableCards.length > 1" :card="tableCards[1]" class="absolute card2 md"/>
|
||||
<CardComp v-if="tableCards.length > 2" :card="tableCards[2]" class="absolute card3 md"/>
|
||||
<CardComp v-if="tableCards.length > 3" :card="tableCards[3]" class="absolute card4 md"/>
|
||||
</div>
|
||||
<div class="absolute left-0 top-1/2 transform -translate-y-1/2">
|
||||
<CardComp v-if="trickCard" :card="trickCard" class="xl"/>
|
||||
</div>
|
||||
|
||||
<div class="absolute bottom-0 w-full">
|
||||
<div class="flex flex-row gap-3 w-fit mx-auto justify-center">
|
||||
<CardComp v-for="i in botCards" :key="i" :card="Card.BACK" class="sm"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss">
|
||||
$card-height: 24rem;
|
||||
|
||||
.card0 {
|
||||
z-index: 1;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.card1 {
|
||||
z-index: 1;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.card2 {
|
||||
z-index: 2;
|
||||
top: calc(50% + ($card-height * 0.10));
|
||||
left: calc(50% - ($card-height * 0.3));
|
||||
transform: rotate(50deg) translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.card3 {
|
||||
z-index: 3;
|
||||
top: calc(50% - ($card-height * 0.125));
|
||||
left: calc(50% + ($card-height * 0.35));
|
||||
transform: rotate(-30deg) translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.card4 {
|
||||
z-index: 4;
|
||||
top: calc(50% - ($card-height * 0.4));
|
||||
left: calc(50% + ($card-height * 0.35));
|
||||
transform: rotate(-60deg) translate(-50%, -50%);
|
||||
}
|
||||
</style>
|
||||
98
Frontend/src/BackendMessage.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
// Enum for KartenSymbol
|
||||
enum KartenFarbe {
|
||||
SCHELL = "SCH",
|
||||
HERZ = "HERZ",
|
||||
BLATT = "BLATT",
|
||||
EICHEL = "EICHEL",
|
||||
TRUMPF = "TRUMPF",
|
||||
}
|
||||
|
||||
enum KartenSymbol {
|
||||
SEVEN = "7",
|
||||
EIGHT = "8",
|
||||
NINE = "9",
|
||||
TEN = "X",
|
||||
UNTER = "U",
|
||||
OBER = "O",
|
||||
KOENIG = "K",
|
||||
ASS = "A",
|
||||
}
|
||||
|
||||
export enum Card {
|
||||
EICHEL_7 = 'EICHEL_7',
|
||||
EICHEL_8 = 'EICHEL_8',
|
||||
EICHEL_9 = 'EICHEL_9',
|
||||
EICHEL_X = 'EICHEL_X',
|
||||
EICHEL_K = 'EICHEL_K',
|
||||
EICHEL_A = 'EICHEL_A',
|
||||
|
||||
BLATT_7 = 'BLATT_7',
|
||||
BLATT_8 = 'BLATT_8',
|
||||
BLATT_9 = 'BLATT_9',
|
||||
BLATT_X = 'BLATT_X',
|
||||
BLATT_K = 'BLATT_K',
|
||||
BLATT_A = 'BLATT_A',
|
||||
|
||||
SCHELL_7 = 'SCHELL_7',
|
||||
SCHELL_8 = 'SCHELL_8',
|
||||
SCHELL_9 = 'SCHELL_9',
|
||||
SCHELL_X = 'SCHELL_X',
|
||||
SCHELL_K = 'SCHELL_K',
|
||||
SCHELL_A = 'SCHELL_A',
|
||||
|
||||
HERZ_7 = 'HERZ_7',
|
||||
HERZ_8 = 'HERZ_8',
|
||||
HERZ_9 = 'HERZ_9',
|
||||
HERZ_X = 'HERZ_X',
|
||||
HERZ_K = 'HERZ_K',
|
||||
HERZ_A = 'HERZ_A',
|
||||
|
||||
SCHELL_U = 'SCHELL_U',
|
||||
HERZ_U = 'HERZ_U',
|
||||
BLATT_U = 'BLATT_U',
|
||||
EICHEL_U = 'EICHEL_U',
|
||||
|
||||
SCHELL_O = 'SCHELL_O',
|
||||
HERZ_O = 'HERZ_O',
|
||||
BLATT_O = 'BLATT_O',
|
||||
EICHEL_O = 'EICHEL_O',
|
||||
|
||||
BACK = "CARD_BACK"
|
||||
// Add other card combinations as needed
|
||||
}
|
||||
|
||||
export enum GamePhase {
|
||||
CHOOSE_GAME = "CHOOSE_GAME",
|
||||
GAME_START = "GAME_START",
|
||||
GAME_STOP = "GAME_STOP",
|
||||
TRICK_START = "TRICK_START",
|
||||
WAIT_FOR_CARD = "WAIT_FOR_CARD",
|
||||
PLAYER_CARD = "PLAYER_CARD",
|
||||
PLAYER_TRICK = "PLAYER_TRICK"
|
||||
}
|
||||
|
||||
// Define the interface for an array of cards
|
||||
export interface CardArray {
|
||||
cards: Card[];
|
||||
}
|
||||
export interface CardObject {
|
||||
card: Card;
|
||||
}
|
||||
|
||||
|
||||
// Define the interface for the game state
|
||||
export interface GameState {
|
||||
gamePhase: GamePhase;
|
||||
currentPlayer?: number;
|
||||
card?: Card;
|
||||
color?: KartenFarbe;
|
||||
trumpf?: boolean;
|
||||
}
|
||||
|
||||
|
||||
export interface GameStateJson {
|
||||
gamestate : GameState
|
||||
}
|
||||
|
||||
// Define a union type for all possible message types
|
||||
export type BackendMessage = CardObject | CardArray | GameStateJson;
|
||||
52
Frontend/src/components/CardComponent.vue
Normal file
@@ -0,0 +1,52 @@
|
||||
<script lang="ts" setup>
|
||||
import {onBeforeMount, ref, watch} from 'vue';
|
||||
import {Card} from "../BackendMessage";
|
||||
|
||||
const props = defineProps<{
|
||||
card: Card;
|
||||
}>();
|
||||
|
||||
const imgSrc = ref('/assets/card_back.png')
|
||||
|
||||
const focus = ref(false);
|
||||
|
||||
onBeforeMount(() => {
|
||||
imgSrc.value = "/assets/" + props.card.toString().toLowerCase() + ".png"
|
||||
})
|
||||
|
||||
watch(() => props.card, (newCard) => {
|
||||
imgSrc.value = `/assets/${newCard.toString().toLowerCase()}.png`;
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<div
|
||||
:class="{'!scale-105 !z-10 !top-1/2 !left-1/2' : focus}" class="card transition overflow-hidden"
|
||||
@click="focus=!focus">
|
||||
<img class="h-full rounded-[1rem] mx-auto" :src="imgSrc" alt="card">
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.card {
|
||||
&.xl {
|
||||
@apply h-[48rem];
|
||||
img {
|
||||
@apply rounded-[2rem]
|
||||
}
|
||||
}
|
||||
|
||||
&.md {
|
||||
@apply h-96;
|
||||
img {
|
||||
@apply rounded-2xl
|
||||
}
|
||||
}
|
||||
|
||||
&.sm {
|
||||
@apply h-64;
|
||||
img {
|
||||
@apply rounded-xl
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
5
Frontend/src/main.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { createApp } from 'vue'
|
||||
import './style.css'
|
||||
import App from './App.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
||||
8
Frontend/src/style.css
Normal file
@@ -0,0 +1,8 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
|
||||
.v-button{
|
||||
@apply bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full transition duration-300 ease-in-out;
|
||||
}
|
||||
1
Frontend/src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
11
Frontend/tailwind.config.js
Normal file
@@ -0,0 +1,11 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: [
|
||||
"./index.html",
|
||||
"./src/**/*.{vue,js,ts,jsx,tsx}",
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
25
Frontend/tsconfig.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "preserve",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
11
Frontend/tsconfig.node.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
7
Frontend/vite.config.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
})
|
||||