Files
outline/shared/editor/components/Widget.tsx
Tom Moor 631d600920 feat: File attachments (#3031)
* stash

* refactor, working in non-collab + collab editor

* attachment styling

* Avoid crypto require in browser

* AttachmentIcon, handling unknown types

* Do not allow attachment creation for file sizes over limit

* Allow image as file attachment

* Upload placeholder styling

* lint

* Refactor: Do not use placeholder for file attachmentuploads

* Add loading spinner

* fix: Extra paragraphs around attachments on insert

* Bump editor

* fix build error

* Remove attachment placeholder when upload fails

* Remove unused styles

* fix: Attachments on shared pages

* Merge fixes
2022-03-06 13:58:58 -08:00

99 lines
2.1 KiB
TypeScript

import * as React from "react";
import styled, { css, DefaultTheme, ThemeProps } from "styled-components";
type Props = {
icon: React.ReactNode;
title: React.ReactNode;
context?: React.ReactNode;
href: string;
isSelected: boolean;
children?: React.ReactNode;
};
export default function Widget(props: Props & ThemeProps<DefaultTheme>) {
return (
<Wrapper
className={
props.isSelected ? "ProseMirror-selectednode widget" : "widget"
}
href={props.href}
target="_blank"
rel="noreferrer nofollow"
>
{props.icon}
<Preview>
<Title>{props.title}</Title>
<Subtitle>{props.context}</Subtitle>
<Children>{props.children}</Children>
</Preview>
</Wrapper>
);
}
const Children = styled.div`
margin-left: auto;
height: 20px;
opacity: 0;
&:hover {
color: ${(props) => props.theme.text};
}
`;
const Title = styled.strong`
font-weight: 500;
font-size: 14px;
color: ${(props) => props.theme.text};
`;
const Preview = styled.div`
gap: 8px;
display: flex;
flex-direction: row;
flex-grow: 1;
align-items: center;
color: ${(props) => props.theme.textTertiary};
`;
const Subtitle = styled.span`
font-size: 13px;
color: ${(props) => props.theme.textTertiary} !important;
line-height: 0;
`;
const Wrapper = styled.a`
display: flex;
align-items: center;
gap: 6px;
background: ${(props) => props.theme.background};
color: ${(props) => props.theme.text} !important;
outline: 1px solid ${(props) => props.theme.divider};
white-space: nowrap;
border-radius: 8px;
padding: 6px 8px;
max-width: 840px;
cursor: default;
user-select: none;
text-overflow: ellipsis;
overflow: hidden;
${(props) =>
props.href &&
css`
&:hover,
&:active,
&:focus,
&:focus:not(.focus-visible) {
cursor: pointer !important;
text-decoration: none !important;
background: ${(props) => props.theme.secondaryBackground};
outline: 1px solid ${(props) => props.theme.divider};
${Children} {
opacity: 1;
}
}
`}
`;