refactor: more tailwind

This commit is contained in:
Tristan Yang
2023-02-07 09:25:05 +08:00
parent 07ddfbf12b
commit c5669f8bc4
48 changed files with 447 additions and 1314 deletions
+24 -61
View File
@@ -1,63 +1,26 @@
import styled from "styled-components";
const StyledButton = styled.button`
cursor: pointer;
padding: 10px 14px;
border: none;
box-sizing: border-box;
box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05);
border-radius: var(--br, 4px);
font-weight: 500;
font-size: 14px;
line-height: 20px;
color: #fff;
background-color: #22ccee;
word-break: keep-all;
&.flex {
width: 100%;
}
&:hover,
&:active {
background-color: #06aed4;
}
&:focus {
background-color: #22ccee;
}
&:disabled {
background-color: #d0d5dd;
}
&.small {
padding: 8px 14px;
font-size: 14px;
line-height: 20px;
}
&.mini {
padding: 4px 10px;
font-size: 12px;
line-height: 18px;
}
&.danger {
border: none;
background-color: #ef4444;
color: #fff;
&:disabled {
background-color: #fecdca;
}
}
&.ghost {
border: 1px solid #1fe1f9;
background: none;
color: #1fe1f9;
}
&.border_less {
box-shadow: none;
border: none !important;
}
&.cancel {
border: 1px solid #e5e7eb;
background: none;
color: #374151;
}
`;
import clsx from "clsx";
import { ButtonHTMLAttributes, ReactNode } from "react";
type Props = ButtonHTMLAttributes<HTMLButtonElement> & { children?: ReactNode }
const StyledButton = ({ children, className = '', ...rest }: Props) => {
const isGhost = className.includes('ghost');
const noBorder = className.includes('border_less');
const isCancel = className.includes('cancel');
const isDanger = className.includes('danger');
const isSmall = className.includes('small');
const isMini = className.includes('mini');
const isFull = className.includes('flex');
return <button className={clsx(`text-sm text-white bg-primary-400 break-keep shadow rounded-lg box-border px-3.5 py-2.5 hover:bg-primary-500 active:bg-primary-500 disabled:bg-gray-300`,
isFull && "w-full",
isGhost && "text-primary-400 border border-primary-400 !bg-transparent",
isCancel && "!bg-transparent text-gray-800 dark:text-gray-50 border border-gray-200",
isSmall && "!py-2",
noBorder && "!shadow-none border-none",
isMini && "!px-2.5 !py-1 !text-xs",
isDanger && "bg-red-700 disabled:bg-gray-300 hover:bg-red-700/80",
className
)} {...rest}>
{children}
</button>;
};
export default StyledButton;
-78
View File
@@ -1,78 +0,0 @@
import styled from "styled-components";
const StyledMenu = styled.ul`
display: flex;
flex-direction: column;
gap: 2px;
padding: 4px;
background-color: #fff;
box-shadow: 0 20px 25px 20px rgba(31, 41, 55, 0.1), 0 10px 10px rgba(31, 41, 55, 0.04);
border-radius: 12px;
min-width: 200px;
.item {
position: relative;
display: flex;
align-items: center;
gap: 14px;
white-space: nowrap;
cursor: pointer;
border-radius: 6px;
padding: 6px;
font-style: normal;
font-weight: 600;
font-size: 14px;
line-height: 20px;
color: #616161;
.icon {
width: 20px;
height: 20px;
path {
fill: #475467;
}
}
&.sb {
justify-content: space-between;
}
&:hover {
background-color: #22ccee;
color: #fff;
.icon {
path {
fill: #fff;
}
}
}
&.bottom_line {
margin-bottom: 9px;
&:before {
position: absolute;
content: "";
left: 6px;
bottom: -4px;
display: block;
padding: 0 6px;
box-sizing: border-box;
width: calc(100% - 12px);
height: 1px;
background-color: #f2f4f7;
}
}
&.danger {
color: #a11043;
&:hover {
background-color: #b42318;
color: #fff;
}
}
&[data-disabled="true"] {
color: #a4a8b3;
.icon {
path {
fill: #a4a8b3;
}
}
}
}
`;
export default StyledMenu;
+10 -68
View File
@@ -1,67 +1,5 @@
import { useState, useId, FC } from "react";
import styled from "styled-components";
const StyledForm = styled.form`
width: 100%;
> .option {
&:not(:last-child) {
margin-bottom: 8px;
}
> input[type="radio"] {
display: none;
& + .box {
background: #ffffff;
border: 1px solid #d0d5dd;
box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05);
border-radius: 8px;
transition: all ease-in-out 250ms;
& > label {
display: flex;
flex-direction: row;
align-items: center;
font-weight: 400;
font-size: 16px;
line-height: 24px;
color: #667085;
cursor: pointer;
user-select: none;
transition: all ease-in-out 250ms;
&:before {
content: "";
display: inline-block;
width: 14px;
height: 14px;
border-radius: 8px;
background: #ffffff;
box-shadow: inset 0 0 0 4px #ffffff;
border: 1px solid #d0d5dd;
margin: 14px 8px 14px 14px;
transition: all ease-in-out 500ms;
}
}
}
&:checked + .box {
background: #22ccee;
border: 1px solid #d0d5dd;
& > label {
color: #ffffff;
&:before {
background: #ffffff;
box-shadow: inset 0 0 0 4px #22ccee;
border: 1px solid #ffffff;
}
}
}
}
}
`;
type Props = {
options: string[];
values: (string | number)[];
@@ -84,12 +22,12 @@ const Radio: FC<Props> = ({
const [fallbackValue, setFallbackValue] = useState(defaultValue);
const _value = value !== VALUE_NOT_SET ? value : fallbackValue;
return (
<StyledForm>
<form className="w-full flex flex-col gap-2">
{options.map((item, index) => (
<div className="option" key={index}>
<div className="relative bg-transparent" key={index}>
<input
className="absolute top-0 left-0 w-full h-full opacity-0 cursor-pointer peer z-50"
type="radio"
checked={(values !== VALUES_NOT_SET ? values.indexOf(_value) : _value) === index}
onChange={() => {
@@ -105,12 +43,16 @@ const Radio: FC<Props> = ({
}}
id={`${id}-${index}`}
/>
<div className="box">
<label htmlFor={`${id}-${index}`}>{item}</label>
<div className="drop-shadow px-2 py-3 border border-solid border-[#d0d5dd] rounded-lg w-full h-full bg-white peer-checked:bg-primary-400 text-sm text-gray-500 peer-checked:text-white">
<label className="ml-6" htmlFor={`${id}-${index}`}>{item}</label>
</div>
<div className="absolute top-1/2 left-3 -translate-y-1/2 w-3.5 h-3.5 rounded-full border border-gray-400 peer-checked:hidden"></div>
<div className="absolute top-1/2 left-3 -translate-y-1/2 w-3.5 h-3.5 rounded-full border border-white invisible peer-checked:visible flex-center">
<div className="w-2 h-2 bg-white rounded-full"></div>
</div>
</div>
))}
</StyledForm>
</form>
);
};
export default Radio;
+2 -3
View File
@@ -2,7 +2,6 @@ import { FC, useState } from "react";
import Tippy from "@tippyjs/react";
import IconSelect from "../../../assets/icons/check.sign.svg";
import IconArrow from "../../../assets/icons/arrow.down.svg";
import Menu from "./Menu";
import { useTranslation } from "react-i18next";
@@ -42,7 +41,7 @@ const Select: FC<Props> = ({ options = [], updateSelect = null, current = null }
placement="bottom"
interactive
content={
<Menu>
<ul className="context-menu">
{options.map(({ title, value, selected, underline }) => {
return (
<li
@@ -56,7 +55,7 @@ const Select: FC<Props> = ({ options = [], updateSelect = null, current = null }
</li>
);
})}
</Menu>
</ul>
}
>
<div className="select-none border border-solid border-slate-200 p-2 flex items-center gap-2" onClick={toggleVisible}>
+11 -35
View File
@@ -1,36 +1,12 @@
import styled from "styled-components";
const StyledToggle = styled.div`
cursor: pointer;
position: relative;
width: 44px;
height: 24px;
background-color: #1fe1f9;
border-radius: 12px;
transition: all 0.2s ease-in;
&:after {
border-radius: 50%;
background-color: #fff;
content: "";
display: block;
width: 20px;
height: 20px;
position: absolute;
top: 2px;
right: 2px;
transition: all 0.4s ease;
}
&[data-checked="false"] {
background-color: #f2f4f7;
&:after {
transform: translateX(-100%);
}
}
&[data-disabled="true"] {
cursor: not-allowed;
background-color: #ccc;
pointer-events: none;
}
`;
import clsx from "clsx";
import { HTMLAttributes } from "react";
const StyledToggle = (props: Pick<HTMLAttributes<HTMLDivElement>, "onClick"> & { checked?: boolean, disabled?: boolean }) => {
const { checked = true, disabled = false } = props;
return <div
{...props}
className={clsx(`cursor-pointer relative w-11 h-6 rounded-xl`, checked ? 'bg-primary-400' : 'bg-gray-300', disabled && "cursor-not-allowed bg-gray-400 pointer-events-none")}
>
<div className={clsx("rounded-full bg-white w-5 h-5 absolute top-0.5 right-0.5 transition-all", !checked && "-translate-x-full")}></div>
</div>;
};
export default StyledToggle;