style: add prettier configuration and format code

This commit is contained in:
2025-03-07 10:33:46 +01:00
parent 4f96206b8a
commit 540c70216c
24 changed files with 8885 additions and 3810 deletions

View File

@ -0,0 +1,8 @@
{
"semi": true,
"tabWidth": 4,
"trailingComma": "es5",
"printWidth": 200,
"bracketSpacing": true,
"arrowParens": "always"
}

View File

@ -42,6 +42,6 @@ If you have state that's important to retain within a component, consider creati
```ts ```ts
// store.ts // store.ts
// An extremely simple external store // An extremely simple external store
import { writable } from 'svelte/store' import { writable } from "svelte/store";
export default writable(0) export default writable(0);
``` ```

View File

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

5082
frontend/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,42 +1,43 @@
{ {
"name": "hexdeck-frontend", "name": "hexdeck-frontend",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "vite build", "build": "vite build",
"preview": "vite preview", "preview": "vite preview",
"check": "svelte-check --tsconfig ./tsconfig.app.json && tsc -p tsconfig.node.json" "check": "svelte-check --tsconfig ./tsconfig.app.json && tsc -p tsconfig.node.json"
}, },
"devDependencies": { "devDependencies": {
"@sveltejs/vite-plugin-svelte": "^5.0.3", "@sveltejs/vite-plugin-svelte": "^5.0.3",
"@tailwindcss/forms": "^0.5.9", "@tailwindcss/forms": "^0.5.9",
"@tailwindcss/typography": "^0.5.15", "@tailwindcss/typography": "^0.5.15",
"@tailwindcss/vite": "^4.0.0", "@tailwindcss/vite": "^4.0.0",
"@tsconfig/svelte": "^5.0.4", "@tsconfig/svelte": "^5.0.4",
"flowbite": "^3.1.2", "flowbite": "^3.1.2",
"flowbite-svelte": "^0.48.4", "flowbite-svelte": "^0.48.4",
"flowbite-svelte-icons": "^2.0.2", "flowbite-svelte-icons": "^2.0.2",
"sass-embedded": "^1.85.1", "prettier": "3.5.3",
"svelte": "^5.22.5", "sass-embedded": "^1.85.1",
"svelte-check": "^4.1.4", "svelte": "^5.22.5",
"tailwindcss": "^4.0.0", "svelte-check": "^4.1.4",
"typescript": "~5.8.2", "tailwindcss": "^4.0.0",
"vite": "^6.2.0" "typescript": "~5.8.2",
}, "vite": "^6.2.0"
"dependencies": { },
"@roxi/routify": "3.0.0-next.254", "dependencies": {
"@tailwindcss/vite": "^4.0.10", "@roxi/routify": "3.0.0-next.254",
"lucide-svelte": "^0.477.0", "@tailwindcss/vite": "^4.0.10",
"routify": "^2.0.1", "lucide-svelte": "^0.477.0",
"socket.io-client": "^4.8.1", "routify": "^2.0.1",
"svelte-exmarkdown": "^4.0.3", "socket.io-client": "^4.8.1",
"svelte-i18n": "^4.0.1", "svelte-exmarkdown": "^4.0.3",
"tailwindcss": "^4.0.10" "svelte-i18n": "^4.0.1",
}, "tailwindcss": "^4.0.10"
"pnpm": { },
"onlyBuiltDependencies": [ "pnpm": {
"esbuild" "onlyBuiltDependencies": [
] "esbuild"
} ]
} }
}

