fix: Emoji in title positioning (#2927)
* wip * fix measure on first render * wip * refactor * tsc * remove fragment * refactor (again) * cleanup
This commit is contained in:
@@ -96,8 +96,8 @@ const Sticky = styled.div`
|
||||
|
||||
box-shadow: 1px 0 0 ${(props) => props.theme.divider};
|
||||
margin-top: 40px;
|
||||
margin-right: 32px;
|
||||
width: 224px;
|
||||
margin-right: 52px;
|
||||
width: 204px;
|
||||
min-height: 40px;
|
||||
overflow-y: auto;
|
||||
`;
|
||||
|
||||
@@ -5,7 +5,6 @@ import styled from "styled-components";
|
||||
import breakpoint from "styled-components-breakpoint";
|
||||
import { MAX_TITLE_LENGTH } from "@shared/constants";
|
||||
import { light } from "@shared/theme";
|
||||
import parseTitle from "@shared/utils/parseTitle";
|
||||
import Document from "~/models/Document";
|
||||
import ContentEditable from "~/components/ContentEditable";
|
||||
import Star, { AnimatedStar } from "~/components/Star";
|
||||
@@ -27,6 +26,9 @@ type Props = {
|
||||
onSave?: (options: { publish?: boolean; done?: boolean }) => void;
|
||||
};
|
||||
|
||||
const lineHeight = "1.25";
|
||||
const fontSize = "2.25em";
|
||||
|
||||
const EditableTitle = React.forwardRef(
|
||||
(
|
||||
{
|
||||
@@ -43,8 +45,6 @@ const EditableTitle = React.forwardRef(
|
||||
const { policies } = useStores();
|
||||
const { t } = useTranslation();
|
||||
const can = policies.abilities(document.id);
|
||||
const { emoji } = parseTitle(value);
|
||||
const startsWithEmojiAndSpace = !!(emoji && value.startsWith(`${emoji} `));
|
||||
const normalizedTitle =
|
||||
!value && readOnly ? document.titleWithDefault : value;
|
||||
|
||||
@@ -88,6 +88,28 @@ const EditableTitle = React.forwardRef(
|
||||
[onGoToNextInput, onSave]
|
||||
);
|
||||
|
||||
/**
|
||||
* Measures the width of the document's emoji in the title
|
||||
*/
|
||||
const emojiWidth = React.useMemo(() => {
|
||||
const element = window.document.createElement("span");
|
||||
if (!document.emoji) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
element.innerText = `${document.emoji}\u00A0`;
|
||||
element.style.visibility = "hidden";
|
||||
element.style.position = "absolute";
|
||||
element.style.left = "-9999px";
|
||||
element.style.lineHeight = lineHeight;
|
||||
element.style.fontSize = fontSize;
|
||||
element.style.width = "max-content";
|
||||
window.document.body?.appendChild(element);
|
||||
const width = window.getComputedStyle(element).width;
|
||||
window.document.body?.removeChild(element);
|
||||
return parseInt(width, 10);
|
||||
}, [document.emoji]);
|
||||
|
||||
return (
|
||||
<Title
|
||||
onChange={onChange}
|
||||
@@ -98,7 +120,7 @@ const EditableTitle = React.forwardRef(
|
||||
: t("Start with a title…")
|
||||
}
|
||||
value={normalizedTitle}
|
||||
$startsWithEmojiAndSpace={startsWithEmojiAndSpace}
|
||||
$emojiWidth={emojiWidth}
|
||||
$isStarred={document.isStarred}
|
||||
autoFocus={!value}
|
||||
maxLength={MAX_TITLE_LENGTH}
|
||||
@@ -121,19 +143,19 @@ const StarButton = styled(Star)`
|
||||
`;
|
||||
|
||||
type TitleProps = {
|
||||
$startsWithEmojiAndSpace: boolean;
|
||||
$isStarred: boolean;
|
||||
$emojiWidth: number;
|
||||
};
|
||||
|
||||
const Title = styled(ContentEditable)<TitleProps>`
|
||||
line-height: 1.25;
|
||||
line-height: ${lineHeight};
|
||||
margin-top: 1em;
|
||||
margin-bottom: 0.5em;
|
||||
background: ${(props) => props.theme.background};
|
||||
transition: ${(props) => props.theme.backgroundTransition};
|
||||
color: ${(props) => props.theme.text};
|
||||
-webkit-text-fill-color: ${(props) => props.theme.text};
|
||||
font-size: 2.25em;
|
||||
font-size: ${fontSize};
|
||||
font-weight: 500;
|
||||
outline: none;
|
||||
border: 0;
|
||||
@@ -150,8 +172,7 @@ const Title = styled(ContentEditable)<TitleProps>`
|
||||
}
|
||||
|
||||
${breakpoint("tablet")`
|
||||
margin-left: ${(props: TitleProps) =>
|
||||
props.$startsWithEmojiAndSpace ? "-1.2em" : 0};
|
||||
margin-left: ${(props: TitleProps) => -props.$emojiWidth}px;
|
||||
`};
|
||||
|
||||
${AnimatedStar} {
|
||||
|
||||
Reference in New Issue
Block a user