Skip to content

Commit 7b9417a

Browse files
committed
Minor improvements
1 parent 9b7e1d4 commit 7b9417a

File tree

12 files changed

+148
-70
lines changed

12 files changed

+148
-70
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# GaliGuessr
22

3-
React geography quiz 🌍 Originally designed for [Galicia](https://en.wikipedia.org/wiki/Galicia_(Spain)) but customizable for any region in the world. Try it for yourself at https://minimuino.github.io/galiguessr/
3+
React geography quiz generator 🌍 Originally designed for [Galicia](https://en.wikipedia.org/wiki/Galicia_(Spain)) but customizable for any region in the world. Try it for yourself at https://minimuino.github.io/galiguessr/
44

55
## Features
66

@@ -33,5 +33,6 @@ You can also make your own geography quiz by following these steps:
3333

3434
[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
3535

36-
Every file in this project is licensed under the [GNU General Public License, version 3](https://www.gnu.org/licenses/gpl-3.0), Copyright (C) 2025 Carlos Pérez Ramil, except for those files in /public/fonts which have the following license:
36+
Every file in this project is licensed under the [GNU General Public License, version 3](https://www.gnu.org/licenses/gpl-3.0), Copyright (C) 2025 Carlos Pérez Ramil, except for the following files in the `/public` folder which have a different copyright owner:
3737
- /public/fonts/GeistMono-Variable.woff2 - SIL Open Font License, Version 1.1. This license is available with a FAQ at https://scripts.sil.org/OFL
38+
- /public/github-mark.svg - Copyright (c) 2025 GitHub, Inc. https://github.com/logos

public/email.svg

Lines changed: 22 additions & 0 deletions
Loading

src/App.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,15 +162,15 @@ export default function Home() {
162162
>
163163
<img
164164
aria-hidden
165-
src="./globe.svg"
165+
src="./email.svg"
166166
alt="Error icon"
167-
width={16}
167+
width={18}
168168
height={16}
169169
/>
170170
{t("contact")}
171171
</a>
172172
<a
173-
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
173+
className="flex items-center gap-2 hover:underline hover:underline-offset-4 cursor-pointer"
174174
onClick={() => modalRef.current?.showModal()}
175175
>
176176
<img

src/assets/locales/en/translation.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
},
2626
"gameovermodal": {
2727
"totalDistance": "Total accumulated error:",
28+
"distanceAverage": "{{avg}} km on average",
2829
"finalScore": "Your final score:",
2930
"share": "Share",
3031
"copiedToClipboard": "Link copied to clipboard",

src/assets/locales/gl/translation.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
},
2626
"gameovermodal": {
2727
"totalDistance": "Erro acumulado total:",
28+
"distanceAverage": "{{avg}} km de media",
2829
"finalScore": "A túa puntuación:",
2930
"share": "Compartir en redes",
3031
"copiedToClipboard": "Enlace copiado ao portapapeis",

src/components/CityMapQuiz.tsx

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -95,16 +95,19 @@ export default function CityMapQuiz({ data, datasetName, onResetGame }: Props) {
9595
>
9696
<AttributionControl position="top-right" compact />
9797
</MaplibreMap>
98-
<div className="absolute bottom-0 sm:bottom-[15%] left-50 sm:left-[10%] pointer-events-none sm:pointer-events-auto overflow-clip sm:overflow-visible py-3 pb-[calc(env(safe-area-inset-bottom)+4px)]">
99-
<QuestionHistory
100-
entries={questionHistory}
101-
/>
102-
<TextInput
103-
onEnterText={handleTextInput}
104-
/>
105-
</div>
98+
{featureIds.length > 0 && (
99+
<div className="absolute bottom-0 sm:bottom-[15%] left-50 sm:left-[10%] pointer-events-none sm:pointer-events-auto overflow-clip sm:overflow-visible py-3 pb-[calc(env(safe-area-inset-bottom)+4px)]">
100+
<QuestionHistory
101+
entries={questionHistory}
102+
/>
103+
<TextInput
104+
onEnterText={handleTextInput}
105+
/>
106+
</div>
107+
)}
106108
<GameOverModal
107109
score={rightGuessFeatureIds.length}
110+
numberOfQuestions={data.features.length}
108111
datasetName={datasetName}
109112
modeName={Mode.CityMap}
110113
playAgainCallback={onResetGame}

src/components/CreditsModal.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ interface Props {
1515
export default function CreditsModal({ ref }: Props) {
1616
const { t } = useTranslation();
1717

18+
const closeModal = () => {
19+
ref.current?.close();
20+
};
21+
1822
return (
1923
<dialog
2024
className="overflow-visible backdrop:bg-black/85 bg-transparent"
@@ -44,6 +48,12 @@ export default function CreditsModal({ ref }: Props) {
4448
>
4549
{t("back")}
4650
</button>
51+
<button
52+
className="close-button"
53+
onClick={closeModal}
54+
>
55+
X
56+
</button>
4757
</div>
4858
</dialog >
4959
);

src/components/GameOverModal.tsx

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,37 +12,44 @@ import { Link } from "react-router";
1212
interface Props {
1313
score?: number;
1414
totalDistanceKm?: number;
15+
numberOfQuestions: number;
1516
datasetName?: string;
1617
modeName?: string;
1718
ref: RefObject<HTMLDialogElement | null>;
1819
playAgainCallback: () => void;
1920
};
2021

21-
export default function GameOverModal({ score, totalDistanceKm, datasetName, modeName, ref, playAgainCallback }: Props) {
22+
export default function GameOverModal({ score, totalDistanceKm, numberOfQuestions, datasetName, modeName, ref, playAgainCallback }: Props) {
2223
const { t } = useTranslation();
2324
const scoreLabel = (totalDistanceKm != null) ? (
2425
<>
2526
<p>
2627
{t("gameovermodal.totalDistance")}
2728
</p>
28-
<label className="text-2xl sm:text-6xl text-[var(--custom-blue)]">
29+
<label className="text-5xl sm:text-6xl text-[var(--custom-blue)]">
2930
{totalDistanceKm.toFixed(2) + " km"}
3031
</label>
32+
<label className="font-mono">
33+
{t("gameovermodal.distanceAverage", { avg: (totalDistanceKm / numberOfQuestions).toFixed(2) })}
34+
</label>
3135
</>)
3236
: (
3337
<>
3438
<p>
3539
{t("gameovermodal.finalScore")}
3640
</p>
37-
<label className="text-2xl sm:text-6xl text-[var(--custom-blue)]">
38-
{score}
41+
<label className="text-5xl sm:text-6xl text-[var(--custom-blue)]">
42+
{`${score} / ${numberOfQuestions}`}
43+
</label>
44+
<label className="font-mono">
45+
{((score || 0) / numberOfQuestions * 100).toFixed(0) + "%"}
3946
</label>
4047
</>
4148
);
4249

4350
const handleShare = async () => {
4451
try {
45-
const scoreText = (totalDistanceKm != null) ? `${totalDistanceKm.toFixed(2)} km` : `${score}`;
52+
const scoreText = (totalDistanceKm != null) ? `${totalDistanceKm.toFixed(2)} km` : `${score} / ${numberOfQuestions}`;
4653
if (navigator.share) {
4754
await navigator.share({
4855
text: `GaliGuessr - ${datasetName} - ${t("modes." + modeName)}: ${scoreText}`,
@@ -57,41 +64,53 @@ export default function GameOverModal({ score, totalDistanceKm, datasetName, mod
5764
}
5865
};
5966

67+
const closeModal = () => {
68+
ref.current?.close();
69+
};
70+
6071
return (
6172
<dialog
6273
className="overflow-visible backdrop:bg-black/85 bg-transparent"
6374
ref={ref}
6475
>
65-
<div className="rounded-xl overflow-hidden bg-white p-8 flex flex-col gap-8 items-center">
76+
<div className="rounded-xl bg-white p-8 py-12 flex flex-col gap-8 items-center">
6677
<img
6778
src="./logo.svg"
6879
alt="Galiguessr logo"
6980
width={280}
7081
height={56}
7182
/>
72-
<p className="text-center font-[family-name:var(--font-geist-mono)]">
83+
<p className="text-center">
7384
{datasetName + " - " + t("modes." + modeName)}
7485
</p>
7586
{scoreLabel}
87+
<div className="flex flex-col gap-6 items-center">
88+
<button
89+
className="basic-button"
90+
// eslint-disable-next-line @typescript-eslint/no-misused-promises
91+
onClick={handleShare}
92+
>
93+
{t("gameovermodal.share")}
94+
</button>
95+
<button
96+
className="basic-button"
97+
onClick={playAgainCallback}
98+
>
99+
{t("gameovermodal.tryAgain")}
100+
</button>
101+
<Link
102+
className="basic-button"
103+
to="/"
104+
>
105+
{t("gameovermodal.backToMenu")}
106+
</Link>
107+
</div>
76108
<button
77-
className="basic-button"
78-
// eslint-disable-next-line @typescript-eslint/no-misused-promises
79-
onClick={handleShare}
109+
className="close-button"
110+
onClick={closeModal}
80111
>
81-
{t("gameovermodal.share")}
112+
X
82113
</button>
83-
<button
84-
className="basic-button"
85-
onClick={playAgainCallback}
86-
>
87-
{t("gameovermodal.tryAgain")}
88-
</button>
89-
<Link
90-
className="basic-button"
91-
to="/"
92-
>
93-
{t("gameovermodal.backToMenu")}
94-
</Link>
95114
</div>
96115
</dialog>
97116
);

src/components/GuessLocationQuiz.tsx

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export default function GuessLocationQuiz({ data, datasetName, onResetGame }: Pr
5353
const { t } = useTranslation();
5454

5555
const handleMouseClick = (event: MapLayerMouseEvent) => {
56-
if (!userGuess) {
56+
if (!userGuess && features.length > 0) {
5757
setUserGuess(event.lngLat);
5858
}
5959
};
@@ -134,16 +134,18 @@ export default function GuessLocationQuiz({ data, datasetName, onResetGame }: Pr
134134
</>
135135
)}
136136
</Map>
137-
<div className="absolute bottom-[85%] sm:bottom-[15%] left-50 sm:left-[10%]">
138-
<QuestionLabel
139-
textToDisplay={features[features.length - 1]?.properties?.name as string}
140-
disabled={userGuess != null}
141-
/>
142-
<StatusLabel
143-
current={data.features.length - features.length + 1}
144-
total={data.features.length}
145-
/>
146-
</div>
137+
{features.length > 0 && (
138+
<div className="absolute bottom-[85%] sm:bottom-[15%] left-50 sm:left-[10%]">
139+
<QuestionLabel
140+
textToDisplay={features[features.length - 1]?.properties?.name as string}
141+
disabled={userGuess != null}
142+
/>
143+
<StatusLabel
144+
current={data.features.length - features.length + 1}
145+
total={data.features.length}
146+
/>
147+
</div>
148+
)}
147149
{userGuess && (
148150
<div className="absolute bottom-[6%] sm:bottom-[10%] flex flex-col items-center gap-2 text-2xl pointer-events-none">
149151
<DistanceLabel distance={currentDistanceKm} />
@@ -158,6 +160,7 @@ export default function GuessLocationQuiz({ data, datasetName, onResetGame }: Pr
158160
)}
159161
<GameOverModal
160162
totalDistanceKm={totalDistanceKm}
163+
numberOfQuestions={data.features.length}
161164
datasetName={datasetName}
162165
modeName={Mode.GuessLocation}
163166
playAgainCallback={onResetGame}

src/components/StandardQuiz.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export default function StandardQuiz({ data, mode, datasetName, onResetGame }: P
8484
onClick={(mode === Mode.PointAndClick) ? handleMouseClick : undefined}
8585
highlightedFeatureId={(mode === Mode.WriteName) ? featureIds[featureIds.length - 1] : undefined}
8686
/>
87-
{mode === Mode.PointAndClick && (
87+
{mode === Mode.PointAndClick && featureIds.length > 0 && (
8888
<div className="absolute bottom-[84%] sm:bottom-[15%] left-50 sm:left-[10%]">
8989
<QuestionLabel
9090
textToDisplay={data.features.find(feature => feature.id === featureIds[featureIds.length - 1])?.properties?.name as string}
@@ -95,7 +95,7 @@ export default function StandardQuiz({ data, mode, datasetName, onResetGame }: P
9595
/>
9696
</div>
9797
)}
98-
{mode === Mode.WriteName && (
98+
{mode === Mode.WriteName && featureIds.length > 0 && (
9999
<div className="absolute bottom-0 sm:bottom-[15%] left-50 sm:left-[10%] pointer-events-none sm:pointer-events-auto overflow-clip sm:overflow-visible py-3 pb-[calc(env(safe-area-inset-bottom)+4px)]">
100100
<QuestionHistory
101101
entries={questionHistory}
@@ -107,6 +107,7 @@ export default function StandardQuiz({ data, mode, datasetName, onResetGame }: P
107107
)}
108108
<GameOverModal
109109
score={rightGuessFeatureIds.length}
110+
numberOfQuestions={data.features.length}
110111
datasetName={datasetName}
111112
modeName={mode}
112113
playAgainCallback={onResetGame}

0 commit comments

Comments
 (0)