diff --git a/.env.sample b/.env.sample
index e4c505d0..dc8f8011 100644
--- a/.env.sample
+++ b/.env.sample
@@ -10,9 +10,14 @@ DATABASE_URL=postgres://user:pass@localhost:5532/outline
DATABASE_URL_TEST=postgres://user:pass@localhost:5532/outline-test
REDIS_URL=redis://localhost:6479
+# Must point to the publicly accessible URL for the installation
URL=http://localhost:3000
PORT=3000
+# Optional. If using a Cloudfront distribution or similar the origin server
+# should be set to the same as URL.
+CDN_URL=
+
# enforce (auto redirect to) https in production, (optional) default is true.
# set to false if your SSL is terminated at a loadbalancer, for example
FORCE_HTTPS=true
@@ -66,4 +71,6 @@ SMTP_REPLY_EMAIL=
# Custom logo that displays on the authentication screen, scaled to height: 60px
# TEAM_LOGO=https://example.com/images/logo.png
+# See translate.getoutline.com for a list of available language codes and their
+# percentage translated.
DEFAULT_LANGUAGE=en_US
\ No newline at end of file
diff --git a/app/components/Editor.js b/app/components/Editor.js
index b16effbc..378d41bd 100644
--- a/app/components/Editor.js
+++ b/app/components/Editor.js
@@ -8,9 +8,9 @@ import UiStore from "stores/UiStore";
import ErrorBoundary from "components/ErrorBoundary";
import Tooltip from "components/Tooltip";
import embeds from "../embeds";
-import isInternalUrl from "utils/isInternalUrl";
import { isMetaKey } from "utils/keyboard";
import { uploadFile } from "utils/uploadFile";
+import { isInternalUrl } from "utils/urls";
const RichMarkdownEditor = React.lazy(() => import("rich-markdown-editor"));
diff --git a/app/components/HoverPreview.js b/app/components/HoverPreview.js
index ba73224a..39b8a3d8 100644
--- a/app/components/HoverPreview.js
+++ b/app/components/HoverPreview.js
@@ -8,7 +8,7 @@ import { fadeAndSlideIn } from "shared/styles/animations";
import parseDocumentSlug from "shared/utils/parseDocumentSlug";
import DocumentsStore from "stores/DocumentsStore";
import HoverPreviewDocument from "components/HoverPreviewDocument";
-import isInternalUrl from "utils/isInternalUrl";
+import { isInternalUrl } from "utils/urls";
const DELAY_OPEN = 300;
const DELAY_CLOSE = 300;
diff --git a/app/components/Image.js b/app/components/Image.js
new file mode 100644
index 00000000..13eb4f58
--- /dev/null
+++ b/app/components/Image.js
@@ -0,0 +1,12 @@
+// @flow
+import * as React from "react";
+import { cdnPath } from "utils/urls";
+
+type Props = {
+ alt: string,
+ src: string,
+};
+
+export default function Image({ src, alt, ...rest }: Props) {
+ return ;
+}
diff --git a/app/components/PageTitle.js b/app/components/PageTitle.js
index a91ef21b..537d8690 100644
--- a/app/components/PageTitle.js
+++ b/app/components/PageTitle.js
@@ -1,16 +1,17 @@
// @flow
-import { observer, inject } from "mobx-react";
+import { observer } from "mobx-react";
import * as React from "react";
import { Helmet } from "react-helmet";
-import AuthStore from "stores/AuthStore";
+import useStores from "hooks/useStores";
+import { cdnPath } from "utils/urls";
-type Props = {
+type Props = {|
title: string,
favicon?: string,
- auth: AuthStore,
-};
+|};
-const PageTitle = observer(({ auth, title, favicon }: Props) => {
+const PageTitle = ({ title, favicon }: Props) => {
+ const { auth } = useStores();
const { team } = auth;
return (
@@ -21,12 +22,12 @@ const PageTitle = observer(({ auth, title, favicon }: Props) => {
);
-});
+};
-export default inject("auth")(PageTitle);
+export default observer(PageTitle);
diff --git a/app/embeds/GoogleDocs.js b/app/embeds/GoogleDocs.js
index 491a8a57..fd5a4263 100644
--- a/app/embeds/GoogleDocs.js
+++ b/app/embeds/GoogleDocs.js
@@ -1,5 +1,6 @@
// @flow
import * as React from "react";
+import Image from "components/Image";
import Frame from "./components/Frame";
const URL_REGEX = new RegExp("^https?://docs.google.com/document/(.*)$");
@@ -20,7 +21,7 @@ export default class GoogleDocs extends React.Component {
{...this.props}
src={this.props.attrs.href.replace("/edit", "/preview")}
icon={
- {
{
{...this.props}
src={this.props.attrs.href.replace("/edit", "/preview")}
icon={
- {
.replace("/edit", "/preview")
.replace("/pub", "/embed")}
icon={
- {
return (
@@ -12,7 +14,7 @@ export default () => {
diff --git a/server/env.js b/server/env.js
index 1f74cd8d..f4d26c06 100644
--- a/server/env.js
+++ b/server/env.js
@@ -1,6 +1,7 @@
// @flow
export default {
URL: process.env.URL,
+ CDN_URL: process.env.CDN_URL || "",
DEPLOYMENT: process.env.DEPLOYMENT,
SENTRY_DSN: process.env.SENTRY_DSN,
TEAM_LOGO: process.env.TEAM_LOGO,
diff --git a/webpack.config.prod.js b/webpack.config.prod.js
index 2a6ccfc1..ee61f901 100644
--- a/webpack.config.prod.js
+++ b/webpack.config.prod.js
@@ -10,7 +10,7 @@ productionWebpackConfig = Object.assign(commonWebpackConfig, {
output: {
path: path.join(__dirname, 'build/app'),
filename: '[name].[contenthash].js',
- publicPath: '/static/',
+ publicPath: `${process.env.CDN_URL || ""}/static/`,
},
cache: true,
mode: "production",