Button.tsx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. import React, { FC } from "react";
  2. import styled, { css } from "styled-components";
  3. import { switchProp, prop, ifProp } from "styled-tools";
  4. import { Flex, BoxProps } from "reflexbox/styled-components";
  5. // TODO: another solution for inline SVG
  6. import SVG from "react-inlinesvg";
  7. import { spin } from "../helpers/animations";
  8. interface Props extends BoxProps {
  9. color?: "purple" | "gray" | "blue" | "red";
  10. disabled?: boolean;
  11. icon?: string; // TODO: better typing
  12. isRound?: boolean;
  13. onClick?: any; // TODO: better typing
  14. type?: "button" | "submit" | "reset";
  15. }
  16. const StyledButton = styled(Flex)<Props>`
  17. position: relative;
  18. align-items: center;
  19. justify-content: center;
  20. font-weight: normal;
  21. text-align: center;
  22. line-height: 1;
  23. word-break: keep-all;
  24. color: ${switchProp(prop("color", "blue"), {
  25. blue: "white",
  26. red: "white",
  27. purple: "white",
  28. gray: "#444"
  29. })};
  30. background: ${switchProp(prop("color", "blue"), {
  31. blue: "linear-gradient(to right, #42a5f5, #2979ff)",
  32. red: "linear-gradient(to right, #ee3b3b, #e11c1c)",
  33. purple: "linear-gradient(to right, #7e57c2, #6200ea)",
  34. gray: "linear-gradient(to right, #e0e0e0, #bdbdbd)"
  35. })};
  36. box-shadow: ${switchProp(prop("color", "blue"), {
  37. blue: "0 5px 6px rgba(66, 165, 245, 0.5)",
  38. red: "0 5px 6px rgba(168, 45, 45, 0.5)",
  39. purple: "0 5px 6px rgba(81, 45, 168, 0.5)",
  40. gray: "0 5px 6px rgba(160, 160, 160, 0.5)"
  41. })};
  42. border: none;
  43. border-radius: 100px;
  44. transition: all 0.4s ease-out;
  45. cursor: pointer;
  46. overflow: hidden;
  47. :hover,
  48. :focus {
  49. outline: none;
  50. box-shadow: ${switchProp(prop("color", "blue"), {
  51. blue: "0 6px 15px rgba(66, 165, 245, 0.5)",
  52. red: "0 6px 15px rgba(168, 45, 45, 0.5)",
  53. purple: "0 6px 15px rgba(81, 45, 168, 0.5)",
  54. gray: "0 6px 15px rgba(160, 160, 160, 0.5)"
  55. })};
  56. transform: translateY(-2px) scale(1.02, 1.02);
  57. }
  58. `;
  59. const Icon = styled(SVG)`
  60. svg {
  61. width: 16px;
  62. height: 16px;
  63. margin-right: 12px;
  64. stroke: ${ifProp({ color: "gray" }, "#444", "#fff")};
  65. ${ifProp(
  66. { icon: "loader" },
  67. css`
  68. width: 20px;
  69. height: 20px;
  70. margin: 0;
  71. animation: ${spin} 1s linear infinite;
  72. `
  73. )}
  74. ${ifProp(
  75. "isRound",
  76. css`
  77. width: 15px;
  78. height: 15px;
  79. margin: 0;
  80. `
  81. )}
  82. @media only screen and (max-width: 768px) {
  83. width: 12px;
  84. height: 12px;
  85. margin-right: 6px;
  86. }
  87. }
  88. `;
  89. export const Button: FC<Props> = props => {
  90. const SVGIcon = props.icon ? (
  91. <Icon
  92. icon={props.icon}
  93. isRound={props.isRound}
  94. color={props.color}
  95. src={`/images/${props.icon}.svg`}
  96. />
  97. ) : (
  98. ""
  99. );
  100. return (
  101. <StyledButton {...props}>
  102. {SVGIcon}
  103. {props.icon !== "loader" && props.children}
  104. </StyledButton>
  105. );
  106. };
  107. Button.defaultProps = {
  108. as: "button",
  109. width: "auto",
  110. flex: "0 0 auto",
  111. height: [32, 40],
  112. py: 0,
  113. px: [24, 32],
  114. fontSize: [12, 13],
  115. color: "blue",
  116. icon: "",
  117. isRound: false
  118. };
  119. interface NavButtonProps extends BoxProps {
  120. disabled?: boolean;
  121. onClick?: any; // TODO: better typing
  122. type?: "button" | "submit" | "reset";
  123. }
  124. export const NavButton = styled(Flex)<NavButtonProps>`
  125. display: flex;
  126. border: none;
  127. border-radius: 4px;
  128. box-shadow: 0 0px 10px rgba(100, 100, 100, 0.1);
  129. background-color: white;
  130. cursor: pointer;
  131. transition: all 0.2s ease-out;
  132. box-sizing: border-box;
  133. :hover {
  134. transform: translateY(-2px);
  135. }
  136. ${ifProp(
  137. "disabled",
  138. css`
  139. background-color: #f6f6f6;
  140. box-shadow: 0 0px 5px rgba(150, 150, 150, 0.1);
  141. cursor: default;
  142. :hover {
  143. transform: none;
  144. }
  145. `
  146. )}
  147. `;
  148. NavButton.defaultProps = {
  149. as: "button",
  150. type: "button",
  151. flex: "0 0 auto",
  152. alignItems: "center",
  153. justifyContent: "center",
  154. width: "auto",
  155. height: [26, 28],
  156. py: 0,
  157. px: ["6px", "8px"],
  158. fontSize: [12]
  159. };