diff --git a/app/components/PageTitle.tsx b/app/components/PageTitle.tsx
index 47e94ec42..24fbd2901 100644
--- a/app/components/PageTitle.tsx
+++ b/app/components/PageTitle.tsx
@@ -1,35 +1,34 @@
import { observer } from "mobx-react";
import * as React from "react";
import { Helmet } from "react-helmet-async";
-import { cdnPath } from "@shared/utils/urls";
import env from "~/env";
import useStores from "~/hooks/useStores";
+import { useTeamContext } from "./TeamContext";
type Props = {
title: React.ReactNode;
favicon?: string;
};
+const originalShortcutHref = document
+ .querySelector('link[rel="shortcut icon"]')
+ ?.getAttribute("href") as string;
+
const PageTitle = ({ title, favicon }: Props) => {
const { auth } = useStores();
- const { team } = auth;
+ const team = useTeamContext() ?? auth.team;
return (
{team?.name ? `${title} - ${team.name}` : `${title} - ${env.APP_NAME}`}
- {favicon ? (
-
- ) : (
-
- )}
+
);
diff --git a/app/components/Sidebar/Shared.tsx b/app/components/Sidebar/Shared.tsx
index 314e88b46..0618beb9a 100644
--- a/app/components/Sidebar/Shared.tsx
+++ b/app/components/Sidebar/Shared.tsx
@@ -8,7 +8,7 @@ import SearchPopover from "~/components/SearchPopover";
import useStores from "~/hooks/useStores";
import history from "~/utils/history";
import { homePath, sharedDocumentPath } from "~/utils/routeHelpers";
-import { IAvatar } from "../Avatar/Avatar";
+import { useTeamContext } from "../TeamContext";
import TeamLogo from "../TeamLogo";
import Sidebar from "./Sidebar";
import HeaderButton from "./components/HeaderButton";
@@ -16,12 +16,12 @@ import Section from "./components/Section";
import DocumentLink from "./components/SharedDocumentLink";
type Props = {
- team?: IAvatar & { name: string };
rootNode: NavigationNode;
shareId: string;
};
-function SharedSidebar({ rootNode, team, shareId }: Props) {
+function SharedSidebar({ rootNode, shareId }: Props) {
+ const team = useTeamContext();
const { ui, documents, auth } = useStores();
const { t } = useTranslation();
diff --git a/app/components/TeamContext.ts b/app/components/TeamContext.ts
new file mode 100644
index 000000000..913350326
--- /dev/null
+++ b/app/components/TeamContext.ts
@@ -0,0 +1,11 @@
+import * as React from "react";
+import { PublicTeam } from "@shared/types";
+import Team from "~/models/Team";
+
+export const TeamContext = React.createContext(
+ undefined
+);
+
+export function useTeamContext() {
+ return React.useContext(TeamContext);
+}
diff --git a/app/scenes/Document/Shared.tsx b/app/scenes/Document/Shared.tsx
index f607c4317..4ddddd7ac 100644
--- a/app/scenes/Document/Shared.tsx
+++ b/app/scenes/Document/Shared.tsx
@@ -7,12 +7,13 @@ import { RouteComponentProps, useLocation, Redirect } from "react-router-dom";
import styled, { ThemeProvider } from "styled-components";
import { setCookie } from "tiny-cookie";
import { s } from "@shared/styles";
-import { CustomTheme, NavigationNode } from "@shared/types";
+import { NavigationNode, PublicTeam } from "@shared/types";
import DocumentModel from "~/models/Document";
import Error404 from "~/scenes/Error404";
import ErrorOffline from "~/scenes/ErrorOffline";
import Layout from "~/components/Layout";
import Sidebar from "~/components/Sidebar/Shared";
+import { TeamContext } from "~/components/TeamContext";
import Text from "~/components/Text";
import env from "~/env";
import useBuildTheme from "~/hooks/useBuildTheme";
@@ -29,11 +30,7 @@ const EMPTY_OBJECT = {};
type Response = {
document: DocumentModel;
- team?: {
- name: string;
- avatarUrl: string;
- customTheme?: Partial;
- };
+ team?: PublicTeam;
sharedTree?: NavigationNode | undefined;
};
@@ -166,14 +163,6 @@ function SharedDocumentScene(props: Props) {
return ;
}
- const sidebar = response.sharedTree?.children.length ? (
-
- ) : undefined;
-
return (
<>
@@ -182,17 +171,26 @@ function SharedDocumentScene(props: Props) {
href={canonicalOrigin + location.pathname.replace(/\/$/, "")}
/>
-
-
-
-
-
+
+
+
+ ) : undefined
+ }
+ >
+
+
+
+
>
);
}
diff --git a/app/stores/DocumentsStore.ts b/app/stores/DocumentsStore.ts
index 1cda37d44..e630bbf39 100644
--- a/app/stores/DocumentsStore.ts
+++ b/app/stores/DocumentsStore.ts
@@ -1,7 +1,7 @@
import invariant from "invariant";
import { find, orderBy, filter, compact, omitBy } from "lodash";
import { observable, action, computed, runInAction } from "mobx";
-import { DateFilter, NavigationNode } from "@shared/types";
+import { DateFilter, NavigationNode, PublicTeam } from "@shared/types";
import { subtractDate } from "@shared/utils/date";
import { bytesToHumanReadable } from "@shared/utils/files";
import naturalSort from "@shared/utils/naturalSort";
@@ -9,7 +9,6 @@ import { DocumentValidation } from "@shared/validations";
import BaseStore from "~/stores/BaseStore";
import RootStore from "~/stores/RootStore";
import Document from "~/models/Document";
-import Team from "~/models/Team";
import env from "~/env";
import { FetchOptions, PaginationParams, SearchResult } from "~/types";
import { client } from "~/utils/ApiClient";
@@ -38,7 +37,7 @@ type ImportOptions = {
export default class DocumentsStore extends BaseStore {
sharedCache: Map<
string,
- { sharedTree: NavigationNode; team: Team } | undefined
+ { sharedTree: NavigationNode; team: PublicTeam } | undefined
> = new Map();
@observable
@@ -471,7 +470,7 @@ export default class DocumentsStore extends BaseStore {
options: FetchOptions = {}
): Promise<{
document: Document;
- team?: Team;
+ team?: PublicTeam;
sharedTree?: NavigationNode;
}> => {
if (!options.prefetch) {
diff --git a/server/routes/app.ts b/server/routes/app.ts
index 532fc2309..9596766ee 100644
--- a/server/routes/app.ts
+++ b/server/routes/app.ts
@@ -5,7 +5,7 @@ import { Context, Next } from "koa";
import { escape } from "lodash";
import { Sequelize } from "sequelize";
import isUUID from "validator/lib/isUUID";
-import { IntegrationType } from "@shared/types";
+import { IntegrationType, TeamPreference } from "@shared/types";
import documentLoader from "@server/commands/documentLoader";
import env from "@server/env";
import { Integration } from "@server/models";
@@ -49,6 +49,7 @@ export const renderApp = async (
title?: string;
description?: string;
canonical?: string;
+ shortcutIcon?: string;
analytics?: Integration | null;
} = {}
) => {
@@ -56,6 +57,7 @@ export const renderApp = async (
title = env.APP_NAME,
description = "A modern team knowledge base for your internal documentation, product specs, support answers, meeting notes, onboarding, & moreā¦",
canonical = "",
+ shortcutIcon = `${env.CDN_URL || ""}/images/favicon-32.png`,
} = options;
if (ctx.request.path === "/realtime/") {
@@ -91,6 +93,7 @@ export const renderApp = async (
.replace(/\{title\}/g, escape(title))
.replace(/\{description\}/g, escape(description))
.replace(/\{canonical-url\}/g, canonical)
+ .replace(/\{shortcut-icon\}/g, shortcutIcon)
.replace(/\{prefetch\}/g, shareId ? "" : prefetchTags)
.replace(/\{slack-app-id\}/g, env.SLACK_APP_ID || "")
.replace(/\{cdn-url\}/g, env.CDN_URL || "")
@@ -102,10 +105,10 @@ export const renderShare = async (ctx: Context, next: Next) => {
// Find the share record if publicly published so that the document title
// can be be returned in the server-rendered HTML. This allows it to appear in
// unfurls with more reliablity
- let share, document, analytics;
+ let share, document, team, analytics;
try {
- const team = await getTeamFromContext(ctx);
+ team = await getTeamFromContext(ctx);
const result = await documentLoader({
id: documentSlug,
shareId,
@@ -146,6 +149,10 @@ export const renderShare = async (ctx: Context, next: Next) => {
return renderApp(ctx, next, {
title: document?.title,
description: document?.getSummary(),
+ shortcutIcon:
+ team?.getPreference(TeamPreference.PublicBranding) && team.avatarUrl
+ ? team.avatarUrl
+ : undefined,
analytics,
canonical: share
? `${share.canonicalUrl}${documentSlug && document ? document.url : ""}`
diff --git a/server/static/index.html b/server/static/index.html
index 3c30ff353..b457231a4 100644
--- a/server/static/index.html
+++ b/server/static/index.html
@@ -14,7 +14,7 @@
;
+};
+
export enum TeamPreference {
/** Whether documents have a separate edit mode instead of seamless editing. */
SeamlessEdit = "seamlessEdit",