Skip to content

Commit

Permalink
Merge branch 'release/v0.4.4'
Browse files Browse the repository at this point in the history
  • Loading branch information
yui10 committed Sep 4, 2024
2 parents 9711ecc + 3243bff commit 2811555
Show file tree
Hide file tree
Showing 11 changed files with 652 additions and 612 deletions.
4 changes: 2 additions & 2 deletions next.config.mjs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
images:{
images: {
dangerouslyAllowSVG: true,
remotePatterns:[
remotePatterns: [
{
protocol: 'https',
hostname: 'cdn.simpleicons.org',
Expand Down
915 changes: 412 additions & 503 deletions package-lock.json

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "icons-karuta",
"version": "0.4.3",
"version": "0.4.4",
"private": true,
"scripts": {
"dev": "next dev",
Expand All @@ -10,11 +10,11 @@
"format": "prettier --write --ignore-path .gitignore './**/*.{js,jsx,ts,tsx,json,css}' && next lint --fix"
},
"dependencies": {
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"@icons-pack/react-simple-icons": "^9.6.0",
"@mui/icons-material": "^5.15.20",
"@mui/material": "^5.15.20",
"@emotion/react": "^11.13.0",
"@emotion/styled": "^11.13.0",
"@icons-pack/react-simple-icons": "^10.0.0",
"@mui/icons-material": "^6",
"@mui/material": "^6",
"@next/third-parties": "^14.2.4",
"@vercel/analytics": "^1.3.1",
"i18next": "^23.11.5",
Expand All @@ -25,7 +25,7 @@
"react": "^18",
"react-dom": "^18",
"react-i18next": "^14.1.2",
"simple-icons": "^13.1.0",
"simple-icons": "^13.8.0",
"string-format": "^2.0.0"
},
"devDependencies": {
Expand Down
24 changes: 15 additions & 9 deletions src/app/[lang]/games/infinite/page.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,35 @@
'use client';
import GameUI from '@/components/game/GameUI';
import useGameService from '@/hooks/useGameService';
import useIcons from '@/hooks/useIcons';
import useIconsService from '@/hooks/useIconsService';
import { useTranslation } from '@/i18n/client';
import { Button, Typography } from '@mui/material';
import { useEffect, useState } from 'react';
import { useEffect } from 'react';
import styles from '../../page.module.css';

const Infinite = ({ params }: { params: { lang: string } }) => {
const lang = params.lang;
const { t } = useTranslation(lang);

const { loaded, icons } = useIcons();
const { correctIcon, restIconList, init } = useIconsService();
const [isTimerRunning, setIsTimerRunning] = useState<boolean>(true);
const { correctIcon, restIconList, initializeIcon } = useIconsService();
const { gameData, initializeGame, onIconClick, NextIcon } = useGameService({
correctIcon,
restIconList,
});

useEffect(() => {
if (loaded) {
init(icons, 12);
initializeIcon(icons, 12);
initializeGame();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [loaded]);

const onNextClick = () => {
init(icons, 12);
NextIcon();
initializeIcon(icons, 12);
};

return (
Expand All @@ -34,10 +41,9 @@ const Infinite = ({ params }: { params: { lang: string } }) => {
<GameUI
correctIcon={correctIcon}
iconList={restIconList}
score={Infinity}
onNextGame={onNextClick}
isTimerRunning={isTimerRunning}
setIsTimerRunning={setIsTimerRunning}
gameData={gameData}
iconClick={onIconClick}
onNext={onNextClick}
/>
<br />
<Button
Expand Down
49 changes: 21 additions & 28 deletions src/app/[lang]/games/ncard/page.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
'use client';
import XShareButton from '@/components/XShareButton';
import GameUI from '@/components/game/GameUI';
import useGameService from '@/hooks/useGameService';
import useIcons from '@/hooks/useIcons';
import useIconsService from '@/hooks/useIconsService';
import { useTranslation } from '@/i18n/client';
import { Box, Button, Stack, Typography } from '@mui/material';
import { useEffect, useState } from 'react';
import { useEffect } from 'react';
import Format from 'string-format';
import styles from '../../page.module.css';

const numList = [12, 24, 36];
type GameState = 'ready' | 'playing' | 'paused' | 'gameover';

const Random = ({
params,
Expand All @@ -19,13 +19,13 @@ const Random = ({
params: { num: string; lang: string };
searchParams: { [key: string]: string };
}) => {
const [totalAttention, setTotalAttention] = useState<number>(0);
const [gameState, setGameState] = useState<GameState>('ready');
const [score, setScore] = useState<number>(0);
const [isTimerRunning, setIsTimerRunning] = useState<boolean>(true);

const { loaded, icons } = useIcons();
const { correctIcon, restIconList, init, onNext } = useIconsService();
const { correctIcon, restIconList, initializeIcon, onNext } = useIconsService();

const { gameData, initializeGame, onIconClick, NextIcon } = useGameService({
correctIcon,
restIconList,
});

const lang = params.lang;
const { t } = useTranslation(lang);
Expand All @@ -35,30 +35,24 @@ const Random = ({
}
useEffect(() => {
if (loaded) {
init(icons, num);
setGameState('playing');
initializeIcon(icons, num);
initializeGame();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [loaded]);

const onNextClick = (attention: number = 0) => {
const _totalAttention = totalAttention + attention;
const _score = score + 5 - Math.min(4, attention);
setScore(_score);
// setScore(score + 5 - Math.min(5, Math.max(attention - Math.floor(iconList.length / 4), 0)));
setTotalAttention(_totalAttention);

const onNextClick = () => {
onNext();
NextIcon();
};

useEffect(() => {
if (restIconList.length === 0 && gameState === 'playing') {
setIsTimerRunning(false);
setGameState('gameover');
if (gameData.gameState === 'gameover') {
const { totalAttention, score } = gameData;
alert(Format(t('game:finish-message'), totalAttention.toString(), score.toString()));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [restIconList.length]);
}, [gameData.gameState]);

return (
<main className={styles.main}>
Expand All @@ -69,12 +63,11 @@ const Random = ({
<GameUI
correctIcon={correctIcon}
iconList={restIconList}
score={score}
onNextGame={onNextClick}
isTimerRunning={isTimerRunning}
setIsTimerRunning={setIsTimerRunning}
gameData={gameData}
iconClick={onIconClick}
onNext={onNextClick}
/>
{gameState === 'gameover' && (
{gameData.gameState === 'gameover' && (
<Box marginTop={4}>
{/** SNS share */}
<Stack spacing={2} direction="row">
Expand All @@ -85,8 +78,8 @@ const Random = ({
message={Format(
t('game:tweet'),
num.toString(),
totalAttention.toString(),
score.toString()
gameData.totalAttention.toString(),
gameData.score.toString()
)}
hashtags={'icons_karuta'}
url={window.location.href}
Expand Down
8 changes: 7 additions & 1 deletion src/components/XShareButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@ const XShareButton = (props: XShareButtonProps) => {
passHref
target="_blank"
>
<Image src="https://cdn.simpleicons.org/x" alt="x" width={32} height={32} />
<Image
unoptimized
src="https://cdn.simpleicons.org/x/black"
alt="x"
width={32}
height={32}
/>
</Link>
);
};
Expand Down
98 changes: 38 additions & 60 deletions src/components/game/GameUI.tsx
Original file line number Diff line number Diff line change
@@ -1,52 +1,49 @@
import { createIconsUrl } from '@/utils/iconUtil';
import { Box, Button, Grid, Paper, Typography } from '@mui/material';
import { useState } from 'react';
'use client';
import { Box, Button, Grid, Typography } from '@mui/material';
import { useEffect, useState } from 'react';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
import { IconData } from 'simple-icons/sdk';

import StopwatchDisplay from '@/components/StopwatchDisplay';
import { useLanguage, useTranslation } from '@/i18n/client';
import { GameData } from '@/types/gameState';
import Format from 'string-format';
import IconGrid from './IconGrid';

type Props = {
correctIcon: IconData | undefined;
iconList: IconData[];
score: number;
onNextGame: (attention: number) => void;
isTimerRunning: boolean;
setIsTimerRunning: (isRunning: boolean) => void;
gameData: GameData;
iconClick: (icon: IconData) => void;
onNext(): void;
};

const GameUI = (props: Props) => {
const { language } = useLanguage();
const { t } = useTranslation(language);
const [isTimerRunning, setIsTimerRunning] = useState<boolean>(true);

const [attention, setAttention] = useState<number>(0);
const [totalAttention, setTotalAttention] = useState<number>(0);
const [correct, setCorrect] = useState<boolean>(false);
const { correctIcon, iconList, gameData, onNext, iconClick } = props;

const { correctIcon, iconList, score, onNextGame, isTimerRunning, setIsTimerRunning } = props;

const iconClick = (icon: IconData) => {
if (correct) {
useEffect(() => {
if (gameData.gameState !== 'playing') {
return;
}

if (icon?.title == correctIcon?.title) {
if (gameData.correct === 'correct') {
alert(t('game:correct'));
setCorrect(true);
} else {
alert(Format(t('game:incorrect'), correctIcon?.title ?? '', icon?.title));
setAttention(attention + 1);
setTotalAttention(totalAttention + 1);
} else if (gameData.correct === 'incorrect') {
const correctIcon_name = correctIcon?.title ?? '';
const selectedIcon_name = gameData.selectedIcon?.title ?? '';
alert(Format(t('game:incorrect'), correctIcon_name, selectedIcon_name));
}
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [gameData.correct, gameData.attention]);

const _onNextClick = () => {
setAttention(0);
onNextGame(attention);
setCorrect(false);
};
useEffect(() => {
const _isTimerRunning = gameData.gameState === 'playing';
setIsTimerRunning(_isTimerRunning);
}, [gameData.gameState]);

return (
<>
Expand All @@ -58,13 +55,13 @@ const GameUI = (props: Props) => {
{t('game:Yomi-fuda')} : {correctIcon?.title}
</Typography>
<Typography variant="h6" component="h6">
{t('game:touches')}: {attention}
{t('game:touches')}: {gameData.attention}
</Typography>
<Box display="flex" justifyContent="center">
<Button
variant="contained"
onClick={_onNextClick}
disabled={!correct}
onClick={onNext}
disabled={gameData.correct !== 'correct'}
>
{t('game:next')}
</Button>
Expand All @@ -74,10 +71,10 @@ const GameUI = (props: Props) => {
<Grid item xs={6} md={12}>
<Box border={1} padding={3} flex={1}>
<Typography variant="h4" component="h4">
{t('game:total-touches')} : {totalAttention}
{t('game:total-touches')} : {gameData.totalAttention}
</Typography>
<Typography variant="h6" component="h6">
{t('game:score')}: {score}
{t('game:score')}: {gameData.score}
</Typography>
<Typography variant="h6" component="h6">
<StopwatchDisplay
Expand All @@ -90,37 +87,18 @@ const GameUI = (props: Props) => {
</Grid>
<Grid item xs={12} md={8}>
<Box marginTop={2}>
<Grid
container
spacing={{ xs: 2, md: 3 }}
rowSpacing={{ xs: 1, sm: 2, md: 3 }}
columnSpacing={{ xs: 1, sm: 2, md: 3 }}
>
{iconList.map((icon, index) => {
return (
<Grid item key={index} xs={6} sm={4} md={3} lg={3} xl={2}>
<Paper
elevation={3}
onClick={() => iconClick(icon)}
component="img"
alt=""
src={createIconsUrl(icon, 0)}
sx={{
width: '100%',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
/>
{/* <Typography variant="body1" component="p" align="center">
{icon.title}
</Typography> */}
</Grid>
);
})}
</Grid>
<IconGrid iconList={iconList} iconClick={iconClick} />
</Box>
</Grid>
{process.env.NODE_ENV === 'development' && (
<Grid item xs={12}>
<pre>{JSON.stringify(gameData, null, 2)}</pre>
<p>correctIcon</p>
<pre>{JSON.stringify(correctIcon, null, 2)}</pre>
<p>iconList</p>
<pre>{JSON.stringify(iconList, null, 2)}</pre>
</Grid>
)}
</Grid>
</>
);
Expand Down
Loading

0 comments on commit 2811555

Please sign in to comment.