Assorted cleanup, minor bug fixes, styling fixes, eslint rules (#5165

* fix: Logic error in toast
fix: Remove useless component

* fix: Logout not clearing all stores

* Add icons to notification settings

* Add eslint rule to enforce spaced comment

* Add eslint rule for arrow-body-style

* Add eslint rule to enforce self-closing components

* Add menu to api key settings
Fix: Deleting webhook subscription does not remove from UI
Split webhook subscriptions into active and inactive
Styling updates
This commit is contained in:
Tom Moor
2023-04-08 08:25:20 -04:00
committed by GitHub
parent 422bdc32d9
commit db73879918
116 changed files with 792 additions and 1088 deletions

View File

@@ -26,12 +26,10 @@ const Content = styled.div`
`};
`;
const CenteredContent: React.FC<Props> = ({ children, ...rest }) => {
return (
<Container {...rest}>
<Content>{children}</Content>
</Container>
);
};
const CenteredContent: React.FC<Props> = ({ children, ...rest }) => (
<Container {...rest}>
<Content>{children}</Content>
</Container>
);
export default CenteredContent;

View File

@@ -42,7 +42,7 @@ const Circle = ({
style={{
transition: "stroke-dashoffset 0.6s ease 0s",
}}
></circle>
/>
);
};

View File

@@ -37,7 +37,7 @@ export type Placement =
| "left-start";
type Props = MenuStateReturn & {
"aria-label": string;
"aria-label"?: string;
/** The parent menu state if this is a submenu. */
parentMenuState?: MenuStateReturn;
/** Called when the context menu is opened. */

View File

@@ -131,7 +131,7 @@ const SmallSlash = styled(GoToIcon)`
vertical-align: middle;
flex-shrink: 0;
fill: ${(props) => props.theme.slate};
fill: ${(props) => props.theme.textTertiary};
opacity: 0.5;
`;

View File

@@ -63,11 +63,13 @@ function DocumentExplorer({ onSubmit, onSelect, items }: Props) {
const VERTICAL_PADDING = 6;
const HORIZONTAL_PADDING = 24;
const searchIndex = React.useMemo(() => {
return new FuzzySearch(items, ["title"], {
caseSensitive: false,
});
}, [items]);
const searchIndex = React.useMemo(
() =>
new FuzzySearch(items, ["title"], {
caseSensitive: false,
}),
[items]
);
React.useEffect(() => {
if (searchTerm) {
@@ -119,9 +121,7 @@ function DocumentExplorer({ onSubmit, onSelect, items }: Props) {
setSearchTerm(ev.target.value);
};
const isExpanded = (node: number) => {
return includes(expandedNodes, nodes[node].id);
};
const isExpanded = (node: number) => includes(expandedNodes, nodes[node].id);
const calculateInitialScrollOffset = (itemCount: number) => {
if (listRef.current) {
@@ -169,9 +169,7 @@ function DocumentExplorer({ onSubmit, onSelect, items }: Props) {
return selectedNodeId === nodeId;
};
const hasChildren = (node: number) => {
return nodes[node].children.length > 0;
};
const hasChildren = (node: number) => nodes[node].children.length > 0;
const toggleCollapse = (node: number) => {
if (!hasChildren(node)) {
@@ -275,13 +273,9 @@ function DocumentExplorer({ onSubmit, onSelect, items }: Props) {
inputSearchRef.current?.focus();
};
const next = () => {
return Math.min(activeNode + 1, nodes.length - 1);
};
const next = () => Math.min(activeNode + 1, nodes.length - 1);
const prev = () => {
return Math.max(activeNode - 1, 0);
};
const prev = () => Math.max(activeNode - 1, 0);
const handleKeyDown = (ev: React.KeyboardEvent<HTMLDivElement>) => {
switch (ev.key) {

View File

@@ -116,13 +116,11 @@ function Editor(props: Props, ref: React.RefObject<SharedEditor> | null) {
const results = await documents.searchTitles(term);
return sortBy(
results.map((document: Document) => {
return {
title: document.title,
subtitle: <DocumentBreadcrumb document={document} onlyText />,
url: document.url,
};
}),
results.map((document: Document) => ({
title: document.title,
subtitle: <DocumentBreadcrumb document={document} onlyText />,
url: document.url,
})),
(document) =>
deburr(document.title)
.toLowerCase()

View File

@@ -240,29 +240,27 @@ function IconPicker({ onOpen, onClose, icon, color, onChange }: Props) {
aria-label={t("Choose icon")}
>
<Icons>
{Object.keys(icons).map((name, index) => {
return (
<MenuItem
key={name}
onClick={() => onChange(color, name)}
{...menu}
>
{(props) => (
<IconButton
style={
{
...style,
"--delay": `${index * 8}ms`,
} as React.CSSProperties
}
{...props}
>
<Icon as={icons[name].component} color={color} size={30} />
</IconButton>
)}
</MenuItem>
);
})}
{Object.keys(icons).map((name, index) => (
<MenuItem
key={name}
onClick={() => onChange(color, name)}
{...menu}
>
{(props) => (
<IconButton
style={
{
...style,
"--delay": `${index * 8}ms`,
} as React.CSSProperties
}
{...props}
>
<Icon as={icons[name].component} color={color} size={30} />
</IconButton>
)}
</MenuItem>
))}
</Icons>
<Colors>
<React.Suspense

View File

@@ -46,9 +46,8 @@ export type Props = {
onChange?: (value: string | null) => void;
};
const getOptionFromValue = (options: Option[], value: string | null) => {
return options.find((option) => option.value === value);
};
const getOptionFromValue = (options: Option[], value: string | null) =>
options.find((option) => option.value === value);
const InputSelect = (props: Props) => {
const {

View File

@@ -14,18 +14,16 @@ type Props = {
body?: PlaceholderTextProps;
};
const Placeholder = ({ count, className, header, body }: Props) => {
return (
<Fade>
{times(count || 2, (index) => (
<Item key={index} className={className} column auto>
<PlaceholderText {...header} header delay={0.2 * index} />
<PlaceholderText {...body} delay={0.2 * index} />
</Item>
))}
</Fade>
);
};
const Placeholder = ({ count, className, header, body }: Props) => (
<Fade>
{times(count || 2, (index) => (
<Item key={index} className={className} column auto>
<PlaceholderText {...header} header delay={0.2 * index} />
<PlaceholderText {...body} delay={0.2 * index} />
</Item>
))}
</Fade>
);
const Item = styled(Flex)`
padding: 10px 0;

