fix: Wide selection of comment toolbar fixes (#5160

* fix: Margin on floating toolbar
fix: Flash of toolbar on wide screens

* fix: Nesting of comment marks

* fix: Post button not visible when there is a draft comment, makes it look like the comment is saved
fix: Styling of link editor results now matches other menus
fix: Allow small link editor in comments sidebar

* fix: Cannot use arrow keys to navigate suggested links
Added animation to link suggestions
Added mixin for text ellipsis

* fix: Link input appears non-rounded when no creation option

* Accidental removal
This commit is contained in:
Tom Moor
2023-04-07 18:52:57 -04:00
committed by GitHub
parent a5c44ee961
commit c202198d61
28 changed files with 211 additions and 171 deletions

View File

@@ -4,6 +4,7 @@ import { Link } from "react-router-dom";
import styled from "styled-components";
import Flex from "~/components/Flex";
import BreadcrumbMenu from "~/menus/BreadcrumbMenu";
import { ellipsis } from "~/styles";
import { MenuInternalLink } from "~/types";
type Props = {
@@ -64,6 +65,7 @@ const Slash = styled(GoToIcon)`
`;
const Item = styled(Link)<{ $highlight: boolean; $withIcon: boolean }>`
${ellipsis()}
display: flex;
flex-shrink: 1;
min-width: 0;
@@ -71,9 +73,6 @@ const Item = styled(Link)<{ $highlight: boolean; $withIcon: boolean }>`
color: ${(props) => props.theme.text};
font-size: 15px;
height: 24px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
font-weight: ${(props) => (props.$highlight ? "500" : "inherit")};
margin-left: ${(props) => (props.$withIcon ? "4px" : "0")};

View File

@@ -4,6 +4,7 @@ import * as React from "react";
import styled, { css, useTheme } from "styled-components";
import Flex from "~/components/Flex";
import Key from "~/components/Key";
import { ellipsis } from "~/styles";
type Props = {
action: ActionImpl;
@@ -85,8 +86,7 @@ const Ancestor = styled.span`
`;
const Content = styled(Flex)`
overflow: hidden;
text-overflow: ellipsis;
${ellipsis()}
flex-shrink: 1;
`;
@@ -102,9 +102,7 @@ const Item = styled.div<{ active?: boolean }>`
justify-content: space-between;
cursor: var(--pointer);
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
${ellipsis()}
user-select: none;
min-width: 0;

View File

@@ -13,6 +13,7 @@ import Flex from "~/components/Flex";
import NudeButton from "~/components/NudeButton";
import Time from "~/components/Time";
import useStores from "~/hooks/useStores";
import { ellipsis } from "~/styles";
import CollectionIcon from "./Icons/CollectionIcon";
import EmojiIcon from "./Icons/EmojiIcon";
import Squircle from "./Squircle";
@@ -217,14 +218,12 @@ const Content = styled(Flex)`
`;
const DocumentMeta = styled(Text)`
${ellipsis()}
display: flex;
align-items: center;
gap: 2px;
color: ${(props) => props.theme.textTertiary};
margin: 0 0 0 -2px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
`;
const DocumentLink = styled(Link)<{

View File

@@ -6,6 +6,7 @@ import breakpoint from "styled-components-breakpoint";
import Flex from "~/components/Flex";
import Disclosure from "~/components/Sidebar/components/Disclosure";
import Text from "~/components/Text";
import { ellipsis } from "~/styles";
type Props = {
selected: boolean;
@@ -70,9 +71,7 @@ function DocumentExplorerNode(
}
const Title = styled(Text)`
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
${ellipsis()}
margin: 0 4px 0 4px;
color: inherit;
`;

View File

@@ -6,6 +6,7 @@ import styled from "styled-components";
import { Node as SearchResult } from "~/components/DocumentExplorerNode";
import Flex from "~/components/Flex";
import Text from "~/components/Text";
import { ellipsis } from "~/styles";
type Props = {
selected: boolean;
@@ -73,10 +74,8 @@ const Title = styled(Text)`
`;
const Path = styled(Text)<{ $selected: boolean }>`
${ellipsis()}
padding-top: 2px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin: 0 4px 0 8px;
color: ${(props) =>
props.$selected ? props.theme.white50 : props.theme.textTertiary};

View File

@@ -11,6 +11,7 @@ import Flex from "~/components/Flex";
import Time from "~/components/Time";
import useCurrentUser from "~/hooks/useCurrentUser";
import useStores from "~/hooks/useStores";
import { ellipsis } from "~/styles";
type Props = {
showCollection?: boolean;
@@ -192,8 +193,7 @@ const Container = styled(Flex)<{ rtl?: boolean }>`
`;
const Viewed = styled.span`
text-overflow: ellipsis;
overflow: hidden;
${ellipsis()}
`;
const Modified = styled.span<{ highlight?: boolean }>`

View File

@@ -4,7 +4,7 @@ import styled from "styled-components";
import breakpoint from "styled-components-breakpoint";
import Flex from "~/components/Flex";
import Text from "~/components/Text";
import { undraggableOnDesktop } from "~/styles";
import { ellipsis, undraggableOnDesktop } from "~/styles";
const RealTextarea = styled.textarea<{ hasIcon?: boolean }>`
border: 0;
@@ -29,9 +29,7 @@ const RealInput = styled.input<{ hasIcon?: boolean }>`
color: ${(props) => props.theme.text};
height: 30px;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
${ellipsis()}
${undraggableOnDesktop()}
&:disabled,

View File

@@ -3,6 +3,7 @@ import * as React from "react";
import styled, { useTheme } from "styled-components";
import Flex from "~/components/Flex";
import NavLink from "~/components/NavLink";
import { ellipsis } from "~/styles";
export type Props = Omit<React.HTMLAttributes<HTMLAnchorElement>, "title"> & {
image?: React.ReactNode;
@@ -103,9 +104,7 @@ const Image = styled(Flex)`
const Heading = styled.p<{ $small?: boolean }>`
font-size: ${(props) => (props.$small ? 14 : 16)}px;
font-weight: 500;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
${ellipsis()}
line-height: ${(props) => (props.$small ? 1.3 : 1.2)};
margin: 0;
`;

View File

@@ -19,7 +19,17 @@ type Props = {
* Automatically animates the height of a container based on it's contents.
*/
export function ResizingHeightContainer(props: Props) {
const { hideOverflow, children, config, style } = props;
const {
hideOverflow,
children,
config = {
transition: {
duration: 0.1,
ease: "easeInOut",
},
},
style,
} = props;
const ref = React.useRef<HTMLDivElement>(null);
const { height } = useComponentSize(ref);

View File

@@ -6,7 +6,7 @@ import styled, { css } from "styled-components";
import breakpoint from "styled-components-breakpoint";
import Document from "~/models/Document";
import Highlight, { Mark } from "~/components/Highlight";
import { hover } from "~/styles";
import { ellipsis, hover } from "~/styles";
import { sharedDocumentPath } from "~/utils/routeHelpers";
type Props = {
@@ -125,8 +125,7 @@ const Heading = styled.h4<{ rtl?: boolean }>`
const Title = styled(Highlight)`
max-width: 90%;
overflow: hidden;
text-overflow: ellipsis;
${ellipsis()}
${Mark} {
padding: 0;
@@ -139,10 +138,7 @@ const ResultContext = styled(Highlight)`
font-size: 14px;
margin-top: -0.25em;
margin-bottom: 0.25em;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
${ellipsis()}
${Mark} {
padding: 0;

View File

@@ -13,13 +13,15 @@ import { useEditor } from "./EditorContext";
type Props = {
active?: boolean;
children: React.ReactNode;
width?: number;
forwardedRef?: React.RefObject<HTMLDivElement> | null;
};
const defaultPosition = {
left: -1000,
left: -10000,
top: 0,
offset: 0,
maxWidth: 1000,
visible: false,
};
@@ -48,6 +50,7 @@ function usePosition({
right: 0,
top: viewportHeight - menuHeight,
offset: 0,
maxWidth: 1000,
visible: true,
};
}
@@ -134,7 +137,7 @@ function usePosition({
const margin = 12;
const left = Math.min(
Math.min(
offsetParent.x + offsetParent.width - menuWidth,
offsetParent.x + offsetParent.width - menuWidth - margin,
window.innerWidth - margin
),
Math.max(
@@ -155,6 +158,7 @@ function usePosition({
left: Math.round(left - offsetParent.left),
top: Math.round(top - offsetParent.top),
offset: Math.round(offset),
maxWidth: offsetParent.width,
visible: true,
};
}
@@ -189,8 +193,10 @@ const FloatingToolbar = React.forwardRef(
<Wrapper
active={props.active && position.visible}
ref={menuRef}
offset={position.offset}
$offset={position.offset}
style={{
width: props.width,
maxWidth: `${position.maxWidth}px`,
top: `${position.top}px`,
left: `${position.left}px`,
}}
@@ -204,7 +210,7 @@ const FloatingToolbar = React.forwardRef(
const Wrapper = styled.div<{
active?: boolean;
offset: number;
$offset: number;
}>`
will-change: opacity, transform;
padding: 8px 16px;
@@ -234,7 +240,7 @@ const Wrapper = styled.div<{
z-index: -1;
position: absolute;
bottom: -2px;
left: calc(50% - ${(props) => props.offset || 0}px);
left: calc(50% - ${(props) => props.$offset || 0}px);
pointer-events: none;
}

View File

@@ -10,6 +10,7 @@ const Input = styled.input`
margin: 0;
outline: none;
flex-grow: 1;
min-width: 0;
@media (hover: none) and (pointer: coarse) {
font-size: 16px;

View File

@@ -3,7 +3,6 @@ import {
DocumentIcon,
CloseIcon,
PlusIcon,
TrashIcon,
OpenIcon,
} from "outline-icons";
import { Mark } from "prosemirror-model";
@@ -13,6 +12,8 @@ import * as React from "react";
import styled from "styled-components";
import { isInternalUrl, sanitizeUrl } from "@shared/utils/urls";
import Flex from "~/components/Flex";
import { ResizingHeightContainer } from "~/components/ResizingHeightContainer";
import Scrollable from "~/components/Scrollable";
import { Dictionary } from "~/hooks/useDictionary";
import { ToastOptions } from "~/types";
import Input from "./Input";
@@ -61,6 +62,7 @@ class LinkEditor extends React.Component<Props, State> {
discardInputValue = false;
initialValue = this.href;
initialSelectionLength = this.props.to - this.props.from;
resultsRef = React.createRef<HTMLDivElement>();
state: State = {
selectedIndex: -1,
@@ -122,11 +124,12 @@ class LinkEditor extends React.Component<Props, State> {
};
handleKeyDown = (event: React.KeyboardEvent): void => {
const results = this.results;
switch (event.key) {
case "Enter": {
event.preventDefault();
const { selectedIndex, value } = this.state;
const results = this.state.results[value] || [];
const { onCreateLink } = this.props;
if (selectedIndex >= 0) {
@@ -181,8 +184,7 @@ class LinkEditor extends React.Component<Props, State> {
event.preventDefault();
event.stopPropagation();
const { selectedIndex, value } = this.state;
const results = this.state.results[value] || [];
const { selectedIndex } = this.state;
const total = results.length;
const nextIndex = selectedIndex + 1;
@@ -264,10 +266,7 @@ class LinkEditor extends React.Component<Props, State> {
dispatch(state.tr.removeMark(from, to, mark));
}
if (onRemoveLink) {
onRemoveLink();
}
onRemoveLink?.();
view.focus();
};
@@ -289,14 +288,19 @@ class LinkEditor extends React.Component<Props, State> {
view.focus();
};
get results() {
const { value } = this.state;
return (
this.state.results[value.trim()] ||
this.state.results[this.state.previousValue] ||
[]
);
}
render() {
const { dictionary } = this.props;
const { value, selectedIndex } = this.state;
const results =
this.state.results[value.trim()] ||
this.state.results[this.state.previousValue] ||
[];
const results = this.results;
const looksLikeUrl = value.match(/^https?:\/\//i);
const suggestedLinkTitle = this.suggestedLinkTitle;
const isInternal = isInternalUrl(value);
@@ -307,7 +311,7 @@ class LinkEditor extends React.Component<Props, State> {
suggestedLinkTitle.length > 0 &&
!looksLikeUrl;
const showResults =
const hasResults =
!!suggestedLinkTitle && (showCreateLink || results.length > 0);
return (
@@ -339,47 +343,53 @@ class LinkEditor extends React.Component<Props, State> {
</Tooltip>
<Tooltip tooltip={dictionary.removeLink}>
<ToolbarButton onClick={this.handleRemoveLink}>
{this.initialValue ? (
<TrashIcon color="currentColor" />
) : (
<CloseIcon color="currentColor" />
)}
<CloseIcon color="currentColor" />
</ToolbarButton>
</Tooltip>
{showResults && (
<SearchResults id="link-search-results">
{results.map((result, index) => (
<LinkSearchResult
key={result.url}
title={result.title}
subtitle={result.subtitle}
icon={<DocumentIcon color="currentColor" />}
onPointerMove={() => this.handleFocusLink(index)}
onClick={this.handleSelectLink(result.url, result.title)}
selected={index === selectedIndex}
/>
))}
<SearchResults
ref={this.resultsRef}
$hasResults={hasResults}
role="menu"
>
<ResizingHeightContainer>
{hasResults && (
<>
{results.map((result, index) => (
<LinkSearchResult
key={result.url}
title={result.title}
subtitle={result.subtitle}
icon={<DocumentIcon color="currentColor" />}
onPointerMove={() => this.handleFocusLink(index)}
onClick={this.handleSelectLink(result.url, result.title)}
selected={index === selectedIndex}
containerRef={this.resultsRef}
/>
))}
{showCreateLink && (
<LinkSearchResult
key="create"
title={suggestedLinkTitle}
subtitle={dictionary.createNewDoc}
icon={<PlusIcon color="currentColor" />}
onPointerMove={() => this.handleFocusLink(results.length)}
onClick={() => {
this.handleCreateLink(suggestedLinkTitle);
{showCreateLink && (
<LinkSearchResult
key="create"
containerRef={this.resultsRef}
title={suggestedLinkTitle}
subtitle={dictionary.createNewDoc}
icon={<PlusIcon color="currentColor" />}
onPointerMove={() => this.handleFocusLink(results.length)}
onClick={() => {
this.handleCreateLink(suggestedLinkTitle);
if (this.initialSelectionLength) {
this.moveSelectionToEnd();
}
}}
selected={results.length === selectedIndex}
/>
if (this.initialSelectionLength) {
this.moveSelectionToEnd();
}
}}
selected={results.length === selectedIndex}
/>
)}
</>
)}
</SearchResults>
)}
</ResizingHeightContainer>
</SearchResults>
</Wrapper>
);
}
@@ -388,25 +398,20 @@ class LinkEditor extends React.Component<Props, State> {
const Wrapper = styled(Flex)`
margin-left: -8px;
margin-right: -8px;
min-width: 336px;
pointer-events: all;
gap: 8px;
`;
const SearchResults = styled.ol`
const SearchResults = styled(Scrollable)<{ $hasResults: boolean }>`
background: ${(props) => props.theme.toolbarBackground};
position: absolute;
top: 100%;
width: 100%;
height: auto;
left: 0;
padding: 0;
margin: 0;
margin-top: -3px;
margin-bottom: 0;
margin: -8px 0 0;
border-radius: 0 0 4px 4px;
overflow-y: auto;
overscroll-behavior: none;
padding: ${(props) => (props.$hasResults ? "8px 0" : "0")};
max-height: 260px;
@media (hover: none) and (pointer: coarse) {

View File

@@ -1,15 +1,24 @@
import * as React from "react";
import scrollIntoView from "smooth-scroll-into-view-if-needed";
import styled from "styled-components";
import { ellipsis } from "~/styles";
type Props = React.HTMLAttributes<HTMLLIElement> & {
type Props = React.HTMLAttributes<HTMLDivElement> & {
icon: React.ReactNode;
selected: boolean;
title: React.ReactNode;
subtitle?: React.ReactNode;
containerRef: React.RefObject<HTMLDivElement>;
};
function LinkSearchResult({ title, subtitle, selected, icon, ...rest }: Props) {
function LinkSearchResult({
title,
subtitle,
containerRef,
selected,
icon,
...rest
}: Props) {
const ref = React.useCallback(
(node: HTMLElement | null) => {
if (selected && node) {
@@ -17,36 +26,46 @@ function LinkSearchResult({ title, subtitle, selected, icon, ...rest }: Props) {
scrollMode: "if-needed",
block: "center",
boundary: (parent) => {
// All the parent elements of your target are checked until they
// reach the #link-search-results. Prevents body and other parent
// elements from being scrolled
return parent.id !== "link-search-results";
// Prevents body and other parent elements from being scrolled
return parent !== containerRef.current;
},
});
}
},
[selected]
[containerRef, selected]
);
return (
<ListItem ref={ref} compact={!subtitle} selected={selected} {...rest}>
<IconWrapper>{icon}</IconWrapper>
<div>
<ListItem
ref={ref}
compact={!subtitle}
selected={selected}
role="menuitem"
{...rest}
>
<IconWrapper selected={selected}>{icon}</IconWrapper>
<Content>
<Title>{title}</Title>
{subtitle ? <Subtitle selected={selected}>{subtitle}</Subtitle> : null}
</div>
</Content>
</ListItem>
);
}
const IconWrapper = styled.span`
flex-shrink: 0;
margin-right: 4px;
opacity: 0.8;
color: ${(props) => props.theme.toolbarItem};
const Content = styled.div`
overflow: hidden;
`;
const ListItem = styled.li<{
const IconWrapper = styled.span<{ selected: boolean }>`
flex-shrink: 0;
margin-right: 4px;
height: 24px;
opacity: 0.8;
color: ${(props) =>
props.selected ? props.theme.accentText : props.theme.toolbarItem};
`;
const ListItem = styled.div<{
selected: boolean;
compact: boolean;
}>`
@@ -54,9 +73,11 @@ const ListItem = styled.li<{
align-items: center;
padding: 8px;
border-radius: 4px;
color: ${(props) => props.theme.toolbarItem};
margin: 0 8px;
color: ${(props) =>
props.selected ? props.theme.accentText : props.theme.toolbarItem};
background: ${(props) =>
props.selected ? props.theme.toolbarHoverBackground : "transparent"};
props.selected ? props.theme.accent : "transparent"};
font-family: ${(props) => props.theme.fontFamily};
text-decoration: none;
overflow: hidden;
@@ -68,6 +89,7 @@ const ListItem = styled.li<{
`;
const Title = styled.div`
${ellipsis()}
font-size: 14px;
font-weight: 500;
`;
@@ -75,6 +97,7 @@ const Title = styled.div`
const Subtitle = styled.div<{
selected: boolean;
}>`
${ellipsis()}
font-size: 13px;
opacity: ${(props) => (props.selected ? 0.75 : 0.5)};
`;

View File

@@ -128,7 +128,7 @@ export default function LinkToolbar({
const active = isActive(view, rest.isActive);
return (
<FloatingToolbar ref={menuRef} active={active}>
<FloatingToolbar ref={menuRef} active={active} width={336}>
{active && (
<LinkEditor
key={`${selection.from}-${selection.to}`}

View File

@@ -222,9 +222,15 @@ export default function SelectionToolbar(props: Props) {
return null;
}
const showLinkToolbar = link && range;
return (
<FloatingToolbar active={isActive} ref={menuRef}>
{link && range ? (
<FloatingToolbar
active={isActive}
ref={menuRef}
width={showLinkToolbar ? 336 : undefined}
>
{showLinkToolbar ? (
<LinkEditor
key={`${range.from}-${range.to}`}
dictionary={dictionary}

View File

@@ -770,6 +770,31 @@ export class Editor extends React.PureComponent<
/>
{!readOnly && this.view && (
<>
{this.marks.link && (
<LinkToolbar
isActive={this.state.linkMenuOpen}
onCreateLink={this.props.onCreateLink}
onSearchLink={this.props.onSearchLink}
onClickLink={this.props.onClickLink}
onClose={this.handleCloseLinkMenu}
/>
)}
{this.nodes.emoji && (
<EmojiMenu
rtl={isRTL}
isActive={this.state.emojiMenuOpen}
search={this.state.blockMenuSearch}
onClose={this.handleCloseEmojiMenu}
/>
)}
{this.nodes.mention && (
<MentionMenu
rtl={isRTL}
isActive={this.state.mentionMenuOpen}
search={this.state.blockMenuSearch}
onClose={this.handleCloseMentionMenu}
/>
)}
<SelectionToolbar
rtl={isRTL}
isTemplate={this.props.template === true}
@@ -779,25 +804,6 @@ export class Editor extends React.PureComponent<
onClickLink={this.props.onClickLink}
onCreateLink={this.props.onCreateLink}
/>
<LinkToolbar
isActive={this.state.linkMenuOpen}
onCreateLink={this.props.onCreateLink}
onSearchLink={this.props.onSearchLink}
onClickLink={this.props.onClickLink}
onClose={this.handleCloseLinkMenu}
/>
<EmojiMenu
rtl={isRTL}
isActive={this.state.emojiMenuOpen}
search={this.state.blockMenuSearch}
onClose={this.handleCloseEmojiMenu}
/>
<MentionMenu
rtl={isRTL}
isActive={this.state.mentionMenuOpen}
search={this.state.blockMenuSearch}
onClose={this.handleCloseMentionMenu}
/>
<BlockMenu
rtl={isRTL}
isActive={this.state.blockMenuOpen}

View File

@@ -45,6 +45,7 @@ import usePolicy from "~/hooks/usePolicy";
import useRequest from "~/hooks/useRequest";
import useStores from "~/hooks/useStores";
import useToasts from "~/hooks/useToasts";
import { ellipsis } from "~/styles";
import { MenuItem } from "~/types";
import { editDocumentUrl, newDocumentPath } from "~/utils/routeHelpers";
@@ -351,9 +352,7 @@ const Style = styled.div`
`;
const CollectionName = styled.div`
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
${ellipsis()}
`;
export default observer(DocumentMenu);

View File

@@ -12,6 +12,7 @@ import CollectionIcon from "~/components/Icons/CollectionIcon";
import useCurrentTeam from "~/hooks/useCurrentTeam";
import usePolicy from "~/hooks/usePolicy";
import useStores from "~/hooks/useStores";
import { ellipsis } from "~/styles";
import { MenuItem } from "~/types";
import { newDocumentPath } from "~/utils/routeHelpers";
@@ -67,9 +68,7 @@ function NewTemplateMenu() {
}
const CollectionName = styled.div`
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
${ellipsis()}
`;
export default observer(NewTemplateMenu);

View File

@@ -11,6 +11,7 @@ import MenuItem from "~/components/ContextMenu/MenuItem";
import Separator from "~/components/ContextMenu/Separator";
import useCurrentUser from "~/hooks/useCurrentUser";
import useStores from "~/hooks/useStores";
import { ellipsis } from "~/styles";
import { replaceTitleVariables } from "~/utils/date";
type Props = {
@@ -81,9 +82,7 @@ function TemplatesMenu({ onSelectTemplate, document }: Props) {
const TemplateItem = styled.div`
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
${ellipsis()}
`;
const Author = styled.div`

View File

@@ -153,7 +153,8 @@ function CommentForm({
const handleChange = (
value: (asString: boolean, trim: boolean) => Record<string, any>
) => {
setData(value(false, true));
const text = value(true, true);
setData(text ? value(false, true) : undefined);
onTyping?.();
};
@@ -251,7 +252,7 @@ function CommentForm({
: `${t("Add a reply")}`)
}
/>
{inputFocused && (
{(inputFocused || data) && (
<Flex justify={dir === "rtl" ? "flex-end" : "flex-start"} gap={8}>
<ButtonSmall type="submit" borderOnHover>
{thread && !thread.isNew ? t("Reply") : t("Post")}

View File

@@ -173,15 +173,7 @@ function CommentThread({
</Flex>
))}
<ResizingHeightContainer
hideOverflow={false}
config={{
transition: {
duration: 0.1,
ease: "easeInOut",
},
}}
>
<ResizingHeightContainer hideOverflow={false}>
{(focused || commentsInThread.length === 0) && (
<Fade timing={100}>
<CommentForm

View File

@@ -8,7 +8,7 @@ import parseTitle from "@shared/utils/parseTitle";
import Document from "~/models/Document";
import Flex from "~/components/Flex";
import EmojiIcon from "~/components/Icons/EmojiIcon";
import { hover } from "~/styles";
import { ellipsis, hover } from "~/styles";
import { sharedDocumentPath } from "~/utils/routeHelpers";
type Props = {
@@ -42,13 +42,11 @@ const Content = styled(Flex)`
`;
const Title = styled.div`
overflow: hidden;
text-overflow: ellipsis;
${ellipsis()}
font-size: 14px;
font-weight: 500;
line-height: 1.25;
padding-top: 3px;
white-space: nowrap;
color: ${(props) => props.theme.text};
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;

View File

@@ -10,6 +10,7 @@ import Flex from "~/components/Flex";
import Scrollable from "~/components/Scrollable";
import Tooltip from "~/components/Tooltip";
import useMobile from "~/hooks/useMobile";
import { ellipsis } from "~/styles";
import { fadeIn } from "~/styles/animations";
type Props = React.HTMLAttributes<HTMLDivElement> & {
@@ -75,15 +76,13 @@ const ForwardIcon = styled(BackIcon)`
`;
const Title = styled(Flex)`
${ellipsis()}
font-size: 16px;
font-weight: 600;
text-align: center;
align-items: center;
justify-content: flex-start;
text-overflow: ellipsis;
white-space: nowrap;
user-select: none;
overflow: hidden;
width: 0;
flex-grow: 1;
`;

View File

@@ -12,6 +12,7 @@ import Text from "~/components/Text";
import useCollectionTrees from "~/hooks/useCollectionTrees";
import useStores from "~/hooks/useStores";
import useToasts from "~/hooks/useToasts";
import { ellipsis } from "~/styles";
import { flattenTree } from "~/utils/tree";
type Props = {
@@ -123,9 +124,7 @@ const Footer = styled(Flex)`
`;
const StyledText = styled(Text)`
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
${ellipsis()}
margin-bottom: 0;
`;

View File

@@ -12,6 +12,7 @@ import Text from "~/components/Text";
import useCollectionTrees from "~/hooks/useCollectionTrees";
import useStores from "~/hooks/useStores";
import useToasts from "~/hooks/useToasts";
import { ellipsis } from "~/styles";
import { flattenTree } from "~/utils/tree";
type Props = {
@@ -111,9 +112,7 @@ const Footer = styled(Flex)`
`;
const StyledText = styled(Text)`
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
${ellipsis()}
margin-bottom: 0;
`;

View File

@@ -52,3 +52,14 @@ export const hideScrollbars = () => `
display: none;
}
`;
/**
* Mixin to make text ellipse when it overflows.
*
* @returns string of CSS
*/
export const ellipsis = () => `
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
`;

View File

@@ -116,4 +116,4 @@ export const richExtensions: Nodes = [
/**
* Add commenting and mentions to a set of nodes
*/
export const withComments = (nodes: Nodes) => [...nodes, Mention, Comment];
export const withComments = (nodes: Nodes) => [Mention, Comment, ...nodes];