Align title correctly when first character is emoji

This commit is contained in:
Tom Moor 2017-07-29 16:15:04 -07:00
parent cfcdae8aa0
commit 297bf850c2
No known key found for this signature in database
GPG Key ID: 495FE29B5F21BD41
9 changed files with 51 additions and 17 deletions

View File

@ -1,5 +1,7 @@
[include]
.*/frontend/.*
.*/server/.*
.*/shared/.*
[ignore]
.*/node_modules/styled-components/.*

View File

@ -29,6 +29,7 @@ type Props = {
onImageUploadStart: Function,
onImageUploadStop: Function,
starred: boolean,
emoji: string,
readOnly: boolean,
heading?: ?React.Element<*>,
};
@ -213,6 +214,7 @@ type KeyData = {
className={cx(styles.editor, { readOnly: this.props.readOnly })}
schema={this.schema}
plugins={this.plugins}
emoji={this.props.emoji}
state={this.state.state}
onKeyDown={this.onKeyDown}
onChange={this.onChange}

View File

@ -25,6 +25,10 @@ type Context = {
starred?: boolean,
};
const Wrapper = styled.div`
margin-left: ${props => (props.hasEmoji ? '-1.2em' : 0)}
`;
const StyledStar = styled(StarIcon)`
top: 3px;
position: relative;
@ -61,10 +65,14 @@ function Heading(props: Props, { starred }: Context) {
const showStar = readOnly && !!onStar;
const showHash = readOnly && !!slugish && !showStar;
const Component = component;
const emoji = editor.props.emoji || '';
const title = node.text.trim();
const startsWithEmojiAndSpace =
emoji && title.match(new RegExp(`^${emoji}\\s`));
return (
<Component className={styles.title}>
{children}
<Wrapper hasEmoji={startsWithEmojiAndSpace}>{children}</Wrapper>
{showPlaceholder &&
<span className={styles.placeholder} contentEditable={false}>
{editor.props.placeholder}

View File

@ -5,15 +5,11 @@ import invariant from 'invariant';
import { client } from 'utils/ApiClient';
import stores from 'stores';
import ErrorsStore from 'stores/ErrorsStore';
import parseTitle from '../../shared/parseTitle';
import type { User } from 'types';
import Collection from './Collection';
const parseHeader = text => {
const firstLine = text.trim().split(/\r?\n/)[0];
return firstLine.replace(/^#/, '').trim();
};
const DEFAULT_TITLE = 'Untitled document';
class Document {
@ -31,6 +27,7 @@ class Document {
html: string;
id: string;
team: string;
emoji: string;
private: boolean = false;
starred: boolean = false;
text: string = '';
@ -181,7 +178,11 @@ class Document {
};
updateData(data: Object = {}, dirty: boolean = false) {
if (data.text) data.title = parseHeader(data.text);
if (data.text) {
const { title, emoji } = parseTitle(data.text);
data.title = title;
data.emoji = emoji;
}
if (dirty) this.hasPendingChanges = true;
this.data = data;
extendObservable(this, data);

View File

@ -203,6 +203,7 @@ type Props = {
<Editor
key={document.id}
text={document.text}
emoji={document.emoji}
onImageUploadStart={this.onImageUploadStart}
onImageUploadStop={this.onImageUploadStop}
onChange={this.onChange}

View File

@ -8,6 +8,7 @@ import isUUID from 'validator/lib/isUUID';
import { DataTypes, sequelize } from '../sequelize';
import { convertToMarkdown } from '../../frontend/utils/markdown';
import { truncateMarkdown } from '../utils/truncate';
import parseTitle from '../../shared/parseTitle';
import Revision from './Revision';
const URL_REGEX = /^[a-zA-Z0-9-]*-([a-zA-Z0-9]{10,15})$/;
@ -35,15 +36,10 @@ const createUrlId = doc => {
return (doc.urlId = doc.urlId || randomstring.generate(10));
};
const extractEmoji = doc => {
const regex = emojiRegex();
const match = regex.exec(doc.title);
if (match.length) return match[0];
return null;
};
const beforeSave = async doc => {
const { emoji } = parseTitle(doc.text);
doc.emoji = emoji;
doc.html = convertToMarkdown(doc.text);
doc.preview = truncateMarkdown(doc.text, 160);
doc.revisionCount += 1;
@ -62,7 +58,6 @@ const beforeSave = async doc => {
// We'll add the current user as revision hasn't been generated yet
ids.push(doc.lastModifiedById);
doc.collaboratorIds = _.uniq(ids);
doc.emoji = extractEmoji(doc);
return doc;
};

18
shared/parseTitle.js Normal file
View File

@ -0,0 +1,18 @@
// @flow
import emojiRegex from 'emoji-regex';
export default function parseTitle(text: string = '') {
const regex = emojiRegex();
// find and extract title
const firstLine = text.trim().split(/\r?\n/)[0];
const title = firstLine.replace(/^#/, '').trim();
// find and extract first emoji
const matches = regex.exec(title);
const firstEmoji = matches ? matches[0] : null;
const startsWithEmoji = firstEmoji && title.startsWith(firstEmoji);
const emoji = startsWithEmoji ? firstEmoji : undefined;
return { title, emoji };
}

View File

@ -26,7 +26,10 @@ module.exports = {
{
test: /\.js$/,
loader: 'babel',
include: path.join(__dirname, 'frontend'),
include: [
path.join(__dirname, 'frontend'),
path.join(__dirname, 'shared'),
]
},
{ test: /\.json$/, loader: 'json-loader' },
// inline base64 URLs for <=8k images, direct URLs for the rest

View File

@ -2499,6 +2499,10 @@ emoji-regex@^6.1.0:
version "6.4.2"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-6.4.2.tgz#a30b6fee353d406d96cfb9fa765bdc82897eff6e"
emoji-regex@^6.5.1:
version "6.5.1"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-6.5.1.tgz#9baea929b155565c11ea41c6626eaa65cef992c2"
emojilib@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/emojilib/-/emojilib-2.0.2.tgz#df91c45ede69f2d0ffd3d80acf8c72771b2a5ea1"