Small Website to play Web-based games.
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 

176 строки
4.7 KiB

  1. import type { NextPage } from 'next'
  2. import {GetServerSideProps} from 'next';
  3. import {Game} from '../../utils/games';
  4. import Link from 'next/link';
  5. import Head from 'next/head';
  6. import Image from 'next/image';
  7. import {useState} from 'react';
  8. type HomeProps = {
  9. games: Game[],
  10. }
  11. const GamesPage: NextPage<HomeProps> = ({
  12. games,
  13. }) => {
  14. const [displayGames, setDisplayGames] = useState(games);
  15. const handleImageError = (game: Game) => () => {
  16. setDisplayGames((games) => games.map(g => ({
  17. ...g,
  18. thumbnail: g.id === game.id ? undefined : g.thumbnail,
  19. })))
  20. }
  21. return (
  22. <>
  23. <Head>
  24. <title>Flash Games</title>
  25. <style>{`
  26. body {
  27. background-color: #eee;
  28. }
  29. @media (min-width: 720px) {
  30. .games {
  31. grid-template-columns: 1fr 1fr;
  32. }
  33. }
  34. .foo {
  35. object-fit: cover;
  36. object-position: center;
  37. }
  38. `}</style>
  39. </Head>
  40. <div
  41. style={{
  42. width: '100%',
  43. maxWidth: 720,
  44. margin: '0 auto',
  45. padding: '0 2rem',
  46. boxSizing: 'border-box',
  47. }}
  48. >
  49. <ul
  50. className="games"
  51. style={{
  52. padding: 0,
  53. margin: '2rem 0',
  54. display: 'grid',
  55. gap: '2rem',
  56. gridGap: '2rem',
  57. }}
  58. >
  59. {
  60. displayGames.map((g) => (
  61. <li
  62. key={g.id}
  63. style={{
  64. display: 'block',
  65. }}
  66. >
  67. <Link
  68. href={{
  69. pathname: '/games/[id]',
  70. query: {
  71. id: g.id,
  72. },
  73. }}
  74. passHref
  75. >
  76. <a
  77. href={`/games/${g.id}`}
  78. style={{
  79. display: 'block',
  80. height: '12rem',
  81. position: 'relative',
  82. overflow: 'hidden',
  83. borderRadius: '0.25rem',
  84. border: '1px solid #ddd',
  85. boxShadow: '0.125rem 0.25rem 0.25rem rgba(0,0,0,0.0625)'
  86. }}
  87. >
  88. <div
  89. style={{
  90. width: '100%',
  91. height: '100%',
  92. backgroundColor: '#ddd',
  93. }}
  94. >
  95. {
  96. g.thumbnail
  97. && (
  98. <Image
  99. alt={g.name}
  100. src={`/games/${g.id}/${g.thumbnail}`}
  101. layout="fill"
  102. className="foo"
  103. onError={handleImageError(g)}
  104. />
  105. )
  106. }
  107. {
  108. !g.thumbnail
  109. && (
  110. <div
  111. style={{
  112. fontSize: '10rem',
  113. display: 'grid',
  114. placeContent: 'center',
  115. width: '100%',
  116. height: '100%',
  117. opacity: 0.125,
  118. filter: 'grayscale(1)',
  119. overflow: 'hidden',
  120. lineHeight: 1,
  121. }}
  122. >
  123. 🎮
  124. </div>
  125. )
  126. }
  127. </div>
  128. <div
  129. style={{
  130. position: 'absolute',
  131. bottom: 0,
  132. left: 0,
  133. width: '100%',
  134. textAlign: 'center',
  135. backgroundColor: 'white',
  136. padding: '0.5rem 0',
  137. boxSizing: 'border-box',
  138. }}
  139. >
  140. {g.name}
  141. </div>
  142. </a>
  143. </Link>
  144. </li>
  145. ))
  146. }
  147. </ul>
  148. </div>
  149. </>
  150. )
  151. }
  152. export const getServerSideProps: GetServerSideProps = async (ctx) => {
  153. const response = await fetch('http://localhost:3000/api/games');
  154. if (response.status !== 200) {
  155. return {
  156. notFound: true,
  157. }
  158. }
  159. const games = await response.json();
  160. return {
  161. props: {
  162. games,
  163. }
  164. }
  165. }
  166. export default GamesPage