GameListItem.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. import React from "react";
  2. import styled from "styled-components";
  3. import { Link } from "react-router-dom";
  4. import { useTranslation } from "react-i18next";
  5. import { getBestTranslationFromConfig } from "../utils/api";
  6. const Game = styled.li`
  7. position: relative;
  8. padding: 0em;
  9. margin: 0px;
  10. margin-bottom: 3em;
  11. flex: 1;
  12. & .game-name {
  13. max-width: 80%;
  14. line-height: 1.2em;
  15. overflow: hidden;
  16. margin-bottom: 3px;
  17. margin: 0.2em 0 0.5em 0;
  18. font-size: 2.5vw;
  19. }
  20. & .unpublished {
  21. position: absolute;
  22. top: 0.5em;
  23. right: 0.5em;
  24. padding: 0em;
  25. }
  26. & .button.play {
  27. margin: 0 2px;
  28. background-color: var(--color-secondary);
  29. }
  30. & .play {
  31. position: absolute;
  32. bottom: 0.5em;
  33. right: 0.5em;
  34. }
  35. & .extra-actions {
  36. position: absolute;
  37. top: 0.5em;
  38. right: 0.5em;
  39. display: none;
  40. }
  41. &:hover .extra-actions {
  42. display: block;
  43. }
  44. & .img {
  45. width: 100%;
  46. min-width: 300px;
  47. max-width: 600px;
  48. background-color: #333;
  49. border-radius: 5px;
  50. }
  51. & .details {
  52. display: flex;
  53. flex-direction: row;
  54. color: var(--font-color2);
  55. font-size: 14px;
  56. padding-top: 1em;
  57. }
  58. & .details > span {
  59. display: flex;
  60. align-items: center;
  61. padding-right: 5px;
  62. margin-right: 5px;
  63. border-right: 1px solid var(--font-color2);
  64. }
  65. & .details > span:last-child {
  66. border: none;
  67. }
  68. & .details img {
  69. margin-right: 0.5em;
  70. }
  71. `;
  72. const GameListItem = ({
  73. game: {
  74. published,
  75. owner,
  76. id,
  77. minAge,
  78. materialLanguage,
  79. duration,
  80. playerCount,
  81. imageUrl,
  82. },
  83. game,
  84. userId,
  85. }) => {
  86. const { t, i18n } = useTranslation();
  87. const translation = React.useMemo(
  88. () => getBestTranslationFromConfig(game, i18n.languages),
  89. [game, i18n.languages]
  90. );
  91. let playerCountDisplay = undefined;
  92. if (playerCount && playerCount.length) {
  93. const [min, max] = playerCount;
  94. if (min === max) {
  95. if (max === 9) {
  96. playerCountDisplay = ["9+"];
  97. } else {
  98. playerCountDisplay = [max];
  99. }
  100. } else {
  101. if (max === 9) {
  102. playerCountDisplay = [min, "9+"];
  103. } else {
  104. playerCountDisplay = [min, max];
  105. }
  106. }
  107. }
  108. let durationDisplay = undefined;
  109. if (duration && duration.length) {
  110. const [min, max] = duration;
  111. if (min === max) {
  112. if (max === 90) {
  113. durationDisplay = "90+";
  114. } else {
  115. durationDisplay = `~${max}`;
  116. }
  117. } else {
  118. if (max === 90) {
  119. durationDisplay = `${min}~90+`;
  120. } else {
  121. durationDisplay = `${min}~${max}`;
  122. }
  123. }
  124. }
  125. let materialLanguageDisplay = t(materialLanguage);
  126. console.log(playerCountDisplay, playerCount);
  127. return (
  128. <Game>
  129. <Link to={`/game/${id}/session/`}>
  130. {imageUrl ? (
  131. <img className="img" src={imageUrl} />
  132. ) : (
  133. <img className="img" src="/default-game.png" />
  134. )}
  135. </Link>
  136. {!published && (
  137. <img
  138. className="unpublished"
  139. src="https://icongr.am/entypo/eye-with-line.svg?size=32&color=888886"
  140. alt={t("Unpublished")}
  141. />
  142. )}
  143. <div className="details">
  144. {playerCountDisplay && (
  145. <span>
  146. {playerCountDisplay.length === 2 &&
  147. t("{{min}} - {{max}} players", {
  148. min: playerCountDisplay[0],
  149. max: playerCountDisplay[1],
  150. })}
  151. {playerCountDisplay.length === 1 &&
  152. t("{{count}} player", {
  153. count: playerCountDisplay[0],
  154. })}
  155. </span>
  156. )}
  157. {durationDisplay && <span>{durationDisplay} mins</span>}
  158. {minAge && <span>age {minAge}+</span>}
  159. {materialLanguageDisplay && <span>{materialLanguageDisplay}</span>}
  160. </div>
  161. <h2 className="game-name">{translation.name}</h2>
  162. {userId && (userId === owner || !owner) && (
  163. <div className="extra-actions">
  164. <Link to={`/game/${id}/edit`} className="button edit icon-only">
  165. <img
  166. src="https://icongr.am/feather/edit.svg?size=16&color=ffffff"
  167. alt={t("Edit")}
  168. />
  169. </Link>
  170. </div>
  171. )}
  172. </Game>
  173. );
  174. };
  175. export default GameListItem;