Dice.jsx 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  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. &
  21. input:not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="color"]):not([type="button"]):not([type="reset"]).result {
  22. width: 3em;
  23. display: block;
  24. text-align: center;
  25. border: none;
  26. margin: 0.2em 0;
  27. padding: 0.2em 0;
  28. user-select: none;
  29. }
  30. `}
  31. `;
  32. const getRandomInt = (sides) => {
  33. let min = 1;
  34. let max = Math.ceil(sides);
  35. return Math.floor(Math.random() * max) + min;
  36. };
  37. const Dice = ({
  38. value = 0,
  39. color = "#CCC",
  40. label = "",
  41. side = 6,
  42. textColor = "#000",
  43. fontSize = "22",
  44. setState,
  45. }) => {
  46. const { t } = useTranslation();
  47. const diceWrapper = React.useRef(null);
  48. const setValue = (e) => {
  49. setState((prevState) => ({
  50. ...prevState,
  51. value: e.target.value,
  52. }));
  53. };
  54. const roll = () => {
  55. diceWrapper.current.className = "hvr-wobble-horizontal";
  56. const simulateRoll = (nextTimeout) => {
  57. setState((prevState) => ({
  58. ...prevState,
  59. value: getRandomInt(side),
  60. }));
  61. if (nextTimeout < 200) {
  62. setTimeout(
  63. () => simulateRoll(nextTimeout + getRandomInt(30)),
  64. nextTimeout
  65. );
  66. }
  67. };
  68. simulateRoll(100);
  69. };
  70. const removeClass = (e) => {
  71. e.target.className = "";
  72. };
  73. return (
  74. <div onAnimationEnd={removeClass} ref={diceWrapper}>
  75. <DicePane color={color}>
  76. <h3>{label}</h3>
  77. <label style={{ userSelect: "none" }}>
  78. <input
  79. style={{
  80. textColor,
  81. fontSize: fontSize + "px",
  82. }}
  83. className="result"
  84. value={value}
  85. onChange={setValue}
  86. />
  87. </label>
  88. <span>
  89. <button onClick={roll}>{t("Roll")}</button>
  90. </span>
  91. </DicePane>
  92. </div>
  93. );
  94. };
  95. export default memo(Dice);