6171
frontend/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -1,88 +1,90 @@
@theme inline { @theme inline {
--color-primary-50: color-mix(in srgb, var(--primary) 10%, white); --color-primary-50: color-mix(in srgb, var(--primary) 10%, white);
--color-primary-100: color-mix(in srgb, var(--primary) 20%, white); --color-primary-100: color-mix(in srgb, var(--primary) 20%, white);
--color-primary-200: color-mix(in srgb, var(--primary) 30%, white); --color-primary-200: color-mix(in srgb, var(--primary) 30%, white);
--color-primary-300: color-mix(in srgb, var(--primary) 40%, white); --color-primary-300: color-mix(in srgb, var(--primary) 40%, white);
--color-primary-400: color-mix(in srgb, var(--primary) 50%, white); --color-primary-400: color-mix(in srgb, var(--primary) 50%, white);
--color-primary-500: color-mix(in srgb, var(--primary) 60%, white); --color-primary-500: color-mix(in srgb, var(--primary) 60%, white);
--color-primary-600: color-mix(in srgb, var(--primary) 70%, white); --color-primary-600: color-mix(in srgb, var(--primary) 70%, white);
--color-primary-700: color-mix(in srgb, var(--primary) 80%, white); --color-primary-700: color-mix(in srgb, var(--primary) 80%, white);
--color-primary-800: color-mix(in srgb, var(--primary) 90%, white); --color-primary-800: color-mix(in srgb, var(--primary) 90%, white);
--color-primary-900: var(--primary); --color-primary-900: var(--primary);
--color-primary-950: color-mix(in srgb, var(--primary) 90%, black); --color-primary-950: color-mix(in srgb, var(--primary) 90%, black);
--color-secondary-50: color-mix(in srgb, var(--secondary) 10%, white); --color-secondary-50: color-mix(in srgb, var(--secondary) 10%, white);
--color-secondary-100: color-mix(in srgb, var(--secondary) 20%, white); --color-secondary-100: color-mix(in srgb, var(--secondary) 20%, white);
--color-secondary-200: color-mix(in srgb, var(--secondary) 30%, white); --color-secondary-200: color-mix(in srgb, var(--secondary) 30%, white);
--color-secondary-300: color-mix(in srgb, var(--secondary) 40%, white); --color-secondary-300: color-mix(in srgb, var(--secondary) 40%, white);
--color-secondary-400: color-mix(in srgb, var(--secondary) 50%, white); --color-secondary-400: color-mix(in srgb, var(--secondary) 50%, white);
--color-secondary-500: color-mix(in srgb, var(--secondary) 60%, white); --color-secondary-500: color-mix(in srgb, var(--secondary) 60%, white);
--color-secondary-600: color-mix(in srgb, var(--secondary) 70%, white); --color-secondary-600: color-mix(in srgb, var(--secondary) 70%, white);
--color-secondary-700: color-mix(in srgb, var(--secondary) 80%, white); --color-secondary-700: color-mix(in srgb, var(--secondary) 80%, white);
--color-secondary-800: color-mix(in srgb, var(--secondary) 90%, white); --color-secondary-800: color-mix(in srgb, var(--secondary) 90%, white);
--color-secondary-900: var(--secondary); --color-secondary-900: var(--secondary);
--color-secondary-950: color-mix(in srgb, var(--secondary) 90%, black); --color-secondary-950: color-mix(in srgb, var(--secondary) 90%, black);
--color-tertiary-50: color-mix(in srgb, var(--tertiary) 10%, white); --color-tertiary-50: color-mix(in srgb, var(--tertiary) 10%, white);
--color-tertiary-100: color-mix(in srgb, var(--tertiary) 20%, white); --color-tertiary-100: color-mix(in srgb, var(--tertiary) 20%, white);
--color-tertiary-200: color-mix(in srgb, var(--tertiary) 30%, white); --color-tertiary-200: color-mix(in srgb, var(--tertiary) 30%, white);
--color-tertiary-300: color-mix(in srgb, var(--tertiary) 40%, white); --color-tertiary-300: color-mix(in srgb, var(--tertiary) 40%, white);
--color-tertiary-400: color-mix(in srgb, var(--tertiary) 50%, white); --color-tertiary-400: color-mix(in srgb, var(--tertiary) 50%, white);
--color-tertiary-500: color-mix(in srgb, var(--tertiary) 60%, white); --color-tertiary-500: color-mix(in srgb, var(--tertiary) 60%, white);
--color-tertiary-600: color-mix(in srgb, var(--tertiary) 70%, white); --color-tertiary-600: color-mix(in srgb, var(--tertiary) 70%, white);
--color-tertiary-700: color-mix(in srgb, var(--tertiary) 80%, white); --color-tertiary-700: color-mix(in srgb, var(--tertiary) 80%, white);
--color-tertiary-800: color-mix(in srgb, var(--tertiary) 90%, white); --color-tertiary-800: color-mix(in srgb, var(--tertiary) 90%, white);
--color-tertiary-900: var(--tertiary); --color-tertiary-900: var(--tertiary);
--color-tertiary-950: color-mix(in srgb, var(--tertiary) 90%, black); --color-tertiary-950: color-mix(in srgb, var(--tertiary) 90%, black);
} }
@layer base { @layer base {
button, button,
[role='button'] { [role="button"] {
cursor: pointer; cursor: pointer;
} }
} }
body { body {
margin: 0; margin: 0;
color: var(--default-element-color); color: var(--default-element-color);
background-color: var(--default-background-color); background-color: var(--default-background-color);
transition: color 0.4s ease, background-color 0.2s ease; transition:
color 0.4s ease,
background-color 0.2s ease;
} }
:root { :root {
font-family: "Lexend Deca", serif; font-family: "Lexend Deca", serif;
font-optical-sizing: auto; font-optical-sizing: auto;
line-height: 1.5; line-height: 1.5;
font-weight: 400; font-weight: 400;
font-synthesis: none; font-synthesis: none;
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
--primary: #d5b6ff; --primary: #d5b6ff;
--secondary: #ffb6f5; --secondary: #ffb6f5;
--tertiary: #08aeea; --tertiary: #08aeea;
--default-element-color: #213547; --default-element-color: #213547;
--default-background-color: #ffffff; --default-background-color: #ffffff;
} }
body.dark-theme { body.dark-theme {
--primary: #53346a; --primary: #53346a;
--secondary: #710cff; --secondary: #710cff;
--tertiary: #0b465c; --tertiary: #0b465c;
--default-element-color: rgba(255, 255, 255, 0.87); --default-element-color: rgba(255, 255, 255, 0.87);
--default-background-color: oklch(0.279 0.041 260.031); --default-background-color: oklch(0.279 0.041 260.031);
} }
body.light-theme { body.light-theme {
--primary: #d5b6ff; --primary: #d5b6ff;
--secondary: #ffb6f5; --secondary: #ffb6f5;
--tertiary: #08aeea; --tertiary: #08aeea;
--default-element-color: #213547; --default-element-color: #213547;
--default-background-color: #ffffff; --default-background-color: #ffffff;
} }

View File

