mirror of
https://github.com/outline/outline.git
synced 2026-06-13 19:35:02 +03:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7a988ed284 | |||
| bab6ded8b6 | |||
| 5cd4dbd9d7 | |||
| 17f55cc140 | |||
| 587a0e0517 | |||
| 686ecdfa92 | |||
| bb019b081f | |||
| 7d5fbeb7b0 | |||
| 056f89fcfd | |||
| 0e7d352781 | |||
| b5e4e4fe82 | |||
| e41f17c701 |
@@ -15,6 +15,7 @@ type Props = {|
|
||||
target?: "_blank",
|
||||
as?: string | React.ComponentType<*>,
|
||||
hide?: () => void,
|
||||
level?: number,
|
||||
|};
|
||||
|
||||
const MenuItem = ({
|
||||
@@ -88,6 +89,7 @@ export const MenuAnchor = styled.a`
|
||||
margin: 0;
|
||||
border: 0;
|
||||
padding: 12px;
|
||||
padding-left: ${(props) => 12 + props.level * 10}px;
|
||||
width: 100%;
|
||||
min-height: 32px;
|
||||
background: none;
|
||||
|
||||
@@ -9,49 +9,11 @@ import {
|
||||
MenuItem as BaseMenuItem,
|
||||
} from "reakit/Menu";
|
||||
import styled from "styled-components";
|
||||
import Header from "./Header";
|
||||
import MenuItem, { MenuAnchor } from "./MenuItem";
|
||||
import Separator from "./Separator";
|
||||
import ContextMenu from ".";
|
||||
|
||||
type TMenuItem =
|
||||
| {|
|
||||
title: React.Node,
|
||||
to: string,
|
||||
visible?: boolean,
|
||||
selected?: boolean,
|
||||
disabled?: boolean,
|
||||
|}
|
||||
| {|
|
||||
title: React.Node,
|
||||
onClick: (event: SyntheticEvent<>) => void | Promise<void>,
|
||||
visible?: boolean,
|
||||
selected?: boolean,
|
||||
disabled?: boolean,
|
||||
|}
|
||||
| {|
|
||||
title: React.Node,
|
||||
href: string,
|
||||
visible?: boolean,
|
||||
selected?: boolean,
|
||||
disabled?: boolean,
|
||||
|}
|
||||
| {|
|
||||
title: React.Node,
|
||||
visible?: boolean,
|
||||
disabled?: boolean,
|
||||
style?: Object,
|
||||
hover?: boolean,
|
||||
items: TMenuItem[],
|
||||
|}
|
||||
| {|
|
||||
type: "separator",
|
||||
visible?: boolean,
|
||||
|}
|
||||
| {|
|
||||
type: "heading",
|
||||
visible?: boolean,
|
||||
title: React.Node,
|
||||
|};
|
||||
import { type MenuItem as TMenuItem } from "types";
|
||||
|
||||
type Props = {|
|
||||
items: TMenuItem[],
|
||||
@@ -128,7 +90,8 @@ function Template({ items, ...menu }: Props): React.Node {
|
||||
key={index}
|
||||
disabled={item.disabled}
|
||||
selected={item.selected}
|
||||
target="_blank"
|
||||
level={item.level}
|
||||
target={item.href.startsWith("#") ? undefined : "_blank"}
|
||||
{...menu}
|
||||
>
|
||||
{item.title}
|
||||
@@ -167,6 +130,11 @@ function Template({ items, ...menu }: Props): React.Node {
|
||||
return <Separator key={index} />;
|
||||
}
|
||||
|
||||
if (item.type === "heading") {
|
||||
return <Header>{item.title}</Header>;
|
||||
}
|
||||
|
||||
console.warn("Unrecognized menu item", item);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -6,14 +6,16 @@ import styled from "styled-components";
|
||||
import breakpoint from "styled-components-breakpoint";
|
||||
import {
|
||||
fadeIn,
|
||||
fadeAndScaleIn,
|
||||
fadeAndSlideIn,
|
||||
fadeAndSlideUp,
|
||||
fadeAndSlideDown,
|
||||
mobileContextMenu,
|
||||
} from "shared/styles/animations";
|
||||
import usePrevious from "hooks/usePrevious";
|
||||
|
||||
type Props = {|
|
||||
"aria-label": string,
|
||||
visible?: boolean,
|
||||
placement?: string,
|
||||
animating?: boolean,
|
||||
children: React.Node,
|
||||
onOpen?: () => void,
|
||||
@@ -44,13 +46,25 @@ export default function ContextMenu({
|
||||
return (
|
||||
<>
|
||||
<Menu hideOnClickOutside preventBodyScroll {...rest}>
|
||||
{(props) => (
|
||||
<Position {...props}>
|
||||
<Background dir="auto">
|
||||
{rest.visible || rest.animating ? children : null}
|
||||
</Background>
|
||||
</Position>
|
||||
)}
|
||||
{(props) => {
|
||||
// kind of hacky, but this is an effective way of telling which way
|
||||
// the menu will _actually_ be placed when taking into account screen
|
||||
// positioning.
|
||||
const topAnchor = props.style.top === "0";
|
||||
const rightAnchor = props.placement === "bottom-end";
|
||||
|
||||
return (
|
||||
<Position {...props}>
|
||||
<Background
|
||||
dir="auto"
|
||||
topAnchor={topAnchor}
|
||||
rightAnchor={rightAnchor}
|
||||
>
|
||||
{rest.visible || rest.animating ? children : null}
|
||||
</Background>
|
||||
</Position>
|
||||
);
|
||||
}}
|
||||
</Menu>
|
||||
{(rest.visible || rest.animating) && (
|
||||
<Portal>
|
||||
@@ -91,7 +105,7 @@ const Position = styled.div`
|
||||
`;
|
||||
|
||||
const Background = styled.div`
|
||||
animation: ${fadeAndSlideIn} 200ms ease;
|
||||
animation: ${mobileContextMenu} 200ms ease;
|
||||
transform-origin: 50% 100%;
|
||||
max-width: 100%;
|
||||
background: ${(props) => props.theme.menuBackground};
|
||||
@@ -109,9 +123,10 @@ const Background = styled.div`
|
||||
}
|
||||
|
||||
${breakpoint("tablet")`
|
||||
animation: ${fadeAndScaleIn} 200ms ease;
|
||||
animation: ${(props) =>
|
||||
props.topAnchor ? fadeAndSlideDown : fadeAndSlideUp} 200ms ease;
|
||||
transform-origin: ${(props) =>
|
||||
props.left !== undefined ? "25%" : "75%"} 0;
|
||||
props.rightAnchor === "bottom-end" ? "75%" : "25%"} 0;
|
||||
max-width: 276px;
|
||||
background: ${(props) => props.theme.menuBackground};
|
||||
box-shadow: ${(props) => props.theme.menuShadow};
|
||||
|
||||
@@ -66,6 +66,9 @@ function DocumentListItem(props: Props, ref) {
|
||||
!document.isDraft && !document.isArchived && !document.isTemplate;
|
||||
const can = policies.abilities(currentTeam.id);
|
||||
|
||||
const handleMenuOpen = React.useCallback(() => setMenuOpen(true), []);
|
||||
const handleMenuClosed = React.useCallback(() => setMenuOpen(false), []);
|
||||
|
||||
return (
|
||||
<DocumentLink
|
||||
ref={ref}
|
||||
@@ -143,8 +146,8 @@ function DocumentListItem(props: Props, ref) {
|
||||
<DocumentMenu
|
||||
document={document}
|
||||
showPin={showPin}
|
||||
onOpen={() => setMenuOpen(true)}
|
||||
onClose={() => setMenuOpen(false)}
|
||||
onOpen={handleMenuOpen}
|
||||
onClose={handleMenuClosed}
|
||||
modal={false}
|
||||
/>
|
||||
</Actions>
|
||||
|
||||
@@ -72,6 +72,10 @@ const Actions = styled(Flex)`
|
||||
flex-basis: 0;
|
||||
min-width: auto;
|
||||
padding-left: 8px;
|
||||
|
||||
${breakpoint("tablet")`
|
||||
position: unset;
|
||||
`};
|
||||
`;
|
||||
|
||||
const Wrapper = styled(Flex)`
|
||||
@@ -84,12 +88,12 @@ const Wrapper = styled(Flex)`
|
||||
transform: translate3d(0, 0, 0);
|
||||
backdrop-filter: blur(20px);
|
||||
min-height: 56px;
|
||||
justify-content: flex-start;
|
||||
|
||||
@media print {
|
||||
display: none;
|
||||
}
|
||||
|
||||
justify-content: flex-start;
|
||||
${breakpoint("tablet")`
|
||||
padding: ${(props) => (props.isCompact ? "12px" : `24px 24px 0`)};
|
||||
justify-content: "center";
|
||||
|
||||
@@ -4,7 +4,7 @@ import { transparentize } from "polished";
|
||||
import * as React from "react";
|
||||
import { Portal } from "react-portal";
|
||||
import styled from "styled-components";
|
||||
import { fadeAndSlideIn } from "shared/styles/animations";
|
||||
import { fadeAndSlideDown } from "shared/styles/animations";
|
||||
import parseDocumentSlug from "shared/utils/parseDocumentSlug";
|
||||
import DocumentsStore from "stores/DocumentsStore";
|
||||
import HoverPreviewDocument from "components/HoverPreviewDocument";
|
||||
@@ -136,7 +136,7 @@ function HoverPreview({ node, ...rest }: Props) {
|
||||
}
|
||||
|
||||
const Animate = styled.div`
|
||||
animation: ${fadeAndSlideIn} 150ms ease;
|
||||
animation: ${fadeAndSlideDown} 150ms ease;
|
||||
|
||||
@media print {
|
||||
display: none;
|
||||
|
||||
@@ -29,6 +29,10 @@ const RealInput = styled.input`
|
||||
background: none;
|
||||
color: ${(props) => props.theme.text};
|
||||
height: 30px;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
||||
&:disabled,
|
||||
&::placeholder {
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
fr,
|
||||
es,
|
||||
it,
|
||||
ja,
|
||||
ko,
|
||||
ptBR,
|
||||
pt,
|
||||
@@ -23,6 +24,7 @@ const locales = {
|
||||
es_ES: es,
|
||||
fr_FR: fr,
|
||||
it_IT: it,
|
||||
ja_JP: ja,
|
||||
ko_KR: ko,
|
||||
pt_BR: ptBR,
|
||||
pt_PT: pt,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// @flow
|
||||
import { observer } from "mobx-react";
|
||||
import * as React from "react";
|
||||
import Document from "models/Document";
|
||||
import DocumentListItem from "components/DocumentListItem";
|
||||
@@ -19,24 +18,26 @@ type Props = {|
|
||||
showTemplate?: boolean,
|
||||
|};
|
||||
|
||||
@observer
|
||||
class PaginatedDocumentList extends React.Component<Props> {
|
||||
render() {
|
||||
const { empty, heading, documents, fetch, options, ...rest } = this.props;
|
||||
|
||||
return (
|
||||
<PaginatedList
|
||||
items={documents}
|
||||
empty={empty}
|
||||
heading={heading}
|
||||
fetch={fetch}
|
||||
options={options}
|
||||
renderItem={(item) => (
|
||||
<DocumentListItem key={item.id} document={item} {...rest} />
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
const PaginatedDocumentList = React.memo<Props>(function PaginatedDocumentList({
|
||||
empty,
|
||||
heading,
|
||||
documents,
|
||||
fetch,
|
||||
options,
|
||||
...rest
|
||||
}: Props) {
|
||||
return (
|
||||
<PaginatedList
|
||||
items={documents}
|
||||
empty={empty}
|
||||
heading={heading}
|
||||
fetch={fetch}
|
||||
options={options}
|
||||
renderItem={(item) => (
|
||||
<DocumentListItem key={item.id} document={item} {...rest} />
|
||||
)}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
export default PaginatedDocumentList;
|
||||
|
||||
+49
-8
@@ -1,14 +1,26 @@
|
||||
// @flow
|
||||
import { m } from "framer-motion";
|
||||
import * as React from "react";
|
||||
import { NavLink } from "react-router-dom";
|
||||
import { NavLink, Route } from "react-router-dom";
|
||||
import styled, { withTheme } from "styled-components";
|
||||
import { type Theme } from "types";
|
||||
|
||||
type Props = {
|
||||
theme: Theme,
|
||||
children: React.Node,
|
||||
};
|
||||
|
||||
const TabLink = styled(NavLink)`
|
||||
const NavLinkWithChildrenFunc = ({ to, exact = false, children, ...rest }) => (
|
||||
<Route path={to} exact={exact}>
|
||||
{({ match }) => (
|
||||
<NavLink to={to} {...rest}>
|
||||
{children(match)}
|
||||
</NavLink>
|
||||
)}
|
||||
</Route>
|
||||
);
|
||||
|
||||
const TabLink = styled(NavLinkWithChildrenFunc)`
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
@@ -20,19 +32,48 @@ const TabLink = styled(NavLink)`
|
||||
|
||||
&:hover {
|
||||
color: ${(props) => props.theme.textSecondary};
|
||||
border-bottom: 3px solid ${(props) => props.theme.divider};
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
`;
|
||||
|
||||
function Tab({ theme, ...rest }: Props) {
|
||||
const Active = styled(m.div)`
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 3px;
|
||||
width: 100%;
|
||||
border-top-left-radius: 2px;
|
||||
border-top-right-radius: 2px;
|
||||
background: ${(props) => props.theme.textSecondary};
|
||||
`;
|
||||
|
||||
const transition = {
|
||||
type: "spring",
|
||||
stiffness: 500,
|
||||
damping: 30,
|
||||
};
|
||||
|
||||
function Tab({ theme, children, ...rest }: Props) {
|
||||
const activeStyle = {
|
||||
paddingBottom: "5px",
|
||||
borderBottom: `3px solid ${theme.textSecondary}`,
|
||||
color: theme.textSecondary,
|
||||
};
|
||||
|
||||
return <TabLink {...rest} activeStyle={activeStyle} />;
|
||||
return (
|
||||
<TabLink {...rest} activeStyle={activeStyle}>
|
||||
{(match) => (
|
||||
<>
|
||||
{children}
|
||||
{match && (
|
||||
<Active
|
||||
layoutId="underline"
|
||||
initial={false}
|
||||
transition={transition}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</TabLink>
|
||||
);
|
||||
}
|
||||
|
||||
export default withTheme(Tab);
|
||||
|
||||
+57
-5
@@ -1,13 +1,40 @@
|
||||
// @flow
|
||||
import { AnimateSharedLayout } from "framer-motion";
|
||||
import { transparentize } from "polished";
|
||||
import * as React from "react";
|
||||
import styled from "styled-components";
|
||||
import useWindowSize from "hooks/useWindowSize";
|
||||
|
||||
const Nav = styled.nav`
|
||||
border-bottom: 1px solid ${(props) => props.theme.divider};
|
||||
margin: 12px 0;
|
||||
overflow-y: auto;
|
||||
white-space: nowrap;
|
||||
transition: opacity 250ms ease-out;
|
||||
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 50px;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
background: ${(props) =>
|
||||
props.$shadowVisible
|
||||
? `linear-gradient(
|
||||
90deg,
|
||||
${transparentize(1, props.theme.background)} 0%,
|
||||
${props.theme.background} 100%
|
||||
)`
|
||||
: `transparent`};
|
||||
}
|
||||
`;
|
||||
|
||||
// When sticky we need extra background coverage around the sides otherwise
|
||||
@@ -30,11 +57,36 @@ export const Separator = styled.span`
|
||||
margin-top: 6px;
|
||||
`;
|
||||
|
||||
const Tabs = (props: {}) => {
|
||||
const Tabs = ({ children }: {| children: React.Node |}) => {
|
||||
const ref = React.useRef<?HTMLDivElement>();
|
||||
const [shadowVisible, setShadow] = React.useState(false);
|
||||
const { width } = useWindowSize();
|
||||
|
||||
const updateShadows = React.useCallback(() => {
|
||||
const c = ref.current;
|
||||
if (!c) return;
|
||||
|
||||
const scrollLeft = c.scrollLeft;
|
||||
const wrapperWidth = c.scrollWidth - c.clientWidth;
|
||||
const fade = !!(wrapperWidth - scrollLeft !== 0);
|
||||
|
||||
if (fade !== shadowVisible) {
|
||||
setShadow(fade);
|
||||
}
|
||||
}, [shadowVisible]);
|
||||
|
||||
React.useEffect(() => {
|
||||
updateShadows();
|
||||
}, [width, updateShadows]);
|
||||
|
||||
return (
|
||||
<Sticky>
|
||||
<Nav {...props}></Nav>
|
||||
</Sticky>
|
||||
<AnimateSharedLayout>
|
||||
<Sticky>
|
||||
<Nav ref={ref} onScroll={updateShadows} $shadowVisible={shadowVisible}>
|
||||
{children}
|
||||
</Nav>
|
||||
</Sticky>
|
||||
</AnimateSharedLayout>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
+16
-9
@@ -1,5 +1,6 @@
|
||||
// @flow
|
||||
import "focus-visible";
|
||||
import { LazyMotion } from "framer-motion";
|
||||
import { createBrowserHistory } from "history";
|
||||
import { Provider } from "mobx-react";
|
||||
import * as React from "react";
|
||||
@@ -49,6 +50,10 @@ if ("serviceWorker" in window.navigator) {
|
||||
});
|
||||
}
|
||||
|
||||
// Make sure to return the specific export containing the feature bundle.
|
||||
const loadFeatures = () =>
|
||||
import("./utils/motion.js").then((res) => res.default);
|
||||
|
||||
if (element) {
|
||||
const App = () => (
|
||||
<React.StrictMode>
|
||||
@@ -56,15 +61,17 @@ if (element) {
|
||||
<Analytics>
|
||||
<Theme>
|
||||
<ErrorBoundary>
|
||||
<Router history={history}>
|
||||
<>
|
||||
<PageTheme />
|
||||
<ScrollToTop>
|
||||
<Routes />
|
||||
</ScrollToTop>
|
||||
<Toasts />
|
||||
</>
|
||||
</Router>
|
||||
<LazyMotion features={loadFeatures}>
|
||||
<Router history={history}>
|
||||
<>
|
||||
<PageTheme />
|
||||
<ScrollToTop>
|
||||
<Routes />
|
||||
</ScrollToTop>
|
||||
<Toasts />
|
||||
</>
|
||||
</Router>
|
||||
</LazyMotion>
|
||||
</ErrorBoundary>
|
||||
</Theme>
|
||||
</Analytics>
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
// @flow
|
||||
import { observer } from "mobx-react";
|
||||
import { TableOfContentsIcon } from "outline-icons";
|
||||
import * as React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { MenuButton, useMenuState } from "reakit/Menu";
|
||||
import Button from "components/Button";
|
||||
import ContextMenu from "components/ContextMenu";
|
||||
import Template from "components/ContextMenu/Template";
|
||||
import { type MenuItem } from "types";
|
||||
|
||||
type Props = {|
|
||||
headings: { title: string, level: number, id: string }[],
|
||||
|};
|
||||
|
||||
function TableOfContentsMenu({ headings }: Props) {
|
||||
const menu = useMenuState({
|
||||
modal: true,
|
||||
unstable_preventOverflow: true,
|
||||
unstable_fixed: true,
|
||||
unstable_flip: true,
|
||||
});
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const minHeading = headings.reduce(
|
||||
(memo, heading) => (heading.level < memo ? heading.level : memo),
|
||||
Infinity
|
||||
);
|
||||
|
||||
const items: MenuItem[] = React.useMemo(() => {
|
||||
let i = [
|
||||
{
|
||||
type: "heading",
|
||||
visible: true,
|
||||
title: t("Contents"),
|
||||
},
|
||||
...headings.map((heading) => ({
|
||||
href: `#${heading.id}`,
|
||||
title: t(heading.title),
|
||||
level: heading.level - minHeading,
|
||||
})),
|
||||
];
|
||||
|
||||
if (i.length === 1) {
|
||||
i.push({
|
||||
href: "#",
|
||||
title: t("Headings you add to the document will appear here"),
|
||||
disabled: true,
|
||||
});
|
||||
}
|
||||
|
||||
return i;
|
||||
}, [t, headings, minHeading]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<MenuButton {...menu}>
|
||||
{(props) => (
|
||||
<Button
|
||||
{...props}
|
||||
icon={<TableOfContentsIcon />}
|
||||
iconColor="currentColor"
|
||||
borderOnHover
|
||||
neutral
|
||||
/>
|
||||
)}
|
||||
</MenuButton>
|
||||
<ContextMenu {...menu} aria-label={t("Table of contents")}>
|
||||
<Template {...menu} items={items} />
|
||||
</ContextMenu>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default observer(TableOfContentsMenu);
|
||||
@@ -70,11 +70,13 @@ const Wrapper = styled("div")`
|
||||
display: none;
|
||||
position: sticky;
|
||||
top: 80px;
|
||||
max-height: calc(100vh - 80px);
|
||||
|
||||
box-shadow: 1px 0 0 ${(props) => props.theme.divider};
|
||||
margin-top: 40px;
|
||||
margin-right: 2em;
|
||||
min-height: 40px;
|
||||
overflow-y: auto;
|
||||
|
||||
${breakpoint("desktopLarge")`
|
||||
margin-left: -16em;
|
||||
|
||||
@@ -374,6 +374,7 @@ class DocumentScene extends React.Component<Props> {
|
||||
sharedTree={this.props.sharedTree}
|
||||
goBack={this.goBack}
|
||||
onSave={this.onSave}
|
||||
headings={headings}
|
||||
/>
|
||||
<MaxWidth
|
||||
archived={document.isArchived}
|
||||
|
||||
@@ -24,6 +24,7 @@ import useMobile from "hooks/useMobile";
|
||||
import useStores from "hooks/useStores";
|
||||
import DocumentMenu from "menus/DocumentMenu";
|
||||
import NewChildDocumentMenu from "menus/NewChildDocumentMenu";
|
||||
import TableOfContentsMenu from "menus/TableOfContentsMenu";
|
||||
import TemplatesMenu from "menus/TemplatesMenu";
|
||||
import { type NavigationNode } from "types";
|
||||
import { metaDisplay } from "utils/keyboard";
|
||||
@@ -46,6 +47,7 @@ type Props = {|
|
||||
publish?: boolean,
|
||||
autosave?: boolean,
|
||||
}) => void,
|
||||
headings: { title: string, level: number, id: string }[],
|
||||
|};
|
||||
|
||||
function DocumentHeader({
|
||||
@@ -60,6 +62,7 @@ function DocumentHeader({
|
||||
publishingIsDisabled,
|
||||
sharedTree,
|
||||
onSave,
|
||||
headings,
|
||||
}: Props) {
|
||||
const { t } = useTranslation();
|
||||
const { auth, ui, policies } = useStores();
|
||||
@@ -153,6 +156,11 @@ function DocumentHeader({
|
||||
}
|
||||
actions={
|
||||
<>
|
||||
{isMobile && (
|
||||
<TocWrapper>
|
||||
<TableOfContentsMenu headings={headings} />
|
||||
</TocWrapper>
|
||||
)}
|
||||
{!isPublishing && isSaving && <Status>{t("Saving")}…</Status>}
|
||||
<Collaborators
|
||||
document={document}
|
||||
@@ -274,4 +282,9 @@ const Status = styled(Action)`
|
||||
color: ${(props) => props.theme.slate};
|
||||
`;
|
||||
|
||||
const TocWrapper = styled(Action)`
|
||||
position: absolute;
|
||||
left: 42px;
|
||||
`;
|
||||
|
||||
export default observer(DocumentHeader);
|
||||
|
||||
@@ -7,3 +7,5 @@ import Adapter from "enzyme-adapter-react-16";
|
||||
Enzyme.configure({ adapter: new Adapter() });
|
||||
|
||||
global.localStorage = localStorage;
|
||||
|
||||
require("jest-fetch-mock").enableMocks();
|
||||
|
||||
@@ -58,3 +58,44 @@ export type SearchResult = {
|
||||
context: string,
|
||||
document: Document,
|
||||
};
|
||||
|
||||
export type MenuItem =
|
||||
| {|
|
||||
title: React.Node,
|
||||
to: string,
|
||||
visible?: boolean,
|
||||
selected?: boolean,
|
||||
disabled?: boolean,
|
||||
|}
|
||||
| {|
|
||||
title: React.Node,
|
||||
onClick: (event: SyntheticEvent<>) => void | Promise<void>,
|
||||
visible?: boolean,
|
||||
selected?: boolean,
|
||||
disabled?: boolean,
|
||||
|}
|
||||
| {|
|
||||
title: React.Node,
|
||||
href: string,
|
||||
visible?: boolean,
|
||||
selected?: boolean,
|
||||
disabled?: boolean,
|
||||
level?: number,
|
||||
|}
|
||||
| {|
|
||||
title: React.Node,
|
||||
visible?: boolean,
|
||||
disabled?: boolean,
|
||||
style?: Object,
|
||||
hover?: boolean,
|
||||
items: MenuItem[],
|
||||
|}
|
||||
| {|
|
||||
type: "separator",
|
||||
visible?: boolean,
|
||||
|}
|
||||
| {|
|
||||
type: "heading",
|
||||
visible?: boolean,
|
||||
title: React.Node,
|
||||
|};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// @flow
|
||||
import retry from "fetch-retry";
|
||||
import invariant from "invariant";
|
||||
import { map, trim } from "lodash";
|
||||
import { getCookie } from "tiny-cookie";
|
||||
@@ -24,6 +25,8 @@ const CF_AUTHORIZATION = getCookie("CF_Authorization");
|
||||
// if the cookie is set, we must pass it with all ApiClient requests
|
||||
const CREDENTIALS = CF_AUTHORIZATION ? "same-origin" : "omit";
|
||||
|
||||
const fetchWithRetry = retry(fetch);
|
||||
|
||||
class ApiClient {
|
||||
baseUrl: string;
|
||||
userAgent: string;
|
||||
@@ -92,7 +95,7 @@ class ApiClient {
|
||||
|
||||
let response;
|
||||
try {
|
||||
response = await fetch(urlToFetch, {
|
||||
response = await fetchWithRetry(urlToFetch, {
|
||||
method,
|
||||
body,
|
||||
headers,
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
// @flow
|
||||
import { domMax } from "framer-motion";
|
||||
export default domMax;
|
||||
+5
-4
@@ -73,11 +73,13 @@
|
||||
"emoji-regex": "^6.5.1",
|
||||
"es6-error": "^4.1.1",
|
||||
"exports-loader": "^0.6.4",
|
||||
"fetch-retry": "^4.1.1",
|
||||
"fetch-with-proxy": "^3.0.1",
|
||||
"file-loader": "^1.1.6",
|
||||
"flow-typed": "^3.3.1",
|
||||
"focus-visible": "^5.1.0",
|
||||
"fractional-index": "^1.0.0",
|
||||
"framer-motion": "^4.1.17",
|
||||
"fs-extra": "^4.0.2",
|
||||
"http-errors": "1.4.0",
|
||||
"i18next": "^19.8.3",
|
||||
@@ -86,7 +88,6 @@
|
||||
"imports-loader": "0.6.5",
|
||||
"invariant": "^2.2.2",
|
||||
"ioredis": "^4.24.3",
|
||||
"isomorphic-fetch": "2.2.1",
|
||||
"joplin-turndown-plugin-gfm": "^1.0.12",
|
||||
"js-search": "^1.4.2",
|
||||
"json-loader": "0.5.4",
|
||||
@@ -110,7 +111,6 @@
|
||||
"mobx": "^4.15.4",
|
||||
"mobx-react": "^6.3.1",
|
||||
"natural-sort": "^1.0.0",
|
||||
"node-htmldiff": "^0.9.3",
|
||||
"nodemailer": "^6.4.16",
|
||||
"outline-icons": "^1.27.0",
|
||||
"oy-vey": "^0.10.0",
|
||||
@@ -162,8 +162,8 @@
|
||||
"styled-normalize": "^8.0.4",
|
||||
"tiny-cookie": "^2.3.1",
|
||||
"tmp": "^0.2.1",
|
||||
"turndown": "^6.0.0",
|
||||
"utf8": "^2.1.0",
|
||||
"turndown": "^7.1.1",
|
||||
"utf8": "^3.0.0",
|
||||
"uuid": "^8.3.2",
|
||||
"validator": "5.2.0"
|
||||
},
|
||||
@@ -190,6 +190,7 @@
|
||||
"html-webpack-plugin": "3.2.0",
|
||||
"i18next-parser": "^3.3.0",
|
||||
"jest-cli": "^26.0.0",
|
||||
"jest-fetch-mock": "^3.0.3",
|
||||
"koa-webpack-dev-middleware": "^1.4.5",
|
||||
"koa-webpack-hot-middleware": "^1.0.3",
|
||||
"nodemon": "^1.19.4",
|
||||
|
||||
@@ -41,13 +41,11 @@ export const CollectionNotificationEmail = ({
|
||||
<Body>
|
||||
<Heading>{collection.name}</Heading>
|
||||
<p>
|
||||
{actor.name} {eventName} the collection “{collection.name}”.
|
||||
{actor.name} {eventName} the collection "{collection.name}".
|
||||
</p>
|
||||
<EmptySpace height={10} />
|
||||
<p>
|
||||
<Button
|
||||
href={`${process.env.URL}${collection.url}?ref=notification-email`}
|
||||
>
|
||||
<Button href={`${process.env.URL}${collection.url}`}>
|
||||
Open Collection
|
||||
</Button>
|
||||
</p>
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// @flow
|
||||
import * as React from "react";
|
||||
import theme from "../../shared/styles/theme";
|
||||
import { User, Document, Team, Collection } from "../models";
|
||||
import Body from "./components/Body";
|
||||
import Button from "./components/Button";
|
||||
import Diff from "./components/Diff";
|
||||
import EmailTemplate from "./components/EmailLayout";
|
||||
import EmptySpace from "./components/EmptySpace";
|
||||
import Footer from "./components/Footer";
|
||||
@@ -17,7 +15,6 @@ export type Props = {
|
||||
document: Document,
|
||||
collection: Collection,
|
||||
eventName: string,
|
||||
summary: string,
|
||||
unsubscribeUrl: string,
|
||||
};
|
||||
|
||||
@@ -41,34 +38,26 @@ export const DocumentNotificationEmail = ({
|
||||
document,
|
||||
collection,
|
||||
eventName = "published",
|
||||
summary,
|
||||
unsubscribeUrl,
|
||||
}: Props) => {
|
||||
const link = `${team.url}${document.url}?ref=notification-email`;
|
||||
|
||||
return (
|
||||
<EmailTemplate>
|
||||
<Header />
|
||||
|
||||
<Body>
|
||||
<Heading>
|
||||
“{document.title}” {eventName}
|
||||
"{document.title}" {eventName}
|
||||
</Heading>
|
||||
<p>
|
||||
{actor.name} {eventName} the document "{document.title}", in the{" "}
|
||||
{collection.name} collection.
|
||||
</p>
|
||||
{summary && (
|
||||
<>
|
||||
<EmptySpace height={20} />
|
||||
<Diff href={link}>
|
||||
<div dangerouslySetInnerHTML={{ __html: summary }} />
|
||||
</Diff>
|
||||
<EmptySpace height={20} />
|
||||
</>
|
||||
)}
|
||||
<hr />
|
||||
<EmptySpace height={10} />
|
||||
<p>{document.getSummary()}</p>
|
||||
<EmptySpace height={10} />
|
||||
<p>
|
||||
<Button href={link}>Open Document</Button>
|
||||
<Button href={`${team.url}${document.url}`}>Open Document</Button>
|
||||
</p>
|
||||
</Body>
|
||||
|
||||
@@ -76,211 +65,3 @@ export const DocumentNotificationEmail = ({
|
||||
</EmailTemplate>
|
||||
);
|
||||
};
|
||||
|
||||
export const css = `
|
||||
font-family: ${theme.fontFamily};
|
||||
font-weight: ${theme.fontWeight};
|
||||
font-size: 1em;
|
||||
line-height: 1.7em;
|
||||
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
img {
|
||||
text-align: center;
|
||||
max-width: 100%;
|
||||
max-height: 75vh;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
img.image-right-50 {
|
||||
float: right;
|
||||
width: 50%;
|
||||
margin-left: 2em;
|
||||
margin-bottom: 1em;
|
||||
clear: initial;
|
||||
}
|
||||
|
||||
img.image-left-50 {
|
||||
float: left;
|
||||
width: 50%;
|
||||
margin-right: 2em;
|
||||
margin-bottom: 1em;
|
||||
clear: initial;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
margin: 1em 0 0.5em;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.notice {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: ${theme.noticeInfoBackground};
|
||||
color: ${theme.noticeInfoText};
|
||||
border-radius: 4px;
|
||||
padding: 8px 16px;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.notice-tip {
|
||||
background: ${theme.noticeTipBackground};
|
||||
color: ${theme.noticeTipText};
|
||||
}
|
||||
|
||||
.notice-warning {
|
||||
background: ${theme.noticeWarningBackground};
|
||||
color: ${theme.noticeWarningText};
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: ${theme.link};
|
||||
}
|
||||
|
||||
ins {
|
||||
background-color: #128a2929;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
del {
|
||||
background-color: ${theme.slateLight};
|
||||
color: ${theme.slate};
|
||||
text-decoration: strikethrough;
|
||||
}
|
||||
|
||||
hr {
|
||||
position: relative;
|
||||
height: 1em;
|
||||
border: 0;
|
||||
}
|
||||
hr:before {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
border-top: 1px solid ${theme.horizontalRule};
|
||||
top: 0.5em;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
hr.page-break {
|
||||
page-break-after: always;
|
||||
}
|
||||
hr.page-break:before {
|
||||
border-top: 1px dashed ${theme.horizontalRule};
|
||||
}
|
||||
|
||||
code {
|
||||
border-radius: 4px;
|
||||
border: 1px solid ${theme.codeBorder};
|
||||
padding: 3px 4px;
|
||||
font-family: ${theme.fontFamilyMono};
|
||||
font-size: 85%;
|
||||
}
|
||||
|
||||
mark {
|
||||
border-radius: 1px;
|
||||
color: ${theme.textHighlightForeground};
|
||||
background: ${theme.textHighlight};
|
||||
a {
|
||||
color: ${theme.textHighlightForeground};
|
||||
}
|
||||
}
|
||||
|
||||
ul {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.checkbox-list-item {
|
||||
list-style: none;
|
||||
padding: 4px 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
font-size: 0;
|
||||
display: block;
|
||||
float: left;
|
||||
white-space: nowrap;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
margin-top: 2px;
|
||||
margin-right: 8px;
|
||||
border: 1px solid ${theme.textSecondary};
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
padding: 0.75em 1em;
|
||||
line-height: 1.4em;
|
||||
position: relative;
|
||||
background: ${theme.codeBackground};
|
||||
border-radius: 4px;
|
||||
border: 1px solid ${theme.codeBorder};
|
||||
-webkit-font-smoothing: initial;
|
||||
font-family: ${theme.fontFamilyMono};
|
||||
font-size: 13px;
|
||||
direction: ltr;
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
word-spacing: normal;
|
||||
word-break: normal;
|
||||
-moz-tab-size: 4;
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
-webkit-hyphens: none;
|
||||
-moz-hyphens: none;
|
||||
-ms-hyphens: none;
|
||||
hyphens: none;
|
||||
margin: 0;
|
||||
|
||||
code {
|
||||
font-size: 13px;
|
||||
background: none;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
border-radius: 4px;
|
||||
margin-top: 1em;
|
||||
box-sizing: border-box;
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
tr {
|
||||
position: relative;
|
||||
border-bottom: 1px solid ${theme.tableDivider};
|
||||
}
|
||||
td,
|
||||
th {
|
||||
position: relative;
|
||||
vertical-align: top;
|
||||
border: 1px solid ${theme.tableDivider};
|
||||
position: relative;
|
||||
padding: 4px 8px;
|
||||
min-width: 100px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -47,7 +47,7 @@ export const InviteEmail = ({
|
||||
</p>
|
||||
<EmptySpace height={10} />
|
||||
<p>
|
||||
<Button href={`${teamUrl}?ref=invite-email`}>Join now</Button>
|
||||
<Button href={teamUrl}>Join now</Button>
|
||||
</p>
|
||||
</Body>
|
||||
|
||||
|
||||
@@ -43,9 +43,7 @@ export const WelcomeEmail = ({ teamUrl }: Props) => {
|
||||
</p>
|
||||
<EmptySpace height={10} />
|
||||
<p>
|
||||
<Button href={`${teamUrl}/home?ref=welcome-email`}>
|
||||
View my dashboard
|
||||
</Button>
|
||||
<Button href={`${teamUrl}/home`}>View my dashboard</Button>
|
||||
</p>
|
||||
</Body>
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
// @flow
|
||||
import * as React from "react";
|
||||
import theme from "../../../shared/styles/theme";
|
||||
|
||||
type Props = {|
|
||||
children: React.Node,
|
||||
href?: string,
|
||||
|};
|
||||
|
||||
export default ({ children, ...rest }: Props) => {
|
||||
const style = {
|
||||
borderRadius: "4px",
|
||||
background: theme.secondaryBackground,
|
||||
padding: ".5em 1em",
|
||||
color: theme.text,
|
||||
display: "block",
|
||||
textDecoration: "none",
|
||||
};
|
||||
|
||||
return (
|
||||
<a width="100%" style={style} {...rest}>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
};
|
||||
@@ -3,9 +3,9 @@ import { Table, TBody, TR, TD } from "oy-vey";
|
||||
import * as React from "react";
|
||||
import theme from "../../../shared/styles/theme";
|
||||
|
||||
type Props = {|
|
||||
type Props = {
|
||||
children: React.Node,
|
||||
|};
|
||||
};
|
||||
|
||||
export default (props: Props) => (
|
||||
<Table width="550" padding="40">
|
||||
|
||||
@@ -100,8 +100,6 @@ export type RevisionEvent = {
|
||||
documentId: string,
|
||||
collectionId: string,
|
||||
teamId: string,
|
||||
actorId: string,
|
||||
modelId: string,
|
||||
};
|
||||
|
||||
export type CollectionImportEvent = {
|
||||
|
||||
+1
-3
@@ -13,7 +13,6 @@ import {
|
||||
type Props as DocumentNotificationEmailT,
|
||||
DocumentNotificationEmail,
|
||||
documentNotificationEmailText,
|
||||
css as documentNotificationEmailCSS,
|
||||
} from "./emails/DocumentNotificationEmail";
|
||||
import { ExportEmail, exportEmailText } from "./emails/ExportEmail";
|
||||
import {
|
||||
@@ -147,9 +146,8 @@ export class Mailer {
|
||||
this.sendMail({
|
||||
to: opts.to,
|
||||
title: `“${opts.document.title}” ${opts.eventName}`,
|
||||
previewText: `${opts.actor.name} ${opts.eventName} a document`,
|
||||
previewText: `${opts.actor.name} ${opts.eventName} a new document`,
|
||||
html: <DocumentNotificationEmail {...opts} />,
|
||||
headCSS: documentNotificationEmailCSS,
|
||||
text: documentNotificationEmailText(opts),
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,60 +1,32 @@
|
||||
// @flow
|
||||
import debug from "debug";
|
||||
import type {
|
||||
DocumentEvent,
|
||||
RevisionEvent,
|
||||
CollectionEvent,
|
||||
Event,
|
||||
} from "../events";
|
||||
import type { DocumentEvent, CollectionEvent, Event } from "../events";
|
||||
import mailer from "../mailer";
|
||||
import {
|
||||
View,
|
||||
Document,
|
||||
Team,
|
||||
Collection,
|
||||
Revision,
|
||||
User,
|
||||
NotificationSetting,
|
||||
Attachment,
|
||||
} from "../models";
|
||||
import { Op } from "../sequelize";
|
||||
import markdownDiff from "../utils/markdownDiff";
|
||||
|
||||
import parseAttachmentIds from "../utils/parseAttachmentIds";
|
||||
import { getSignedImageUrl } from "../utils/s3";
|
||||
|
||||
const log = debug("services");
|
||||
|
||||
async function replaceImageAttachments(text: string) {
|
||||
const attachmentIds = parseAttachmentIds(text);
|
||||
|
||||
await Promise.all(
|
||||
attachmentIds.map(async (id) => {
|
||||
const attachment = await Attachment.findByPk(id);
|
||||
if (attachment) {
|
||||
const accessUrl = await getSignedImageUrl(attachment.key, 86400 * 4);
|
||||
text = text.replace(attachment.redirectUrl, accessUrl);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
export default class Notifications {
|
||||
async on(event: Event) {
|
||||
switch (event.name) {
|
||||
case "documents.publish":
|
||||
return this.documentPublished(event);
|
||||
case "revisions.create":
|
||||
return this.revisionCreated(event);
|
||||
case "documents.update.debounced":
|
||||
return this.documentUpdated(event);
|
||||
case "collections.create":
|
||||
return this.collectionCreated(event);
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
async documentPublished(event: DocumentEvent) {
|
||||
async documentUpdated(event: DocumentEvent) {
|
||||
// never send notifications when batch importing documents
|
||||
if (event.data && event.data.source === "import") return;
|
||||
|
||||
@@ -73,7 +45,10 @@ export default class Notifications {
|
||||
[Op.ne]: document.lastModifiedById,
|
||||
},
|
||||
teamId: document.teamId,
|
||||
event: "documents.publish",
|
||||
event:
|
||||
event.name === "documents.publish"
|
||||
? "documents.publish"
|
||||
: "documents.update",
|
||||
},
|
||||
include: [
|
||||
{
|
||||
@@ -84,104 +59,25 @@ export default class Notifications {
|
||||
],
|
||||
});
|
||||
|
||||
const eventName = "published";
|
||||
|
||||
for (const setting of notificationSettings) {
|
||||
// Check the user has access to the collection this document is in. Just
|
||||
// because they were a collaborator once doesn't mean they still are.
|
||||
const collectionIds = await setting.user.collectionIds();
|
||||
if (!collectionIds.includes(document.collectionId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this user has viewed the document since the last update was made
|
||||
// then we can avoid sending them a useless notification, yay.
|
||||
const view = await View.findOne({
|
||||
where: {
|
||||
userId: setting.userId,
|
||||
documentId: event.documentId,
|
||||
updatedAt: {
|
||||
[Op.gt]: document.updatedAt,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (view) {
|
||||
log(
|
||||
`suppressing notification to ${setting.userId} because update viewed`
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
mailer.documentNotification({
|
||||
to: setting.user.email,
|
||||
eventName,
|
||||
document,
|
||||
team,
|
||||
collection,
|
||||
summary: document.getSummary(),
|
||||
actor: document.updatedBy,
|
||||
unsubscribeUrl: setting.unsubscribeUrl,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async revisionCreated(event: RevisionEvent) {
|
||||
const revision = await Revision.findByPk(event.modelId, {
|
||||
include: [
|
||||
{
|
||||
model: Document,
|
||||
as: "document",
|
||||
include: [
|
||||
{
|
||||
model: Collection,
|
||||
as: "collection",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
if (!revision) return;
|
||||
|
||||
const { document } = revision;
|
||||
const { collection } = document;
|
||||
if (!collection || !document) return;
|
||||
|
||||
const team = await Team.findByPk(document.teamId);
|
||||
if (!team) return;
|
||||
|
||||
const notificationSettings = await NotificationSetting.findAll({
|
||||
where: {
|
||||
userId: {
|
||||
[Op.ne]: revision.userId,
|
||||
},
|
||||
teamId: document.teamId,
|
||||
event: "documents.update",
|
||||
},
|
||||
include: [
|
||||
{
|
||||
model: User,
|
||||
required: true,
|
||||
as: "user",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const eventName = "updated";
|
||||
const eventName =
|
||||
event.name === "documents.publish" ? "published" : "updated";
|
||||
|
||||
for (const setting of notificationSettings) {
|
||||
// For document updates we only want to send notifications if
|
||||
// the document has been edited by the user with this notification setting
|
||||
// This could be replaced with ability to "follow" in the future
|
||||
if (!document.collaboratorIds.includes(setting.userId)) {
|
||||
continue;
|
||||
if (
|
||||
eventName === "updated" &&
|
||||
!document.collaboratorIds.includes(setting.userId)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the user has access to the collection this document is in. Just
|
||||
// because they were a collaborator once doesn't mean they still are.
|
||||
const collectionIds = await setting.user.collectionIds();
|
||||
if (!collectionIds.includes(document.collectionId)) {
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
// If this user has viewed the document since the last update was made
|
||||
@@ -200,33 +96,16 @@ export default class Notifications {
|
||||
log(
|
||||
`suppressing notification to ${setting.userId} because update viewed`
|
||||
);
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
const previous = await Revision.findOne({
|
||||
where: {
|
||||
documentId: document.id,
|
||||
createdAt: {
|
||||
[Op.lt]: revision.createdAt,
|
||||
},
|
||||
},
|
||||
order: [["createdAt", "DESC"]],
|
||||
});
|
||||
|
||||
let summary = markdownDiff(previous ? previous.text : "", revision.text);
|
||||
|
||||
console.log(summary);
|
||||
summary = await replaceImageAttachments(summary);
|
||||
console.log(summary);
|
||||
|
||||
mailer.documentNotification({
|
||||
to: setting.user.email,
|
||||
eventName,
|
||||
document,
|
||||
team,
|
||||
collection,
|
||||
summary,
|
||||
actor: revision.user,
|
||||
actor: document.updatedBy,
|
||||
unsubscribeUrl: setting.unsubscribeUrl,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* eslint-disable flowtype/require-valid-file-annotation */
|
||||
import mailer from "../mailer";
|
||||
import { View, NotificationSetting, Revision } from "../models";
|
||||
import { View, NotificationSetting } from "../models";
|
||||
import { buildDocument, buildCollection, buildUser } from "../test/factories";
|
||||
import { flushdb } from "../test/support";
|
||||
import NotificationsService from "./notifications";
|
||||
@@ -89,10 +89,9 @@ describe("documents.publish", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("revisions.create", () => {
|
||||
describe("documents.update.debounced", () => {
|
||||
test("should send a notification to other collaborator", async () => {
|
||||
const document = await buildDocument();
|
||||
const revision = await Revision.createFromDocument(document);
|
||||
const collaborator = await buildUser({ teamId: document.teamId });
|
||||
document.collaboratorIds = [collaborator.id];
|
||||
await document.save();
|
||||
@@ -104,9 +103,8 @@ describe("revisions.create", () => {
|
||||
});
|
||||
|
||||
await Notifications.on({
|
||||
name: "revisions.create",
|
||||
name: "documents.update.debounced",
|
||||
documentId: document.id,
|
||||
modelId: revision.id,
|
||||
collectionId: document.collectionId,
|
||||
teamId: document.teamId,
|
||||
actorId: document.createdById,
|
||||
@@ -117,7 +115,6 @@ describe("revisions.create", () => {
|
||||
|
||||
test("should not send a notification if viewed since update", async () => {
|
||||
const document = await buildDocument();
|
||||
const revision = await Revision.createFromDocument(document);
|
||||
const collaborator = await buildUser({ teamId: document.teamId });
|
||||
document.collaboratorIds = [collaborator.id];
|
||||
await document.save();
|
||||
@@ -131,10 +128,9 @@ describe("revisions.create", () => {
|
||||
await View.touch(document.id, collaborator.id, true);
|
||||
|
||||
await Notifications.on({
|
||||
name: "revisions.create",
|
||||
name: "documents.update.debounced",
|
||||
documentId: document.id,
|
||||
collectionId: document.collectionId,
|
||||
modelId: revision.id,
|
||||
teamId: document.teamId,
|
||||
actorId: document.createdById,
|
||||
});
|
||||
@@ -142,13 +138,12 @@ describe("revisions.create", () => {
|
||||
expect(mailer.documentNotification).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("should not send a notification to the last user that modified", async () => {
|
||||
test("should not send a notification to last editor", async () => {
|
||||
const user = await buildUser();
|
||||
const document = await buildDocument({
|
||||
teamId: user.teamId,
|
||||
lastModifiedById: user.id,
|
||||
});
|
||||
const revision = await Revision.createFromDocument(document);
|
||||
|
||||
await NotificationSetting.create({
|
||||
userId: user.id,
|
||||
@@ -157,9 +152,8 @@ describe("revisions.create", () => {
|
||||
});
|
||||
|
||||
await Notifications.on({
|
||||
name: "revisions.create",
|
||||
name: "documents.update.debounced",
|
||||
documentId: document.id,
|
||||
modelId: revision.id,
|
||||
collectionId: document.collectionId,
|
||||
teamId: document.teamId,
|
||||
actorId: document.createdById,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @flow
|
||||
import type { DocumentEvent, RevisionEvent } from "../events";
|
||||
import { Revision, Document, Event } from "../models";
|
||||
import { Revision, Document } from "../models";
|
||||
|
||||
export default class Revisions {
|
||||
async on(event: DocumentEvent | RevisionEvent) {
|
||||
@@ -22,15 +22,7 @@ export default class Revisions {
|
||||
return;
|
||||
}
|
||||
|
||||
const revision = await Revision.createFromDocument(document);
|
||||
Event.add({
|
||||
name: "revisions.create",
|
||||
documentId: document.id,
|
||||
collectionId: document.collectionId,
|
||||
modelId: revision.id,
|
||||
teamId: document.teamId,
|
||||
actorId: revision.userId,
|
||||
});
|
||||
await Revision.createFromDocument(document);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
Vendored
-34
@@ -1,34 +0,0 @@
|
||||
# Heading 1
|
||||
|
||||
## Heading 2
|
||||
|
||||
This is a test paragraph
|
||||
|
||||
This is a second test paragraph. This is a second sentence.
|
||||
|
||||
This is a another test paragraph. This is a another sentence.
|
||||
|
||||
- list item 1
|
||||
- list item 2
|
||||
|
||||
```
|
||||
this is a codeblock
|
||||
```
|
||||
|
||||
:::info
|
||||
This is an info block
|
||||
:::
|
||||
|
||||
!!This is a placeholder!!
|
||||
|
||||
==this is a highlight==
|
||||
|
||||
- [ ] checklist item 1
|
||||
- [ ] checklist item 2
|
||||
- [x] checklist item 3
|
||||
|
||||
same on both sides
|
||||
|
||||
same on both sides
|
||||
|
||||
same on both sides
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
# Heading 1
|
||||
|
||||
## Heading 2
|
||||
|
||||
This is a test paragraph
|
||||
|
||||
This is a second test paragraph. This is a second sentence.
|
||||
|
||||
This is a another test paragraph. This is a another sentence.
|
||||
|
||||
- list item 1
|
||||
|
||||
```
|
||||
this is a codeblock
|
||||
```
|
||||
|
||||
This is a new paragraph.
|
||||
|
||||
:::info
|
||||
This is an info block
|
||||
:::
|
||||
|
||||
!!This is a placeholder!!
|
||||
|
||||
==this is a highlight==
|
||||
|
||||
- [x] checklist item 1
|
||||
- [x] checklist item 2
|
||||
- [ ] checklist item 3
|
||||
- [ ] checklist item 4
|
||||
- [x] checklist item 5
|
||||
|
||||
same on both sides
|
||||
|
||||
same on both sides
|
||||
|
||||
same on both sides
|
||||
@@ -2,11 +2,9 @@
|
||||
require("dotenv").config({ silent: true });
|
||||
|
||||
// test environment variables
|
||||
process.env.URL = "http://localhost:3000";
|
||||
process.env.DATABASE_URL = process.env.DATABASE_URL_TEST;
|
||||
process.env.NODE_ENV = "test";
|
||||
process.env.GOOGLE_CLIENT_ID = "123";
|
||||
process.env.AZURE_CLIENT_ID = "";
|
||||
process.env.SLACK_KEY = "123";
|
||||
process.env.DEPLOYMENT = "";
|
||||
process.env.ALLOWED_DOMAINS = "allowed-domain.com";
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`should diff a complex document 1`] = `
|
||||
"<p>This is a second test paragraph. This is a second sentence.</p>
|
||||
<p>This is a another test paragraph. This is a another sentence.</p>
|
||||
<ul>
|
||||
<li>list item 1</li>
|
||||
<li data-diff-node=\\"del\\" data-operation-index=\\"1\\"><del data-operation-index=\\"1\\">list item 2</del></li></ul>
|
||||
<pre><code>this is a codeblock
|
||||
</code></pre><p data-diff-node=\\"ins\\" data-operation-index=\\"3\\"><ins data-operation-index=\\"3\\">This is a new paragraph.</ins></p>
|
||||
<div class=\\"notice notice-info\\">
|
||||
<p>This is an info block</p>
|
||||
</div>
|
||||
<p><span class=\\"placeholder\\">This is a placeholder</span></p>
|
||||
<p><span class=\\"highlight\\">this is a highlight</span></p>
|
||||
<ul>
|
||||
<li class=\\"checkbox-list-item\\"><span class=\\"checkbox checked\\">[<del data-operation-index=\\"5\\"> ]</del><ins data-operation-index=\\"5\\">x]</ins></span>checklist item 1</li><li class=\\"checkbox-list-item\\"><span class=\\"checkbox checked\\" data-diff-node=\\"ins\\" data-operation-index=\\"7\\"><ins data-operation-index=\\"7\\">[x]</ins></span><ins data-operation-index=\\"7\\">checklist item 2</ins></li>
|
||||
<li class=\\"checkbox-list-item\\"><span class=\\"checkbox \\">[ ]</span>checklist item <del data-operation-index=\\"9\\">2</del><ins data-operation-index=\\"9\\">3</ins></li><li class=\\"checkbox-list-item\\"><span class=\\"checkbox \\" data-diff-node=\\"ins\\" data-operation-index=\\"9\\"><ins data-operation-index=\\"9\\">[ ]</ins></span><ins data-operation-index=\\"9\\">checklist item 4</ins></li>
|
||||
<li class=\\"checkbox-list-item\\"><span class=\\"checkbox checked\\">[x]</span>checklist item <del data-operation-index=\\"11\\">3</del><ins data-operation-index=\\"11\\">5</ins></li>
|
||||
</ul>"
|
||||
`;
|
||||
|
||||
exports[`should return everything inserted when previously empty 1`] = `
|
||||
"<h1 data-diff-node=\\"ins\\" data-operation-index=\\"0\\"><ins data-operation-index=\\"0\\">Heading 1</ins></h1><h2 data-diff-node=\\"ins\\" data-operation-index=\\"0\\"><ins data-operation-index=\\"0\\">Heading 2</ins></h2><p data-diff-node=\\"ins\\" data-operation-index=\\"0\\"><ins data-operation-index=\\"0\\">This is a test paragraph</ins></p><p data-diff-node=\\"ins\\" data-operation-index=\\"0\\"><ins data-operation-index=\\"0\\">This is a second test paragraph. This is a second sentence.</ins></p><p data-diff-node=\\"ins\\" data-operation-index=\\"0\\"><ins data-operation-index=\\"0\\">This is a another test paragraph. This is a another sentence.</ins></p><ul data-diff-node=\\"ins\\" data-operation-index=\\"0\\"><li data-diff-node=\\"ins\\" data-operation-index=\\"0\\"><ins data-operation-index=\\"0\\">list item 1</ins></li><li data-diff-node=\\"ins\\" data-operation-index=\\"0\\"><ins data-operation-index=\\"0\\">list item 2</ins></li></ul><pre data-diff-node=\\"ins\\" data-operation-index=\\"0\\"><code data-diff-node=\\"ins\\" data-operation-index=\\"0\\"><ins data-operation-index=\\"0\\">this is a codeblock
|
||||
</ins></code></pre><div class=\\"notice notice-info\\" data-diff-node=\\"ins\\" data-operation-index=\\"0\\"><p data-diff-node=\\"ins\\" data-operation-index=\\"0\\"><ins data-operation-index=\\"0\\">This is an info block</ins></p></div><p data-diff-node=\\"ins\\" data-operation-index=\\"0\\"><span class=\\"placeholder\\" data-diff-node=\\"ins\\" data-operation-index=\\"0\\"><ins data-operation-index=\\"0\\">This is a placeholder</ins></span></p><p data-diff-node=\\"ins\\" data-operation-index=\\"0\\"><span class=\\"highlight\\" data-diff-node=\\"ins\\" data-operation-index=\\"0\\"><ins data-operation-index=\\"0\\">this is a highlight</ins></span></p><ul data-diff-node=\\"ins\\" data-operation-index=\\"0\\"><li class=\\"checkbox-list-item\\" data-diff-node=\\"ins\\" data-operation-index=\\"0\\"><span class=\\"checkbox \\" data-diff-node=\\"ins\\" data-operation-index=\\"0\\"><ins data-operation-index=\\"0\\">[ ]</ins></span><ins data-operation-index=\\"0\\">checklist item 1</ins></li><li class=\\"checkbox-list-item\\" data-diff-node=\\"ins\\" data-operation-index=\\"0\\"><span class=\\"checkbox \\" data-diff-node=\\"ins\\" data-operation-index=\\"0\\"><ins data-operation-index=\\"0\\">[ ]</ins></span><ins data-operation-index=\\"0\\">checklist item 2</ins></li><li class=\\"checkbox-list-item\\" data-diff-node=\\"ins\\" data-operation-index=\\"0\\"><span class=\\"checkbox checked\\" data-diff-node=\\"ins\\" data-operation-index=\\"0\\"><ins data-operation-index=\\"0\\">[x]</ins></span><ins data-operation-index=\\"0\\">checklist item 3</ins></li></ul><p data-diff-node=\\"ins\\" data-operation-index=\\"0\\"><ins data-operation-index=\\"0\\">same on both sides</ins></p><p data-diff-node=\\"ins\\" data-operation-index=\\"0\\"><ins data-operation-index=\\"0\\">same on both sides</ins></p><p data-diff-node=\\"ins\\" data-operation-index=\\"0\\"><ins data-operation-index=\\"0\\">same on both sides</ins></p>"
|
||||
`;
|
||||
@@ -1,57 +0,0 @@
|
||||
// @flow
|
||||
import { findIndex, findLastIndex } from "lodash";
|
||||
import diff from "node-htmldiff";
|
||||
import { renderToHtml } from "rich-markdown-editor";
|
||||
|
||||
export default function markdownDiff(
|
||||
before: string,
|
||||
after: string,
|
||||
fullDiff: boolean = false,
|
||||
buffer: number = 1
|
||||
) {
|
||||
// The basic idea here is to first render the Markdown to HTML, then diff the
|
||||
// HTML - both sides will have valid HTML so we should have a valid diff as well
|
||||
|
||||
const beforeHtml = renderToHtml(before);
|
||||
const afterHtml = renderToHtml(after);
|
||||
const diffHtml = diff(beforeHtml, afterHtml);
|
||||
|
||||
if (fullDiff) {
|
||||
return diffHtml;
|
||||
}
|
||||
|
||||
if (before === after) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Split diff at paragraphs and find the first and last changed tags
|
||||
// so we can chop around paragraphs rather than return the entire document.
|
||||
//
|
||||
// In an ideal world we'd use an AST here and parse that rather than be doing
|
||||
// operations on strings. I hope this can be revisted in the future with an
|
||||
// improved diffing library.
|
||||
const newParagraph = /(?:^|\n)<p>/;
|
||||
let lines = diffHtml.split(newParagraph);
|
||||
|
||||
const firstChangedLineIndex = findIndex(
|
||||
lines,
|
||||
(value) => value.includes("<ins ") || value.includes("<del ")
|
||||
);
|
||||
const lastChangedLineIndex = findLastIndex(
|
||||
lines,
|
||||
(value) => value.includes("</ins>") || value.includes("</del>")
|
||||
);
|
||||
|
||||
const start = Math.max(0, firstChangedLineIndex - buffer);
|
||||
const end = Math.min(lines.length, lastChangedLineIndex + buffer);
|
||||
lines = lines.slice(start, end);
|
||||
|
||||
if (!lines.length) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return [start > 0 ? "" : undefined, ...lines]
|
||||
.filter((x) => x !== undefined)
|
||||
.join("\n<p>")
|
||||
.trim();
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
// @flow
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import markdownDiff from "./markdownDiff";
|
||||
|
||||
it("should diff a complex document", async () => {
|
||||
const before = await fs.promises.readFile(
|
||||
path.resolve(process.cwd(), "server", "test", "fixtures", "complex.md"),
|
||||
"utf8"
|
||||
);
|
||||
|
||||
const after = await fs.promises.readFile(
|
||||
path.resolve(
|
||||
process.cwd(),
|
||||
"server",
|
||||
"test",
|
||||
"fixtures",
|
||||
"complexModified.md"
|
||||
),
|
||||
"utf8"
|
||||
);
|
||||
|
||||
const diff = markdownDiff(before, after);
|
||||
expect(diff).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should return empty string when both sides are empty", () => {
|
||||
const diff = markdownDiff("", "");
|
||||
expect(diff).toEqual("");
|
||||
});
|
||||
|
||||
it("should return everything inserted when previously empty", async () => {
|
||||
const content = await fs.promises.readFile(
|
||||
path.resolve(process.cwd(), "server", "test", "fixtures", "complex.md"),
|
||||
"utf8"
|
||||
);
|
||||
|
||||
const diff = markdownDiff("", content);
|
||||
expect(diff).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should return empty for changed nodes", async () => {
|
||||
// Note: This isn't ideal behavior, but it is current behavior. If the diffing
|
||||
// library is improved then we could potentially render the old + new heading
|
||||
// with ins/del tags as appropriate.
|
||||
const diff = markdownDiff("# Heading", "## Heading");
|
||||
expect(diff).toEqual("");
|
||||
});
|
||||
|
||||
it("should return deleted nodes", async () => {
|
||||
const diff = markdownDiff("", "");
|
||||
expect(diff).toEqual(
|
||||
'<p><del data-operation-index="0"><img src="/image.png" alt="caption"></del></p>'
|
||||
);
|
||||
});
|
||||
+2
-2
@@ -163,13 +163,13 @@ export const deleteFromS3 = (key: string) => {
|
||||
.promise();
|
||||
};
|
||||
|
||||
export const getSignedImageUrl = async (key: string, expires: number = 60) => {
|
||||
export const getSignedImageUrl = async (key: string) => {
|
||||
const isDocker = process.env.AWS_S3_UPLOAD_BUCKET_URL.match(/http:\/\/s3:/);
|
||||
|
||||
const params = {
|
||||
Bucket: AWS_S3_UPLOAD_BUCKET_NAME,
|
||||
Key: key,
|
||||
Expires: expires,
|
||||
Expires: 60,
|
||||
};
|
||||
|
||||
return isDocker
|
||||
|
||||
@@ -13,6 +13,7 @@ export const languageOptions = [
|
||||
{ label: "Español (España)", value: "es_ES" },
|
||||
{ label: "Français (France)", value: "fr_FR" },
|
||||
{ label: "Italiano (Italia)", value: "it_IT" },
|
||||
{ label: "日本語 (Japanese)", value: "ja_JP" },
|
||||
{ label: "한국어 (Korean)", value: "ko_KR" },
|
||||
{ label: "Português (Brazil)", value: "pt_BR" },
|
||||
{ label: "Português (Portugal)", value: "pt_PT" },
|
||||
|
||||
@@ -152,12 +152,12 @@
|
||||
"Path to document": "Pfad zum Dokument",
|
||||
"Group member options": "Optionen für Gruppenmitglieder",
|
||||
"Remove": "Entfernen",
|
||||
"Collection": "Sammlung",
|
||||
"New document": "Neues Dokument",
|
||||
"Import document": "Dokument importieren",
|
||||
"Edit": "Bearbeiten",
|
||||
"Permissions": "Berechtigungen",
|
||||
"Delete": "Löschen",
|
||||
"Collection": "Sammlung",
|
||||
"Collection permissions": "Berechtigungen für Sammlungen",
|
||||
"Edit collection": "Sammlung bearbeiten",
|
||||
"Delete collection": "Sammlung löschen",
|
||||
@@ -206,6 +206,7 @@
|
||||
"Share options": "Teilen-Einstellungen",
|
||||
"Go to document": "Zum Dokument gehen",
|
||||
"Revoke link": "Link widerrufen",
|
||||
"Table of contents": "Inhaltsverzeichnis",
|
||||
"By {{ author }}": "Von {{ author }}",
|
||||
"Are you sure you want to make {{ userName }} an admin? Admins can modify team and billing information.": "Sind Sie sicher, dass Sie {{ userName }} zu einem Administrator machen möchten? Administratoren können Team- und Rechnungsinformationen ändern.",
|
||||
"Are you sure you want to make {{ userName }} a member?": "Sind Sie sicher, dass Sie {{ userName }} zu einem Mitglied machen möchten?",
|
||||
@@ -337,7 +338,6 @@
|
||||
"Move current document": "Aktuelles Dokument verschieben",
|
||||
"Jump to search": "Zur Suche springen",
|
||||
"Jump to home": "Zurück zum Dashboard",
|
||||
"Table of contents": "Inhaltsverzeichnis",
|
||||
"Toggle navigation": "Navigation ausblenden",
|
||||
"Focus search input": "Fokussiere Suchergebnis",
|
||||
"Open this guide": "Diese Anleitung öffnen",
|
||||
|
||||
@@ -206,6 +206,9 @@
|
||||
"Share options": "Share options",
|
||||
"Go to document": "Go to document",
|
||||
"Revoke link": "Revoke link",
|
||||
"Contents": "Contents",
|
||||
"Headings you add to the document will appear here": "Headings you add to the document will appear here",
|
||||
"Table of contents": "Table of contents",
|
||||
"By {{ author }}": "By {{ author }}",
|
||||
"Are you sure you want to make {{ userName }} an admin? Admins can modify team and billing information.": "Are you sure you want to make {{ userName }} an admin? Admins can modify team and billing information.",
|
||||
"Are you sure you want to make {{ userName }} a member?": "Are you sure you want to make {{ userName }} a member?",
|
||||
@@ -337,7 +340,6 @@
|
||||
"Move current document": "Move current document",
|
||||
"Jump to search": "Jump to search",
|
||||
"Jump to home": "Jump to home",
|
||||
"Table of contents": "Table of contents",
|
||||
"Toggle navigation": "Toggle navigation",
|
||||
"Focus search input": "Focus search input",
|
||||
"Open this guide": "Open this guide",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"currently editing": "actualmente editando",
|
||||
"currently viewing": "viendo actualmente",
|
||||
"previously edited": "previously edited",
|
||||
"previously edited": "editado previamente",
|
||||
"You": "Usted",
|
||||
"Viewers": "Viewers",
|
||||
"Sorry, an error occurred saving the collection": "Lo sentimos, se produjo un error al guardar la colección",
|
||||
@@ -30,9 +30,9 @@
|
||||
"in": "en",
|
||||
"nested document": "documento anidado",
|
||||
"nested document_plural": "documentos anidados",
|
||||
"Viewed by": "Viewed by",
|
||||
"only you": "only you",
|
||||
"person": "person",
|
||||
"Viewed by": "Visto por",
|
||||
"only you": "sólo tú",
|
||||
"person": "persona",
|
||||
"people": "people",
|
||||
"Currently editing": "Currently editing",
|
||||
"Currently viewing": "Currently viewing",
|
||||
@@ -55,8 +55,8 @@
|
||||
"Delete column": "Eliminar columna",
|
||||
"Delete row": "Borrar fila",
|
||||
"Delete table": "Eliminar tabla",
|
||||
"Delete image": "Delete image",
|
||||
"Download image": "Download image",
|
||||
"Delete image": "Eliminar imagen",
|
||||
"Download image": "Descargar imagen",
|
||||
"Float left": "Float left",
|
||||
"Float right": "Float right",
|
||||
"Center large": "Center large",
|
||||
@@ -109,7 +109,7 @@
|
||||
"Dismiss": "Descartar",
|
||||
"Keyboard shortcuts": "Atajos del teclado",
|
||||
"Back": "Atras",
|
||||
"Collections could not be loaded, please reload the app": "Collections could not be loaded, please reload the app",
|
||||
"Collections could not be loaded, please reload the app": "No se pudieron cargar las colecciones, por favor recarga la aplicación",
|
||||
"New collection": "Nueva colección",
|
||||
"Collections": "Colecciones",
|
||||
"Untitled": "Sin título",
|
||||
@@ -136,8 +136,8 @@
|
||||
"Installation": "Instalación",
|
||||
"Unstar": "Eliminar de favoritos",
|
||||
"Star": "Favorito",
|
||||
"Previous page": "Previous page",
|
||||
"Next page": "Next page",
|
||||
"Previous page": "Página anterior",
|
||||
"Next page": "Página siguiente",
|
||||
"Could not import file": "No se pudo importar el archivo",
|
||||
"Appearance": "Apariencia",
|
||||
"System": "Sistema",
|
||||
@@ -152,12 +152,12 @@
|
||||
"Path to document": "Ruta al documento",
|
||||
"Group member options": "Opciones de miembros del grupo",
|
||||
"Remove": "Eliminar",
|
||||
"Collection": "Colección",
|
||||
"New document": "Nuevo documento",
|
||||
"Import document": "Importar documento",
|
||||
"Edit": "Editar",
|
||||
"Permissions": "Permisos",
|
||||
"Delete": "Borrar",
|
||||
"Collection": "Colección",
|
||||
"Collection permissions": "Permisos de colección",
|
||||
"Edit collection": "Editar colección",
|
||||
"Delete collection": "Eliminar colección",
|
||||
@@ -181,7 +181,7 @@
|
||||
"Create template": "Crear plantilla",
|
||||
"Duplicate": "Duplicar",
|
||||
"Unpublish": "Cancelar publicación",
|
||||
"Permanently delete": "Permanently delete",
|
||||
"Permanently delete": "Eliminar permanentemente",
|
||||
"Move": "Mover",
|
||||
"History": "Historial",
|
||||
"Download": "Descargar",
|
||||
@@ -206,19 +206,20 @@
|
||||
"Share options": "Share options",
|
||||
"Go to document": "Ir al documento",
|
||||
"Revoke link": "Revocar enlace",
|
||||
"Table of contents": "Tabla de contenido",
|
||||
"By {{ author }}": "Por {{ author }}",
|
||||
"Are you sure you want to make {{ userName }} an admin? Admins can modify team and billing information.": "¿Estás seguro de que quieres convertir a {{ userName }} en administrador? Los administradores pueden modificar el equipo e información de facturación.",
|
||||
"Are you sure you want to make {{ userName }} a member?": "¿Estás seguro de que quieres convertir a {{ userName }} en miembro?",
|
||||
"Are you sure you want to make {{ userName }} a read-only viewer? They will not be able to edit any content": "Are you sure you want to make {{ userName }} a read-only viewer? They will not be able to edit any content",
|
||||
"Are you sure you want to suspend this account? Suspended users will be prevented from logging in.": "¿Está seguro que desea suspender esta cuenta? Los usuarios suspendidos no podrán iniciar sesión.",
|
||||
"User options": "User options",
|
||||
"User options": "Opciones de usuario",
|
||||
"Make {{ userName }} a member": "Make {{ userName }} a member",
|
||||
"Make {{ userName }} a viewer": "Make {{ userName }} a viewer",
|
||||
"Make {{ userName }} an admin…": "Hacer a {{ userName }} un administrador…",
|
||||
"Revoke invite": "Revocar Invitación",
|
||||
"Activate account": "Activar cuenta",
|
||||
"Suspend account": "Suspender cuenta",
|
||||
"API token created": "API token created",
|
||||
"API token created": "Token de API creado",
|
||||
"Name your token something that will help you to remember it's use in the future, for example \"local development\", \"production\", or \"continuous integration\".": "Name your token something that will help you to remember it's use in the future, for example \"local development\", \"production\", or \"continuous integration\".",
|
||||
"Documents": "Documentos",
|
||||
"The document archive is empty at the moment.": "El archivo de documento está vacío en este momento.",
|
||||
@@ -226,9 +227,9 @@
|
||||
"<em>{{ collectionName }}</em> doesn’t contain any\n documents yet.": "<em>{{ collectionName }}</em> aún no contiene\n documentos.",
|
||||
"Get started by creating a new one!": "¡Empiece creando uno nuevo!",
|
||||
"Create a document": "Crear documento",
|
||||
"Manage permissions": "Manage permissions",
|
||||
"This collection is only visible to those given access": "This collection is only visible to those given access",
|
||||
"Private": "Private",
|
||||
"Manage permissions": "Administrar permisos",
|
||||
"This collection is only visible to those given access": "Esta colección sólo es visible a aquellos con acceso",
|
||||
"Private": "Privado",
|
||||
"Pinned": "Fijado",
|
||||
"Recently updated": "Recientemente actualizado",
|
||||
"Recently published": "Recientemente publicado",
|
||||
@@ -241,7 +242,7 @@
|
||||
"Alphabetical": "Alfabético",
|
||||
"Public document sharing": "Public document sharing",
|
||||
"When enabled, documents can be shared publicly on the internet.": "When enabled, documents can be shared publicly on the internet.",
|
||||
"Public sharing is currently disabled in the team security settings.": "Public sharing is currently disabled in the team security settings.",
|
||||
"Public sharing is currently disabled in the team security settings.": "Compartir públicamente está desactivado en las configuraciones de seguridad del equipo.",
|
||||
"Saving": "Guardando",
|
||||
"Save": "Guardar",
|
||||
"Collections are for grouping your documents. They work best when organized around a topic or internal team — Product or Engineering for example.": "Collections are for grouping your documents. They work best when organized around a topic or internal team — Product or Engineering for example.",
|
||||
@@ -268,15 +269,15 @@
|
||||
"Never signed in": "No ha iniciado sesión nunca",
|
||||
"Invited": "Invitado",
|
||||
"Admin": "Admin",
|
||||
"{{ userName }} was removed from the collection": "{{ userName }} was removed from the collection",
|
||||
"{{ userName }} was removed from the collection": "{{ userName }} fue quitado de la colección",
|
||||
"Could not remove user": "No se pudo remover al usuario",
|
||||
"{{ userName }} permissions were updated": "{{ userName }} permissions were updated",
|
||||
"Could not update user": "Could not update user",
|
||||
"The {{ groupName }} group was removed from the collection": "The {{ groupName }} group was removed from the collection",
|
||||
"Could not remove group": "Could not remove group",
|
||||
"{{ userName }} permissions were updated": "Se actualizaron los permisos de {{ userName }}",
|
||||
"Could not update user": "No se pudo actualizar el usuario",
|
||||
"The {{ groupName }} group was removed from the collection": "El grupo {{ groupName }} fue quitado de la colección",
|
||||
"Could not remove group": "No se pudo eliminar el grupo",
|
||||
"{{ groupName }} permissions were updated": "{{ groupName }} permissions were updated",
|
||||
"Default access permissions were updated": "Default access permissions were updated",
|
||||
"Could not update permissions": "Could not update permissions",
|
||||
"Could not update permissions": "No se pudo actualizar los permisos",
|
||||
"The <em>{{ collectionName }}</em> collection is private. Team members have no access to it by default.": "The <em>{{ collectionName }}</em> collection is private. Team members have no access to it by default.",
|
||||
"Team members can view documents in the <em>{{ collectionName }}</em> collection by default.": "Team members can view documents in the <em>{{ collectionName }}</em> collection by default.",
|
||||
"Team members can view and edit documents in the <em>{{ collectionName }}</em> collection by\n default.": "Team members can view and edit documents in the <em>{{ collectionName }}</em> collection by\n default.",
|
||||
@@ -337,7 +338,6 @@
|
||||
"Move current document": "Mover el documento actual",
|
||||
"Jump to search": "Ir a la búsqueda",
|
||||
"Jump to home": "Jump to home",
|
||||
"Table of contents": "Tabla de contenido",
|
||||
"Toggle navigation": "Toggle navigation",
|
||||
"Focus search input": "Focus search input",
|
||||
"Open this guide": "Abra esta guía",
|
||||
|
||||
@@ -152,12 +152,12 @@
|
||||
"Path to document": "Path to document",
|
||||
"Group member options": "Group member options",
|
||||
"Remove": "حذف",
|
||||
"Collection": "مجموعه",
|
||||
"New document": "سند جدید",
|
||||
"Import document": "وارد کردن سند",
|
||||
"Edit": "ویرایش",
|
||||
"Permissions": "دسترسیها",
|
||||
"Delete": "حذف",
|
||||
"Collection": "مجموعه",
|
||||
"Collection permissions": "دسترسیهای مجموعه",
|
||||
"Edit collection": "ویرایش مجموعه",
|
||||
"Delete collection": "حذف مجموعه",
|
||||
@@ -206,6 +206,7 @@
|
||||
"Share options": "Share options",
|
||||
"Go to document": "Go to document",
|
||||
"Revoke link": "Revoke link",
|
||||
"Table of contents": "Table of contents",
|
||||
"By {{ author }}": "By {{ author }}",
|
||||
"Are you sure you want to make {{ userName }} an admin? Admins can modify team and billing information.": "Are you sure you want to make {{ userName }} an admin? Admins can modify team and billing information.",
|
||||
"Are you sure you want to make {{ userName }} a member?": "Are you sure you want to make {{ userName }} a member?",
|
||||
@@ -337,7 +338,6 @@
|
||||
"Move current document": "Move current document",
|
||||
"Jump to search": "Jump to search",
|
||||
"Jump to home": "Jump to home",
|
||||
"Table of contents": "Table of contents",
|
||||
"Toggle navigation": "Toggle navigation",
|
||||
"Focus search input": "Focus search input",
|
||||
"Open this guide": "Open this guide",
|
||||
|
||||
@@ -152,12 +152,12 @@
|
||||
"Path to document": "Chemin d'accès au document",
|
||||
"Group member options": "Options des membres du groupe",
|
||||
"Remove": "Supprimer",
|
||||
"Collection": "Collection",
|
||||
"New document": "Nouveau document",
|
||||
"Import document": "Importer un document",
|
||||
"Edit": "Modifier",
|
||||
"Permissions": "Permissions",
|
||||
"Delete": "Supprimer",
|
||||
"Collection": "Collection",
|
||||
"Collection permissions": "Permissions sur les collections",
|
||||
"Edit collection": "Modifier la collection",
|
||||
"Delete collection": "Supprimer la collection",
|
||||
@@ -206,6 +206,7 @@
|
||||
"Share options": "Options de partage",
|
||||
"Go to document": "Accéder au document",
|
||||
"Revoke link": "Révoquer le lien",
|
||||
"Table of contents": "Table des matières",
|
||||
"By {{ author }}": "Par {{ author }}",
|
||||
"Are you sure you want to make {{ userName }} an admin? Admins can modify team and billing information.": "Voulez-vous vraiment faire de {{ userName }} un administrateur ? Les administrateurs peuvent modifier les informations relatives à l'équipe et à la facturation.",
|
||||
"Are you sure you want to make {{ userName }} a member?": "Êtes-vous sûr de vouloir faire de {{ userName }} un membre ?",
|
||||
@@ -337,7 +338,6 @@
|
||||
"Move current document": "Déplacer le document courant",
|
||||
"Jump to search": "Aller à la recherche",
|
||||
"Jump to home": "Jump to home",
|
||||
"Table of contents": "Table des matières",
|
||||
"Toggle navigation": "Toggle navigation",
|
||||
"Focus search input": "Focus search input",
|
||||
"Open this guide": "Ouvrir ce guide",
|
||||
|
||||
@@ -152,12 +152,12 @@
|
||||
"Path to document": "Percorso del documento",
|
||||
"Group member options": "Opzioni membri del gruppo",
|
||||
"Remove": "Elimina",
|
||||
"Collection": "Raccolta",
|
||||
"New document": "Nuovo documento",
|
||||
"Import document": "Importa documento",
|
||||
"Edit": "Modifica",
|
||||
"Permissions": "Permessi",
|
||||
"Delete": "Cancella",
|
||||
"Collection": "Raccolta",
|
||||
"Collection permissions": "Collection permissions",
|
||||
"Edit collection": "Modifica raccolta",
|
||||
"Delete collection": "Elimina raccolta",
|
||||
@@ -206,6 +206,7 @@
|
||||
"Share options": "Opzioni di condivisione",
|
||||
"Go to document": "Vai al documento",
|
||||
"Revoke link": "Revoca il link",
|
||||
"Table of contents": "Indice contenuti",
|
||||
"By {{ author }}": "Di {{ author }}",
|
||||
"Are you sure you want to make {{ userName }} an admin? Admins can modify team and billing information.": "Sei sicuro di voler rendere {{ userName }} un amministratore? Gli amministratori possono modificare le informazioni sul team e sulla fatturazione.",
|
||||
"Are you sure you want to make {{ userName }} a member?": "Sei sicuro di voler rendere {{ userName }} un membro?",
|
||||
@@ -337,7 +338,6 @@
|
||||
"Move current document": "Sposta il documento corrente",
|
||||
"Jump to search": "Vai alla ricerca",
|
||||
"Jump to home": "Jump to home",
|
||||
"Table of contents": "Indice contenuti",
|
||||
"Toggle navigation": "Toggle navigation",
|
||||
"Focus search input": "Focus search input",
|
||||
"Open this guide": "Apri questa guida",
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
"in": "に",
|
||||
"nested document": "ネストされたドキュメント",
|
||||
"nested document_plural": "ネストされたドキュメント",
|
||||
"Viewed by": "閲覧者:",
|
||||
"Viewed by": "閲覧者",
|
||||
"only you": "自分のみ",
|
||||
"person": "個人",
|
||||
"people": "メンバー",
|
||||
@@ -98,7 +98,7 @@
|
||||
"Icon": "アイコン",
|
||||
"Show menu": "メニューを表示",
|
||||
"Choose icon": "アイコンの選択",
|
||||
"Loading": "ローディング...",
|
||||
"Loading": "ローディング",
|
||||
"Search": "検索",
|
||||
"Default access": "デフォルトアクセス",
|
||||
"View and edit": "表示・編集",
|
||||
@@ -109,7 +109,7 @@
|
||||
"Dismiss": "終了",
|
||||
"Keyboard shortcuts": "キーボードショートカット",
|
||||
"Back": "戻る",
|
||||
"Collections could not be loaded, please reload the app": "Collections could not be loaded, please reload the app",
|
||||
"Collections could not be loaded, please reload the app": "コレクションを読み込めませんでした。アプリを再読み込みしてください。",
|
||||
"New collection": "コレクションを追加",
|
||||
"Collections": "コレクション",
|
||||
"Untitled": "文書",
|
||||
@@ -152,12 +152,12 @@
|
||||
"Path to document": "ドキュメントのパス",
|
||||
"Group member options": "グループメンバーのオプション",
|
||||
"Remove": "削除",
|
||||
"Collection": "コレクション",
|
||||
"New document": "新しいドキュメント",
|
||||
"Import document": "ドキュメントのインポート",
|
||||
"Edit": "編集",
|
||||
"Permissions": "権限",
|
||||
"Delete": "削除",
|
||||
"Collection": "コレクション",
|
||||
"Collection permissions": "コレクションの権限",
|
||||
"Edit collection": "編集コレクション",
|
||||
"Delete collection": "コレクションの削除",
|
||||
@@ -181,14 +181,14 @@
|
||||
"Create template": "テンプレートの作成",
|
||||
"Duplicate": "文書の複製",
|
||||
"Unpublish": "未発表",
|
||||
"Permanently delete": "Permanently delete",
|
||||
"Permanently delete": "完全に削除します。",
|
||||
"Move": "移動",
|
||||
"History": "変更履歴",
|
||||
"Download": "ダウンロード",
|
||||
"Print": "プリント",
|
||||
"Move {{ documentName }}": "{{ documentName }} を移動",
|
||||
"Delete {{ documentName }}": "{{ documentName }}を削除します。",
|
||||
"Permanently delete {{ documentName }}": "Permanently delete {{ documentName }}",
|
||||
"Permanently delete {{ documentName }}": "{{ documentName }} を完全に削除します。",
|
||||
"Edit group": "グループの編集",
|
||||
"Delete group": "グループを削除",
|
||||
"Group options": "グループのオプション",
|
||||
@@ -206,6 +206,7 @@
|
||||
"Share options": "共有オプション",
|
||||
"Go to document": "ドキュメントに移動",
|
||||
"Revoke link": "リンクを取り消す",
|
||||
"Table of contents": "目次",
|
||||
"By {{ author }}": "作ったのは{{ author }}",
|
||||
"Are you sure you want to make {{ userName }} an admin? Admins can modify team and billing information.": "本当に{{ userName }}を管理者にしていいのか?管理者は課金情報を修正することができます。また、チームを変更することもできます。",
|
||||
"Are you sure you want to make {{ userName }} a member?": "本当に{{ userName }}をメンバーにしていいのか?",
|
||||
@@ -219,7 +220,7 @@
|
||||
"Activate account": "アカウントの有効化",
|
||||
"Suspend account": "アカウントの一時停止",
|
||||
"API token created": "APIトークンが作成されました",
|
||||
"Name your token something that will help you to remember it's use in the future, for example \"local development\", \"production\", or \"continuous integration\".": "Name your token something that will help you to remember it's use in the future, for example \"local development\", \"production\", or \"continuous integration\".",
|
||||
"Name your token something that will help you to remember it's use in the future, for example \"local development\", \"production\", or \"continuous integration\".": "トークンには、「ローカル開発」、「本番」、「継続的インテグレーション」など、使用目的を思い出しやすい名前を付けてください。",
|
||||
"Documents": "ドキュメント",
|
||||
"The document archive is empty at the moment.": "ドキュメントアーカイブは現在空です。",
|
||||
"Search in collection": "コレクション内を検索",
|
||||
@@ -242,7 +243,7 @@
|
||||
"Public document sharing": "公開ドキュメントを共有",
|
||||
"When enabled, documents can be shared publicly on the internet.": "有効にすると、ドキュメントをインターネット上で公開して共有できます。",
|
||||
"Public sharing is currently disabled in the team security settings.": "チームのセキュリティ設定で公開共有が無効になっています。",
|
||||
"Saving": "保存文書...",
|
||||
"Saving": "保存",
|
||||
"Save": "セーブ",
|
||||
"Collections are for grouping your documents. They work best when organized around a topic or internal team — Product or Engineering for example.": "コレクションは、ドキュメントをグループ化するためのものです。製品やエンジニアリングなど、トピックや社内のチームを基準に作成することで、最も効果的に機能します。",
|
||||
"This is the default level of access given to team members, you can give specific users or groups more access once the collection is created.": "これはチームメンバーに付与されるデフォルトのアクセスレベルです。コレクションが作成されると、さらに多くのアクセスを特定のユーザーまたはグループに付与できます。",
|
||||
@@ -272,9 +273,9 @@
|
||||
"Could not remove user": "このユーザーを削除することはできません。",
|
||||
"{{ userName }} permissions were updated": "{{ userName }} の権限が更新されました",
|
||||
"Could not update user": "ユーザーを更新できませんでした",
|
||||
"The {{ groupName }} group was removed from the collection": "グループ:{{ groupName }} がコレクションから削除されました",
|
||||
"The {{ groupName }} group was removed from the collection": "グループ {{ groupName }} がコレクションから削除されました",
|
||||
"Could not remove group": "グループを削除できませんでした",
|
||||
"{{ groupName }} permissions were updated": "グループ:{{ groupName }} の権限が更新されました",
|
||||
"{{ groupName }} permissions were updated": "グループ {{ groupName }} の権限が更新されました",
|
||||
"Default access permissions were updated": "デフォルトのアクセス権限が更新されました",
|
||||
"Could not update permissions": "権限を更新できませんでした",
|
||||
"The <em>{{ collectionName }}</em> collection is private. Team members have no access to it by default.": "<em>{{ collectionName }}</em> コレクションは非公開です。チームメンバーはデフォルトではアクセスできません。",
|
||||
@@ -307,15 +308,15 @@
|
||||
"Share nested documents": "ネストされたドキュメントを共有する",
|
||||
"Nested documents are publicly available": "ネストされたドキュメントも公開されます",
|
||||
"Nested documents are not shared": "ネストされたドキュメントは共有されません",
|
||||
"Are you sure you want to delete the <em>{{ documentTitle }}</em> template?": "テンプレート:<em>{{ documentTitle }}</em> を削除してもよろしいですか?",
|
||||
"Are you sure you want to delete the <em>{{ documentTitle }}</em> template?": "テンプレート <em>{{ documentTitle }}</em> を削除してもよろしいですか?",
|
||||
"Are you sure about that? Deleting the <em>{{ documentTitle }}</em> document will delete all of its history and any nested documents.": "<em>{{ documentTitle }}</em> ドキュメントを削除すると、その履歴とネストされたドキュメントがすべて削除されます。よろしいですか?",
|
||||
"If you’d like the option of referencing or restoring the {{noun}} in the future, consider archiving it instead.": "将来的に {{noun}} の参照または復元が必要になる可能性がある場合は、代わりにアーカイブすることを検討してください。",
|
||||
"Deleting": "削除中",
|
||||
"I’m sure – Delete": "間違いありません – 削除",
|
||||
"Archiving": "アーカイブ中",
|
||||
"Couldn’t create the document, try again?": "Couldn’t create the document, try again?",
|
||||
"Document permanently deleted": "Document permanently deleted",
|
||||
"Are you sure you want to permanently delete the <em>{{ documentTitle }}</em> document? This action is immediate and cannot be undone.": "Are you sure you want to permanently delete the <em>{{ documentTitle }}</em> document? This action is immediate and cannot be undone.",
|
||||
"Couldn’t create the document, try again?": "ドキュメントを作成できませんでした。もう一度やり直してください。",
|
||||
"Document permanently deleted": "ドキュメントが完全に削除されました。",
|
||||
"Are you sure you want to permanently delete the <em>{{ documentTitle }}</em> document? This action is immediate and cannot be undone.": "<em>{{ documentTitle }}</em> ドキュメントを完全に削除してもよろしいですか?この操作は即時に反映され、元に戻すことはできません。",
|
||||
"Search documents": "ドキュメントの検索",
|
||||
"No documents found for your filters.": "検索結果はありませんでした。",
|
||||
"You’ve not got any drafts at the moment.": "この時は下書きがない。",
|
||||
@@ -337,7 +338,6 @@
|
||||
"Move current document": "現在のドキュメントを移動する",
|
||||
"Jump to search": "検索へ",
|
||||
"Jump to home": "ホームへ移動",
|
||||
"Table of contents": "目次",
|
||||
"Toggle navigation": "ナビゲーションの切り替え",
|
||||
"Focus search input": "検索窓にフォーカスする",
|
||||
"Open this guide": "ガイドを開く",
|
||||
@@ -397,7 +397,7 @@
|
||||
"All groups": "すべてのグループ",
|
||||
"No groups have been created yet": "グループはまだ作成されていません",
|
||||
"Import started": "インポートを開始しました",
|
||||
"Export in progress…": "エクスポートが進行中...",
|
||||
"Export in progress…": "エクスポートが進行中…",
|
||||
"It is possible to import a zip file of folders and Markdown files previously exported from an Outline instance. Support will soon be added for importing from other services.": "OutlineからエクスポートしたフォルダーとMarkdownファイルを含むzipファイルをインポートすることができます。他のサービスからのインポートについては、間もなくサポートが追加される予定です。",
|
||||
"Your file has been uploaded and the import is currently being processed, you can safely leave this page while it completes.": "ファイルのアップロードが成功し、現在インポート処理を行っています。完了後、このページを離れることが出来ます。",
|
||||
"Sorry, the file <em>{{ fileName }}</em> is missing valid collections or documents.": "ファイル <em>{{ fileName }}</em> は有効なコレクションまたはドキュメントがありません。",
|
||||
|
||||
@@ -152,12 +152,12 @@
|
||||
"Path to document": "문서 경로",
|
||||
"Group member options": "그룹 멤버 옵션",
|
||||
"Remove": "제거",
|
||||
"Collection": "컬렉션",
|
||||
"New document": "새 문서",
|
||||
"Import document": "문서 가져 오기",
|
||||
"Edit": "편집",
|
||||
"Permissions": "권한",
|
||||
"Delete": "삭제",
|
||||
"Collection": "컬렉션",
|
||||
"Collection permissions": "Collection permissions",
|
||||
"Edit collection": "컬렉션 편집",
|
||||
"Delete collection": "컬렉션 삭제",
|
||||
@@ -206,6 +206,7 @@
|
||||
"Share options": "공유 옵션",
|
||||
"Go to document": "문서로 이동",
|
||||
"Revoke link": "링크 삭제",
|
||||
"Table of contents": "목차",
|
||||
"By {{ author }}": "{{ author }} 작성",
|
||||
"Are you sure you want to make {{ userName }} an admin? Admins can modify team and billing information.": "정말로 {{ userName }} 에게 관리자 권한을 부여 하시겠습니까? 관리자는 팀과 결제 정보를 수정할 수 있습니다.",
|
||||
"Are you sure you want to make {{ userName }} a member?": "정말로 {{ userName }} 에게 멤버 권한을 부여 하시겠습니까?",
|
||||
@@ -337,7 +338,6 @@
|
||||
"Move current document": "현재 문서로 이동",
|
||||
"Jump to search": "검색으로 이동",
|
||||
"Jump to home": "홈으로 이동",
|
||||
"Table of contents": "목차",
|
||||
"Toggle navigation": "Toggle navigation",
|
||||
"Focus search input": "Focus search input",
|
||||
"Open this guide": "이 가이드 열기",
|
||||
|
||||
@@ -152,12 +152,12 @@
|
||||
"Path to document": "Path to document",
|
||||
"Group member options": "Group member options",
|
||||
"Remove": "Verwijder",
|
||||
"Collection": "Collectie",
|
||||
"New document": "Nieuw document",
|
||||
"Import document": "Importeer document",
|
||||
"Edit": "Wijzig",
|
||||
"Permissions": "Rechten",
|
||||
"Delete": "Verwijder",
|
||||
"Collection": "Collectie",
|
||||
"Collection permissions": "Collection permissions",
|
||||
"Edit collection": "Wijzig collectie",
|
||||
"Delete collection": "Verwijder collectie",
|
||||
@@ -206,6 +206,7 @@
|
||||
"Share options": "Deel opties",
|
||||
"Go to document": "Ga naar document",
|
||||
"Revoke link": "Trek link in",
|
||||
"Table of contents": "Table of contents",
|
||||
"By {{ author }}": "Door {{ author }}",
|
||||
"Are you sure you want to make {{ userName }} an admin? Admins can modify team and billing information.": "Are you sure you want to make {{ userName }} an admin? Admins can modify team and billing information.",
|
||||
"Are you sure you want to make {{ userName }} a member?": "Are you sure you want to make {{ userName }} a member?",
|
||||
@@ -337,7 +338,6 @@
|
||||
"Move current document": "Move current document",
|
||||
"Jump to search": "Jump to search",
|
||||
"Jump to home": "Jump to home",
|
||||
"Table of contents": "Table of contents",
|
||||
"Toggle navigation": "Toggle navigation",
|
||||
"Focus search input": "Focus search input",
|
||||
"Open this guide": "Open this guide",
|
||||
|
||||
@@ -152,12 +152,12 @@
|
||||
"Path to document": "Ścieżka do dokumentu",
|
||||
"Group member options": "Group member options",
|
||||
"Remove": "Usuń",
|
||||
"Collection": "Kolekcja",
|
||||
"New document": "Nowy dokument",
|
||||
"Import document": "Zaimportuj dokument",
|
||||
"Edit": "Edytuj",
|
||||
"Permissions": "Uprawnienia",
|
||||
"Delete": "Usuń",
|
||||
"Collection": "Kolekcja",
|
||||
"Collection permissions": "Uprawnienia kolekcji",
|
||||
"Edit collection": "Edit collection",
|
||||
"Delete collection": "Delete collection",
|
||||
@@ -206,6 +206,7 @@
|
||||
"Share options": "Opcje udostępniania",
|
||||
"Go to document": "Przejdź do dokumentu",
|
||||
"Revoke link": "Unieważnij link",
|
||||
"Table of contents": "Table of contents",
|
||||
"By {{ author }}": "By {{ author }}",
|
||||
"Are you sure you want to make {{ userName }} an admin? Admins can modify team and billing information.": "Czy na pewno chcesz uczynić {{ userName }} administratorem? Administratorzy mogą modyfikować informacje o zespole i rozliczeniach.",
|
||||
"Are you sure you want to make {{ userName }} a member?": "Are you sure you want to make {{ userName }} a member?",
|
||||
@@ -337,7 +338,6 @@
|
||||
"Move current document": "Przenieś bieżący dokument",
|
||||
"Jump to search": "Jump to search",
|
||||
"Jump to home": "Jump to home",
|
||||
"Table of contents": "Table of contents",
|
||||
"Toggle navigation": "Toggle navigation",
|
||||
"Focus search input": "Focus search input",
|
||||
"Open this guide": "Open this guide",
|
||||
|
||||
@@ -152,12 +152,12 @@
|
||||
"Path to document": "Caminho para o documento",
|
||||
"Group member options": "Opções de membros do grupo",
|
||||
"Remove": "Remover",
|
||||
"Collection": "Coleção",
|
||||
"New document": "Novo documento",
|
||||
"Import document": "Importar documento",
|
||||
"Edit": "Editar",
|
||||
"Permissions": "Permissões",
|
||||
"Delete": "Excluir",
|
||||
"Collection": "Coleção",
|
||||
"Collection permissions": "Permissões da coleção",
|
||||
"Edit collection": "Editar coleção",
|
||||
"Delete collection": "Excluir coleção",
|
||||
@@ -206,6 +206,7 @@
|
||||
"Share options": "Opções de compartilhamento",
|
||||
"Go to document": "Ir para o documento",
|
||||
"Revoke link": "Revogar link",
|
||||
"Table of contents": "Índice",
|
||||
"By {{ author }}": "Por {{ author }}",
|
||||
"Are you sure you want to make {{ userName }} an admin? Admins can modify team and billing information.": "Tem certeza que deseja tornar {{ userName }} um administrador? Os administradores podem modificar as informações da equipe e do faturamento.",
|
||||
"Are you sure you want to make {{ userName }} a member?": "Tem certeza de que deseja tornar {{ userName }} um membro?",
|
||||
@@ -337,7 +338,6 @@
|
||||
"Move current document": "Mover documento atual",
|
||||
"Jump to search": "Ir para pesquisa",
|
||||
"Jump to home": "Ir para a tela inicial",
|
||||
"Table of contents": "Índice",
|
||||
"Toggle navigation": "Alternar de navegação",
|
||||
"Focus search input": "Focar pesquisa",
|
||||
"Open this guide": "Abrir este guia",
|
||||
|
||||
@@ -152,12 +152,12 @@
|
||||
"Path to document": "Path to document",
|
||||
"Group member options": "Group member options",
|
||||
"Remove": "Remover",
|
||||
"Collection": "Coleção",
|
||||
"New document": "Novo documento",
|
||||
"Import document": "Importar documento",
|
||||
"Edit": "Editar",
|
||||
"Permissions": "Permissões",
|
||||
"Delete": "Apagar",
|
||||
"Collection": "Coleção",
|
||||
"Collection permissions": "Collection permissions",
|
||||
"Edit collection": "Editar coleção",
|
||||
"Delete collection": "Apagar coleção",
|
||||
@@ -206,6 +206,7 @@
|
||||
"Share options": "Share options",
|
||||
"Go to document": "Ir para documento",
|
||||
"Revoke link": "Revogar link",
|
||||
"Table of contents": "Índice de conteúdos",
|
||||
"By {{ author }}": "De {{ author }}",
|
||||
"Are you sure you want to make {{ userName }} an admin? Admins can modify team and billing information.": "Tem a certeza que deseja tornar {{ userName }} um administrador? Os administradores podem modificar as informações de faturação e da equipa.",
|
||||
"Are you sure you want to make {{ userName }} a member?": "Tem a certeza de que deseja tornar {{ userName }} um membro?",
|
||||
@@ -337,7 +338,6 @@
|
||||
"Move current document": "Mover documento atual",
|
||||
"Jump to search": "Ir para a pesquisa",
|
||||
"Jump to home": "Jump to home",
|
||||
"Table of contents": "Índice de conteúdos",
|
||||
"Toggle navigation": "Toggle navigation",
|
||||
"Focus search input": "Focus search input",
|
||||
"Open this guide": "Abrir este guia",
|
||||
|
||||
@@ -152,12 +152,12 @@
|
||||
"Path to document": "Путь к документу",
|
||||
"Group member options": "Параметры участников группы",
|
||||
"Remove": "Удалить",
|
||||
"Collection": "Коллекция",
|
||||
"New document": "Новый документ",
|
||||
"Import document": "Импорт документа",
|
||||
"Edit": "Редактировать",
|
||||
"Permissions": "Права доступа",
|
||||
"Delete": "Удалить",
|
||||
"Collection": "Коллекция",
|
||||
"Collection permissions": "Права доступа к коллекции",
|
||||
"Edit collection": "Изменить подборку",
|
||||
"Delete collection": "Удалить коллекцию",
|
||||
@@ -206,6 +206,7 @@
|
||||
"Share options": "Настройка доступа",
|
||||
"Go to document": "Перейти к документу",
|
||||
"Revoke link": "Отозвать ссылку",
|
||||
"Table of contents": "Содержание",
|
||||
"By {{ author }}": "По {{ author }}",
|
||||
"Are you sure you want to make {{ userName }} an admin? Admins can modify team and billing information.": "Удаляем админа {{ userName }}? Админы могут настраивать команду и платежную информацию.",
|
||||
"Are you sure you want to make {{ userName }} a member?": "Делаем {{ userName }} участником?",
|
||||
@@ -337,7 +338,6 @@
|
||||
"Move current document": "Переместить текущий документ",
|
||||
"Jump to search": "Перейти к поиску",
|
||||
"Jump to home": "Перейти на главную",
|
||||
"Table of contents": "Содержание",
|
||||
"Toggle navigation": "Toggle navigation",
|
||||
"Focus search input": "Focus search input",
|
||||
"Open this guide": "Открыть эту инструкцию",
|
||||
|
||||
@@ -3,37 +3,37 @@
|
||||
"currently viewing": "currently viewing",
|
||||
"previously edited": "previously edited",
|
||||
"You": "Du",
|
||||
"Viewers": "Viewers",
|
||||
"Viewers": "Tittare",
|
||||
"Sorry, an error occurred saving the collection": "Sorry, an error occurred saving the collection",
|
||||
"Add a description": "Lägg till en beskrivning",
|
||||
"Collapse": "Collapse",
|
||||
"Expand": "Expand",
|
||||
"Expand": "Expandera",
|
||||
"Submenu": "Undermeny",
|
||||
"Trash": "Papperskorg",
|
||||
"Archive": "Arkiv",
|
||||
"Drafts": "Utkast",
|
||||
"Templates": "Mallar",
|
||||
"Deleted Collection": "Deleted Collection",
|
||||
"New": "New",
|
||||
"New": "Ny",
|
||||
"Only visible to you": "Only visible to you",
|
||||
"Draft": "Utkast",
|
||||
"Template": "Mall",
|
||||
"New doc": "New doc",
|
||||
"deleted": "deleted",
|
||||
"archived": "archived",
|
||||
"New doc": "Nytt dokument",
|
||||
"deleted": "raderad",
|
||||
"archived": "arkiverad",
|
||||
"created": "skapad",
|
||||
"published": "publicerad",
|
||||
"saved": "sparad",
|
||||
"updated": "uppdaterad",
|
||||
"Never viewed": "Never viewed",
|
||||
"Viewed": "Viewed",
|
||||
"Viewed": "Sett",
|
||||
"in": "i",
|
||||
"nested document": "nested document",
|
||||
"nested document_plural": "nested documents",
|
||||
"Viewed by": "Viewed by",
|
||||
"only you": "only you",
|
||||
"only you": "endast dig",
|
||||
"person": "person",
|
||||
"people": "people",
|
||||
"people": "människor",
|
||||
"Currently editing": "Currently editing",
|
||||
"Currently viewing": "Currently viewing",
|
||||
"Viewed {{ timeAgo }} ago": "Viewed {{ timeAgo }} ago",
|
||||
@@ -48,7 +48,7 @@
|
||||
"Todo list": "Att göra-lista",
|
||||
"Code block": "Kodblock",
|
||||
"Copied to clipboard": "Copied to clipboard",
|
||||
"Code": "Code",
|
||||
"Code": "Kod",
|
||||
"Create link": "Skapa länk",
|
||||
"Sorry, an error occurred creating the link": "Sorry, an error occurred creating the link",
|
||||
"Create a new doc": "Create a new doc",
|
||||
@@ -124,7 +124,7 @@
|
||||
"Profile": "Profil",
|
||||
"Notifications": "Notifications",
|
||||
"API Tokens": "API Tokens",
|
||||
"Team": "Team",
|
||||
"Team": "Lag",
|
||||
"Details": "Detaljer",
|
||||
"Security": "Säkerhet",
|
||||
"Members": "Members",
|
||||
@@ -134,15 +134,15 @@
|
||||
"Export": "Exportera",
|
||||
"Integrations": "Integrations",
|
||||
"Installation": "Installation",
|
||||
"Unstar": "Unstar",
|
||||
"Star": "Star",
|
||||
"Unstar": "Ta bort stjärnmärkning",
|
||||
"Star": "Stjärna",
|
||||
"Previous page": "Previous page",
|
||||
"Next page": "Next page",
|
||||
"Could not import file": "Could not import file",
|
||||
"Appearance": "Utseende",
|
||||
"System": "System",
|
||||
"Light": "Light",
|
||||
"Dark": "Dark",
|
||||
"Light": "Ljus",
|
||||
"Dark": "Mörk",
|
||||
"API documentation": "API documentation",
|
||||
"Changelog": "Changelog",
|
||||
"Send us feedback": "Send us feedback",
|
||||
@@ -151,13 +151,13 @@
|
||||
"Show path to document": "Show path to document",
|
||||
"Path to document": "Path to document",
|
||||
"Group member options": "Group member options",
|
||||
"Remove": "Remove",
|
||||
"Collection": "Collection",
|
||||
"Remove": "Ta bort",
|
||||
"New document": "New document",
|
||||
"Import document": "Import document",
|
||||
"Edit": "Edit",
|
||||
"Edit": "Redigera",
|
||||
"Permissions": "Permissions",
|
||||
"Delete": "Delete",
|
||||
"Delete": "Radera",
|
||||
"Collection": "Collection",
|
||||
"Collection permissions": "Collection permissions",
|
||||
"Edit collection": "Edit collection",
|
||||
"Delete collection": "Delete collection",
|
||||
@@ -173,7 +173,7 @@
|
||||
"Document options": "Document options",
|
||||
"Restore": "Återställ",
|
||||
"Choose a collection": "Choose a collection",
|
||||
"Unpin": "Unpin",
|
||||
"Unpin": "Lossa",
|
||||
"Pin to collection": "Pin to collection",
|
||||
"Enable embeds": "Enable embeds",
|
||||
"Disable embeds": "Disable embeds",
|
||||
@@ -206,6 +206,7 @@
|
||||
"Share options": "Share options",
|
||||
"Go to document": "Go to document",
|
||||
"Revoke link": "Revoke link",
|
||||
"Table of contents": "Table of contents",
|
||||
"By {{ author }}": "By {{ author }}",
|
||||
"Are you sure you want to make {{ userName }} an admin? Admins can modify team and billing information.": "Are you sure you want to make {{ userName }} an admin? Admins can modify team and billing information.",
|
||||
"Are you sure you want to make {{ userName }} a member?": "Are you sure you want to make {{ userName }} a member?",
|
||||
@@ -229,7 +230,7 @@
|
||||
"Manage permissions": "Manage permissions",
|
||||
"This collection is only visible to those given access": "This collection is only visible to those given access",
|
||||
"Private": "Private",
|
||||
"Pinned": "Pinned",
|
||||
"Pinned": "Fastsatt",
|
||||
"Recently updated": "Recently updated",
|
||||
"Recently published": "Recently published",
|
||||
"Least recently updated": "Least recently updated",
|
||||
@@ -242,12 +243,12 @@
|
||||
"Public document sharing": "Public document sharing",
|
||||
"When enabled, documents can be shared publicly on the internet.": "When enabled, documents can be shared publicly on the internet.",
|
||||
"Public sharing is currently disabled in the team security settings.": "Public sharing is currently disabled in the team security settings.",
|
||||
"Saving": "Saving",
|
||||
"Saving": "Sparar",
|
||||
"Save": "Spara",
|
||||
"Collections are for grouping your documents. They work best when organized around a topic or internal team — Product or Engineering for example.": "Collections are for grouping your documents. They work best when organized around a topic or internal team — Product or Engineering for example.",
|
||||
"This is the default level of access given to team members, you can give specific users or groups more access once the collection is created.": "This is the default level of access given to team members, you can give specific users or groups more access once the collection is created.",
|
||||
"Creating": "Creating",
|
||||
"Create": "Create",
|
||||
"Create": "Skapa",
|
||||
"{{ groupName }} was added to the collection": "{{ groupName }} was added to the collection",
|
||||
"Could not add user": "Could not add user",
|
||||
"Can’t find the group you’re looking for?": "Can’t find the group you’re looking for?",
|
||||
@@ -297,7 +298,7 @@
|
||||
"Publishing": "Publishing",
|
||||
"Nested documents": "Nested documents",
|
||||
"Anyone with the link <1></1>can view this document": "Anyone with the link <1></1>can view this document",
|
||||
"Share": "Share",
|
||||
"Share": "Dela",
|
||||
"Share this document": "Share this document",
|
||||
"This document is shared because the parent <em>{{ documentTitle }}</em> is publicly shared": "This document is shared because the parent <em>{{ documentTitle }}</em> is publicly shared",
|
||||
"Publish to internet": "Publish to internet",
|
||||
@@ -337,7 +338,6 @@
|
||||
"Move current document": "Move current document",
|
||||
"Jump to search": "Jump to search",
|
||||
"Jump to home": "Jump to home",
|
||||
"Table of contents": "Table of contents",
|
||||
"Toggle navigation": "Toggle navigation",
|
||||
"Focus search input": "Focus search input",
|
||||
"Open this guide": "Open this guide",
|
||||
@@ -352,8 +352,8 @@
|
||||
"Small header": "Small header",
|
||||
"Underline": "Underline",
|
||||
"Undo": "Ångra",
|
||||
"Redo": "Redo",
|
||||
"Lists": "Lists",
|
||||
"Redo": "Upprepa",
|
||||
"Lists": "Listor",
|
||||
"Indent list item": "Indent list item",
|
||||
"Outdent list item": "Outdent list item",
|
||||
"Move list item up": "Move list item up",
|
||||
@@ -373,25 +373,25 @@
|
||||
"All documents": "All documents",
|
||||
"Include documents that are in the archive": "Include documents that are in the archive",
|
||||
"Any author": "Any author",
|
||||
"Author": "Author",
|
||||
"Author": "Författare",
|
||||
"Not Found": "Not Found",
|
||||
"We were unable to find the page you’re looking for.": "We were unable to find the page you’re looking for.",
|
||||
"Use the <em>{{ meta }}+K</em> shortcut to search from anywhere in your knowledge base": "Use the <em>{{ meta }}+K</em> shortcut to search from anywhere in your knowledge base",
|
||||
"No documents found for your search filters. <1></1>": "No documents found for your search filters. <1></1>",
|
||||
"Create a new document?": "Create a new document?",
|
||||
"Clear filters": "Clear filters",
|
||||
"Email": "Email",
|
||||
"Email": "E-post",
|
||||
"Last active": "Last active",
|
||||
"Role": "Role",
|
||||
"Viewer": "Viewer",
|
||||
"Role": "Roll",
|
||||
"Viewer": "Läs",
|
||||
"Suspended": "Suspended",
|
||||
"Shared": "Shared",
|
||||
"Shared": "Delad",
|
||||
"by {{ name }}": "by {{ name }}",
|
||||
"Last accessed": "Last accessed",
|
||||
"Add to Slack": "Add to Slack",
|
||||
"Active": "Active",
|
||||
"Active": "Aktiv",
|
||||
"Everyone": "Everyone",
|
||||
"Admins": "Admins",
|
||||
"Admins": "Administratörer",
|
||||
"New group": "New group",
|
||||
"Groups can be used to organize and manage the people on your team.": "Groups can be used to organize and manage the people on your team.",
|
||||
"All groups": "All groups",
|
||||
|
||||
@@ -152,12 +152,12 @@
|
||||
"Path to document": "Path to document",
|
||||
"Group member options": "Group member options",
|
||||
"Remove": "Remove",
|
||||
"Collection": "Collection",
|
||||
"New document": "New document",
|
||||
"Import document": "Import document",
|
||||
"Edit": "Edit",
|
||||
"Permissions": "Permissions",
|
||||
"Delete": "Delete",
|
||||
"Collection": "Collection",
|
||||
"Collection permissions": "Collection permissions",
|
||||
"Edit collection": "Edit collection",
|
||||
"Delete collection": "Delete collection",
|
||||
@@ -206,6 +206,7 @@
|
||||
"Share options": "Share options",
|
||||
"Go to document": "Go to document",
|
||||
"Revoke link": "Revoke link",
|
||||
"Table of contents": "Table of contents",
|
||||
"By {{ author }}": "By {{ author }}",
|
||||
"Are you sure you want to make {{ userName }} an admin? Admins can modify team and billing information.": "Are you sure you want to make {{ userName }} an admin? Admins can modify team and billing information.",
|
||||
"Are you sure you want to make {{ userName }} a member?": "Are you sure you want to make {{ userName }} a member?",
|
||||
@@ -337,7 +338,6 @@
|
||||
"Move current document": "Move current document",
|
||||
"Jump to search": "Jump to search",
|
||||
"Jump to home": "Jump to home",
|
||||
"Table of contents": "Table of contents",
|
||||
"Toggle navigation": "Toggle navigation",
|
||||
"Focus search input": "Focus search input",
|
||||
"Open this guide": "Open this guide",
|
||||
|
||||
@@ -152,12 +152,12 @@
|
||||
"Path to document": "文件路径",
|
||||
"Group member options": "小组成员选项",
|
||||
"Remove": "移除",
|
||||
"Collection": "文档集",
|
||||
"New document": "新建文档",
|
||||
"Import document": "导入文档",
|
||||
"Edit": "编辑",
|
||||
"Permissions": "权限",
|
||||
"Delete": "删除",
|
||||
"Collection": "文档集",
|
||||
"Collection permissions": "文档集权限",
|
||||
"Edit collection": "编辑文档集",
|
||||
"Delete collection": "删除文档集",
|
||||
@@ -206,6 +206,7 @@
|
||||
"Share options": "分享选项",
|
||||
"Go to document": "转到文档",
|
||||
"Revoke link": "撤消链接",
|
||||
"Table of contents": "目录",
|
||||
"By {{ author }}": "创建人 {{ author }}",
|
||||
"Are you sure you want to make {{ userName }} an admin? Admins can modify team and billing information.": "您确定要设置 {{ userName }} 为管理员吗?管理员可以修改团队和帐单信息。",
|
||||
"Are you sure you want to make {{ userName }} a member?": "您确定要设置 {{ userName }} 为成员吗?",
|
||||
@@ -337,7 +338,6 @@
|
||||
"Move current document": "移动当前文档",
|
||||
"Jump to search": "跳转到搜索",
|
||||
"Jump to home": "跳到页",
|
||||
"Table of contents": "目录",
|
||||
"Toggle navigation": "切换导航",
|
||||
"Focus search input": "聚焦搜索结果",
|
||||
"Open this guide": "打开指南",
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
"nested document_plural": "子文件",
|
||||
"Viewed by": "已瀏覽過",
|
||||
"only you": "僅限自己",
|
||||
"person": "person",
|
||||
"people": "people",
|
||||
"person": "人",
|
||||
"people": "人",
|
||||
"Currently editing": "正在編輯",
|
||||
"Currently viewing": "正在瀏覽",
|
||||
"Viewed {{ timeAgo }} ago": "{{ timeAgo }} 前瀏覽過",
|
||||
@@ -57,8 +57,8 @@
|
||||
"Delete table": "刪除表格",
|
||||
"Delete image": "刪除圖片",
|
||||
"Download image": "下載圖片",
|
||||
"Float left": "Float left",
|
||||
"Float right": "Float right",
|
||||
"Float left": "靠左",
|
||||
"Float right": "靠右",
|
||||
"Center large": "Center large",
|
||||
"Italic": "斜體",
|
||||
"Sorry, that link won’t work for this embed type": "抱歉,不支援將這個連結嵌入到文件",
|
||||
@@ -152,12 +152,12 @@
|
||||
"Path to document": "文件路徑",
|
||||
"Group member options": "群組成員選項",
|
||||
"Remove": "移除",
|
||||
"Collection": "文件集",
|
||||
"New document": "建立新文件",
|
||||
"Import document": "匯入文件",
|
||||
"Edit": "編輯",
|
||||
"Permissions": "權限設定",
|
||||
"Delete": "刪除",
|
||||
"Collection": "文件集",
|
||||
"Collection permissions": "文件集權限",
|
||||
"Edit collection": "編輯文件集",
|
||||
"Delete collection": "刪除文件集",
|
||||
@@ -206,9 +206,10 @@
|
||||
"Share options": "分享設定",
|
||||
"Go to document": "跳轉到文件",
|
||||
"Revoke link": "註銷連結",
|
||||
"Table of contents": "目錄",
|
||||
"By {{ author }}": "由 {{ author }}",
|
||||
"Are you sure you want to make {{ userName }} an admin? Admins can modify team and billing information.": "你確定要將 {{ userName }} 設為管理員嗎?管理員可以修改團隊及帳單資訊。",
|
||||
"Are you sure you want to make {{ userName }} a member?": "您卻將要將 {{ userName }} 設定設為成員之一嗎?",
|
||||
"Are you sure you want to make {{ userName }} a member?": "您確定要將 {{ userName }} 設定設為成員之一嗎?",
|
||||
"Are you sure you want to make {{ userName }} a read-only viewer? They will not be able to edit any content": "你確定要將 {{ userName }} 設定為唯讀檢視者嗎?他們將無法編輯任何內容。",
|
||||
"Are you sure you want to suspend this account? Suspended users will be prevented from logging in.": "你確定要停用這個使用者帳號嗎?遭到停用的使用者將無法登入。",
|
||||
"User options": "使用者選項",
|
||||
@@ -255,15 +256,15 @@
|
||||
"Search by group name": "依照群組名稱搜尋",
|
||||
"Search groups": "搜尋群組",
|
||||
"No groups matching your search": "找不到符合搜尋條件的群組",
|
||||
"No groups left to add": "No groups left to add",
|
||||
"No groups left to add": "所有群組都已經被新增",
|
||||
"Add": "新增",
|
||||
"{{ userName }} was added to the collection": "{{ userName }} 已經被新增到文件集",
|
||||
"Need to add someone who’s not yet on the team yet?": "Need to add someone who’s not yet on the team yet?",
|
||||
"Need to add someone who’s not yet on the team yet?": "需要新增尚未加入團隊的人嗎?",
|
||||
"Invite people to {{ teamName }}": "邀請他人加入 {{ teamName }}",
|
||||
"Search by name": "依名稱搜尋",
|
||||
"Search people": "搜尋使用者",
|
||||
"No people matching your search": "找不到符合搜尋條件的使用者",
|
||||
"No people left to add": "No people left to add",
|
||||
"No people left to add": "所有人員都已經被新增",
|
||||
"Active <1></1> ago": "最後活動於 <1></1> 前",
|
||||
"Never signed in": "從未登入",
|
||||
"Invited": "已邀請",
|
||||
@@ -285,7 +286,7 @@
|
||||
"Add people": "新增人員",
|
||||
"Add specific access for individual groups and team members": "為個別群組和團隊成員增加特定的存取權限",
|
||||
"Add groups to {{ collectionName }}": "將群組加入到 {{ collectionName }}",
|
||||
"Add people to {{ collectionName }}": "將使用者加入到 {{ collectionName }}",
|
||||
"Add people to {{ collectionName }}": "將人員加入到 {{ collectionName }}",
|
||||
"Hide contents": "隱藏內容",
|
||||
"Show contents": "顯示內容",
|
||||
"Edit {{noun}}": "編輯 {{noun}}",
|
||||
@@ -337,7 +338,6 @@
|
||||
"Move current document": "移動目前文件",
|
||||
"Jump to search": "跳轉到搜尋",
|
||||
"Jump to home": "跳轉到首頁",
|
||||
"Table of contents": "目錄",
|
||||
"Toggle navigation": "切換導覽",
|
||||
"Focus search input": "Focus search input",
|
||||
"Open this guide": "Open this guide",
|
||||
|
||||
@@ -18,7 +18,19 @@ export const fadeAndScaleIn = keyframes`
|
||||
}
|
||||
`;
|
||||
|
||||
export const fadeAndSlideIn = keyframes`
|
||||
export const fadeAndSlideDown = keyframes`
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(.98) translateY(-10px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1) translateY(0px);
|
||||
}
|
||||
`;
|
||||
|
||||
export const fadeAndSlideUp = keyframes`
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(.98) translateY(10px);
|
||||
@@ -30,6 +42,18 @@ export const fadeAndSlideIn = keyframes`
|
||||
}
|
||||
`;
|
||||
|
||||
export const mobileContextMenu = keyframes`
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(.98) translateY(10vh);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1) translateY(0px);
|
||||
}
|
||||
`;
|
||||
|
||||
export const bounceIn = keyframes`
|
||||
from,
|
||||
20%,
|
||||
|
||||
@@ -57,9 +57,6 @@ module.exports = {
|
||||
new webpack.DefinePlugin({
|
||||
EDITOR_VERSION: JSON.stringify(pkg.version)
|
||||
}),
|
||||
new webpack.ProvidePlugin({
|
||||
fetch: 'imports-loader?this=>global!exports-loader?global.fetch!isomorphic-fetch',
|
||||
}),
|
||||
new webpack.IgnorePlugin(/unicode\/category\/So/),
|
||||
new HtmlWebpackPlugin({
|
||||
template: 'server/static/index.html',
|
||||
|
||||
@@ -1040,7 +1040,7 @@
|
||||
exec-sh "^0.3.2"
|
||||
minimist "^1.2.0"
|
||||
|
||||
"@emotion/is-prop-valid@^0.8.8":
|
||||
"@emotion/is-prop-valid@^0.8.2", "@emotion/is-prop-valid@^0.8.8":
|
||||
version "0.8.8"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a"
|
||||
integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==
|
||||
@@ -4323,6 +4323,13 @@ cron-parser@^2.13.0:
|
||||
is-nan "^1.3.0"
|
||||
moment-timezone "^0.5.31"
|
||||
|
||||
cross-fetch@^3.0.4:
|
||||
version "3.1.4"
|
||||
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.4.tgz#9723f3a3a247bf8b89039f3a380a9244e8fa2f39"
|
||||
integrity sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==
|
||||
dependencies:
|
||||
node-fetch "2.6.1"
|
||||
|
||||
cross-spawn@^5.0.1:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
|
||||
@@ -4861,6 +4868,11 @@ domhandler@^4.0.0, domhandler@^4.2.0:
|
||||
dependencies:
|
||||
domelementtype "^2.2.0"
|
||||
|
||||
domino@^2.1.6:
|
||||
version "2.1.6"
|
||||
resolved "https://registry.yarnpkg.com/domino/-/domino-2.1.6.tgz#fe4ace4310526e5e7b9d12c7de01b7f485a57ffe"
|
||||
integrity sha512-3VdM/SXBZX2omc9JF9nOPCtDaYQ67BGp5CoLpIQlO2KCAPETs8TcDHacF26jXadGbvUteZzRTeos2fhID5+ucQ==
|
||||
|
||||
domutils@1.5.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf"
|
||||
@@ -5040,13 +5052,6 @@ encodeurl@^1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
|
||||
integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
|
||||
|
||||
encoding@^0.1.11:
|
||||
version "0.1.13"
|
||||
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9"
|
||||
integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==
|
||||
dependencies:
|
||||
iconv-lite "^0.6.2"
|
||||
|
||||
end-of-stream@^1.0.0, end-of-stream@^1.1.0:
|
||||
version "1.4.4"
|
||||
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
|
||||
@@ -5764,6 +5769,11 @@ feature-policy@0.3.0:
|
||||
resolved "https://registry.yarnpkg.com/feature-policy/-/feature-policy-0.3.0.tgz#7430e8e54a40da01156ca30aaec1a381ce536069"
|
||||
integrity sha512-ZtijOTFN7TzCujt1fnNhfWPFPSHeZkesff9AXZj+UEjYBynWNUIYpC87Ve4wHzyexQsImicLu7WsC2LHq7/xrQ==
|
||||
|
||||
fetch-retry@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/fetch-retry/-/fetch-retry-4.1.1.tgz#fafe0bb22b54f4d0a9c788dff6dd7f8673ca63f3"
|
||||
integrity sha512-e6eB7zN6UBSwGVwrbWVH+gdLnkW9WwHhmq2YDK1Sh30pzx1onRVGBvogTlUeWxwTa+L86NYdo4hFkh7O8ZjSnA==
|
||||
|
||||
fetch-test-server@^1.1.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/fetch-test-server/-/fetch-test-server-1.2.0.tgz#65f23af1d030c293249a49bbd1b51e45fc68eb69"
|
||||
@@ -6004,6 +6014,26 @@ fragment-cache@^0.2.1:
|
||||
dependencies:
|
||||
map-cache "^0.2.2"
|
||||
|
||||
framer-motion@^4.1.17:
|
||||
version "4.1.17"
|
||||
resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-4.1.17.tgz#4029469252a62ea599902e5a92b537120cc89721"
|
||||
integrity sha512-thx1wvKzblzbs0XaK2X0G1JuwIdARcoNOW7VVwjO8BUltzXPyONGAElLu6CiCScsOQRI7FIk/45YTFtJw5Yozw==
|
||||
dependencies:
|
||||
framesync "5.3.0"
|
||||
hey-listen "^1.0.8"
|
||||
popmotion "9.3.6"
|
||||
style-value-types "4.1.4"
|
||||
tslib "^2.1.0"
|
||||
optionalDependencies:
|
||||
"@emotion/is-prop-valid" "^0.8.2"
|
||||
|
||||
framesync@5.3.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/framesync/-/framesync-5.3.0.tgz#0ecfc955e8f5a6ddc8fdb0cc024070947e1a0d9b"
|
||||
integrity sha512-oc5m68HDO/tuK2blj7ZcdEBRx3p1PjrgHazL8GYEpvULhrtGIFbQArN6cQS2QhW8mitffaB+VYzMjDqBxxQeoA==
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
fresh@~0.5.2:
|
||||
version "0.5.2"
|
||||
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
|
||||
@@ -6601,6 +6631,11 @@ helmet@^3.21.1:
|
||||
referrer-policy "1.2.0"
|
||||
x-xss-protection "1.3.0"
|
||||
|
||||
hey-listen@^1.0.8:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/hey-listen/-/hey-listen-1.0.8.tgz#8e59561ff724908de1aa924ed6ecc84a56a9aa68"
|
||||
integrity sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==
|
||||
|
||||
hide-powered-by@1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/hide-powered-by/-/hide-powered-by-1.1.0.tgz#be3ea9cab4bdb16f8744be873755ca663383fa7a"
|
||||
@@ -6866,13 +6901,6 @@ iconv-lite@0.4.24:
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3"
|
||||
|
||||
iconv-lite@^0.6.2:
|
||||
version "0.6.2"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.2.tgz#ce13d1875b0c3a674bd6a04b7f76b01b1b6ded01"
|
||||
integrity sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3.0.0"
|
||||
|
||||
ieee754@1.1.13:
|
||||
version "1.1.13"
|
||||
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84"
|
||||
@@ -7391,7 +7419,7 @@ is-retry-allowed@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4"
|
||||
integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==
|
||||
|
||||
is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0:
|
||||
is-stream@^1.0.0, is-stream@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
|
||||
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
|
||||
@@ -7489,14 +7517,6 @@ isobject@^3.0.0, isobject@^3.0.1:
|
||||
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
|
||||
integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
|
||||
|
||||
isomorphic-fetch@2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
|
||||
integrity sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=
|
||||
dependencies:
|
||||
node-fetch "^1.0.1"
|
||||
whatwg-fetch ">=0.10.0"
|
||||
|
||||
isomorphic-fetch@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz#0267b005049046d2421207215d45d6a262b8b8b4"
|
||||
@@ -7661,6 +7681,14 @@ jest-environment-node@^26.6.2:
|
||||
jest-mock "^26.6.2"
|
||||
jest-util "^26.6.2"
|
||||
|
||||
jest-fetch-mock@^3.0.3:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/jest-fetch-mock/-/jest-fetch-mock-3.0.3.tgz#31749c456ae27b8919d69824f1c2bd85fe0a1f3b"
|
||||
integrity sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw==
|
||||
dependencies:
|
||||
cross-fetch "^3.0.4"
|
||||
promise-polyfill "^8.1.3"
|
||||
|
||||
jest-get-type@^26.3.0:
|
||||
version "26.3.0"
|
||||
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0"
|
||||
@@ -7985,7 +8013,7 @@ jsbn@~0.1.0:
|
||||
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
|
||||
integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
|
||||
|
||||
jsdom@^16.2.0, jsdom@^16.4.0:
|
||||
jsdom@^16.4.0:
|
||||
version "16.4.0"
|
||||
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.4.0.tgz#36005bde2d136f73eee1a830c6d45e55408edddb"
|
||||
integrity sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w==
|
||||
@@ -9424,24 +9452,11 @@ node-fetch@2.6.1, node-fetch@^2.1.2, node-fetch@^2.6.1:
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
||||
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
||||
|
||||
node-fetch@^1.0.1:
|
||||
version "1.7.3"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef"
|
||||
integrity sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==
|
||||
dependencies:
|
||||
encoding "^0.1.11"
|
||||
is-stream "^1.0.1"
|
||||
|
||||
node-gyp-build@^3.8.0:
|
||||
version "3.9.0"
|
||||
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-3.9.0.tgz#53a350187dd4d5276750da21605d1cb681d09e25"
|
||||
integrity sha512-zLcTg6P4AbcHPq465ZMFNXx7XpKKJh+7kkN699NiQWisR2uWYOWNWqRHAmbnmKiL4e9aLSlmy5U7rEMUXV59+A==
|
||||
|
||||
node-htmldiff@^0.9.3:
|
||||
version "0.9.3"
|
||||
resolved "https://registry.yarnpkg.com/node-htmldiff/-/node-htmldiff-0.9.3.tgz#020704e381597e5e449a4708996edf23eebb7fcc"
|
||||
integrity sha1-AgcE44FZfl5EmkcImW7fI+67f8w=
|
||||
|
||||
node-int64@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
|
||||
@@ -10362,6 +10377,16 @@ polished@3.6.5:
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.9.2"
|
||||
|
||||
popmotion@9.3.6:
|
||||
version "9.3.6"
|
||||
resolved "https://registry.yarnpkg.com/popmotion/-/popmotion-9.3.6.tgz#b5236fa28f242aff3871b9e23721f093133248d1"
|
||||
integrity sha512-ZTbXiu6zIggXzIliMi8LGxXBF5ST+wkpXGEjeTUDUOCdSQ356hij/xjeUdv0F8zCQNeqB1+PR5/BB+gC+QLAPw==
|
||||
dependencies:
|
||||
framesync "5.3.0"
|
||||
hey-listen "^1.0.8"
|
||||
style-value-types "4.1.4"
|
||||
tslib "^2.1.0"
|
||||
|
||||
popper.js@^1.14.7:
|
||||
version "1.16.1"
|
||||
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b"
|
||||
@@ -10488,6 +10513,11 @@ promise-map-series@^0.2.1:
|
||||
dependencies:
|
||||
rsvp "^3.0.14"
|
||||
|
||||
promise-polyfill@^8.1.3:
|
||||
version "8.2.0"
|
||||
resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-8.2.0.tgz#367394726da7561457aba2133c9ceefbd6267da0"
|
||||
integrity sha512-k/TC0mIcPVF6yHhUvwAp7cvL6I2fFV7TzF1DuGPI8mBh4QQazf36xCKEHKTZKRysEoTQoQdKyP25J8MPJp7j5g==
|
||||
|
||||
promise.prototype.finally@^3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/promise.prototype.finally/-/promise.prototype.finally-3.1.2.tgz#b8af89160c9c673cefe3b4c4435b53cfd0287067"
|
||||
@@ -11706,7 +11736,7 @@ safe-regex@^1.1.0:
|
||||
dependencies:
|
||||
ret "~0.1.10"
|
||||
|
||||
"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
|
||||
"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
@@ -12632,6 +12662,14 @@ strip-json-comments@~2.0.1:
|
||||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
|
||||
integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
|
||||
|
||||
style-value-types@4.1.4:
|
||||
version "4.1.4"
|
||||
resolved "https://registry.yarnpkg.com/style-value-types/-/style-value-types-4.1.4.tgz#80f37cb4fb024d6394087403dfb275e8bb627e75"
|
||||
integrity sha512-LCJL6tB+vPSUoxgUBt9juXIlNJHtBMy8jkXzUJSBzeHWdBu6lhzHqCvLVkXFGsFIlNa2ln1sQHya/gzaFmB2Lg==
|
||||
dependencies:
|
||||
hey-listen "^1.0.8"
|
||||
tslib "^2.1.0"
|
||||
|
||||
styled-components-breakpoint@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/styled-components-breakpoint/-/styled-components-breakpoint-2.1.1.tgz#37c1b92b0e96c1bbc5d293724d7a114daaa15fca"
|
||||
@@ -13108,7 +13146,7 @@ tslib@^1.9.0, tslib@^1.9.3:
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
||||
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
||||
|
||||
tslib@^2.0.3, tslib@^2.2.0:
|
||||
tslib@^2.0.3, tslib@^2.1.0, tslib@^2.2.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e"
|
||||
integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
|
||||
@@ -13130,12 +13168,12 @@ tunnel-agent@^0.6.0:
|
||||
dependencies:
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
turndown@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/turndown/-/turndown-6.0.0.tgz#c083d6109a9366be1b84b86b20af09140ea4b413"
|
||||
integrity sha512-UVJBhSyRHCpNKtQ00mNWlYUM/i+tcipkb++F0PrOpt0L7EhNd0AX9mWEpL2dRFBu7LWXMp4HgAMA4OeKKnN7og==
|
||||
turndown@^7.1.1:
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/turndown/-/turndown-7.1.1.tgz#96992f2d9b40a1a03d3ea61ad31b5a5c751ef77f"
|
||||
integrity sha512-BEkXaWH7Wh7e9bd2QumhfAXk5g34+6QUmmWx+0q6ThaVOLuLUqsnkq35HQ5SBHSaxjSfSM7US5o4lhJNH7B9MA==
|
||||
dependencies:
|
||||
jsdom "^16.2.0"
|
||||
domino "^2.1.6"
|
||||
|
||||
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
|
||||
version "0.14.5"
|
||||
@@ -13524,6 +13562,11 @@ utf8@^2.1.0:
|
||||
resolved "https://registry.yarnpkg.com/utf8/-/utf8-2.1.2.tgz#1fa0d9270e9be850d9b05027f63519bf46457d96"
|
||||
integrity sha1-H6DZJw6b6FDZsFAn9jUZv0ZFfZY=
|
||||
|
||||
utf8@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1"
|
||||
integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==
|
||||
|
||||
utif@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/utif/-/utif-2.0.1.tgz#9e1582d9bbd20011a6588548ed3266298e711759"
|
||||
@@ -13902,7 +13945,7 @@ whatwg-encoding@^1.0.5:
|
||||
dependencies:
|
||||
iconv-lite "0.4.24"
|
||||
|
||||
whatwg-fetch@>=0.10.0, whatwg-fetch@^3.4.1:
|
||||
whatwg-fetch@^3.4.1:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.5.0.tgz#605a2cd0a7146e5db141e29d1c62ab84c0c4c868"
|
||||
integrity sha512-jXkLtsR42xhXg7akoDKvKWE40eJeI+2KZqcp2h3NsOrRnDvtWX36KcKl30dy+hxECivdk2BVUHVNrPtoMBUx6A==
|
||||
|
||||
Reference in New Issue
Block a user