View File

@@ -2,13 +2,11 @@ import * as React from "react";
import styled, { keyframes } from "styled-components";
import { depths, s } from "@shared/styles";
const LoadingIndicatorBar = () => {
return (
<Container>
<Loader />
</Container>
);
};
const LoadingIndicatorBar = () => (
<Container>
<Loader />
</Container>
);
const loadingFrame = keyframes`
from { margin-left: -100%; }

View File

@@ -9,24 +9,22 @@ type Props = {
description?: JSX.Element;
};
const Notice: React.FC<Props> = ({ children, icon, description }) => {
return (
<Container>
<Flex as="span" gap={8}>
{icon}
<span>
<Title>{children}</Title>
{description && (
<>
<br />
{description}
</>
)}
</span>
</Flex>
</Container>
);
};
const Notice: React.FC<Props> = ({ children, icon, description }) => (
<Container>
<Flex as="span" gap={8}>
{icon}
<span>
<Title>{children}</Title>
{description && (
<>
<br />
{description}
</>
)}
</span>
</Flex>
</Container>
);
const Title = styled.span`
font-weight: 500;

View File

@@ -1,29 +0,0 @@
import * as React from "react";
import Notice from "~/components/Notice";
const NoticeAlert: React.FC = ({ children }) => {
return (
<Notice>
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
style={{
position: "relative",
top: "2px",
marginRight: "4px",
}}
>
<path
d="M15.6676 11.5372L10.0155 1.14735C9.10744 -0.381434 6.89378 -0.383465 5.98447 1.14735L0.332715 11.5372C-0.595598 13.0994 0.528309 15.0776 2.34778 15.0776H13.652C15.47 15.0776 16.5959 13.101 15.6676 11.5372ZM8 13.2026C7.48319 13.2026 7.0625 12.7819 7.0625 12.2651C7.0625 11.7483 7.48319 11.3276 8 11.3276C8.51681 11.3276 8.9375 11.7483 8.9375 12.2651C8.9375 12.7819 8.51681 13.2026 8 13.2026ZM8.9375 9.45257C8.9375 9.96938 8.51681 10.3901 8 10.3901C7.48319 10.3901 7.0625 9.96938 7.0625 9.45257V4.76507C7.0625 4.24826 7.48319 3.82757 8 3.82757C8.51681 3.82757 8.9375 4.24826 8.9375 4.76507V9.45257Z"
fill="currentColor"
/>
</svg>{" "}
{children}
</Notice>
);
};
export default NoticeAlert;