@ -1,103 +1,103 @@
{ {
"page_name": "HexDeck", "page_name": "HexDeck",
"header": { "header": {
"theme_btn": { "theme_btn": {
"tooltip": "Thema wechseln: {current_theme}", "tooltip": "Thema wechseln: {current_theme}",
"dark": "Dunkel", "dark": "Dunkel",
"light": "Hell", "light": "Hell",
"system": "System" "system": "System"
}
},
"footer": {
"imprint": "Impressum",
"github": "GitHub"
},
"404": {
"404_page_not_found": "404 - Seite nicht gefunden",
"page_not_found": "Die Seite {page} konnte nicht gefunden werden."
},
"imprint": {
"title": "Impressum",
"something_went_wrong": "Etwas ist schief gelaufen",
"timeout_while_loading": "Zeitüberschreitung beim Laden",
"retry": "Erneut versuchen",
"go_back": "Zurück"
},
"landing_page": {
"sub_title": "Multiplayer, kostenlos, für alle",
"connect_room": {
"rejoin_last_room": "Letztes Spiel erneut beitreten",
"join_last_room": "Letztem Raum beitreten",
"enter_room_code": "Raumcode eingeben",
"join_room": "Beitreten",
"enter_room_code_to_join": "Bitte geben Sie einen Raumcode ein, um beizutreten",
"or": "oder",
"create_a_room": "Einen Raum erstellen"
},
"open_source_container": {
"title": "Open Source",
"content": "Der Quellcode dieses Spiels ist auf GitHub verfügbar",
"github": "GitHub"
},
"stats_container": {
"title": "Statistiken",
"online_player_count": "Aktuelle Spieler: {count}",
"current_game_rooms": "Aktuelle Spiele: {count}",
"games_played": "Gespielte Spiele: {count}",
"no_data": "Keine Daten"
},
"show_footer": "Footer anzeigen"
},
"lobby": {
"search_player": "Spieler suchen...",
"kick_player": "Spieler entfernen",
"confirm_kick_player_message": "Möchten Sie den Spieler {player_name} wirklich entfernen?",
"confirm_kick_player": "Entfernen",
"rename_yourself": "Sich selbst umbenennen",
"rename_player": "Spieler umbenennen",
"regenerate_join_code": "Beitrittscode neu generieren",
"copy_join_code": "Beitrittscode kopieren",
"room_join_code": "Raum Beitrittscode",
"copy_code": "Code kopieren",
"copy_join_link": "Link kopieren",
"leave_game": "Spiel verlassen",
"confirm_leave_message": "Möchten Sie das Spiel wirklich verlassen?",
"confirm_leave": "Ja, verlassen",
"cancel": "Abbrechen",
"start_game": "Spiel starten",
"copied": "Kopiert",
"player_name": "Spielername",
"status": "Status",
"host": "Host",
"you": "Du"
},
"player_status": {
"connected": "Verbunden",
"disconnected": "Getrennt"
},
"game_status": {
"game_status": "Spielstatus: {game_status}",
"lobby": "Lobby",
"running": "Läuft",
"ended": "Beendet"
},
"error_messages": {
"no_room_found": "Kein Raum mit diesem Code gefunden",
"request_timeout": "Internet fehlgeschlagen! (Zeitüberschreitung)",
"invalid_player": "Ungültiger Spieler",
"invalid_session": "Ungültige Sitzung",
"game_not_running": "Das Spiel läuft nicht",
"player_not_active": "Der Spieler ist nicht aktiv",
"insufficient_permission": "Unzureichende Berechtigung",
"username_taken": "Der Benutzername ist bereits vergeben",
"game_already_started": "Das Spiel hat bereits begonnen",
"missing_parameter": "Fehlender Parameter",
"invalid_card_index": "Ungültige Karte ausgewählt (Index außerhalb der Grenzen)",
"card_not_playable": "Die Karte ist nicht spielbar",
"card_not_updatable": "Die Karte ist nicht aktualisierbar",
"error_message": "Fehlermeldung: {error_message}"
},
"game_screen": {
"loading": "Laden"
} }
}, }
"footer": {
"imprint": "Impressum",
"github": "GitHub"
},
"404": {
"404_page_not_found": "404 - Seite nicht gefunden",
"page_not_found": "Die Seite {page} konnte nicht gefunden werden."
},
"imprint": {
"title": "Impressum",
"something_went_wrong": "Etwas ist schief gelaufen",
"timeout_while_loading": "Zeitüberschreitung beim Laden",
"retry": "Erneut versuchen",
"go_back": "Zurück"
},
"landing_page": {
"sub_title": "Multiplayer, kostenlos, für alle",
"connect_room": {
"rejoin_last_room": "Letztes Spiel erneut beitreten",
"join_last_room": "Letztem Raum beitreten",
"enter_room_code": "Raumcode eingeben",
"join_room": "Beitreten",
"enter_room_code_to_join": "Bitte geben Sie einen Raumcode ein, um beizutreten",
"or": "oder",
"create_a_room": "Einen Raum erstellen"
},
"open_source_container": {
"title": "Open Source",
"content": "Der Quellcode dieses Spiels ist auf GitHub verfügbar",
"github": "GitHub"
},
"stats_container": {
"title": "Statistiken",
"online_player_count": "Aktuelle Spieler: {count}",
"current_game_rooms": "Aktuelle Spiele: {count}",
"games_played": "Gespielte Spiele: {count}",
"no_data": "Keine Daten"
},
"show_footer": "Footer anzeigen"
},
"lobby": {
"search_player": "Spieler suchen...",
"kick_player": "Spieler entfernen",
"confirm_kick_player_message": "Möchten Sie den Spieler {player_name} wirklich entfernen?",
"confirm_kick_player": "Entfernen",
"rename_yourself": "Sich selbst umbenennen",
"rename_player": "Spieler umbenennen",
"regenerate_join_code": "Beitrittscode neu generieren",
"copy_join_code": "Beitrittscode kopieren",
"room_join_code": "Raum Beitrittscode",
"copy_code": "Code kopieren",
"copy_join_link": "Link kopieren",
"leave_game": "Spiel verlassen",
"confirm_leave_message": "Möchten Sie das Spiel wirklich verlassen?",
"confirm_leave": "Ja, verlassen",
"cancel": "Abbrechen",
"start_game": "Spiel starten",
"copied": "Kopiert",
"player_name": "Spielername",
"status": "Status",
"host": "Host",
"you": "Du"
},
"player_status": {
"connected": "Verbunden",
"disconnected": "Getrennt"
},
"game_status": {
"game_status": "Spielstatus: {game_status}",
"lobby": "Lobby",
"running": "Läuft",
"ended": "Beendet"
},
"error_messages": {
"no_room_found": "Kein Raum mit diesem Code gefunden",
"request_timeout": "Internet fehlgeschlagen! (Zeitüberschreitung)",
"invalid_player": "Ungültiger Spieler",
"invalid_session": "Ungültige Sitzung",
"game_not_running": "Das Spiel läuft nicht",
"player_not_active": "Der Spieler ist nicht aktiv",
"insufficient_permission": "Unzureichende Berechtigung",
"username_taken": "Der Benutzername ist bereits vergeben",
"game_already_started": "Das Spiel hat bereits begonnen",
"missing_parameter": "Fehlender Parameter",
"invalid_card_index": "Ungültige Karte ausgewählt (Index außerhalb der Grenzen)",
"card_not_playable": "Die Karte ist nicht spielbar",
"card_not_updatable": "Die Karte ist nicht aktualisierbar",
"error_message": "Fehlermeldung: {error_message}"
},
"game_screen": {
"loading": "Laden"
}
}

View File

