diff --git a/app/models/Document.ts b/app/models/Document.ts
index c57836723..5a9e03f79 100644
--- a/app/models/Document.ts
+++ b/app/models/Document.ts
@@ -96,6 +96,7 @@ export default class Document extends BaseModel {
}
}
+ @computed
get emoji() {
const { emoji } = parseTitle(this.title);
return emoji;
diff --git a/app/scenes/Document/components/Contents.tsx b/app/scenes/Document/components/Contents.tsx
index ca18242db..299ee862a 100644
--- a/app/scenes/Document/components/Contents.tsx
+++ b/app/scenes/Document/components/Contents.tsx
@@ -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;
`;
diff --git a/app/scenes/Document/components/EditableTitle.tsx b/app/scenes/Document/components/EditableTitle.tsx
index a511032ac..5ca621924 100644
--- a/app/scenes/Document/components/EditableTitle.tsx
+++ b/app/scenes/Document/components/EditableTitle.tsx
@@ -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 (
`
- 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)`
}
${breakpoint("tablet")`
- margin-left: ${(props: TitleProps) =>
- props.$startsWithEmojiAndSpace ? "-1.2em" : 0};
+ margin-left: ${(props: TitleProps) => -props.$emojiWidth}px;
`};
${AnimatedStar} {
diff --git a/package.json b/package.json
index 3bb7bd9d0..4f1921c4c 100644
--- a/package.json
+++ b/package.json
@@ -76,7 +76,7 @@
"date-fns": "^2.25.0",
"dd-trace": "^0.32.2",
"dotenv": "^4.0.0",
- "emoji-regex": "^6.5.1",
+ "emoji-regex": "^10.0.0",
"es6-error": "^4.1.1",
"exports-loader": "^0.6.4",
"fetch-retry": "^4.1.1",
@@ -140,11 +140,9 @@
"react-dropzone": "^11.3.2",
"react-helmet": "^6.1.0",
"react-i18next": "^11.13.0",
- "react-is": "^17.0.2",
"react-portal": "^4.2.0",
"react-router-dom": "^5.2.0",
"react-table": "^7.7.0",
- "react-virtual": "^2.8.2",
"react-virtualized-auto-sizer": "^1.0.5",
"react-waypoint": "^10.1.0",
"react-window": "^1.8.6",
diff --git a/server/presenters/document.ts b/server/presenters/document.ts
index 40f26f3e7..86a8e6bc8 100644
--- a/server/presenters/document.ts
+++ b/server/presenters/document.ts
@@ -44,7 +44,6 @@ export default async function present(
urlId: document.urlId,
title: document.title,
text,
- emoji: document.emoji,
tasks: document.tasks,
createdAt: document.createdAt,
createdBy: undefined,
diff --git a/shared/typings/index.d.ts b/shared/typings/index.d.ts
deleted file mode 100644
index 80af8845f..000000000
--- a/shared/typings/index.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-declare module "emoji-regex" {
- const RegExpFactory: () => RegExp;
- export = RegExpFactory;
-}
diff --git a/shared/utils/parseTitle.ts b/shared/utils/parseTitle.ts
index 67d168fe5..27e4a5e29 100644
--- a/shared/utils/parseTitle.ts
+++ b/shared/utils/parseTitle.ts
@@ -14,7 +14,7 @@ export default function parseTitle(text = "") {
// find and extract first emoji
const matches = regex.exec(title);
const firstEmoji = matches ? matches[0] : null;
- const startsWithEmoji = firstEmoji && title.startsWith(firstEmoji);
+ const startsWithEmoji = firstEmoji && title.startsWith(`${firstEmoji} `);
const emoji = startsWithEmoji ? firstEmoji : undefined;
return {
diff --git a/yarn.lock b/yarn.lock
index 99b218a75..37ce3c2d3 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5714,9 +5714,9 @@ cssstyle@^2.3.0:
cssom "~0.3.6"
csstype@^3.0.2, csstype@^3.0.4:
- version "3.0.9"
- resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.9.tgz#6410af31b26bd0520933d02cbc64fce9ce3fbf0b"
- integrity sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw==
+ version "3.0.10"
+ resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.10.tgz#2ad3a7bed70f35b965707c092e5f30b327c290e5"
+ integrity sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==
cyclist@^1.0.1:
version "1.0.1"
@@ -6262,16 +6262,11 @@ emittery@^0.8.1:
resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860"
integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==
-emoji-regex@*:
+emoji-regex@*, emoji-regex@^10.0.0:
version "10.0.0"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.0.0.tgz#96559e19f82231b436403e059571241d627c42b8"
integrity sha512-KmJa8l6uHi1HrBI34udwlzZY1jOEuID/ft4d8BSSEdRyap7PwBEt910453PJa5MuGvxkLqlt4Uvhu7tttFHViw==
-emoji-regex@^6.5.1:
- version "6.5.1"
- resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-6.5.1.tgz#9baea929b155565c11ea41c6626eaa65cef992c2"
- integrity sha512-PAHp6TxrCy7MGMFidro8uikr+zlJJKJ/Q6mm2ExZ7HwkyR9lSVFfE3kt36qcwa24BQL7y0G9axycGjK1A/0uNQ==
-
emoji-regex@^7.0.1:
version "7.0.3"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
@@ -12186,7 +12181,7 @@ react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-i
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
-react-is@^17.0.1, react-is@^17.0.2:
+react-is@^17.0.1:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==