View File

@@ -21,32 +21,30 @@ const Scene: React.FC<Props> = ({
left,
children,
centered,
}) => {
return (
<FillWidth>
<PageTitle title={textTitle || title} />
<Header
hasSidebar
title={
icon ? (
<>
{icon}&nbsp;{title}
</>
) : (
title
)
}
actions={actions}
left={left}
/>
{centered !== false ? (
<CenteredContent withStickyHeader>{children}</CenteredContent>
) : (
children
)}
</FillWidth>
);
};
}) => (
<FillWidth>
<PageTitle title={textTitle || title} />
<Header
hasSidebar
title={
icon ? (
<>
{icon}&nbsp;{title}
</>
) : (
title
)
}
actions={actions}
left={left}
/>
{centered !== false ? (
<CenteredContent withStickyHeader>{children}</CenteredContent>
) : (
children
)}
</FillWidth>
);
const FillWidth = styled.div`
width: 100%;

View File

@@ -158,21 +158,19 @@ function SearchPopover({ shareId }: Props) {
return (
<>
<PopoverDisclosure {...popover}>
{(props) => {
{(props) => (
// props assumes the disclosure is a button, but we want a type-ahead
// so we take the aria props, and ref and ignore the event handlers
return (
<StyledInputSearch
aria-controls={props["aria-controls"]}
aria-expanded={props["aria-expanded"]}
aria-haspopup={props["aria-haspopup"]}
ref={props.ref}
onChange={handleSearchInputChange}
onFocus={handleSearchInputFocus}
onKeyDown={handleKeyDown}
/>
);
}}
<StyledInputSearch
aria-controls={props["aria-controls"]}
aria-expanded={props["aria-expanded"]}
aria-haspopup={props["aria-haspopup"]}
ref={props.ref}
onChange={handleSearchInputChange}
onFocus={handleSearchInputFocus}
onKeyDown={handleKeyDown}
/>
)}
</PopoverDisclosure>
<Popover
{...popover}

View File

@@ -34,9 +34,7 @@ function Collections() {
fractionalIndex(null, orderedCollections[0].index)
);
},
canDrop: (item) => {
return item.id !== orderedCollections[0].id;
},
canDrop: (item) => item.id !== orderedCollections[0].id,
collect: (monitor) => ({
isCollectionDropping: monitor.isOver(),
isDraggingAnyCollection: monitor.getItemType() === "collection",

View File

@@ -76,18 +76,20 @@ function InnerDocumentLink(
[collection, node]
);
const showChildren = React.useMemo(() => {
return !!(
hasChildDocuments &&
activeDocument &&
collection &&
(collection
.pathToDocument(activeDocument.id)
.map((entry) => entry.id)
.includes(node.id) ||
isActiveDocument)
);
}, [hasChildDocuments, activeDocument, isActiveDocument, node, collection]);
const showChildren = React.useMemo(
() =>
!!(
hasChildDocuments &&
activeDocument &&
collection &&
(collection
.pathToDocument(activeDocument.id)
.map((entry) => entry.id)
.includes(node.id) ||
isActiveDocument)
),
[hasChildDocuments, activeDocument, isActiveDocument, node, collection]
);
const [expanded, setExpanded] = React.useState(showChildren);

View File

@@ -56,12 +56,9 @@ function DraggableCollectionLink({
fractionalIndex(collection.index, belowCollectionIndex)
);
},
canDrop: (item) => {
return (
collection.id !== item.id &&
(!belowCollection || item.id !== belowCollection.id)
);
},
canDrop: (item) =>
collection.id !== item.id &&
(!belowCollection || item.id !== belowCollection.id),
collect: (monitor: DropTargetMonitor<Collection, Collection>) => ({
isCollectionDropping: monitor.isOver(),
isDraggingAnyCollection: monitor.canDrop(),

View File

@@ -21,15 +21,13 @@ const resolveToLocation = (
const normalizeToLocation = (
to: LocationDescriptor,
currentLocation: Location
) => {
return typeof to === "string"
) =>
typeof to === "string"
? createLocation(to, null, undefined, currentLocation)
: to;
};
const joinClassnames = (...classnames: (string | undefined)[]) => {
return classnames.filter((i) => i).join(" ");
};
const joinClassnames = (...classnames: (string | undefined)[]) =>
classnames.filter((i) => i).join(" ");
export type Props = React.AnchorHTMLAttributes<HTMLAnchorElement> & {
activeClassName?: string;
@@ -103,16 +101,13 @@ const NavLink = ({
}, [linkRef, scrollIntoViewIfNeeded, isActive]);
const shouldFastClick = React.useCallback(
(event: React.MouseEvent<HTMLAnchorElement>): boolean => {
return (
event.button === 0 && // Only intercept left clicks
!event.defaultPrevented &&
!rest.target &&
!event.altKey &&
!event.metaKey &&
!event.ctrlKey
);
},
(event: React.MouseEvent<HTMLAnchorElement>): boolean =>
event.button === 0 && // Only intercept left clicks
!event.defaultPrevented &&
!rest.target &&
!event.altKey &&
!event.metaKey &&
!event.ctrlKey,
[rest.target]
);
@@ -153,7 +148,7 @@ const NavLink = ({
<Link
key={isActive ? "active" : "inactive"}
ref={linkRef}
//onMouseDown={handleClick}
// onMouseDown={handleClick}
onKeyDown={(event) => {
if (["Enter", " "].includes(event.key)) {
navigateTo();

View File

@@ -42,9 +42,9 @@ function DocumentLink(
!!node.children.length || activeDocument?.parentDocumentId === node.id;
const document = documents.get(node.id);
const showChildren = React.useMemo(() => {
return !!hasChildDocuments;
}, [hasChildDocuments]);
const showChildren = React.useMemo(() => !!hasChildDocuments, [
hasChildDocuments,
]);
const [expanded, setExpanded] = React.useState(showChildren);
@@ -111,9 +111,7 @@ function DocumentLink(
scrollIntoViewIfNeeded={!document?.isStarred}
isDraft={isDraft}
ref={ref}
isActive={() => {
return !!isActiveDocument;
}}
isActive={() => !!isActiveDocument}
/>
{expanded &&
nodeChildren.map((childNode, index) => (

View File

@@ -6,7 +6,6 @@ import { useTranslation } from "react-i18next";
import Star from "~/models/Star";
import Flex from "~/components/Flex";
import useStores from "~/hooks/useStores";
import useToasts from "~/hooks/useToasts";
import DropCursor from "./DropCursor";
import Header from "./Header";
import PlaceholderCollections from "./PlaceholderCollections";
@@ -22,7 +21,6 @@ function Starred() {
const [displayedStarsCount, setDisplayedStarsCount] = React.useState(
STARRED_PAGINATION_LIMIT
);
const { showToast } = useToasts();
const { stars } = useStores();
const { t } = useTranslation();
@@ -34,13 +32,10 @@ function Starred() {
offset,
});
} catch (error) {
showToast(t("Starred documents could not be loaded"), {
type: "error",
});
setFetchError(error);
}
},
[stars, showToast, t]
[stars]
);
React.useEffect(() => {

View File

@@ -22,7 +22,7 @@ export default function Spinner({ color, ...props }: Props) {
cx="8"
cy="8"
r="6"
></Circle>
/>
</SVG>
);
}

View File

@@ -7,23 +7,21 @@ type Props = {
color?: string;
};
const Squircle: React.FC<Props> = ({ color, size = 28, children }) => {
return (
<Wrapper
style={{ width: size, height: size }}
align="center"
justify="center"
>
<svg width={size} height={size} viewBox="0 0 28 28">
<path
fill={color}
d="M0 11.1776C0 1.97285 1.97285 0 11.1776 0H16.8224C26.0272 0 28 1.97285 28 11.1776V16.8224C28 26.0272 26.0272 28 16.8224 28H11.1776C1.97285 28 0 26.0272 0 16.8224V11.1776Z"
/>
</svg>
<Content>{children}</Content>
</Wrapper>
);
};
const Squircle: React.FC<Props> = ({ color, size = 28, children }) => (
<Wrapper
style={{ width: size, height: size }}
align="center"
justify="center"
>
<svg width={size} height={size} viewBox="0 0 28 28">
<path
fill={color}
d="M0 11.1776C0 1.97285 1.97285 0 11.1776 0H16.8224C26.0272 0 28 1.97285 28 11.1776V16.8224C28 26.0272 26.0272 28 16.8224 28H11.1776C1.97285 28 0 26.0272 0 16.8224V11.1776Z"
/>
</svg>
<Content>{children}</Content>
</Wrapper>
);
const Wrapper = styled(Flex)`
position: relative;

