Screen.jsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. import React from "react";
  2. import { memo } from "react";
  3. import styled, { css } from "styled-components";
  4. import { useUsers } from "react-sync-board";
  5. import { useTranslation } from "react-i18next";
  6. import { readableColor, lighten } from "color2k";
  7. const ScreenWrapper = styled.div`
  8. ${({
  9. width = 200,
  10. height = 200,
  11. borderColor = "#cccccc33",
  12. borderStyle = "solid",
  13. backgroundColor = "#ccc",
  14. owned = false,
  15. }) => css`
  16. width: ${width}px;
  17. height: ${height}px;
  18. ${owned ? `border: 2px ${borderStyle} ${borderColor};` : ""}
  19. border-radius: 5px;
  20. position: relative;
  21. color: ${readableColor(backgroundColor)};
  22. .screen__release-button {
  23. position: absolute;
  24. bottom: -48px;
  25. left: 0;
  26. }
  27. .screen__claim-button {
  28. .item-library__component & {
  29. display: none;
  30. }
  31. }
  32. .screen__visible-message,
  33. .screen__claimed-message {
  34. width: 80%;
  35. text-align: center;
  36. .item-library__component & {
  37. display: none;
  38. }
  39. }
  40. .screen__overlay {
  41. position: absolute;
  42. inset: 0;
  43. ${owned
  44. ? ""
  45. : `background-image: radial-gradient(${lighten(
  46. backgroundColor,
  47. 0.2
  48. )}, ${backgroundColor});`}
  49. display: flex;
  50. justify-content: center;
  51. align-items: center;
  52. flex-direction: column;
  53. border-radius: 5px;
  54. }
  55. `}
  56. `;
  57. const Screen = ({
  58. width,
  59. height,
  60. borderColor,
  61. borderStyle,
  62. backgroundColor,
  63. ownedBy,
  64. setState,
  65. }) => {
  66. const { t } = useTranslation();
  67. const { currentUser, localUsers: users } = useUsers();
  68. const ownedByUser = React.useMemo(() => {
  69. if (Array.isArray(ownedBy)) {
  70. const result = ownedBy
  71. .filter((userId) => users.find(({ uid }) => userId === uid))
  72. .map((userId) => users.find(({ uid }) => userId === uid));
  73. if (result.length > 0) {
  74. return result[0];
  75. }
  76. }
  77. return null;
  78. }, [ownedBy, users]);
  79. const ownedByMe = ownedByUser?.uid === currentUser.uid;
  80. const claimIt = React.useCallback(
  81. (e) => {
  82. e.stopPropagation();
  83. setState((prev) => {
  84. let ownedBy = Array.isArray(prev.ownedBy) ? prev.ownedBy : [];
  85. if (!ownedBy.includes(currentUser.uid)) {
  86. ownedBy = [currentUser.uid];
  87. } else {
  88. ownedBy = ownedBy.filter((id) => id !== currentUser.uid);
  89. }
  90. return {
  91. ...prev,
  92. ownedBy,
  93. };
  94. });
  95. },
  96. [currentUser.uid, setState]
  97. );
  98. return (
  99. <ScreenWrapper
  100. width={width}
  101. height={height}
  102. borderStyle={borderStyle}
  103. borderColor={borderColor}
  104. backgroundColor={backgroundColor}
  105. owned={ownedByMe}
  106. >
  107. <div className="screen__overlay">
  108. {!ownedByUser && (
  109. <>
  110. <button className="screen__claim-button" onClick={claimIt}>
  111. {t("Claim it")}
  112. </button>
  113. <div className="screen__visible-message">
  114. {t(
  115. "If you claim this screen, everything inside this zone will be hidden from other players."
  116. )}
  117. </div>
  118. </>
  119. )}
  120. {ownedByUser && !ownedByMe && (
  121. <div className="screen__claimed-message">
  122. {t("This screen is owned by {{name}}", ownedByUser)}
  123. </div>
  124. )}
  125. </div>
  126. {ownedByMe && (
  127. <button className="screen__release-button" onClick={claimIt}>
  128. {t("Release it")}
  129. </button>
  130. )}
  131. </ScreenWrapper>
  132. );
  133. };
  134. export default memo(Screen);