feat: add renderTopRight
prop & remove GH corner from core (#3539)
* feat: add `renderTopRight` prop & remove GH corner from core * reuse `--space-factor` var * update readme & changelog
This commit is contained in:
parent
f28f7ffb6e
commit
bac76778ce
@ -452,6 +452,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
const {
|
const {
|
||||||
onCollabButtonClick,
|
onCollabButtonClick,
|
||||||
onExportToBackend,
|
onExportToBackend,
|
||||||
|
renderTopRight,
|
||||||
renderFooter,
|
renderFooter,
|
||||||
renderCustomStats,
|
renderCustomStats,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
@ -492,6 +493,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
langCode={getLanguage().code}
|
langCode={getLanguage().code}
|
||||||
isCollaborating={this.props.isCollaborating || false}
|
isCollaborating={this.props.isCollaborating || false}
|
||||||
onExportToBackend={onExportToBackend}
|
onExportToBackend={onExportToBackend}
|
||||||
|
renderTopRight={renderTopRight}
|
||||||
renderCustomFooter={renderFooter}
|
renderCustomFooter={renderFooter}
|
||||||
viewModeEnabled={viewModeEnabled}
|
viewModeEnabled={viewModeEnabled}
|
||||||
showExitZenModeBtn={
|
showExitZenModeBtn={
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
.excalidraw {
|
.excalidraw {
|
||||||
.FixedSideContainer {
|
.FixedSideContainer {
|
||||||
--margin: 0.25rem;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
@ -10,9 +9,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.FixedSideContainer_side_top {
|
.FixedSideContainer_side_top {
|
||||||
left: var(--margin);
|
left: var(--space-factor);
|
||||||
top: var(--margin);
|
top: var(--space-factor);
|
||||||
right: var(--margin);
|
right: var(--space-factor);
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,16 +22,16 @@
|
|||||||
|
|
||||||
/* TODO: if these are used, make sure to implement RTL support
|
/* TODO: if these are used, make sure to implement RTL support
|
||||||
.FixedSideContainer_side_left {
|
.FixedSideContainer_side_left {
|
||||||
left: var(--margin);
|
left: var(--space-factor);
|
||||||
top: var(--margin);
|
top: var(--space-factor);
|
||||||
bottom: var(--margin);
|
bottom: var(--space-factor);
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.FixedSideContainer_side_right {
|
.FixedSideContainer_side_right {
|
||||||
right: var(--margin);
|
right: var(--space-factor);
|
||||||
top: var(--margin);
|
top: var(--space-factor);
|
||||||
bottom: var(--margin);
|
bottom: var(--space-factor);
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
@ -55,19 +55,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__github-corner {
|
&__top-right {
|
||||||
top: 0;
|
display: flex;
|
||||||
|
|
||||||
:root[dir="ltr"] & {
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:root[dir="rtl"] & {
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
width: 40px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__footer {
|
&__footer {
|
||||||
|
@ -30,7 +30,6 @@ import CollabButton from "./CollabButton";
|
|||||||
import { ErrorDialog } from "./ErrorDialog";
|
import { ErrorDialog } from "./ErrorDialog";
|
||||||
import { ExportCB, ExportDialog } from "./ExportDialog";
|
import { ExportCB, ExportDialog } from "./ExportDialog";
|
||||||
import { FixedSideContainer } from "./FixedSideContainer";
|
import { FixedSideContainer } from "./FixedSideContainer";
|
||||||
import { GitHubCorner } from "./GitHubCorner";
|
|
||||||
import { HintViewer } from "./HintViewer";
|
import { HintViewer } from "./HintViewer";
|
||||||
import { exportFile, load, shield, trash } from "./icons";
|
import { exportFile, load, shield, trash } from "./icons";
|
||||||
import { Island } from "./Island";
|
import { Island } from "./Island";
|
||||||
@ -68,6 +67,7 @@ interface LayerUIProps {
|
|||||||
appState: AppState,
|
appState: AppState,
|
||||||
canvas: HTMLCanvasElement | null,
|
canvas: HTMLCanvasElement | null,
|
||||||
) => void;
|
) => void;
|
||||||
|
renderTopRight?: (isMobile: boolean, appState: AppState) => JSX.Element;
|
||||||
renderCustomFooter?: (isMobile: boolean) => JSX.Element;
|
renderCustomFooter?: (isMobile: boolean) => JSX.Element;
|
||||||
viewModeEnabled: boolean;
|
viewModeEnabled: boolean;
|
||||||
libraryReturnUrl: ExcalidrawProps["libraryReturnUrl"];
|
libraryReturnUrl: ExcalidrawProps["libraryReturnUrl"];
|
||||||
@ -371,6 +371,7 @@ const LayerUI = ({
|
|||||||
toggleZenMode,
|
toggleZenMode,
|
||||||
isCollaborating,
|
isCollaborating,
|
||||||
onExportToBackend,
|
onExportToBackend,
|
||||||
|
renderTopRight,
|
||||||
renderCustomFooter,
|
renderCustomFooter,
|
||||||
viewModeEnabled,
|
viewModeEnabled,
|
||||||
libraryReturnUrl,
|
libraryReturnUrl,
|
||||||
@ -604,11 +605,15 @@ const LayerUI = ({
|
|||||||
)}
|
)}
|
||||||
</Section>
|
</Section>
|
||||||
)}
|
)}
|
||||||
<UserList
|
<div
|
||||||
className={clsx("zen-mode-transition", {
|
className={clsx(
|
||||||
|
"layer-ui__wrapper__top-right zen-mode-transition",
|
||||||
|
{
|
||||||
"transition-right": zenModeEnabled,
|
"transition-right": zenModeEnabled,
|
||||||
})}
|
},
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
|
<UserList>
|
||||||
{appState.collaborators.size > 0 &&
|
{appState.collaborators.size > 0 &&
|
||||||
Array.from(appState.collaborators)
|
Array.from(appState.collaborators)
|
||||||
// Collaborator is either not initialized or is actually the current user.
|
// Collaborator is either not initialized or is actually the current user.
|
||||||
@ -622,6 +627,8 @@ const LayerUI = ({
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
))}
|
))}
|
||||||
</UserList>
|
</UserList>
|
||||||
|
{renderTopRight?.(isMobile, appState)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</FixedSideContainer>
|
</FixedSideContainer>
|
||||||
);
|
);
|
||||||
@ -649,20 +656,6 @@ const LayerUI = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderGitHubCorner = () => {
|
|
||||||
return (
|
|
||||||
<aside
|
|
||||||
className={clsx(
|
|
||||||
"layer-ui__wrapper__github-corner zen-mode-transition",
|
|
||||||
{
|
|
||||||
"transition-right": zenModeEnabled,
|
|
||||||
},
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<GitHubCorner theme={appState.theme} />
|
|
||||||
</aside>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const renderFooter = () => (
|
const renderFooter = () => (
|
||||||
<footer role="contentinfo" className="layer-ui__wrapper__footer">
|
<footer role="contentinfo" className="layer-ui__wrapper__footer">
|
||||||
<div
|
<div
|
||||||
@ -746,7 +739,6 @@ const LayerUI = ({
|
|||||||
{dialogs}
|
{dialogs}
|
||||||
{renderFixedSideContainer()}
|
{renderFixedSideContainer()}
|
||||||
{renderBottomAppMenu()}
|
{renderBottomAppMenu()}
|
||||||
{renderGitHubCorner()}
|
|
||||||
{renderFooter()}
|
{renderFooter()}
|
||||||
{appState.scrolledOutside && (
|
{appState.scrolledOutside && (
|
||||||
<button
|
<button
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
.UserList {
|
.UserList {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
/*github corner*/
|
/*github corner*/
|
||||||
padding: var(--space-factor) 40px var(--space-factor) var(--space-factor);
|
padding: var(--space-factor) var(--space-factor) var(--space-factor)
|
||||||
|
var(--space-factor);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
@ -500,20 +500,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.github-corner {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
z-index: 2;
|
|
||||||
|
|
||||||
:root[dir="ltr"] & {
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:root[dir="rtl"] & {
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.zen-mode-visibility {
|
.zen-mode-visibility {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
--focus-highlight-color: #{$oc-blue-2};
|
--focus-highlight-color: #{$oc-blue-2};
|
||||||
--icon-fill-color: #{$oc-black};
|
--icon-fill-color: #{$oc-black};
|
||||||
--icon-green-fill-color: #{$oc-green-9};
|
--icon-green-fill-color: #{$oc-green-9};
|
||||||
|
--default-bg-color: #{$oc-white};
|
||||||
--input-bg-color: #{$oc-white};
|
--input-bg-color: #{$oc-white};
|
||||||
--input-border-color: #{$oc-gray-3};
|
--input-border-color: #{$oc-gray-3};
|
||||||
--input-hover-bg-color: #{$oc-gray-1};
|
--input-hover-bg-color: #{$oc-gray-1};
|
||||||
@ -56,6 +57,7 @@
|
|||||||
--focus-highlight-color: #{$oc-blue-6};
|
--focus-highlight-color: #{$oc-blue-6};
|
||||||
--icon-fill-color: #{$oc-gray-4};
|
--icon-fill-color: #{$oc-gray-4};
|
||||||
--icon-green-fill-color: #{$oc-green-4};
|
--icon-green-fill-color: #{$oc-green-4};
|
||||||
|
--default-bg-color: #121212;
|
||||||
--input-bg-color: #121212;
|
--input-bg-color: #121212;
|
||||||
--input-border-color: #2e2e2e;
|
--input-border-color: #2e2e2e;
|
||||||
--input-hover-bg-color: #181818;
|
--input-hover-bg-color: #181818;
|
||||||
|
@ -3,13 +3,19 @@ import React from "react";
|
|||||||
|
|
||||||
// https://github.com/tholman/github-corners
|
// https://github.com/tholman/github-corners
|
||||||
export const GitHubCorner = React.memo(
|
export const GitHubCorner = React.memo(
|
||||||
({ theme }: { theme: "light" | "dark" }) => (
|
({ theme, dir }: { theme: "light" | "dark"; dir: string }) => (
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="40"
|
width="40"
|
||||||
height="40"
|
height="40"
|
||||||
viewBox="0 0 250 250"
|
viewBox="0 0 250 250"
|
||||||
className="github-corner rtl-mirror"
|
className="rtl-mirror"
|
||||||
|
style={{
|
||||||
|
marginTop: "calc(var(--space-factor) * -1)",
|
||||||
|
[dir === "rtl"
|
||||||
|
? "marginLeft"
|
||||||
|
: "marginRight"]: "calc(var(--space-factor) * -1)",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
href="https://github.com/excalidraw/excalidraw"
|
href="https://github.com/excalidraw/excalidraw"
|
||||||
@ -19,18 +25,18 @@ export const GitHubCorner = React.memo(
|
|||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
d="M0 0l115 115h15l12 27 108 108V0z"
|
d="M0 0l115 115h15l12 27 108 108V0z"
|
||||||
fill={theme === "light" ? oc.gray[6] : oc.gray[8]}
|
fill={theme === "light" ? oc.gray[6] : oc.gray[7]}
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
className="octo-arm"
|
className="octo-arm"
|
||||||
d="M128 109c-15-9-9-19-9-19 3-7 2-11 2-11-1-7 3-2 3-2 4 5 2 11 2 11-3 10 5 15 9 16"
|
d="M128 109c-15-9-9-19-9-19 3-7 2-11 2-11-1-7 3-2 3-2 4 5 2 11 2 11-3 10 5 15 9 16"
|
||||||
style={{ transformOrigin: "130px 106px" }}
|
style={{ transformOrigin: "130px 106px" }}
|
||||||
fill={theme === "light" ? oc.white : oc.black}
|
fill={theme === "light" ? oc.white : "var(--default-bg-color)"}
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
className="octo-body"
|
className="octo-body"
|
||||||
d="M115 115s4 2 5 0l14-14c3-2 6-3 8-3-8-11-15-24 2-41 5-5 10-7 16-7 1-2 3-7 12-11 0 0 5 3 7 16 4 2 8 5 12 9s7 8 9 12c14 3 17 7 17 7-4 8-9 11-11 11 0 6-2 11-7 16-16 16-30 10-41 2 0 3-1 7-5 11l-12 11c-1 1 1 5 1 5z"
|
d="M115 115s4 2 5 0l14-14c3-2 6-3 8-3-8-11-15-24 2-41 5-5 10-7 16-7 1-2 3-7 12-11 0 0 5 3 7 16 4 2 8 5 12 9s7 8 9 12c14 3 17 7 17 7-4 8-9 11-11 11 0 6-2 11-7 16-16 16-30 10-41 2 0 3-1 7-5 11l-12 11c-1 1 1 5 1 5z"
|
||||||
fill={theme === "light" ? oc.white : oc.black}
|
fill={theme === "light" ? oc.white : "var(--default-bg-color)"}
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
</svg>
|
</svg>
|
@ -52,6 +52,7 @@ import {
|
|||||||
} from "./data/localStorage";
|
} from "./data/localStorage";
|
||||||
import CustomStats from "./CustomStats";
|
import CustomStats from "./CustomStats";
|
||||||
import { RestoredDataState } from "../data/restore";
|
import { RestoredDataState } from "../data/restore";
|
||||||
|
import { GitHubCorner } from "./components/GitHubCorner";
|
||||||
|
|
||||||
const languageDetector = new LanguageDetector();
|
const languageDetector = new LanguageDetector();
|
||||||
languageDetector.init({
|
languageDetector.init({
|
||||||
@ -290,6 +291,17 @@ const ExcalidrawWrapper = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const renderTopRight = useCallback(
|
||||||
|
(isMobile: boolean, appState: AppState) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<GitHubCorner theme={appState.theme} dir={document.dir} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
const renderFooter = useCallback(
|
const renderFooter = useCallback(
|
||||||
(isMobile: boolean) => {
|
(isMobile: boolean) => {
|
||||||
const renderLanguageList = () => (
|
const renderLanguageList = () => (
|
||||||
@ -331,6 +343,7 @@ const ExcalidrawWrapper = () => {
|
|||||||
const serializedItems = JSON.stringify(items);
|
const serializedItems = JSON.stringify(items);
|
||||||
localStorage.setItem(STORAGE_KEYS.LOCAL_STORAGE_LIBRARY, serializedItems);
|
localStorage.setItem(STORAGE_KEYS.LOCAL_STORAGE_LIBRARY, serializedItems);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Excalidraw
|
<Excalidraw
|
||||||
@ -341,6 +354,7 @@ const ExcalidrawWrapper = () => {
|
|||||||
isCollaborating={collabAPI?.isCollaborating()}
|
isCollaborating={collabAPI?.isCollaborating()}
|
||||||
onPointerUpdate={collabAPI?.onPointerUpdate}
|
onPointerUpdate={collabAPI?.onPointerUpdate}
|
||||||
onExportToBackend={onExportToBackend}
|
onExportToBackend={onExportToBackend}
|
||||||
|
renderTopRight={renderTopRight}
|
||||||
renderFooter={renderFooter}
|
renderFooter={renderFooter}
|
||||||
langCode={langCode}
|
langCode={langCode}
|
||||||
renderCustomStats={renderCustomStats}
|
renderCustomStats={renderCustomStats}
|
||||||
|
@ -11,6 +11,14 @@ The change should be grouped under one of the below section and must contain PR
|
|||||||
Please add the latest change on the top under the correct section.
|
Please add the latest change on the top under the correct section.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
## Excalidraw API
|
||||||
|
|
||||||
|
- Add support to render custom UI in the top right corner via [`renderTopRight`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#renderTopRight) prop [#3539](https://github.com/excalidraw/excalidraw/pull/3539).
|
||||||
|
|
||||||
|
This also removes the GitHub icon, keeping it local to the https://excalidraw.com app.
|
||||||
|
|
||||||
## 0.7.0 (2021-04-26)
|
## 0.7.0 (2021-04-26)
|
||||||
|
|
||||||
## Excalidraw API
|
## Excalidraw API
|
||||||
|
@ -355,6 +355,7 @@ To view the full example visit :point_down:
|
|||||||
| [`onPointerUpdate`](#onPointerUpdate) | Function | | Callback triggered when mouse pointer is updated. |
|
| [`onPointerUpdate`](#onPointerUpdate) | Function | | Callback triggered when mouse pointer is updated. |
|
||||||
| [`onExportToBackend`](#onExportToBackend) | Function | | Callback triggered when link button is clicked on export dialog |
|
| [`onExportToBackend`](#onExportToBackend) | Function | | Callback triggered when link button is clicked on export dialog |
|
||||||
| [`langCode`](#langCode) | string | `en` | Language code string |
|
| [`langCode`](#langCode) | string | `en` | Language code string |
|
||||||
|
| [`renderTopRight `](#renderTopRight) | Function | | Function that renders custom UI in top right corner |
|
||||||
| [`renderFooter `](#renderFooter) | Function | | Function that renders custom UI footer |
|
| [`renderFooter `](#renderFooter) | Function | | Function that renders custom UI footer |
|
||||||
| [`renderCustomStats`](#renderCustomStats) | Function | | Function that can be used to render custom stats on the stats dialog. |
|
| [`renderCustomStats`](#renderCustomStats) | Function | | Function that can be used to render custom stats on the stats dialog. |
|
||||||
| [`viewModeEnabled`](#viewModeEnabled) | boolean | | This implies if the app is in view mode. |
|
| [`viewModeEnabled`](#viewModeEnabled) | boolean | | This implies if the app is in view mode. |
|
||||||
@ -502,9 +503,13 @@ import { defaultLang, languages } from "@excalidraw/excalidraw";
|
|||||||
| defaultLang | string |
|
| defaultLang | string |
|
||||||
| languages | [Language[]](https://github.com/excalidraw/excalidraw/blob/master/src/i18n.ts#L8) |
|
| languages | [Language[]](https://github.com/excalidraw/excalidraw/blob/master/src/i18n.ts#L8) |
|
||||||
|
|
||||||
|
#### `renderTopRight`
|
||||||
|
|
||||||
|
A function returning JSX to render custom UI in the top right corner of the app.
|
||||||
|
|
||||||
#### `renderFooter`
|
#### `renderFooter`
|
||||||
|
|
||||||
A function that renders (returns JSX) custom UI footer. For example, you can use this to render a language picker that was previously being rendered by Excalidraw itself (for now, you'll need to implement your own language picker).
|
A function returning JSX to render custom UI footer. For example, you can use this to render a language picker that was previously being rendered by Excalidraw itself (for now, you'll need to implement your own language picker).
|
||||||
|
|
||||||
#### `renderCustomStats`
|
#### `renderCustomStats`
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ const Excalidraw = (props: ExcalidrawProps) => {
|
|||||||
isCollaborating,
|
isCollaborating,
|
||||||
onPointerUpdate,
|
onPointerUpdate,
|
||||||
onExportToBackend,
|
onExportToBackend,
|
||||||
|
renderTopRight,
|
||||||
renderFooter,
|
renderFooter,
|
||||||
langCode = defaultLang.code,
|
langCode = defaultLang.code,
|
||||||
viewModeEnabled,
|
viewModeEnabled,
|
||||||
@ -72,6 +73,7 @@ const Excalidraw = (props: ExcalidrawProps) => {
|
|||||||
isCollaborating={isCollaborating}
|
isCollaborating={isCollaborating}
|
||||||
onPointerUpdate={onPointerUpdate}
|
onPointerUpdate={onPointerUpdate}
|
||||||
onExportToBackend={onExportToBackend}
|
onExportToBackend={onExportToBackend}
|
||||||
|
renderTopRight={renderTopRight}
|
||||||
renderFooter={renderFooter}
|
renderFooter={renderFooter}
|
||||||
langCode={langCode}
|
langCode={langCode}
|
||||||
viewModeEnabled={viewModeEnabled}
|
viewModeEnabled={viewModeEnabled}
|
||||||
|
@ -182,6 +182,7 @@ export interface ExcalidrawProps {
|
|||||||
data: ClipboardData,
|
data: ClipboardData,
|
||||||
event: ClipboardEvent | null,
|
event: ClipboardEvent | null,
|
||||||
) => Promise<boolean> | boolean;
|
) => Promise<boolean> | boolean;
|
||||||
|
renderTopRight?: (isMobile: boolean, appState: AppState) => JSX.Element;
|
||||||
renderFooter?: (isMobile: boolean) => JSX.Element;
|
renderFooter?: (isMobile: boolean) => JSX.Element;
|
||||||
langCode?: Language["code"];
|
langCode?: Language["code"];
|
||||||
viewModeEnabled?: boolean;
|
viewModeEnabled?: boolean;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user