More deletes. Fixed sticky header.

This commit is contained in:
Mike Cao 2023-02-08 23:14:11 -08:00
parent 87bbaa7f1d
commit 45c13da262
23 changed files with 69 additions and 582 deletions

View file

@ -1,28 +0,0 @@
import PropTypes from 'prop-types';
import classNames from 'classnames';
import styles from './Icon.module.css';
function Icon({ icon, className, size = 'medium', ...props }) {
return (
<div
className={classNames(styles.icon, className, {
[styles.xlarge]: size === 'xlarge',
[styles.large]: size === 'large',
[styles.medium]: size === 'medium',
[styles.small]: size === 'small',
[styles.xsmall]: size === 'xsmall',
})}
{...props}
>
{icon}
</div>
);
}
Icon.propTypes = {
className: PropTypes.string,
icon: PropTypes.node.isRequired,
size: PropTypes.oneOf(['xlarge', 'large', 'medium', 'small', 'xsmall']),
};
export default Icon;

View file

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

View file

@ -1,34 +0,0 @@
import PropTypes from 'prop-types';
import classNames from 'classnames';
import NextLink from 'next/link';
import { Icon } from 'react-basics';
import styles from './Link.module.css';
function Link({ className, icon, children, size, iconRight, onClick, ...props }) {
return (
<NextLink {...props}>
<a
className={classNames(styles.link, className, {
[styles.large]: size === 'large',
[styles.small]: size === 'small',
[styles.xsmall]: size === 'xsmall',
[styles.iconRight]: iconRight,
})}
onClick={onClick}
>
{icon && <Icon className={styles.icon} icon={icon} size={size} />}
{children}
</a>
</NextLink>
);
}
Link.propTypes = {
className: PropTypes.string,
icon: PropTypes.node,
children: PropTypes.node,
size: PropTypes.oneOf(['large', 'small', 'xsmall']),
iconRight: PropTypes.bool,
};
export default Link;

View file

@ -1,42 +0,0 @@
a.link,
a.link:active,
a.link:visited {
position: relative;
color: var(--base900);
text-decoration: none;
display: inline-flex;
align-items: center;
}
a.link span {
border-bottom: 2px solid transparent;
}
a.link:hover span {
border-bottom: 2px solid var(--primary400);
}
a.link.large {
font-size: var(--font-size-lg);
}
a.link.small {
font-size: var(--font-size-sm);
}
a.link.xsmall {
font-size: var(--font-size-xs);
}
a.link .icon + * {
margin-left: 10px;
}
a.link.iconRight .icon {
order: 1;
margin-left: 10px;
}
a.link.iconRight .icon + * {
margin: 0;
}

View file

@ -1,69 +0,0 @@
import PropTypes from 'prop-types';
import classNames from 'classnames';
import styles from './Menu.module.css';
function Menu({
options = [],
selectedOption,
className,
float,
align = 'left',
optionClassName,
selectedClassName,
onSelect = () => {},
}) {
return (
<div
className={classNames(styles.menu, className, {
[styles.float]: float,
[styles.top]: float === 'top',
[styles.bottom]: float === 'bottom',
[styles.left]: align === 'left',
[styles.right]: align === 'right',
})}
>
{options
.filter(({ hidden }) => !hidden)
.map(option => {
const { label, value, className: customClassName, render, divider } = option;
return render ? (
render(option)
) : (
<div
key={value}
className={classNames(styles.option, optionClassName, customClassName, {
[selectedClassName]: selectedOption === option,
[styles.selected]: selectedOption === option,
[styles.divider]: divider,
})}
onClick={e => onSelect(value, e)}
>
{label}
</div>
);
})}
</div>
);
}
Menu.propTypes = {
options: PropTypes.arrayOf(
PropTypes.shape({
label: PropTypes.node,
value: PropTypes.any,
className: PropTypes.string,
render: PropTypes.func,
divider: PropTypes.bool,
}),
),
selectedOption: PropTypes.any,
className: PropTypes.string,
float: PropTypes.oneOf(['top', 'bottom']),
align: PropTypes.oneOf(['left', 'right']),
optionClassName: PropTypes.string,
selectedClassName: PropTypes.string,
onSelect: PropTypes.func,
};
export default Menu;

View file

