Added tracking code form.

This commit is contained in:
Mike Cao 2020-08-07 20:36:57 -07:00
parent c4b75e4aec
commit 58a1be7a30
27 changed files with 100 additions and 42 deletions

View file

@ -0,0 +1,30 @@
import React from 'react';
import classNames from 'classnames';
import Icon from './Icon';
import styles from './Button.module.css';
export default function Button({
type = 'button',
icon,
size,
variant,
children,
className,
...props
}) {
return (
<button
type={type}
className={classNames(styles.button, className, {
[styles.small]: size === 'S',
[styles.large]: size === 'L',
[styles.action]: variant === 'action',
[styles.danger]: variant === 'danger',
})}
{...props}
>
{icon && <Icon icon={icon} size={size} />}
{children}
</button>
);
}

View file

@ -0,0 +1,46 @@
.button {
display: flex;
justify-content: center;
align-items: center;
font-size: var(--font-size-normal);
background: var(--gray100);
padding: 8px 16px;
border-radius: 4px;
border: 0;
outline: none;
cursor: pointer;
}
.button:hover {
background: #eaeaea;
}
.button + .button {
margin-left: 10px;
}
.small {
font-size: var(--font-size-small);
}
.large {
font-size: var(--font-size-large);
}
.action {
color: var(--gray50) !important;
background: var(--gray900) !important;
}
.action:hover {
background: var(--gray800) !important;
}
.danger {
color: var(--gray50) !important;
background: var(--red500) !important;
}
.danger:hover {
background: var(--red400) !important;
}

View file

@ -0,0 +1,23 @@
import React, { useState } from 'react';
import Button from './Button';
const defaultText = 'Copy to clipboard';
export default function CopyButton({ element, ...props }) {
const [text, setText] = useState(defaultText);
function handleClick() {
if (element?.current) {
element.current.select();
document.execCommand('copy');
setText('Copied!');
window.getSelection().removeAllRanges();
}
}
return (
<Button {...props} onClick={handleClick}>
{text}
</Button>
);
}

View file

@ -1,10 +1,10 @@
import React, { useState, useRef } from 'react';
import classNames from 'classnames';
import Menu from '../interface/Menu';
import Menu from './Menu';
import useDocumentClick from 'hooks/useDocumentClick';
import Chevron from 'assets/chevron-down.svg';
import styles from './Dropdown.module.css';
import Icon from '../interface/Icon';
import Icon from './Icon';
export default function DropDown({
value,

18
components/common/Icon.js Normal file
View file

@ -0,0 +1,18 @@
import React from 'react';
import classNames from 'classnames';
import styles from './Icon.module.css';
export default function Icon({ icon, className, size = 'M' }) {
return (
<div
className={classNames(styles.icon, className, {
[styles.xl]: size === 'XL',
[styles.large]: size === 'L',
[styles.medium]: size === 'M',
[styles.small]: size === 'S',
})}
>
{icon}
</div>
);
}

View file

@ -0,0 +1,34 @@
.icon {
display: inline-flex;
justify-content: center;
align-items: center;
vertical-align: middle;
}
.icon + * {
margin-left: 10px;
}
.icon svg {
fill: currentColor;
}
.xl > svg {
width: 48px;
height: 48px;
}
.large > svg {
width: 24px;
height: 24px;
}
.medium > svg {
width: 16px;
height: 16px;
}
.small > svg {
width: 12px;
height: 12px;
}

12
components/common/Link.js Normal file
View file

@ -0,0 +1,12 @@
import React from 'react';
import classNames from 'classnames';
import NextLink from 'next/link';
import styles from './Link.module.css';
export default function Link({ className, children, ...props }) {
return (
<NextLink {...props}>
<a className={classNames(styles.link, className)}>{children}</a>
</NextLink>
);
}

View file

@ -0,0 +1,23 @@
.link,
.link:active,
.link:visited {
position: relative;
color: #2c2c2c;
text-decoration: none;
}
.link:before {
content: '';
position: absolute;
bottom: -2px;
width: 0;
height: 2px;
background: #2680eb;
opacity: 0.5;
transition: width 100ms;
}
.link:hover:before {
width: 100%;
transition: width 100ms;
}

24
components/common/Menu.js Normal file
View file

@ -0,0 +1,24 @@
import React from 'react';
import classNames from 'classnames';
import styles from './Menu.module.css';
export default function Menu({ options = [], className, align = 'left', onSelect = () => {} }) {
return (
<div
className={classNames(styles.menu, className, {
[styles.left]: align === 'left',
[styles.right]: align === 'right',
})}
>
{options.map(({ label, value, className: optionClassName }) => (
<div
key={value}
className={classNames(styles.option, optionClassName)}
onClick={e => onSelect(value, e)}
>
{label}
</div>
))}
</div>
);
}

View file

@ -0,0 +1,31 @@
.menu {
position: absolute;
min-width: 100px;
top: 100%;
margin-top: 4px;
border: 1px solid var(--gray500);
border-radius: 4px;
overflow: hidden;
z-index: 2;
}
.option {
font-size: var(--font-size-small);
font-weight: normal;
background: #fff;
padding: 4px 16px;
cursor: pointer;
white-space: nowrap;
}
.option:hover {
background: #f5f5f5;
}
.left {
left: 0;
}
.right {
right: 0;
}

View file

@ -12,6 +12,7 @@
font-weight: 600;
line-height: 40px;
flex: 1;
border-bottom: 1px solid var(--gray300);
}
.body {

View file

@ -0,0 +1,56 @@
import React, { useState, useRef } from 'react';
import { useSelector } from 'react-redux';
import { useRouter } from 'next/router';
import Menu from './Menu';
import Icon from './Icon';
import useDocumentClick from 'hooks/useDocumentClick';
import User from 'assets/user.svg';
import Chevron from 'assets/chevron-down.svg';
import styles from './UserButton.module.css';
export default function UserButton() {
const [showMenu, setShowMenu] = useState(false);
const user = useSelector(state => state.user);
const ref = useRef();
const router = useRouter();
const menuOptions = [
{
label: (
<>
Logged in as <b>{user.username}</b>
</>
),
value: 'username',
className: styles.username,
},
{ label: 'Account', value: 'account' },
{ label: 'Logout', value: 'logout' },
];
function handleSelect(value) {
setShowMenu(false);
if (value === 'account') {
router.push('/account');
} else if (value === 'logout') {
router.push('/logout');
}
}
useDocumentClick(e => {
if (!ref.current.contains(e.target)) {
setShowMenu(false);
}
});
return (
<div ref={ref} className={styles.container}>
<div onClick={() => setShowMenu(state => !state)}>
<Icon icon={<User />} size="L" />
<Icon icon={<Chevron />} size="S" />
</div>
{showMenu && <Menu options={menuOptions} onSelect={handleSelect} align="right" />}
</div>
);
}

View file

@ -0,0 +1,13 @@
.container {
display: flex;
position: relative;
cursor: pointer;
}
.username {
border-bottom: 1px solid var(--gray500);
}
.username:hover {
background: var(--gray50);
}