@ -1,105 +1,105 @@
{ {
"page_name": "HexDeck", "page_name": "HexDeck",
"header": { "header": {
"theme_btn": { "theme_btn": {
"tooltip": "Switch theme: {current_theme}", "tooltip": "Switch theme: {current_theme}",
"dark": "Dark", "dark": "Dark",
"light": "Light", "light": "Light",
"system": "System" "system": "System"
}
},
"footer": {
"imprint": "Imprint",
"github": "GitHub"
},
"404": {
"404_page_not_found": "404 - Page not found",
"page_not_found": "The page {page} could not be found."
},
"imprint": {
"title": "Imprint",
"something_went_wrong": "Something went wrong",
"timeout_while_loading": "Timeout while loading",
"retry": "Retry",
"go_back": "Back"
},
"landing_page": {
"sub_title": "Multiplayer, free, for everyone",
"connect_room": {
"rejoin_last_room": "Rejoin last game",
"join_last_room": "Join last room",
"enter_room_code": "Enter a room code",
"join_room": "Join",
"enter_room_code_to_join": "Please enter a room code to join",
"or": "or",
"create_a_room": "Create a room"
},
"open_source_container": {
"title": "Open Source",
"content": "The Source Code of this game is available on GitHub",
"github": "GitHub"
},
"stats_container": {
"title": "Stats",
"online_player_count": "Current player: {count}",
"current_game_rooms": "Current games: {count}",
"games_played": "Games played: {count}",
"no_data": "No data"
},
"show_footer": "Show footer"
},
"lobby": {
"search_player": "Search player...",
"kick_player": "Kick player",
"confirm_kick_player_message": "Do you really want to kick the player {player_name}?",
"confirm_kick_player": "Kick",
"rename_yourself": "Rename yourself",
"rename_player": "Rename player",
"regenerate_join_code": "Regenerate join code",
"copy_join_code": "Copy join code",
"room_join_code": "Room Join Code",
"copy_code": "Copy Code",
"copy_join_link": "Copy Link",
"leave_game": "Leave game",
"confirm_leave_message": "Do you really want to leave the game?",
"confirm_leave": "Yes, leave",
"cancel": "Cancel",
"start_game": "Start game",
"copied": "Copied",
"player_name": "Player Name",
"status": "Status",
"host": "Host",
"you": "You",
"player": "Player",
"return_to_game": "Return to game"
},
"player_status": {
"connected": "Connected",
"disconnected": "Disconnected"
},
"game_status": {
"game_status": "Game status:",
"lobby": "Lobby",
"running": "Running",
"ended": "Ended"
},
"error_messages": {
"no_room_found": "No room was found with this code",
"request_timeout": "Internet failed! (Timeout)",
"invalid_player": "Invalid player",
"invalid_session": "Invalid session",
"game_not_running": "The game is not running",
"player_not_active": "The player ist not active",
"insufficient_permission": "Insufficient permission",
"username_taken": "The username is already taken",
"game_already_started": "The game has already started",
"missing_parameter": "Missing parameter",
"invalid_card_index": "Invalid card selected (Index not in bounds)",
"card_not_playable": "The card is not playable",
"card_not_updatable": "The card is not updatable",
"error_message": "Error message: {error_message}"
},
"game_screen": {
"loading": "Loading"
} }
}, }
"footer": {
"imprint": "Imprint",
"github": "GitHub"
},
"404": {
"404_page_not_found": "404 - Page not found",
"page_not_found": "The page {page} could not be found."
},
"imprint": {
"title": "Imprint",
"something_went_wrong": "Something went wrong",
"timeout_while_loading": "Timeout while loading",
"retry": "Retry",
"go_back": "Back"
},
"landing_page": {
"sub_title": "Multiplayer, free, for everyone",
"connect_room": {
"rejoin_last_room": "Rejoin last game",
"join_last_room": "Join last room",
"enter_room_code": "Enter a room code",
"join_room": "Join",
"enter_room_code_to_join": "Please enter a room code to join",
"or": "or",
"create_a_room": "Create a room"
},
"open_source_container": {
"title": "Open Source",
"content": "The Source Code of this game is available on GitHub",
"github": "GitHub"
},
"stats_container": {
"title": "Stats",
"online_player_count": "Current player: {count}",
"current_game_rooms": "Current games: {count}",
"games_played": "Games played: {count}",
"no_data": "No data"
},
"show_footer": "Show footer"
},
"lobby": {
"search_player": "Search player...",
"kick_player": "Kick player",
"confirm_kick_player_message": "Do you really want to kick the player {player_name}?",
"confirm_kick_player": "Kick",
"rename_yourself": "Rename yourself",
"rename_player": "Rename player",
"regenerate_join_code": "Regenerate join code",
"copy_join_code": "Copy join code",
"room_join_code": "Room Join Code",
"copy_code": "Copy Code",
"copy_join_link": "Copy Link",
"leave_game": "Leave game",
"confirm_leave_message": "Do you really want to leave the game?",
"confirm_leave": "Yes, leave",
"cancel": "Cancel",
"start_game": "Start game",
"copied": "Copied",
"player_name": "Player Name",
"status": "Status",
"host": "Host",
"you": "You",
"player": "Player",
"return_to_game": "Return to game"
},
"player_status": {
"connected": "Connected",
"disconnected": "Disconnected"
},
"game_status": {
"game_status": "Game status:",
"lobby": "Lobby",
"running": "Running",
"ended": "Ended"
},
"error_messages": {
"no_room_found": "No room was found with this code",
"request_timeout": "Internet failed! (Timeout)",
"invalid_player": "Invalid player",
"invalid_session": "Invalid session",
"game_not_running": "The game is not running",
"player_not_active": "The player ist not active",
"insufficient_permission": "Insufficient permission",
"username_taken": "The username is already taken",
"game_already_started": "The game has already started",
"missing_parameter": "Missing parameter",
"invalid_card_index": "Invalid card selected (Index not in bounds)",
"card_not_playable": "The card is not playable",
"card_not_updatable": "The card is not updatable",
"error_message": "Error message: {error_message}"
},
"game_screen": {
"loading": "Loading"
}
}

View File

@ -1,18 +1,18 @@
import { addMessages, register, init, getLocaleFromNavigator } from 'svelte-i18n'; import { addMessages, register, init, getLocaleFromNavigator } from "svelte-i18n";
import en from './en.json'; import en from "./en.json";
import de from './de.json'; import de from "./de.json";
addMessages('en', en); addMessages("en", en);
addMessages('de', de); addMessages("de", de);
register('en', () => import('./en.json')); register("en", () => import("./en.json"));
register('de', () => import('./de.json')); register("de", () => import("./de.json"));
const initialLocale = getLocaleFromNavigator(); const initialLocale = getLocaleFromNavigator();
console.log('Initial locale:', initialLocale); console.log("Initial locale:", initialLocale);
init({ init({
fallbackLocale: 'en', fallbackLocale: "en",
initialLocale: initialLocale, initialLocale: initialLocale,
}); });

View File

@ -1,12 +1,12 @@
@import url('https://fonts.googleapis.com/css2?family=Lexend+Deca:wght@100..900&display=swap'); @import url("https://fonts.googleapis.com/css2?family=Lexend+Deca:wght@100..900&display=swap");
@import 'tailwindcss'; @import "tailwindcss";
@plugin 'flowbite/plugin'; @plugin 'flowbite/plugin';
@custom-variant dark { @custom-variant dark {
@media not print { @media not print {
.dark & { .dark & {
@slot; @slot;
} }
} }
} }
@source "../node_modules/flowbite-svelte/dist"; @source "../node_modules/flowbite-svelte/dist";
@import './app.scss'; @import "./app.scss";

View File

@ -1,11 +1,10 @@
import { mount } from 'svelte' import { mount } from "svelte";
import './i18n/i18n' import "./i18n/i18n";
import './index.css' import "./index.css";
import App from './App.svelte' import App from "./App.svelte";
const app = mount(App, { const app = mount(App, {
target: document.getElementById('app')!, target: document.getElementById("app")!,
}) });
export default app
export default app;

View File

