RTL document support (#2263)
* Basic RTL support in documents * fix: DocumentListItem and ReferenceListItem for RTL content
This commit is contained in:
@ -46,7 +46,7 @@ export default function ContextMenu({
|
||||
<Menu hideOnClickOutside preventBodyScroll {...rest}>
|
||||
{(props) => (
|
||||
<Position {...props}>
|
||||
<Background>
|
||||
<Background dir="auto">
|
||||
{rest.visible || rest.animating ? children : null}
|
||||
</Background>
|
||||
</Position>
|
||||
|
@ -69,6 +69,7 @@ function DocumentListItem(props: Props, ref) {
|
||||
return (
|
||||
<DocumentLink
|
||||
ref={ref}
|
||||
dir={document.dir}
|
||||
$isStarred={document.isStarred}
|
||||
$menuOpen={menuOpen}
|
||||
to={{
|
||||
@ -77,8 +78,12 @@ function DocumentListItem(props: Props, ref) {
|
||||
}}
|
||||
>
|
||||
<Content>
|
||||
<Heading>
|
||||
<Title text={document.titleWithDefault} highlight={highlight} />
|
||||
<Heading dir={document.dir}>
|
||||
<Title
|
||||
text={document.titleWithDefault}
|
||||
highlight={highlight}
|
||||
dir={document.dir}
|
||||
/>
|
||||
{document.isNew && document.createdBy.id !== currentUser.id && (
|
||||
<Badge yellow>{t("New")}</Badge>
|
||||
)}
|
||||
@ -222,6 +227,7 @@ const DocumentLink = styled(Link)`
|
||||
|
||||
const Heading = styled.h3`
|
||||
display: flex;
|
||||
justify-content: ${(props) => (props.rtl ? "flex-end" : "flex-start")};
|
||||
align-items: center;
|
||||
height: 24px;
|
||||
margin-top: 0;
|
||||
|
@ -11,6 +11,7 @@ import Time from "components/Time";
|
||||
import useStores from "hooks/useStores";
|
||||
|
||||
const Container = styled(Flex)`
|
||||
justify-content: ${(props) => (props.rtl ? "flex-end" : "flex-start")};
|
||||
color: ${(props) => props.theme.textTertiary};
|
||||
font-size: 13px;
|
||||
white-space: nowrap;
|
||||
@ -135,7 +136,7 @@ function DocumentMeta({
|
||||
: 0;
|
||||
|
||||
return (
|
||||
<Container align="center" {...rest}>
|
||||
<Container align="center" rtl={document.dir === "rtl"} {...rest} dir="ltr">
|
||||
{updatedByMe ? t("You") : updatedBy.name}
|
||||
{to ? <Link to={to}>{content}</Link> : content}
|
||||
{showCollection && collection && (
|
||||
|
@ -14,6 +14,7 @@ type Props = {|
|
||||
document: Document,
|
||||
isDraft: boolean,
|
||||
to?: string,
|
||||
rtl?: boolean,
|
||||
|};
|
||||
|
||||
function DocumentMetaWithViews({ to, isDraft, document, ...rest }: Props) {
|
||||
@ -62,6 +63,7 @@ function DocumentMetaWithViews({ to, isDraft, document, ...rest }: Props) {
|
||||
}
|
||||
|
||||
const Meta = styled(DocumentMeta)`
|
||||
justify-content: ${(props) => (props.rtl ? "flex-end" : "flex-start")};
|
||||
margin: -12px 0 2em 0;
|
||||
font-size: 14px;
|
||||
position: relative;
|
||||
|
@ -84,7 +84,7 @@ function SidebarLink(
|
||||
ref={ref}
|
||||
>
|
||||
{icon && <IconWrapper>{icon}</IconWrapper>}
|
||||
<Label>{label}</Label>
|
||||
<Label dir="auto">{label}</Label>
|
||||
</Link>
|
||||
{menu && <Actions showActions={showActions}>{menu}</Actions>}
|
||||
</>
|
||||
|
@ -58,6 +58,26 @@ export default class Document extends BaseModel {
|
||||
return emoji;
|
||||
}
|
||||
|
||||
/**
|
||||
* Best-guess the text direction of the document based on the language the
|
||||
* title is written in. Note: wrapping as a computed getter means that it will
|
||||
* only be called directly when the title changes.
|
||||
*/
|
||||
@computed
|
||||
get dir(): "rtl" | "ltr" {
|
||||
const element = document.createElement("p");
|
||||
element.innerHTML = this.title;
|
||||
element.style.visibility = "hidden";
|
||||
element.dir = "auto";
|
||||
|
||||
// element must appear in body for direction to be computed
|
||||
document.body?.appendChild(element);
|
||||
|
||||
const direction = window.getComputedStyle(element).direction;
|
||||
document.body?.removeChild(element);
|
||||
return direction;
|
||||
}
|
||||
|
||||
@computed
|
||||
get noun(): string {
|
||||
return this.template ? "template" : "document";
|
||||
|
@ -33,6 +33,7 @@ type Props = {|
|
||||
@observer
|
||||
class DocumentEditor extends React.Component<Props> {
|
||||
@observable activeLinkEvent: ?MouseEvent;
|
||||
@observable ref = React.createRef<HTMLDivElement | HTMLInputElement>();
|
||||
|
||||
focusAtStart = () => {
|
||||
if (this.props.innerRef.current) {
|
||||
@ -109,13 +110,17 @@ class DocumentEditor extends React.Component<Props> {
|
||||
const normalizedTitle =
|
||||
!title && readOnly ? document.titleWithDefault : title;
|
||||
|
||||
console.log(this.ref.current);
|
||||
|
||||
return (
|
||||
<Flex auto column>
|
||||
{readOnly ? (
|
||||
<Title
|
||||
as="div"
|
||||
ref={this.ref}
|
||||
$startsWithEmojiAndSpace={startsWithEmojiAndSpace}
|
||||
$isStarred={document.isStarred}
|
||||
dir="auto"
|
||||
>
|
||||
<span>{normalizedTitle}</span>{" "}
|
||||
{!shareId && <StarButton document={document} size={32} />}
|
||||
@ -123,6 +128,7 @@ class DocumentEditor extends React.Component<Props> {
|
||||
) : (
|
||||
<Title
|
||||
type="text"
|
||||
ref={this.ref}
|
||||
onChange={onChangeTitle}
|
||||
onKeyDown={this.handleTitleKeyDown}
|
||||
placeholder={document.placeholder}
|
||||
@ -130,6 +136,7 @@ class DocumentEditor extends React.Component<Props> {
|
||||
$startsWithEmojiAndSpace={startsWithEmojiAndSpace}
|
||||
autoFocus={!title}
|
||||
maxLength={MAX_TITLE_LENGTH}
|
||||
dir="auto"
|
||||
/>
|
||||
)}
|
||||
{!shareId && (
|
||||
@ -137,6 +144,11 @@ class DocumentEditor extends React.Component<Props> {
|
||||
isDraft={isDraft}
|
||||
document={document}
|
||||
to={documentHistoryUrl(document)}
|
||||
rtl={
|
||||
this.ref.current
|
||||
? window.getComputedStyle(this.ref.current).direction === "rtl"
|
||||
: false
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<Editor
|
||||
|
@ -35,7 +35,6 @@ const DocumentLink = styled(Link)`
|
||||
const Title = styled.h3`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
max-width: 90%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-size: 14px;
|
||||
@ -78,7 +77,7 @@ function ReferenceListItem({
|
||||
}}
|
||||
{...rest}
|
||||
>
|
||||
<Title>
|
||||
<Title dir="auto">
|
||||
{document.emoji ? (
|
||||
<Emoji>{document.emoji}</Emoji>
|
||||
) : (
|
||||
|
@ -123,7 +123,7 @@
|
||||
"randomstring": "1.1.5",
|
||||
"raw-loader": "^0.5.1",
|
||||
"react": "^17.0.2",
|
||||
"react-autosize-textarea": "^6.0.0",
|
||||
"react-autosize-textarea": "^7.1.0",
|
||||
"react-avatar-editor": "^11.1.0",
|
||||
"react-color": "^2.17.3",
|
||||
"react-dnd": "^14.0.1",
|
||||
@ -142,7 +142,7 @@
|
||||
"react-window": "^1.8.6",
|
||||
"reakit": "^1.3.6",
|
||||
"regenerator-runtime": "^0.13.7",
|
||||
"rich-markdown-editor": "^11.12.0",
|
||||
"rich-markdown-editor": "^11.13.0",
|
||||
"semver": "^7.3.2",
|
||||
"sequelize": "^6.3.4",
|
||||
"sequelize-cli": "^6.2.0",
|
||||
|
@ -11606,10 +11606,10 @@ retry-as-promised@^3.2.0:
|
||||
dependencies:
|
||||
any-promise "^1.3.0"
|
||||
|
||||
rich-markdown-editor@^11.12.0:
|
||||
version "11.12.0"
|
||||
resolved "https://registry.yarnpkg.com/rich-markdown-editor/-/rich-markdown-editor-11.12.0.tgz#7fd9bd80b0afcb06d2bbcb8a2d38ac2279bc3110"
|
||||
integrity sha512-mf5i/JJZktNwQnEjjQIYGzIoBvh3LAmCZoRC8EcbsACO3ISgOcNdccmdd0utZMs4QHASUgE+eBjtM+awvhIPqw==
|
||||
rich-markdown-editor@^11.13.0:
|
||||
version "11.13.0"
|
||||
resolved "https://registry.yarnpkg.com/rich-markdown-editor/-/rich-markdown-editor-11.13.0.tgz#7009bddbd667c2fdcf6a7d4210913a1c040acdde"
|
||||
integrity sha512-WZLL7z0sE7kogYjpPWPbLnbWjYwCn5RLoju6Vg6WfVDVWPSRRfWo+IHSKpBAK8kP+h9pKxZItwHrHN4ShXapjA==
|
||||
dependencies:
|
||||
copy-to-clipboard "^3.0.8"
|
||||
lodash "^4.17.11"
|
||||
|
Reference in New Issue
Block a user