Dice.jsx 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import React, { memo } from "react";
  2. import styled, { css } from "styled-components";
  3. import { useTranslation } from "react-i18next";
  4. const DicePane = styled.div`
  5. ${({ color }) => css`
  6. background-color: ${color};
  7. padding: 0.3em;
  8. text-align: center;
  9. display: flex;
  10. justify-content: space-between;
  11. flex-direction: column;
  12. align-items: center;
  13. border-radius: 3px;
  14. box-shadow: 3px 3px 8px 0px rgb(0, 0, 0, 0.3);
  15. & h3 {
  16. user-select: none;
  17. padding: 0;
  18. margin: 0;
  19. }
  20. .item-library__component & {
  21. transform: scale(0.8);
  22. }
  23. &
  24. input:not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="color"]):not([type="button"]):not([type="reset"]).result {
  25. width: 3em;
  26. display: block;
  27. text-align: center;
  28. border: none;
  29. margin: 0.2em 0;
  30. padding: 0.2em 0;
  31. user-select: none;
  32. }
  33. `}
  34. `;
  35. const getRandomInt = (sides) => {
  36. let min = 1;
  37. let max = Math.ceil(sides);
  38. return Math.floor(Math.random() * max) + min;
  39. };
  40. const Dice = ({
  41. value = 0,
  42. color = "#CCC",
  43. label = "",
  44. side = 6,
  45. textColor = "#000",
  46. fontSize = "22",
  47. setState,
  48. }) => {
  49. const { t } = useTranslation();
  50. const diceWrapper = React.useRef(null);
  51. const setValue = (e) => {
  52. setState((prevState) => ({
  53. ...prevState,
  54. value: e.target.value,
  55. }));
  56. };
  57. const roll = () => {
  58. diceWrapper.current.className = "hvr-wobble-horizontal";
  59. const simulateRoll = (nextTimeout) => {
  60. setState((prevState) => ({
  61. ...prevState,
  62. value: getRandomInt(side),
  63. }));
  64. if (nextTimeout < 200) {
  65. setTimeout(
  66. () => simulateRoll(nextTimeout + getRandomInt(30)),
  67. nextTimeout
  68. );
  69. }
  70. };
  71. simulateRoll(100);
  72. };
  73. const removeClass = (e) => {
  74. e.target.className = "";
  75. };
  76. return (
  77. <div onAnimationEnd={removeClass} ref={diceWrapper}>
  78. <DicePane color={color}>
  79. <h3>{label}</h3>
  80. <label style={{ userSelect: "none" }}>
  81. <input
  82. style={{
  83. textColor,
  84. fontSize: fontSize + "px",
  85. }}
  86. className="result"
  87. value={value}
  88. onKeyUp={(e) => e.stopPropagation()}
  89. onKeyDown={(e) => e.stopPropagation()}
  90. onChange={setValue}
  91. />
  92. </label>
  93. <span>
  94. <button onClick={roll}>{t("Roll")}</button>
  95. </span>
  96. </DicePane>
  97. </div>
  98. );
  99. };
  100. export default memo(Dice);