Skip to content

Commit

Permalink
Upgrade in loading system
Browse files Browse the repository at this point in the history
  • Loading branch information
ZonianMidian committed Oct 30, 2024
1 parent efcb11f commit ffcd20a
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 64 deletions.
12 changes: 2 additions & 10 deletions src/components/Spinner.svelte
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
<script lang="ts">
export let isDiv: Boolean;
</script>

<div class="loading" class:loading-div={isDiv}>
<div class="loading">
<div class="spinner"></div>
</div>

Expand All @@ -29,10 +25,6 @@
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.loading-div {
height: 100% !important;
height: 70vh;
}
</style>
5 changes: 5 additions & 0 deletions src/lib/stores/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import type { CountryData, Category } from '$types';
import { writable } from 'svelte/store';

export const countriesStore = writable<Record<string, CountryData>>({});
export const categoriesStore = writable<Record<string, Category>>({});
12 changes: 12 additions & 0 deletions src/lib/types/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export type CountryData = {
name: { [key: string]: string };
alt: string[];
};

export type Category = {
[key: string]: string[];
};

export type LanguageData = {
[key: string]: string;
};
13 changes: 13 additions & 0 deletions src/lib/utils/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
import type { CountryData } from '$types';

export async function loadCountryData(countryCode: string): Promise<CountryData | null> {
try {
const response = await fetch(`/api/names/${countryCode}`);
if (!response.ok) throw new Error('Failed to load country data');
return await response.json();
} catch (error) {
console.error(`Error loading data for ${countryCode}:`, error);
return null;
}
}

