Compare commits
4 Commits
master
...
aakansha-f
Author | SHA1 | Date | |
---|---|---|---|
|
9809eb5ef2 | ||
|
e20b3325e9 | ||
|
274294a367 | ||
|
67bc10f33b |
@ -474,12 +474,8 @@ class App extends React.Component<AppProps, AppState> {
|
||||
this.scene.getNonDeletedElements(),
|
||||
this.state,
|
||||
);
|
||||
const {
|
||||
onCollabButtonClick,
|
||||
renderTopRightUI,
|
||||
renderFooter,
|
||||
renderCustomStats,
|
||||
} = this.props;
|
||||
const { onCollabButtonClick, renderTopRightUI, renderCustomStats } =
|
||||
this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
@ -520,7 +516,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
langCode={getLanguage().code}
|
||||
isCollaborating={this.props.isCollaborating}
|
||||
renderTopRightUI={renderTopRightUI}
|
||||
renderCustomFooter={renderFooter}
|
||||
renderCustomStats={renderCustomStats}
|
||||
viewModeEnabled={viewModeEnabled}
|
||||
showExitZenModeBtn={
|
||||
@ -537,7 +532,9 @@ class App extends React.Component<AppProps, AppState> {
|
||||
library={this.library}
|
||||
id={this.id}
|
||||
onImageAction={this.onImageAction}
|
||||
/>
|
||||
>
|
||||
{this.props.children}
|
||||
</LayerUI>
|
||||
<div className="excalidraw-textEditorContainer" />
|
||||
<div className="excalidraw-contextMenuContainer" />
|
||||
{selectedElement.length === 1 && this.state.showHyperlinkPopup && (
|
||||
|
@ -58,7 +58,6 @@ interface LayerUIProps {
|
||||
langCode: Language["code"];
|
||||
isCollaborating: boolean;
|
||||
renderTopRightUI?: ExcalidrawProps["renderTopRightUI"];
|
||||
renderCustomFooter?: ExcalidrawProps["renderFooter"];
|
||||
renderCustomStats?: ExcalidrawProps["renderCustomStats"];
|
||||
viewModeEnabled: boolean;
|
||||
libraryReturnUrl: ExcalidrawProps["libraryReturnUrl"];
|
||||
@ -67,6 +66,7 @@ interface LayerUIProps {
|
||||
library: Library;
|
||||
id: string;
|
||||
onImageAction: (data: { insertOnCanvasDirectly: boolean }) => void;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
const LayerUI = ({
|
||||
actionManager,
|
||||
@ -85,7 +85,6 @@ const LayerUI = ({
|
||||
toggleZenMode,
|
||||
isCollaborating,
|
||||
renderTopRightUI,
|
||||
renderCustomFooter,
|
||||
renderCustomStats,
|
||||
viewModeEnabled,
|
||||
libraryReturnUrl,
|
||||
@ -94,6 +93,7 @@ const LayerUI = ({
|
||||
library,
|
||||
id,
|
||||
onImageAction,
|
||||
children,
|
||||
}: LayerUIProps) => {
|
||||
const device = useDevice();
|
||||
|
||||
@ -454,7 +454,7 @@ const LayerUI = ({
|
||||
},
|
||||
)}
|
||||
>
|
||||
{renderCustomFooter?.(false, appState)}
|
||||
{children}
|
||||
</div>
|
||||
<div
|
||||
className={clsx(
|
||||
@ -542,13 +542,14 @@ const LayerUI = ({
|
||||
onPenModeToggle={onPenModeToggle}
|
||||
canvas={canvas}
|
||||
isCollaborating={isCollaborating}
|
||||
renderCustomFooter={renderCustomFooter}
|
||||
viewModeEnabled={viewModeEnabled}
|
||||
showThemeBtn={showThemeBtn}
|
||||
onImageAction={onImageAction}
|
||||
renderTopRightUI={renderTopRightUI}
|
||||
renderStats={renderStats}
|
||||
/>
|
||||
>
|
||||
{children}
|
||||
</MobileMenu>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
@ -606,7 +607,6 @@ const areEqual = (prev: LayerUIProps, next: LayerUIProps) => {
|
||||
|
||||
const keys = Object.keys(prevAppState) as (keyof Partial<AppState>)[];
|
||||
return (
|
||||
prev.renderCustomFooter === next.renderCustomFooter &&
|
||||
prev.langCode === next.langCode &&
|
||||
prev.elements === next.elements &&
|
||||
prev.files === next.files &&
|
||||
|
@ -32,10 +32,7 @@ type MobileMenuProps = {
|
||||
onPenModeToggle: () => void;
|
||||
canvas: HTMLCanvasElement | null;
|
||||
isCollaborating: boolean;
|
||||
renderCustomFooter?: (
|
||||
isMobile: boolean,
|
||||
appState: AppState,
|
||||
) => JSX.Element | null;
|
||||
|
||||
viewModeEnabled: boolean;
|
||||
showThemeBtn: boolean;
|
||||
onImageAction: (data: { insertOnCanvasDirectly: boolean }) => void;
|
||||
@ -44,6 +41,7 @@ type MobileMenuProps = {
|
||||
appState: AppState,
|
||||
) => JSX.Element | null;
|
||||
renderStats: () => JSX.Element | null;
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
export const MobileMenu = ({
|
||||
@ -59,12 +57,12 @@ export const MobileMenu = ({
|
||||
onPenModeToggle,
|
||||
canvas,
|
||||
isCollaborating,
|
||||
renderCustomFooter,
|
||||
viewModeEnabled,
|
||||
showThemeBtn,
|
||||
onImageAction,
|
||||
renderTopRightUI,
|
||||
renderStats,
|
||||
children,
|
||||
}: MobileMenuProps) => {
|
||||
const renderToolbar = () => {
|
||||
return (
|
||||
@ -201,7 +199,7 @@ export const MobileMenu = ({
|
||||
<div className="panelColumn">
|
||||
<Stack.Col gap={4}>
|
||||
{renderCanvasActions()}
|
||||
{renderCustomFooter?.(true, appState)}
|
||||
{children}
|
||||
{appState.collaborators.size > 0 && (
|
||||
<fieldset>
|
||||
<legend>{t("labels.collaborators")}</legend>
|
||||
|
79
src/excalidraw-app/components/Footer.tsx
Normal file
79
src/excalidraw-app/components/Footer.tsx
Normal file
@ -0,0 +1,79 @@
|
||||
import { shield } from "../../components/icons";
|
||||
import { Tooltip } from "../../components/Tooltip";
|
||||
import { t } from "../../i18n";
|
||||
import { languages, useDevice } from "../../packages/excalidraw/index";
|
||||
import { LanguageList } from "./LanguageList";
|
||||
import PlusAppLink, { isExcalidrawPlusSignedUser } from "./PlusAppLink";
|
||||
import PlusLPLink from "./PlusLPLink";
|
||||
|
||||
const EncryptedIcon = () => (
|
||||
<a
|
||||
className="encrypted-icon tooltip"
|
||||
href="https://blog.excalidraw.com/end-to-end-encryption/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label={t("encrypted.link")}
|
||||
>
|
||||
<Tooltip label={t("encrypted.tooltip")} long={true}>
|
||||
{shield}
|
||||
</Tooltip>
|
||||
</a>
|
||||
);
|
||||
|
||||
const Footer = ({
|
||||
langCode,
|
||||
onLangChange,
|
||||
}: {
|
||||
langCode: string;
|
||||
onLangChange: (langCode: string) => void;
|
||||
}) => {
|
||||
const device = useDevice();
|
||||
if (device.isMobile) {
|
||||
const isTinyDevice = window.innerWidth < 362;
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: isTinyDevice ? "column" : "row",
|
||||
}}
|
||||
>
|
||||
<fieldset>
|
||||
<legend>{t("labels.language")}</legend>
|
||||
<LanguageList
|
||||
onChange={onLangChange}
|
||||
languages={languages}
|
||||
currentLangCode={langCode}
|
||||
/>
|
||||
</fieldset>
|
||||
{/* FIXME remove after 2021-05-20 */}
|
||||
<div
|
||||
style={{
|
||||
width: "24ch",
|
||||
fontSize: "0.7em",
|
||||
textAlign: "center",
|
||||
marginTop: isTinyDevice ? 16 : undefined,
|
||||
marginLeft: "auto",
|
||||
marginRight: isTinyDevice ? "auto" : undefined,
|
||||
padding: isExcalidrawPlusSignedUser ? undefined : "4px 2px",
|
||||
border: isExcalidrawPlusSignedUser ? undefined : "1px dashed #aaa",
|
||||
borderRadius: 12,
|
||||
}}
|
||||
>
|
||||
{isExcalidrawPlusSignedUser ? <PlusAppLink /> : <PlusLPLink />}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<EncryptedIcon />
|
||||
<LanguageList
|
||||
onChange={onLangChange}
|
||||
languages={languages}
|
||||
currentLangCode={langCode}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Footer;
|
20
src/excalidraw-app/components/PlusAppLink.tsx
Normal file
20
src/excalidraw-app/components/PlusAppLink.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import { COOKIES } from "../../constants";
|
||||
|
||||
export const isExcalidrawPlusSignedUser = document.cookie.includes(
|
||||
COOKIES.AUTH_STATE_COOKIE,
|
||||
);
|
||||
|
||||
const PlusAppLink = () => {
|
||||
return (
|
||||
<a
|
||||
href={`${process.env.REACT_APP_PLUS_APP}/#excalidraw-redirect`}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="plus-button"
|
||||
>
|
||||
Go to Excalidraw+
|
||||
</a>
|
||||
);
|
||||
};
|
||||
|
||||
export default PlusAppLink;
|
17
src/excalidraw-app/components/PlusLPLink.tsx
Normal file
17
src/excalidraw-app/components/PlusLPLink.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
const PlusLPLink = () => {
|
||||
return (
|
||||
<p style={{ direction: "ltr", unicodeBidi: "embed" }}>
|
||||
Introducing Excalidraw+
|
||||
<br />
|
||||
<a
|
||||
href="https://plus.excalidraw.com/plus?utm_source=excalidraw&utm_medium=banner&utm_campaign=launch"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Try out now!
|
||||
</a>
|
||||
</p>
|
||||
);
|
||||
};
|
||||
|
||||
export default PlusLPLink;
|
@ -4,13 +4,7 @@ import { trackEvent } from "../analytics";
|
||||
import { getDefaultAppState } from "../appState";
|
||||
import { ErrorDialog } from "../components/ErrorDialog";
|
||||
import { TopErrorBoundary } from "../components/TopErrorBoundary";
|
||||
import {
|
||||
APP_NAME,
|
||||
COOKIES,
|
||||
EVENT,
|
||||
TITLE_TIMEOUT,
|
||||
VERSION_TIMEOUT,
|
||||
} from "../constants";
|
||||
import { APP_NAME, EVENT, TITLE_TIMEOUT, VERSION_TIMEOUT } from "../constants";
|
||||
import { loadFromBlob } from "../data/blob";
|
||||
import {
|
||||
ExcalidrawElement,
|
||||
@ -19,11 +13,7 @@ import {
|
||||
} from "../element/types";
|
||||
import { useCallbackRefState } from "../hooks/useCallbackRefState";
|
||||
import { t } from "../i18n";
|
||||
import {
|
||||
Excalidraw,
|
||||
defaultLang,
|
||||
languages,
|
||||
} from "../packages/excalidraw/index";
|
||||
import { Excalidraw, defaultLang } from "../packages/excalidraw/index";
|
||||
import {
|
||||
AppState,
|
||||
LibraryItems,
|
||||
@ -51,7 +41,6 @@ import Collab, {
|
||||
collabDialogShownAtom,
|
||||
isCollaboratingAtom,
|
||||
} from "./collab/Collab";
|
||||
import { LanguageList } from "./components/LanguageList";
|
||||
import {
|
||||
exportToBackend,
|
||||
getCollaborationLinkData,
|
||||
@ -65,8 +54,6 @@ import {
|
||||
} from "./data/localStorage";
|
||||
import CustomStats from "./CustomStats";
|
||||
import { restore, restoreAppState, RestoredDataState } from "../data/restore";
|
||||
import { Tooltip } from "../components/Tooltip";
|
||||
import { shield } from "../components/icons";
|
||||
|
||||
import "./index.scss";
|
||||
import { ExportToExcalidrawPlus } from "./components/ExportToExcalidrawPlus";
|
||||
@ -82,10 +69,11 @@ import { Provider, useAtom } from "jotai";
|
||||
import { jotaiStore, useAtomWithInitialValue } from "../jotai";
|
||||
import { reconcileElements } from "./collab/reconciliation";
|
||||
import { parseLibraryTokensFromUrl, useHandleLibrary } from "../data/library";
|
||||
|
||||
const isExcalidrawPlusSignedUser = document.cookie.includes(
|
||||
COOKIES.AUTH_STATE_COOKIE,
|
||||
);
|
||||
import Footer from "./components/Footer";
|
||||
import PlusAppLink, {
|
||||
isExcalidrawPlusSignedUser,
|
||||
} from "./components/PlusAppLink";
|
||||
import PlusLPLink from "./components/PlusLPLink";
|
||||
|
||||
const languageDetector = new LanguageDetector();
|
||||
languageDetector.init({
|
||||
@ -197,31 +185,6 @@ const initializeScene = async (opts: {
|
||||
return { scene: null, isExternalScene: false };
|
||||
};
|
||||
|
||||
const PlusLPLinkJSX = (
|
||||
<p style={{ direction: "ltr", unicodeBidi: "embed" }}>
|
||||
Introducing Excalidraw+
|
||||
<br />
|
||||
<a
|
||||
href="https://plus.excalidraw.com/plus?utm_source=excalidraw&utm_medium=banner&utm_campaign=launch"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Try out now!
|
||||
</a>
|
||||
</p>
|
||||
);
|
||||
|
||||
const PlusAppLinkJSX = (
|
||||
<a
|
||||
href={`${process.env.REACT_APP_PLUS_APP}/#excalidraw-redirect`}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="plus-button"
|
||||
>
|
||||
Go to Excalidraw+
|
||||
</a>
|
||||
);
|
||||
|
||||
const ExcalidrawWrapper = () => {
|
||||
const [errorMessage, setErrorMessage] = useState("");
|
||||
let currentLangCode = languageDetector.detect() || defaultLang.code;
|
||||
@ -581,80 +544,13 @@ const ExcalidrawWrapper = () => {
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
{isExcalidrawPlusSignedUser ? PlusAppLinkJSX : PlusLPLinkJSX}
|
||||
{isExcalidrawPlusSignedUser ? <PlusAppLink /> : <PlusLPLink />}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const renderFooter = useCallback(
|
||||
(isMobile: boolean) => {
|
||||
const renderEncryptedIcon = () => (
|
||||
<a
|
||||
className="encrypted-icon tooltip"
|
||||
href="https://blog.excalidraw.com/end-to-end-encryption/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label={t("encrypted.link")}
|
||||
>
|
||||
<Tooltip label={t("encrypted.tooltip")} long={true}>
|
||||
{shield}
|
||||
</Tooltip>
|
||||
</a>
|
||||
);
|
||||
|
||||
const renderLanguageList = () => (
|
||||
<LanguageList
|
||||
onChange={(langCode) => setLangCode(langCode)}
|
||||
languages={languages}
|
||||
currentLangCode={langCode}
|
||||
/>
|
||||
);
|
||||
if (isMobile) {
|
||||
const isTinyDevice = window.innerWidth < 362;
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: isTinyDevice ? "column" : "row",
|
||||
}}
|
||||
>
|
||||
<fieldset>
|
||||
<legend>{t("labels.language")}</legend>
|
||||
{renderLanguageList()}
|
||||
</fieldset>
|
||||
{/* FIXME remove after 2021-05-20 */}
|
||||
<div
|
||||
style={{
|
||||
width: "24ch",
|
||||
fontSize: "0.7em",
|
||||
textAlign: "center",
|
||||
marginTop: isTinyDevice ? 16 : undefined,
|
||||
marginLeft: "auto",
|
||||
marginRight: isTinyDevice ? "auto" : undefined,
|
||||
padding: isExcalidrawPlusSignedUser ? undefined : "4px 2px",
|
||||
border: isExcalidrawPlusSignedUser
|
||||
? undefined
|
||||
: "1px dashed #aaa",
|
||||
borderRadius: 12,
|
||||
}}
|
||||
>
|
||||
{isExcalidrawPlusSignedUser ? PlusAppLinkJSX : PlusLPLinkJSX}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{renderEncryptedIcon()}
|
||||
{renderLanguageList()}
|
||||
</>
|
||||
);
|
||||
},
|
||||
[langCode],
|
||||
);
|
||||
|
||||
const renderCustomStats = () => {
|
||||
return (
|
||||
<CustomStats
|
||||
@ -710,14 +606,18 @@ const ExcalidrawWrapper = () => {
|
||||
},
|
||||
}}
|
||||
renderTopRightUI={renderTopRightUI}
|
||||
renderFooter={renderFooter}
|
||||
langCode={langCode}
|
||||
renderCustomStats={renderCustomStats}
|
||||
detectScroll={false}
|
||||
handleKeyboardGlobally={true}
|
||||
onLibraryChange={onLibraryChange}
|
||||
autoFocus={true}
|
||||
>
|
||||
<Footer
|
||||
langCode={langCode}
|
||||
onLangChange={(langCode) => setLangCode(langCode)}
|
||||
/>
|
||||
</Excalidraw>
|
||||
{excalidrawAPI && <Collab excalidrawAPI={excalidrawAPI} />}
|
||||
{errorMessage && (
|
||||
<ErrorDialog
|
||||
|
@ -654,11 +654,12 @@ export default function App() {
|
||||
name="Custom name of drawing"
|
||||
UIOptions={{ canvasActions: { loadScene: false } }}
|
||||
renderTopRightUI={renderTopRightUI}
|
||||
renderFooter={renderFooter}
|
||||
onLinkOpen={onLinkOpen}
|
||||
onPointerDown={onPointerDown}
|
||||
onScrollChange={rerenderCommentIcons}
|
||||
/>
|
||||
>
|
||||
{renderFooter()}
|
||||
</Excalidraw>
|
||||
{Object.keys(commentIcons || []).length > 0 && renderCommentIcons()}
|
||||
{comment && renderComment()}
|
||||
</div>
|
||||
|
@ -21,7 +21,6 @@ const ExcalidrawBase = (props: ExcalidrawProps) => {
|
||||
isCollaborating = false,
|
||||
onPointerUpdate,
|
||||
renderTopRightUI,
|
||||
renderFooter,
|
||||
langCode = defaultLang.code,
|
||||
viewModeEnabled,
|
||||
zenModeEnabled,
|
||||
@ -39,6 +38,7 @@ const ExcalidrawBase = (props: ExcalidrawProps) => {
|
||||
onLinkOpen,
|
||||
onPointerDown,
|
||||
onScrollChange,
|
||||
children,
|
||||
} = props;
|
||||
|
||||
const canvasActions = props.UIOptions?.canvasActions;
|
||||
@ -86,7 +86,6 @@ const ExcalidrawBase = (props: ExcalidrawProps) => {
|
||||
isCollaborating={isCollaborating}
|
||||
onPointerUpdate={onPointerUpdate}
|
||||
renderTopRightUI={renderTopRightUI}
|
||||
renderFooter={renderFooter}
|
||||
langCode={langCode}
|
||||
viewModeEnabled={viewModeEnabled}
|
||||
zenModeEnabled={zenModeEnabled}
|
||||
@ -105,7 +104,9 @@ const ExcalidrawBase = (props: ExcalidrawProps) => {
|
||||
onLinkOpen={onLinkOpen}
|
||||
onPointerDown={onPointerDown}
|
||||
onScrollChange={onScrollChange}
|
||||
/>
|
||||
>
|
||||
{children}
|
||||
</App>
|
||||
</Provider>
|
||||
</InitializeApp>
|
||||
);
|
||||
@ -225,3 +226,5 @@ export {
|
||||
sceneCoordsToViewportCoords,
|
||||
viewportCoordsToSceneCoords,
|
||||
} from "../../utils";
|
||||
|
||||
export { useDevice } from "../../components/App";
|
||||
|
@ -280,7 +280,6 @@ export interface ExcalidrawProps {
|
||||
isMobile: boolean,
|
||||
appState: AppState,
|
||||
) => JSX.Element | null;
|
||||
renderFooter?: (isMobile: boolean, appState: AppState) => JSX.Element | null;
|
||||
langCode?: Language["code"];
|
||||
viewModeEnabled?: boolean;
|
||||
zenModeEnabled?: boolean;
|
||||
@ -312,6 +311,7 @@ export interface ExcalidrawProps {
|
||||
pointerDownState: PointerDownState,
|
||||
) => void;
|
||||
onScrollChange?: (scrollX: number, scrollY: number) => void;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export type SceneData = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user