@ -1,49 +0,0 @@
.menu {
background: var(--base50);
border: 1px solid var(--base500);
border-radius: 4px;
overflow: hidden;
z-index: 100;
}
.option {
background: var(--base50);
padding: 4px 16px;
cursor: pointer;
white-space: nowrap;
}
.option:hover {
background: var(--base100);
}
.float {
position: absolute;
min-width: 100px;
}
.top {
bottom: 100%;
margin-bottom: 5px;
}
.bottom {
top: 100%;
margin-top: 5px;
}
.left {
left: 0;
}
.right {
right: 0;
}
.divider {
border-top: 1px solid var(--base300);
}
.selected {
font-weight: 600;
}

View file

@ -1,87 +0,0 @@
import { useState, useRef } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import Menu from 'components/common/Menu';
import useDocumentClick from 'hooks/useDocumentClick';
import styles from './MenuButton.module.css';
import { Button } from 'react-basics';
function MenuButton({
children,
value,
options,
buttonClassName,
buttonVariant,
menuClassName,
menuPosition = 'bottom',
menuAlign = 'right',
onSelect,
renderValue,
hideLabel,
}) {
const [showMenu, setShowMenu] = useState(false);
const ref = useRef();
const selectedOption = options.find(e => e.value === value);
function handleSelect(value) {
onSelect(value);
setShowMenu(false);
}
function toggleMenu() {
setShowMenu(state => !state);
}
useDocumentClick(e => {
if (!ref.current?.contains(e.target)) {
setShowMenu(false);
}
});
return (
<div className={styles.container} ref={ref}>
<Button
className={classNames(styles.button, buttonClassName, { [styles.open]: showMenu })}
onClick={toggleMenu}
variant={buttonVariant}
>
{!hideLabel && (
<div className={styles.text}>{renderValue ? renderValue(selectedOption) : value}</div>
)}
{children}
</Button>
{showMenu && (
<Menu
className={menuClassName}
options={options}
selectedOption={selectedOption}
onSelect={handleSelect}
float={menuPosition}
align={menuAlign}
/>
)}
</div>
);
}
MenuButton.propTypes = {
icon: PropTypes.node,
value: PropTypes.any,
options: PropTypes.arrayOf(
PropTypes.shape({
label: PropTypes.node,
value: PropTypes.any,
className: PropTypes.string,
render: PropTypes.func,
divider: PropTypes.bool,
}),
),
buttonClassName: PropTypes.string,
menuClassName: PropTypes.string,
menuPosition: PropTypes.oneOf(['top', 'bottom']),
menuAlign: PropTypes.oneOf(['left', 'right']),
onSelect: PropTypes.func,
renderValue: PropTypes.func,
};
export default MenuButton;

View file

@ -1,20 +0,0 @@
.container {
display: flex;
position: relative;
cursor: pointer;
}
.button {
border: 1px solid transparent;
border-radius: 4px;
}
.text {
font-size: var(--font-size-sm);
}
.open,
.open:hover {
background: var(--base50);
border: 1px solid var(--base500);
}

View file

@ -1,46 +0,0 @@
import PropTypes from 'prop-types';
import { useRouter } from 'next/router';
import classNames from 'classnames';
import styles from './NavMenu.module.css';
function NavMenu({ options = [], className, onSelect = () => {} }) {
const router = useRouter();
return (
<div className={classNames(styles.menu, className)}>
{options
.filter(({ hidden }) => !hidden)
.map(option => {
const { label, value, className: customClassName, render } = option;
return render ? (
render(option)
) : (
<div
key={value}
className={classNames(styles.option, customClassName, {
[styles.selected]: router.asPath === value,
})}
onClick={e => onSelect(value, e)}
>
{label}
</div>
);
})}
</div>
);
}
NavMenu.propTypes = {
options: PropTypes.arrayOf(
PropTypes.shape({
label: PropTypes.node,
value: PropTypes.any,
className: PropTypes.string,
render: PropTypes.func,
}),
),
className: PropTypes.string,
onSelect: PropTypes.func,
};
export default NavMenu;

View file

@ -1,22 +0,0 @@
.menu {
color: var(--base800);
border: 1px solid var(--base500);
border-radius: 4px;
overflow: hidden;
z-index: 2;
}
.option {
padding: 8px 16px;
cursor: pointer;
border-radius: 4px;
}
.option:hover {
background: var(--base75);
}
.selected {
color: var(--base900);
font-weight: 600;
}