@ -5,11 +5,10 @@
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { onMount } from "svelte"; import { onMount } from "svelte";
import { GameState, sessionStore } from "../stores/sessionStore"; import { GameState, sessionStore } from "../stores/sessionStore";
import { Button, Spinner, Tooltip } from "flowbite-svelte"; import { Spinner } from "flowbite-svelte";
import { SvelteDate } from "svelte/reactivity"; import { SvelteDate } from "svelte/reactivity";
import { requestJoinRoom } from "../stores/roomStore"; import { requestJoinRoom } from "../stores/roomStore";
import gameStore, { toggleLobbyOverlay } from "../stores/gameStore"; import gameStore from "../stores/gameStore";
import { UsersRound } from "lucide-svelte";
onMount(async () => { onMount(async () => {
// TODO: check if already connected to room, currently its overwriting the session // TODO: check if already connected to room, currently its overwriting the session
@ -31,9 +30,7 @@
{#if !$sessionStore.connected} {#if !$sessionStore.connected}
<div class="flex flex-row w-full mt-32 h-full justify-center items-center"> <div class="flex flex-row w-full mt-32 h-full justify-center items-center">
<div <div class="flex flex-col items-center gap-6 p-7 md:flex-row md:gap-8 rounded-2xl">
class="flex flex-col items-center gap-6 p-7 md:flex-row md:gap-8 rounded-2xl"
>
<div> <div>
<Spinner size="12" class="text-primary-100" /> <Spinner size="12" class="text-primary-100" />
</div> </div>
@ -42,9 +39,7 @@
{$_("game_screen.loading")} {$_("game_screen.loading")}
</span> </span>
<span class="font-medium text-sky-500"> <span class="font-medium text-sky-500">
{$sessionStore.players?.find( {$sessionStore.players?.find((player) => player.PlayerId == $sessionStore.userId)?.Username}
(player) => player.PlayerId == $sessionStore.userId,
)?.Username}
</span> </span>
<span class="flex gap-2 font-medium text-gray-600 dark:text-gray-400"> <span class="flex gap-2 font-medium text-gray-600 dark:text-gray-400">
<span>{new SvelteDate().toLocaleString()}</span> <span>{new SvelteDate().toLocaleString()}</span>

View File

@ -88,11 +88,7 @@
} }
.Header { .Header {
background: linear-gradient( background: linear-gradient(180deg, var(--default-background-color) 30%, transparent 100%);
180deg,
var(--default-background-color) 30%,
transparent 100%
);
opacity: 1; opacity: 1;
position: fixed; position: fixed;
height: 100px; height: 100px;
@ -103,11 +99,7 @@
} }
.Header-bg { .Header-bg {
background: linear-gradient( background: linear-gradient(180deg, var(--primary) 50%, transparent 100%);
180deg,
var(--primary) 50%,
transparent 100%
);
z-index: -1; z-index: -1;
margin: 0px; margin: 0px;
position: absolute; position: absolute;

View File

@ -1,4 +1,4 @@
import { writable } from 'svelte/store'; import { writable } from "svelte/store";
interface GameState { interface GameState {
isLobbyOverlayShown: boolean; isLobbyOverlayShown: boolean;
@ -11,10 +11,10 @@ const initialState: GameState = {
const gameStore = writable<GameState>(initialState); const gameStore = writable<GameState>(initialState);
export const toggleLobbyOverlay = () => { export const toggleLobbyOverlay = () => {
gameStore.update(state => ({ gameStore.update((state) => ({
...state, ...state,
isLobbyOverlayShown: !state.isLobbyOverlayShown, isLobbyOverlayShown: !state.isLobbyOverlayShown,
})); }));
}; };
export default gameStore; export default gameStore;

View File

@ -1,7 +1,7 @@
import { Gamepad2 } from 'lucide-svelte'; import { Gamepad2 } from "lucide-svelte";
const options = { const options = {
page_icon: Gamepad2, page_icon: Gamepad2,
} };
export default options; export default options;

View File

@ -1,5 +1,5 @@
import { writable } from 'svelte/store'; import { writable } from "svelte/store";
import { sessionStore } from './sessionStore'; import { sessionStore } from "./sessionStore";
export const loading = writable<"join" | "create" | false>(false); export const loading = writable<"join" | "create" | false>(false);
export const join_error = writable<string | false>(false); export const join_error = writable<string | false>(false);
@ -143,4 +143,4 @@ export async function checkSessionData() {
rejoinRoomCode.set(lastSessionData.joinCode as string); rejoinRoomCode.set(lastSessionData.joinCode as string);
return; return;
} }
} }

View File

@ -1,303 +1,303 @@
import { writable, get } from 'svelte/store'; import { writable, get } from "svelte/store";
import { io, Socket } from 'socket.io-client'; import { io, Socket } from "socket.io-client";
export enum GameState { export enum GameState {
Undefined = -1, Undefined = -1,
Lobby, Lobby,
Running, Running,
Ended Ended,
} }
interface PlayerPermissionObj { interface PlayerPermissionObj {
isHost: boolean; isHost: boolean;
} }
interface GameOptions { } interface GameOptions {}
interface PlayerObj { interface PlayerObj {
PlayerId: string; PlayerId: string;
Username: string; Username: string;
Permissions: number; Permissions: number;
IsConnected: boolean; IsConnected: boolean;
} }
interface SessionData { interface SessionData {
roomId: string | null; roomId: string | null;
joinCode: string | null; joinCode: string | null;
gameOptions: GameOptions; gameOptions: GameOptions;
players: Array<PlayerObj>; players: Array<PlayerObj>;
cardDeckId: string | null; cardDeckId: string | null;
gameState: GameState; gameState: GameState;
socket: Socket | null; socket: Socket | null;
connected: boolean; connected: boolean;
userId: string | null; userId: string | null;
messages: string[]; messages: string[];
sessionToken: string | null; sessionToken: string | null;
} }
interface RoomInfoObj { interface RoomInfoObj {
RoomId: string; RoomId: string;
JoinCode: string; JoinCode: string;
TopCard: any; TopCard: any;
GameState: GameState; GameState: GameState;
CardDeckId: number; CardDeckId: number;
Winner?: string; Winner?: string;
Players: PlayerObj[]; Players: PlayerObj[];
} }
interface StatusInfoObj { interface StatusInfoObj {
IsError: boolean; IsError: boolean;
StatusCode: string; StatusCode: string;
Message: string; Message: string;
} }
class SessionManager { class SessionManager {
private store = writable<SessionData>({ private store = writable<SessionData>({
roomId: null, roomId: null,
joinCode: null, joinCode: null,
gameState: -1, gameState: -1,
gameOptions: {}, gameOptions: {},
players: [], players: [],
cardDeckId: null, cardDeckId: null,
socket: null, socket: null,
connected: false, connected: false,
userId: null, userId: null,
messages: [], messages: [],
sessionToken: null, sessionToken: null,
});
private socket: Socket | null = null;
constructor() {
const storedSessionIds = this.getStoredSessionIds();
if (storedSessionIds) {
console.info(`Found stored session: ${JSON.stringify(storedSessionIds)}`);
// this.connect(storedSessionIds.sessionToken, storedSessionIds.userId);
}
}
getState() {
return get(this.store);
}
startGame() {
this.socket?.emit("StartGame");
}
hasSessionData(): boolean {
const state = this.getState();
if (state.sessionToken && state.userId) return true;
const sessionIds = localStorage.getItem('currentSessionIds');
if (!sessionIds) return false;
const sessionIdsJson = JSON.parse(sessionIds);
return typeof sessionIdsJson.userId === "string" && typeof sessionIdsJson.sessionToken === "string";
}
private checkPermissionBit(permissionNumber: number, bitIndex: number): boolean {
return (permissionNumber & (1 << bitIndex)) > 0;
}
getPlayerPermissions(PlayerId?: string): PlayerPermissionObj {
if (!PlayerId) PlayerId = this.getState().userId ?? undefined;
const playerPermissionNumber: number = this.getState().players?.find((player) => player.PlayerId == PlayerId)?.Permissions ?? 0;
return {
isHost: this.checkPermissionBit(playerPermissionNumber, 0)
};
}
subscribe = this.store.subscribe;
private getStoredSessionIds(): { sessionToken: string, userId: string } | null {
if (typeof window === 'undefined') return null;
const sessionIds = localStorage.getItem('currentSessionIds');
if (!sessionIds) return null;
const sessionIdsJson = JSON.parse(sessionIds);
if (typeof sessionIdsJson.userId !== "string" || typeof sessionIdsJson.sessionToken !== "string") {
return null;
}
return { sessionToken: sessionIdsJson.sessionToken, userId: sessionIdsJson.userId };
}
private saveSessionIds(sessionToken: string, userId: string) {
if (typeof window !== 'undefined') {
localStorage.setItem('currentSessionIds', JSON.stringify({ sessionToken, userId, joinCode: this.getState().joinCode }));
}
}
private saveJoinCode() {
const sessionIds = localStorage.getItem('currentSessionIds');
if (!sessionIds) return;
const sessionIdsJson = JSON.parse(sessionIds);
localStorage.setItem('currentSessionIds', JSON.stringify({ sessionToken: sessionIdsJson.sessionToken, userId: sessionIdsJson.userId, joinCode: this.getState().joinCode }));
}
private clearSessionIds() {
if (typeof window !== 'undefined') {
const sessionIds = localStorage.getItem('currentSessionIds');
if (!sessionIds) return;
const sessionIdsJson = JSON.parse(sessionIds);
const lastSessionData = { joinCode: sessionIdsJson.joinCode };
localStorage.setItem('lastSessionIds', JSON.stringify(lastSessionData));
localStorage.removeItem('currentSessionIds');
}
}
isConnected(): boolean {
return this.socket?.connected ?? false;
}
hasRoomData(): boolean {
return get(this.store).gameState != -1;
}
getUserId(): string | undefined {
return this.getState().userId ?? undefined;
}
getUser(playerId?: string): PlayerObj | undefined {
if (!playerId) playerId = this.getUserId();
return this.getState().players.find((player) => player.PlayerId == playerId);
}
kickPlayer(playerId: string) {
if (!this.getPlayerPermissions().isHost) return;
this.socket?.emit("KickPlayer", JSON.stringify({ PlayerId: playerId }));
}
renamePlayer(playerId: string | undefined, newName: string) {
if (!playerId) playerId = this.getUserId();
if (!this.getPlayerPermissions().isHost && playerId != this.getUserId()) return;
this.socket?.emit("UpdatePlayer", JSON.stringify({ PlayerId: playerId, Username: newName }));
}
isCurrentPlayer(playerId: string): boolean {
return this.getState().userId == playerId;
}
connect(sessionToken?: string, userId?: string) {
if (!sessionToken) sessionToken = this.getState().sessionToken || undefined;
if (!userId) userId = this.getState().userId || undefined;
if (!sessionToken || !userId) {
const storedSessionIds = this.getStoredSessionIds();
if (!sessionToken) sessionToken = storedSessionIds?.sessionToken;
if (!userId) userId = storedSessionIds?.userId;
}
if (this.socket) {
console.warn(`Socket already connected! Rejecting new connection to ${sessionToken}`);
return;
}
this.socket = io({
transports: ['websocket'],
query: { sessionToken },
}); });
this.setupSocketEventHandlers(sessionToken, userId); private socket: Socket | null = null;
}
private setupSocketEventHandlers(sessionToken: string, userId: string) { constructor() {
this.socket?.on('connect', () => this.handleConnect(sessionToken, userId)); const storedSessionIds = this.getStoredSessionIds();
this.socket?.on('disconnect', this.handleDisconnect.bind(this)); if (storedSessionIds) {
this.socket?.on('Status', this.handleStatus.bind(this)); console.info(`Found stored session: ${JSON.stringify(storedSessionIds)}`);
this.socket?.on('RoomInfo', this.handleRoomInfo.bind(this)); // this.connect(storedSessionIds.sessionToken, storedSessionIds.userId);
this.socket?.on('error', this.handleError.bind(this)); }
}
private handleConnect(sessionToken: string, userId: string) {
console.info('Connected to room');
this.saveSessionIds(sessionToken, userId);
window.history.replaceState({}, "", "/Game");
this.store.update((state) => ({
...state,
socket: this.socket,
userId,
connected: true,
sessionToken,
}));
}
private handleDisconnect() {
console.info('Disconnected from server');
this.store.update((state) => ({ ...state, connected: false }));
}
private handleStatus(message: StatusInfoObj) {
console.log("Status: ", message);
if (message.IsError && message.StatusCode !== "connection_from_different_socket") {
this.leaveRoom();
} }
if (message.IsError) {
this.socket = null;
window.history.replaceState({}, "", "/");
}
this.store.update((state) => ({
...state,
messages: [...state.messages, message],
}));
}
private handleRoomInfo(message: RoomInfoObj) { getState() {
console.log("RoomInfo: ", message); return get(this.store);
this.store.update((state) => ({
...state,
roomId: message.RoomId,
joinCode: message.JoinCode,
gameState: message.GameState,
cardDeckId: message.CardDeckId,
players: message.Players,
}));
this.saveJoinCode();
this.store.update((state) => ({
...state,
messages: [...state.messages, message],
}));
}
private handleError(error: string) {
console.error('Socket error:', error);
}
sendMessage(message: string) {
if (this.socket && message.trim()) {
this.socket.emit('event', message);
} }
}
leaveRoom() { startGame() {
console.log("leave room"); this.socket?.emit("StartGame");
if (this.socket) {
this.socket.disconnect();
this.socket = null;
} }
if (this.getState().sessionToken) {
fetch(`/api/room/leave`, { hasSessionData(): boolean {
method: "POST", const state = this.getState();
body: JSON.stringify({ if (state.sessionToken && state.userId) return true;
SessionToken: this.getState().sessionToken const sessionIds = localStorage.getItem("currentSessionIds");
}), if (!sessionIds) return false;
headers: { const sessionIdsJson = JSON.parse(sessionIds);
"Content-Type": "application/json", return typeof sessionIdsJson.userId === "string" && typeof sessionIdsJson.sessionToken === "string";
}, }
});
private checkPermissionBit(permissionNumber: number, bitIndex: number): boolean {
return (permissionNumber & (1 << bitIndex)) > 0;
}
getPlayerPermissions(PlayerId?: string): PlayerPermissionObj {
if (!PlayerId) PlayerId = this.getState().userId ?? undefined;
const playerPermissionNumber: number = this.getState().players?.find((player) => player.PlayerId == PlayerId)?.Permissions ?? 0;
return {
isHost: this.checkPermissionBit(playerPermissionNumber, 0),
};
}
subscribe = this.store.subscribe;
private getStoredSessionIds(): { sessionToken: string; userId: string } | null {
if (typeof window === "undefined") return null;
const sessionIds = localStorage.getItem("currentSessionIds");
if (!sessionIds) return null;
const sessionIdsJson = JSON.parse(sessionIds);
if (typeof sessionIdsJson.userId !== "string" || typeof sessionIdsJson.sessionToken !== "string") {
return null;
}
return { sessionToken: sessionIdsJson.sessionToken, userId: sessionIdsJson.userId };
}
private saveSessionIds(sessionToken: string, userId: string) {
if (typeof window !== "undefined") {
localStorage.setItem("currentSessionIds", JSON.stringify({ sessionToken, userId, joinCode: this.getState().joinCode }));
}
}
private saveJoinCode() {
const sessionIds = localStorage.getItem("currentSessionIds");
if (!sessionIds) return;
const sessionIdsJson = JSON.parse(sessionIds);
localStorage.setItem("currentSessionIds", JSON.stringify({ sessionToken: sessionIdsJson.sessionToken, userId: sessionIdsJson.userId, joinCode: this.getState().joinCode }));
}
private clearSessionIds() {
if (typeof window !== "undefined") {
const sessionIds = localStorage.getItem("currentSessionIds");
if (!sessionIds) return;
const sessionIdsJson = JSON.parse(sessionIds);
const lastSessionData = { joinCode: sessionIdsJson.joinCode };
localStorage.setItem("lastSessionIds", JSON.stringify(lastSessionData));
localStorage.removeItem("currentSessionIds");
}
}
isConnected(): boolean {
return this.socket?.connected ?? false;
}
hasRoomData(): boolean {
return get(this.store).gameState != -1;
}
getUserId(): string | undefined {
return this.getState().userId ?? undefined;
}
getUser(playerId?: string): PlayerObj | undefined {
if (!playerId) playerId = this.getUserId();
return this.getState().players.find((player) => player.PlayerId == playerId);
}
kickPlayer(playerId: string) {
if (!this.getPlayerPermissions().isHost) return;
this.socket?.emit("KickPlayer", JSON.stringify({ PlayerId: playerId }));
}
renamePlayer(playerId: string | undefined, newName: string) {
if (!playerId) playerId = this.getUserId();
if (!this.getPlayerPermissions().isHost && playerId != this.getUserId()) return;
this.socket?.emit("UpdatePlayer", JSON.stringify({ PlayerId: playerId, Username: newName }));
}
isCurrentPlayer(playerId: string): boolean {
return this.getState().userId == playerId;
}
connect(sessionToken?: string, userId?: string) {
if (!sessionToken) sessionToken = this.getState().sessionToken || undefined;
if (!userId) userId = this.getState().userId || undefined;
if (!sessionToken || !userId) {
const storedSessionIds = this.getStoredSessionIds();
if (!sessionToken) sessionToken = storedSessionIds?.sessionToken;
if (!userId) userId = storedSessionIds?.userId;
}
if (this.socket) {
console.warn(`Socket already connected! Rejecting new connection to ${sessionToken}`);
return;
}
this.socket = io({
transports: ["websocket"],
query: { sessionToken },
});
this.setupSocketEventHandlers(sessionToken, userId);
}
private setupSocketEventHandlers(sessionToken: string, userId: string) {
this.socket?.on("connect", () => this.handleConnect(sessionToken, userId));
this.socket?.on("disconnect", this.handleDisconnect.bind(this));
this.socket?.on("Status", this.handleStatus.bind(this));
this.socket?.on("RoomInfo", this.handleRoomInfo.bind(this));
this.socket?.on("error", this.handleError.bind(this));
}
private handleConnect(sessionToken: string, userId: string) {
console.info("Connected to room");
this.saveSessionIds(sessionToken, userId);
window.history.replaceState({}, "", "/Game");
this.store.update((state) => ({
...state,
socket: this.socket,
userId,
connected: true,
sessionToken,
}));
}
private handleDisconnect() {
console.info("Disconnected from server");
this.store.update((state) => ({ ...state, connected: false }));
}
private handleStatus(message: StatusInfoObj) {
console.log("Status: ", message);
if (message.IsError && message.StatusCode !== "connection_from_different_socket") {
this.leaveRoom();
}
if (message.IsError) {
this.socket = null;
window.history.replaceState({}, "", "/");
}
this.store.update((state) => ({
...state,
messages: [...state.messages, message],
}));
}
private handleRoomInfo(message: RoomInfoObj) {
console.log("RoomInfo: ", message);
this.store.update((state) => ({
...state,
roomId: message.RoomId,
joinCode: message.JoinCode,
gameState: message.GameState,
cardDeckId: message.CardDeckId,
players: message.Players,
}));
this.saveJoinCode();
this.store.update((state) => ({
...state,
messages: [...state.messages, message],
}));
}
private handleError(error: string) {
console.error("Socket error:", error);
}
sendMessage(message: string) {
if (this.socket && message.trim()) {
this.socket.emit("event", message);
}
}
leaveRoom() {
console.log("leave room");
if (this.socket) {
this.socket.disconnect();
this.socket = null;
}
if (this.getState().sessionToken) {
fetch(`/api/room/leave`, {
method: "POST",
body: JSON.stringify({
SessionToken: this.getState().sessionToken,
}),
headers: {
"Content-Type": "application/json",
},
});
}
this.clearSessionIds();
this.store.set({
roomId: null,
joinCode: null,
gameState: -1,
gameOptions: {},
players: [],
cardDeckId: null,
socket: null,
connected: false,
userId: null,
messages: [],
sessionToken: null,
});
window.history.replaceState({}, "", "/");
} }
this.clearSessionIds();
this.store.set({
roomId: null,
joinCode: null,
gameState: -1,
gameOptions: {},
players: [],
cardDeckId: null,
socket: null,
connected: false,
userId: null,
messages: [],
sessionToken: null,
});
window.history.replaceState({}, "", "/");
}
} }
export const sessionStore = new SessionManager(); export const sessionStore = new SessionManager();

View File

@ -1,6 +1,6 @@
import { writable } from 'svelte/store'; import { writable } from "svelte/store";
const getSystemTheme = () => window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"; const getSystemTheme = () => (window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");
const storedTheme = localStorage.getItem("theme") as Theme | null; const storedTheme = localStorage.getItem("theme") as Theme | null;
const initialTheme: Theme = storedTheme === "dark" || storedTheme === "light" ? storedTheme : "system"; const initialTheme: Theme = storedTheme === "dark" || storedTheme === "light" ? storedTheme : "system";
@ -10,7 +10,7 @@ export const theme = writable<Theme>(initialTheme);
const applyTheme = (value: Theme) => { const applyTheme = (value: Theme) => {
const resolvedTheme = value === "system" ? getSystemTheme() : value; const resolvedTheme = value === "system" ? getSystemTheme() : value;
document.documentElement.classList.toggle("dark", resolvedTheme === "dark"); document.documentElement.classList.toggle("dark", resolvedTheme === "dark");
document.documentElement.setAttribute("data-theme", resolvedTheme); document.documentElement.setAttribute("data-theme", resolvedTheme);
document.body.classList.toggle("dark-theme", resolvedTheme === "dark"); document.body.classList.toggle("dark-theme", resolvedTheme === "dark");
@ -24,7 +24,7 @@ theme.subscribe(applyTheme);
// Watch for system theme changes when "system" mode is enabled // Watch for system theme changes when "system" mode is enabled
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)"); const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
mediaQuery.addEventListener("change", () => { mediaQuery.addEventListener("change", () => {
theme.update(current => { theme.update((current) => {
if (current === "system") applyTheme("system"); if (current === "system") applyTheme("system");
return current; return current;
}); });
@ -35,7 +35,7 @@ export const setTheme = (value: Theme) => {
}; };
export const toggleTheme = () => { export const toggleTheme = () => {
theme.update(current => { theme.update((current) => {
if (current === "dark") return "light"; if (current === "dark") return "light";
if (current === "light") return "system"; if (current === "light") return "system";
return "dark"; return "dark";

View File

@ -1,7 +1,7 @@
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
export default { export default {
// Consult https://svelte.dev/docs#compile-time-svelte-preprocess // Consult https://svelte.dev/docs#compile-time-svelte-preprocess
// for more information about preprocessors // for more information about preprocessors
preprocess: vitePreprocess(), preprocess: vitePreprocess(),
} };

View File

@ -1,21 +1,21 @@
{ {
"extends": "@tsconfig/svelte/tsconfig.json", "extends": "@tsconfig/svelte/tsconfig.json",
"compilerOptions": { "compilerOptions": {
"target": "ESNext", "target": "ESNext",
"useDefineForClassFields": true, "useDefineForClassFields": true,
"module": "ESNext", "module": "ESNext",
"resolveJsonModule": true, "resolveJsonModule": true,
/** /**
* Typecheck JS in `.svelte` and `.js` files by default. * Typecheck JS in `.svelte` and `.js` files by default.
* Disable checkJs if you'd like to use dynamic types in JS. * Disable checkJs if you'd like to use dynamic types in JS.
* Note that setting allowJs false does not prevent the use * Note that setting allowJs false does not prevent the use
* of JS in `.svelte` files. * of JS in `.svelte` files.
*/ */
"allowJs": true, "allowJs": true,
"checkJs": true, "checkJs": true,
"isolatedModules": true, "isolatedModules": true,
"moduleDetection": "force" "moduleDetection": "force"
}, },
"include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"],
"exclude": [".routify"] "exclude": [".routify"]
} }

View File

@ -1,7 +1,4 @@
{ {
"files": [], "files": [],
"references": [ "references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }]
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
} }

View File

@ -1,24 +1,24 @@
{ {
"compilerOptions": { "compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2022", "target": "ES2022",
"lib": ["ES2023"], "lib": ["ES2023"],
"module": "ESNext", "module": "ESNext",
"skipLibCheck": true, "skipLibCheck": true,
/* Bundler mode */ /* Bundler mode */
"moduleResolution": "bundler", "moduleResolution": "bundler",
"allowImportingTsExtensions": true, "allowImportingTsExtensions": true,
"isolatedModules": true, "isolatedModules": true,
"moduleDetection": "force", "moduleDetection": "force",
"noEmit": true, "noEmit": true,
/* Linting */ /* Linting */
"strict": true, "strict": true,
"noUnusedLocals": true, "noUnusedLocals": true,
"noUnusedParameters": true, "noUnusedParameters": true,
"noFallthroughCasesInSwitch": true, "noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true "noUncheckedSideEffectImports": true
}, },
"include": ["vite.config.ts"] "include": ["vite.config.ts"]
} }

View File

@ -1,26 +1,28 @@
import { defineConfig } from 'vite' import { defineConfig } from "vite";
import { svelte } from '@sveltejs/vite-plugin-svelte' import { svelte } from "@sveltejs/vite-plugin-svelte";
import routify from '@roxi/routify/vite-plugin' import routify from "@roxi/routify/vite-plugin";
import tailwindcss from '@tailwindcss/vite' import tailwindcss from "@tailwindcss/vite";
export default defineConfig({ export default defineConfig({
plugins: [ plugins: [
routify({/* config */ }), routify({
tailwindcss(), /* config */
svelte() }),
], tailwindcss(),
server: { svelte(),
host: true, ],
proxy: { server: {
'/api': { host: true,
target: 'http://10.10.39.145:3000', proxy: {
changeOrigin: true, "/api": {
}, target: "http://10.10.39.145:3000",
'/socket.io': { changeOrigin: true,
target: 'http://10.10.39.145:3000', },
ws: true, "/socket.io": {
changeOrigin: true, target: "http://10.10.39.145:3000",
} ws: true,
} changeOrigin: true,
} },
}) },
},
});