function normalizeText(text: string): string {
return text
.normalize('NFD')
Expand Down
25 changes: 25 additions & 0 deletions src/routes/+page.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { Category, CountryData } from '$types';
import type { PageServerLoad } from './$types';

export const load: PageServerLoad = async () => {
const categoriesFiles = import.meta.glob<{ default: Category }>('$data/categories/*.json');
const categories: Record<string, Category> = {};

for (const path in categoriesFiles) {
const module = await categoriesFiles[path]();
const categoryName = path.split('/').pop()?.replace('.json', '') || '';
categories[categoryName] = module.default;
}

const countriesFiles = import.meta.glob<{ default: CountryData }>('$data/names/*.json');
const allFlags = [];
for (const path in countriesFiles) {
const countryCode = path.split('/').pop()?.replace('.json', '') || '';
allFlags.push(countryCode);
}

return {
categories,
allFlags
};
};
108 changes: 54 additions & 54 deletions src/routes/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,31 +1,24 @@
<script lang="ts">
import { checkMatch, formatTime, loadCountryData } from '$utils/utils';
import { countriesStore, categoriesStore } from '$stores/store';
import { getLocaleFromNavigator, t } from 'svelte-i18n';
import { checkMatch, formatTime } from '$utils/utils';
import { effectSounds } from '$utils/soundEffects';
import Spinner from '$components/Spinner.svelte';
import type { LanguageData } from '$types';
import { onMount } from 'svelte';
import '../app.css';
type LanguageData = {
[key: string]: string;
};
export let data;
const allFlags = data.allFlags;
type CountryData = {
name: { [key: string]: string };
alt: string[];
};
type Category = {
[key: string]: string[];
};
$: {
$categoriesStore = data.categories;
}
let categories: Record<string, Category> = {};
let countries: Record<string, CountryData> = {};
let timer: ReturnType<typeof setInterval> | null = null;
let actualTime: number = 0;
let timeLimit: number = 60;
let guessedCountries: string[] = [];
let totalCountries: number = 0;
let languageData: LanguageData = {};
let currentLang: string = 'en';
let gameStarted: boolean = false;
Expand All @@ -44,26 +37,6 @@
let showAnswersAtEnd: boolean = false;
let playSoundEffects: boolean = true;
async function loadCategoriesAndCountries() {
const categoriesFiles = import.meta.glob<{ default: Category }>('$data/categories/*.json');
for (const path in categoriesFiles) {
const module = await categoriesFiles[path]();
const categoryName = path.split('/').pop()?.replace('.json', '') || '';
categories[categoryName] = module.default;
}
const countriesFiles = import.meta.glob<{ default: CountryData }>('$data/names/*.json');
for (const path in countriesFiles) {
const module = await countriesFiles[path]();
const countryCode = path.split('/').pop()?.replace('.json', '') || '';
countries[countryCode] = module.default;
}
totalCountries = Object.keys(countries).length;
shuffleCountries();
isLoading = false;
}
async function loadLanguage() {
currentLang = getLocaleFromNavigator() ?? 'en';
const langFile = await import(`$data/languages/${currentLang}.json`);
Expand All @@ -87,9 +60,12 @@
}
onMount(() => {
loadCategoriesAndCountries();
effectSounds.preload();
loadLanguage();
(async () => {
effectSounds.preload();
await loadLanguage();
shuffleCountries();
isLoading = false;
})();
window.addEventListener('keydown', handleKeyDown);
Expand All @@ -101,8 +77,8 @@
function shuffleCountries() {
filteredCountries =
selectedCategory === 'All'
? Object.keys(countries)
: Object.values(categories).flatMap((cat) => cat[selectedCategory] || []);
? allFlags
: Object.values($categoriesStore).flatMap((cat) => cat[selectedCategory] || []);
filteredCountries = filteredCountries.sort(() => Math.random() - 0.5);
}
Expand Down Expand Up @@ -170,10 +146,8 @@
if (gameStarted) {
endGame();
clearAllInputs();
shuffleCountries();
startGame();
} else {
gameStarted = false;
Expand Down Expand Up @@ -210,15 +184,21 @@
});
}
function revealAllCountries() {
async function revealAllCountries() {
const inputs = document.querySelectorAll('.country-input') as NodeListOf<HTMLInputElement>;
inputs.forEach((input) => {
for (const input of inputs) {
const countryCode = input.getAttribute('data-country-code');
if (countryCode && countries[countryCode]) {
input.value = countries[countryCode].name[currentLang] || '';
if (countryCode && !$countriesStore[countryCode]) {
const countryData = await loadCountryData(countryCode);
if (countryData) {
$countriesStore = { ...$countriesStore, [countryCode]: countryData };
}
}
if (countryCode && $countriesStore[countryCode]) {
input.value = $countriesStore[countryCode].name[currentLang] || '';
input.disabled = true;
}
});
}
}
function showAllPercentages() {
Expand Down Expand Up @@ -250,11 +230,22 @@
});
}
function checkAnswer(event: KeyboardEvent, countryCode: string) {
async function checkAnswer(event: KeyboardEvent, countryCode: string) {
if ((event.key === 'Enter' || event.key === 'Tab') && gameStarted) {
const inputElement = event.target as HTMLInputElement;
const inputValue = inputElement.value;
const country = countries[countryCode];
if (!$countriesStore[countryCode]) {
const countryData = await loadCountryData(countryCode);
if (countryData) {
$countriesStore = { ...$countriesStore, [countryCode]: countryData };
} else {
console.error(`Failed to load data for ${countryCode}`);
return;
}
}
const country = $countriesStore[countryCode];
if (country && inputValue) {
const result = checkMatch(country, currentLang, inputValue);
Expand Down Expand Up @@ -337,7 +328,7 @@

<div>
{#if isLoading}
<Spinner isDiv={false} />
<Spinner />
{:else}
<div class="game-buttons">
<button id="start-button" on:click={startGame} disabled={!isStartEnabled}
Expand All @@ -353,14 +344,13 @@
bind:value={selectedCategory}
on:change={handleCategoryChange}
class="game-control">
<option value="All"
>{$t('categories.all')} [{Object.keys(countries).length}]</option>
{#each Object.entries(categories) as [categoryGroup, subcategories]}
<option value="All">{$t('categories.all')} [{allFlags.length}]</option>
{#each Object.entries($categoriesStore) as [categoryGroup, subcategories]}
<optgroup label={$t(`categories.${categoryGroup}.name`)}>
{#each Object.keys(subcategories) as subcategory}
<option value={subcategory}
>{$t(`categories.${categoryGroup}.${subcategory}`)} [{Object.values(
categories
$categoriesStore
).flatMap((cat) => cat[subcategory] || []).length}]</option>
{/each}
</optgroup>
Expand Down Expand Up @@ -439,6 +429,16 @@
</div>
</div>

<div class="info-card timer-card">
<div class="timer">
{#if mode === 'Timer' && !gameStarted}
{formatTime(timeLimit)}
{:else}
{formatTime(actualTime)}
{/if}
</div>
</div>

<div class="info-card score-card">
<div class="game-info">
<strong>{guessedCountries.length}/{filteredCountries.length}</strong>
Expand Down
11 changes: 11 additions & 0 deletions src/routes/api/languages/[langCode]/+server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';

export const GET: RequestHandler = async ({ params }) => {
try {
const countryData = await import(`$data/languages/${params.langCode}.json`);
return json(countryData.default);
} catch (error) {
return new Response('Language not found', { status: 404 });
}
};
11 changes: 11 additions & 0 deletions src/routes/api/names/[countryCode]/+server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';

export const GET: RequestHandler = async ({ params }) => {
try {
const countryData = await import(`$data/names/${params.countryCode}.json`);
return json(countryData.default);
} catch (error) {
return new Response('Names not found', { status: 404 });
}
};
2 changes: 2 additions & 0 deletions svelte.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ const config = {
}),
alias: {
$data: resolve('./src/lib/data'),
$types: resolve('./src/lib/types'),
$utils: resolve('./src/lib/utils'),
$locales: resolve('./src/locales'),
$stores: resolve('./src/lib/stores'),
$components: resolve('./src/components')
}
}
Expand Down

0 comments on commit ffcd20a

Please sign in to comment.