GameListItem.js 4.4 KB

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