feat: Full width images (#4389)
* feat: Full width images * lint * fix: Enable TOC overlaid on full size images * Vendorize react-medium-image-zoom * tsc * fix * Remove body scroll lock
This commit is contained in:
@@ -68,6 +68,7 @@ export default class ComponentView {
|
||||
const children = this.component({
|
||||
theme,
|
||||
node: this.node,
|
||||
view: this.view,
|
||||
isSelected: this.isSelected,
|
||||
isEditable: this.view.editable,
|
||||
getPos: this.getPos,
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
AlignImageLeftIcon,
|
||||
AlignImageRightIcon,
|
||||
AlignImageCenterIcon,
|
||||
AlignFullWidthIcon,
|
||||
} from "outline-icons";
|
||||
import { EditorState } from "prosemirror-state";
|
||||
import * as React from "react";
|
||||
@@ -23,6 +24,9 @@ export default function imageMenuItems(
|
||||
const isRightAligned = isNodeActive(schema.nodes.image, {
|
||||
layoutClass: "right-50",
|
||||
});
|
||||
const isFullWidthAligned = isNodeActive(schema.nodes.image, {
|
||||
layoutClass: "full-width",
|
||||
});
|
||||
|
||||
return [
|
||||
{
|
||||
@@ -40,7 +44,8 @@ export default function imageMenuItems(
|
||||
active: (state) =>
|
||||
isNodeActive(schema.nodes.image)(state) &&
|
||||
!isLeftAligned(state) &&
|
||||
!isRightAligned(state),
|
||||
!isRightAligned(state) &&
|
||||
!isFullWidthAligned(state),
|
||||
},
|
||||
{
|
||||
name: "alignRight",
|
||||
@@ -49,6 +54,13 @@ export default function imageMenuItems(
|
||||
visible: true,
|
||||
active: isRightAligned,
|
||||
},
|
||||
{
|
||||
name: "alignFullWidth",
|
||||
tooltip: dictionary.alignFullWidth,
|
||||
icon: <AlignFullWidthIcon />,
|
||||
visible: true,
|
||||
active: isFullWidthAligned,
|
||||
},
|
||||
{
|
||||
name: "separator",
|
||||
visible: true,
|
||||
|
||||
@@ -13,6 +13,7 @@ export default function useDictionary() {
|
||||
alignCenter: t("Align center"),
|
||||
alignLeft: t("Align left"),
|
||||
alignRight: t("Align right"),
|
||||
alignFullWidth: t("Full width"),
|
||||
bulletList: t("Bulleted list"),
|
||||
checkboxList: t("Todo list"),
|
||||
codeBlock: t("Code block"),
|
||||
@@ -28,9 +29,6 @@ export default function useDictionary() {
|
||||
deleteImage: t("Delete image"),
|
||||
downloadImage: t("Download image"),
|
||||
replaceImage: t("Replace image"),
|
||||
alignImageLeft: t("Float left"),
|
||||
alignImageRight: t("Float right"),
|
||||
alignImageDefault: t("Center large"),
|
||||
em: t("Italic"),
|
||||
embedInvalidLink: t("Sorry, that link won’t work for this embed type"),
|
||||
file: t("File attachment"),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { transparentize } from "polished";
|
||||
import * as React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import styled from "styled-components";
|
||||
@@ -100,21 +101,27 @@ const Sticky = styled.div`
|
||||
top: 80px;
|
||||
max-height: calc(100vh - 80px);
|
||||
|
||||
box-shadow: 1px 0 0 ${(props) => props.theme.divider};
|
||||
margin-top: 40px;
|
||||
background: ${(props) => props.theme.background};
|
||||
margin-top: 72px;
|
||||
margin-right: 52px;
|
||||
min-width: 204px;
|
||||
width: 204px;
|
||||
width: 228px;
|
||||
min-height: 40px;
|
||||
overflow-y: auto;
|
||||
padding: 4px 16px;
|
||||
border-radius: 8px;
|
||||
|
||||
@supports (backdrop-filter: blur(20px)) {
|
||||
backdrop-filter: blur(20px);
|
||||
background: ${(props) => transparentize(0.2, props.theme.background)};
|
||||
}
|
||||
`;
|
||||
|
||||
const Heading = styled.h3`
|
||||
font-size: 11px;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
color: ${(props) => props.theme.sidebarText};
|
||||
letter-spacing: 0.04em;
|
||||
color: ${(props) => props.theme.textTertiary};
|
||||
letter-spacing: 0.03em;
|
||||
`;
|
||||
|
||||
const Empty = styled(Text)`
|
||||
@@ -128,10 +135,9 @@ const ListItem = styled.li<{ level: number; active?: boolean }>`
|
||||
margin-bottom: 8px;
|
||||
padding-right: 2em;
|
||||
line-height: 1.3;
|
||||
border-right: 3px solid
|
||||
${(props) => (props.active ? props.theme.divider : "transparent")};
|
||||
|
||||
a {
|
||||
font-weight: ${(props) => (props.active ? "600" : "inherit")};
|
||||
color: ${(props) =>
|
||||
props.active ? props.theme.primary : props.theme.text};
|
||||
}
|
||||
|
||||
@@ -481,7 +481,12 @@ class DocumentScene extends React.Component<Props> {
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Background key={revision ? revision.id : document.id} column auto>
|
||||
<Background
|
||||
id="full-width-container"
|
||||
key={revision ? revision.id : document.id}
|
||||
column
|
||||
auto
|
||||
>
|
||||
<Route
|
||||
path={`${document.url}/move`}
|
||||
component={() => (
|
||||
@@ -562,7 +567,7 @@ class DocumentScene extends React.Component<Props> {
|
||||
>
|
||||
<Notices document={document} readOnly={readOnly} />
|
||||
<React.Suspense fallback={<PlaceholderDocument />}>
|
||||
<Flex auto={!readOnly}>
|
||||
<Flex auto={!readOnly} reverse>
|
||||
{revision ? (
|
||||
<RevisionViewer
|
||||
isDraft={document.isDraft}
|
||||
@@ -572,12 +577,6 @@ class DocumentScene extends React.Component<Props> {
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
{showContents && (
|
||||
<Contents
|
||||
headings={this.headings}
|
||||
isFullWidth={document.fullWidth}
|
||||
/>
|
||||
)}
|
||||
<Editor
|
||||
id={document.id}
|
||||
key={embedsDisabled ? "disabled" : "enabled"}
|
||||
@@ -624,6 +623,13 @@ class DocumentScene extends React.Component<Props> {
|
||||
</>
|
||||
)}
|
||||
</Editor>
|
||||
|
||||
{showContents && (
|
||||
<Contents
|
||||
headings={this.headings}
|
||||
isFullWidth={document.fullWidth}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Flex>
|
||||
|
||||
@@ -287,7 +287,8 @@ function MultiplayerEditor({ onSynced, ...props }: Props, ref: any) {
|
||||
style={
|
||||
showCache
|
||||
? {
|
||||
display: "none",
|
||||
opacity: 0,
|
||||
pointerEvents: "none",
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user