View File

@@ -34,14 +34,12 @@ const Background = styled.div<{ sticky?: boolean }>`
z-index: 1;
`;
const Subheading: React.FC<Props> = ({ children, sticky, ...rest }) => {
return (
<Background sticky={sticky}>
<H3 {...rest}>
<Underline>{children}</Underline>
</H3>
</Background>
);
};
const Subheading: React.FC<Props> = ({ children, sticky, ...rest }) => (
<Background sticky={sticky}>
<H3 {...rest}>
<Underline>{children}</Underline>
</H3>
</Background>
);
export default Subheading;

View File

@@ -17,6 +17,7 @@ const TabLink = styled(NavLink)`
font-size: 14px;
cursor: var(--pointer);
color: ${s("textTertiary")};
user-select: none;
margin-right: 24px;
padding: 6px 0;

View File

@@ -195,23 +195,21 @@ export const Placeholder = ({
}: {
columns: number;
rows?: number;
}) => {
return (
<DelayedMount>
<tbody>
{new Array(rows).fill(1).map((_, row) => (
<Row key={row}>
{new Array(columns).fill(1).map((_, col) => (
<Cell key={col}>
<PlaceholderText minWidth={25} maxWidth={75} />
</Cell>
))}
</Row>
))}
</tbody>
</DelayedMount>
);
};
}) => (
<DelayedMount>
<tbody>
{new Array(rows).fill(1).map((_, row) => (
<Row key={row}>
{new Array(columns).fill(1).map((_, col) => (
<Cell key={col}>
<PlaceholderText minWidth={25} maxWidth={75} />
</Cell>
))}
</Row>
))}
</tbody>
</DelayedMount>
);
const Anchor = styled.div`
top: -32px;

View File

@@ -61,8 +61,9 @@ function Toast({ closeAfterMs = 3000, onRequestClose, toast }: Props) {
{type === "loading" && <Spinner color="currentColor" />}
{type === "info" && <InfoIcon color="currentColor" />}
{type === "success" && <CheckboxIcon checked color="currentColor" />}
{type === "warning" ||
(type === "error" && <WarningIcon color="currentColor" />)}
{(type === "warning" || type === "error") && (
<WarningIcon color="currentColor" />
)}
<Message>{toast.message}</Message>
{action && <Action onClick={action.onClick}>{action.text}</Action>}
</Container>