Browse Source

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
vanilla_orig
David Luzar 4 years ago
parent
commit
bac76778ce
No account linked to committer's email address

+ 2
- 0
src/components/App.tsx View File

@@ -452,6 +452,7 @@ class App extends React.Component<AppProps, AppState> {
452 452
     const {
453 453
       onCollabButtonClick,
454 454
       onExportToBackend,
455
+      renderTopRight,
455 456
       renderFooter,
456 457
       renderCustomStats,
457 458
     } = this.props;
@@ -492,6 +493,7 @@ class App extends React.Component<AppProps, AppState> {
492 493
               langCode={getLanguage().code}
493 494
               isCollaborating={this.props.isCollaborating || false}
494 495
               onExportToBackend={onExportToBackend}
496
+              renderTopRight={renderTopRight}
495 497
               renderCustomFooter={renderFooter}
496 498
               viewModeEnabled={viewModeEnabled}
497 499
               showExitZenModeBtn={

+ 9
- 10
src/components/FixedSideContainer.scss View File

@@ -1,6 +1,5 @@
1 1
 .excalidraw {
2 2
   .FixedSideContainer {
3
-    --margin: 0.25rem;
4 3
     position: absolute;
5 4
     pointer-events: none;
6 5
   }
@@ -10,9 +9,9 @@
10 9
   }
11 10
 
12 11
   .FixedSideContainer_side_top {
13
-    left: var(--margin);
14
-    top: var(--margin);
15
-    right: var(--margin);
12
+    left: var(--space-factor);
13
+    top: var(--space-factor);
14
+    right: var(--space-factor);
16 15
     z-index: 2;
17 16
   }
18 17
 
@@ -23,16 +22,16 @@
23 22
 
24 23
 /* TODO: if these are used, make sure to implement RTL support
25 24
 .FixedSideContainer_side_left {
26
-  left: var(--margin);
27
-  top: var(--margin);
28
-  bottom: var(--margin);
25
+  left: var(--space-factor);
26
+  top: var(--space-factor);
27
+  bottom: var(--space-factor);
29 28
   z-index: 1;
30 29
 }
31 30
 
32 31
 .FixedSideContainer_side_right {
33
-  right: var(--margin);
34
-  top: var(--margin);
35
-  bottom: var(--margin);
32
+  right: var(--space-factor);
33
+  top: var(--space-factor);
34
+  bottom: var(--space-factor);
36 35
   z-index: 3;
37 36
 }
38 37
 */

+ 2
- 13
src/components/LayerUI.scss View File

@@ -55,19 +55,8 @@
55 55
       }
56 56
     }
57 57
 
58
-    &__github-corner {
59
-      top: 0;
60
-
61
-      :root[dir="ltr"] & {
62
-        right: 0;
63
-      }
64
-
65
-      :root[dir="rtl"] & {
66
-        left: 0;
67
-      }
68
-
69
-      position: absolute;
70
-      width: 40px;
58
+    &__top-right {
59
+      display: flex;
71 60
     }
72 61
 
73 62
     &__footer {

+ 25
- 33
src/components/LayerUI.tsx View File

@@ -30,7 +30,6 @@ import CollabButton from "./CollabButton";
30 30
 import { ErrorDialog } from "./ErrorDialog";
31 31
 import { ExportCB, ExportDialog } from "./ExportDialog";
32 32
 import { FixedSideContainer } from "./FixedSideContainer";
33
-import { GitHubCorner } from "./GitHubCorner";
34 33
 import { HintViewer } from "./HintViewer";
35 34
 import { exportFile, load, shield, trash } from "./icons";
36 35
 import { Island } from "./Island";
@@ -68,6 +67,7 @@ interface LayerUIProps {
68 67
     appState: AppState,
69 68
     canvas: HTMLCanvasElement | null,
70 69
   ) => void;
70
+  renderTopRight?: (isMobile: boolean, appState: AppState) => JSX.Element;
71 71
   renderCustomFooter?: (isMobile: boolean) => JSX.Element;
72 72
   viewModeEnabled: boolean;
73 73
   libraryReturnUrl: ExcalidrawProps["libraryReturnUrl"];
@@ -371,6 +371,7 @@ const LayerUI = ({
371 371
   toggleZenMode,
372 372
   isCollaborating,
373 373
   onExportToBackend,
374
+  renderTopRight,
374 375
   renderCustomFooter,
375 376
   viewModeEnabled,
376 377
   libraryReturnUrl,
@@ -604,24 +605,30 @@ const LayerUI = ({
604 605
               )}
605 606
             </Section>
606 607
           )}
607
-          <UserList
608
-            className={clsx("zen-mode-transition", {
609
-              "transition-right": zenModeEnabled,
610
-            })}
608
+          <div
609
+            className={clsx(
610
+              "layer-ui__wrapper__top-right zen-mode-transition",
611
+              {
612
+                "transition-right": zenModeEnabled,
613
+              },
614
+            )}
611 615
           >
612
-            {appState.collaborators.size > 0 &&
613
-              Array.from(appState.collaborators)
614
-                // Collaborator is either not initialized or is actually the current user.
615
-                .filter(([_, client]) => Object.keys(client).length !== 0)
616
-                .map(([clientId, client]) => (
617
-                  <Tooltip
618
-                    label={client.username || "Unknown user"}
619
-                    key={clientId}
620
-                  >
621
-                    {actionManager.renderAction("goToCollaborator", clientId)}
622
-                  </Tooltip>
623
-                ))}
624
-          </UserList>
616
+            <UserList>
617
+              {appState.collaborators.size > 0 &&
618
+                Array.from(appState.collaborators)
619
+                  // Collaborator is either not initialized or is actually the current user.
620
+                  .filter(([_, client]) => Object.keys(client).length !== 0)
621
+                  .map(([clientId, client]) => (
622
+                    <Tooltip
623
+                      label={client.username || "Unknown user"}
624
+                      key={clientId}
625
+                    >
626
+                      {actionManager.renderAction("goToCollaborator", clientId)}
627
+                    </Tooltip>
628
+                  ))}
629
+            </UserList>
630
+            {renderTopRight?.(isMobile, appState)}
631
+          </div>
625 632
         </div>
626 633
       </FixedSideContainer>
627 634
     );
@@ -649,20 +656,6 @@ const LayerUI = ({
649 656
     );
650 657
   };
651 658
 
652
-  const renderGitHubCorner = () => {
653
-    return (
654
-      <aside
655
-        className={clsx(
656
-          "layer-ui__wrapper__github-corner zen-mode-transition",
657
-          {
658
-            "transition-right": zenModeEnabled,
659
-          },
660
-        )}
661
-      >
662
-        <GitHubCorner theme={appState.theme} />
663
-      </aside>
664
-    );
665
-  };
666 659
   const renderFooter = () => (
667 660
     <footer role="contentinfo" className="layer-ui__wrapper__footer">
668 661
       <div
@@ -746,7 +739,6 @@ const LayerUI = ({
746 739
       {dialogs}
747 740
       {renderFixedSideContainer()}
748 741
       {renderBottomAppMenu()}
749
-      {renderGitHubCorner()}
750 742
       {renderFooter()}
751 743
       {appState.scrolledOutside && (
752 744
         <button

+ 2
- 1
src/components/UserList.scss View File

@@ -2,7 +2,8 @@
2 2
   .UserList {
3 3
     pointer-events: none;
4 4
     /*github corner*/
5
-    padding: var(--space-factor) 40px var(--space-factor) var(--space-factor);
5
+    padding: var(--space-factor) var(--space-factor) var(--space-factor)
6
+      var(--space-factor);
6 7
     display: flex;
7 8
     flex-wrap: wrap;
8 9
     justify-content: flex-end;

+ 0
- 14
src/css/styles.scss View File

@@ -500,20 +500,6 @@
500 500
     }
501 501
   }
502 502
 
503
-  .github-corner {
504
-    position: absolute;
505
-    top: 0;
506
-    z-index: 2;
507
-
508
-    :root[dir="ltr"] & {
509
-      right: 0;
510
-    }
511
-
512
-    :root[dir="rtl"] & {
513
-      left: 0;
514
-    }
515
-  }
516
-
517 503
   .zen-mode-visibility {
518 504
     visibility: visible;
519 505
     opacity: 1;

+ 2
- 0
src/css/theme.scss View File

@@ -14,6 +14,7 @@
14 14
   --focus-highlight-color: #{$oc-blue-2};
15 15
   --icon-fill-color: #{$oc-black};
16 16
   --icon-green-fill-color: #{$oc-green-9};
17
+  --default-bg-color: #{$oc-white};
17 18
   --input-bg-color: #{$oc-white};
18 19
   --input-border-color: #{$oc-gray-3};
19 20
   --input-hover-bg-color: #{$oc-gray-1};
@@ -56,6 +57,7 @@
56 57
     --focus-highlight-color: #{$oc-blue-6};
57 58
     --icon-fill-color: #{$oc-gray-4};
58 59
     --icon-green-fill-color: #{$oc-green-4};
60
+    --default-bg-color: #121212;
59 61
     --input-bg-color: #121212;
60 62
     --input-border-color: #2e2e2e;
61 63
     --input-hover-bg-color: #181818;

src/components/GitHubCorner.tsx → src/excalidraw-app/components/GitHubCorner.tsx View File

@@ -3,13 +3,19 @@ import React from "react";
3 3
 
4 4
 // https://github.com/tholman/github-corners
5 5
 export const GitHubCorner = React.memo(
6
-  ({ theme }: { theme: "light" | "dark" }) => (
6
+  ({ theme, dir }: { theme: "light" | "dark"; dir: string }) => (
7 7
     <svg
8 8
       xmlns="http://www.w3.org/2000/svg"
9 9
       width="40"
10 10
       height="40"
11 11
       viewBox="0 0 250 250"
12
-      className="github-corner rtl-mirror"
12
+      className="rtl-mirror"
13
+      style={{
14
+        marginTop: "calc(var(--space-factor) * -1)",
15
+        [dir === "rtl"
16
+          ? "marginLeft"
17
+          : "marginRight"]: "calc(var(--space-factor) * -1)",
18
+      }}
13 19
     >
14 20
       <a
15 21
         href="https://github.com/excalidraw/excalidraw"
@@ -19,18 +25,18 @@ export const GitHubCorner = React.memo(
19 25
       >
20 26
         <path
21 27
           d="M0 0l115 115h15l12 27 108 108V0z"
22
-          fill={theme === "light" ? oc.gray[6] : oc.gray[8]}
28
+          fill={theme === "light" ? oc.gray[6] : oc.gray[7]}
23 29
         />
24 30
         <path
25 31
           className="octo-arm"
26 32
           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"
27 33
           style={{ transformOrigin: "130px 106px" }}
28
-          fill={theme === "light" ? oc.white : oc.black}
34
+          fill={theme === "light" ? oc.white : "var(--default-bg-color)"}
29 35
         />
30 36
         <path
31 37
           className="octo-body"
32 38
           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"
33
-          fill={theme === "light" ? oc.white : oc.black}
39
+          fill={theme === "light" ? oc.white : "var(--default-bg-color)"}
34 40
         />
35 41
       </a>
36 42
     </svg>

+ 14
- 0
src/excalidraw-app/index.tsx View File

@@ -52,6 +52,7 @@ import {
52 52
 } from "./data/localStorage";
53 53
 import CustomStats from "./CustomStats";
54 54
 import { RestoredDataState } from "../data/restore";
55
+import { GitHubCorner } from "./components/GitHubCorner";
55 56
 
56 57
 const languageDetector = new LanguageDetector();
57 58
 languageDetector.init({
@@ -290,6 +291,17 @@ const ExcalidrawWrapper = () => {
290 291
     }
291 292
   };
292 293
 
294
+  const renderTopRight = useCallback(
295
+    (isMobile: boolean, appState: AppState) => {
296
+      return (
297
+        <div>
298
+          <GitHubCorner theme={appState.theme} dir={document.dir} />
299
+        </div>
300
+      );
301
+    },
302
+    [],
303
+  );
304
+
293 305
   const renderFooter = useCallback(
294 306
     (isMobile: boolean) => {
295 307
       const renderLanguageList = () => (
@@ -331,6 +343,7 @@ const ExcalidrawWrapper = () => {
331 343
     const serializedItems = JSON.stringify(items);
332 344
     localStorage.setItem(STORAGE_KEYS.LOCAL_STORAGE_LIBRARY, serializedItems);
333 345
   };
346
+
334 347
   return (
335 348
     <>
336 349
       <Excalidraw
@@ -341,6 +354,7 @@ const ExcalidrawWrapper = () => {
341 354
         isCollaborating={collabAPI?.isCollaborating()}
342 355
         onPointerUpdate={collabAPI?.onPointerUpdate}
343 356
         onExportToBackend={onExportToBackend}
357
+        renderTopRight={renderTopRight}
344 358
         renderFooter={renderFooter}
345 359
         langCode={langCode}
346 360
         renderCustomStats={renderCustomStats}

+ 8
- 0
src/packages/excalidraw/CHANGELOG.md View File

@@ -11,6 +11,14 @@ The change should be grouped under one of the below section and must contain PR
11 11
 Please add the latest change on the top under the correct section.
12 12
 -->
13 13
 
14
+## Unreleased
15
+
16
+## Excalidraw API
17
+
18
+- 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).
19
+
20
+  This also removes the GitHub icon, keeping it local to the https://excalidraw.com app.
21
+
14 22
 ## 0.7.0 (2021-04-26)
15 23
 
16 24
 ## Excalidraw API

+ 6
- 1
src/packages/excalidraw/README_NEXT.md View File

@@ -355,6 +355,7 @@ To view the full example visit :point_down:
355 355
 | [`onPointerUpdate`](#onPointerUpdate) | Function |  | Callback triggered when mouse pointer is updated. |
356 356
 | [`onExportToBackend`](#onExportToBackend) | Function |  | Callback triggered when link button is clicked on export dialog |
357 357
 | [`langCode`](#langCode) | string | `en` | Language code string |
358
+| [`renderTopRight `](#renderTopRight) | Function |  | Function that renders custom UI in top right corner |
358 359
 | [`renderFooter `](#renderFooter) | Function |  | Function that renders custom UI footer |
359 360
 | [`renderCustomStats`](#renderCustomStats) | Function |  | Function that can be used to render custom stats on the stats dialog. |
360 361
 | [`viewModeEnabled`](#viewModeEnabled) | boolean |  | This implies if the app is in view mode. |
@@ -502,9 +503,13 @@ import { defaultLang, languages } from "@excalidraw/excalidraw";
502 503
 | defaultLang | string |
503 504
 | languages | [Language[]](https://github.com/excalidraw/excalidraw/blob/master/src/i18n.ts#L8) |
504 505
 
506
+#### `renderTopRight`
507
+
508
+A function returning JSX to render custom UI in the top right corner of the app.
509
+
505 510
 #### `renderFooter`
506 511
 
507
-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).
512
+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).
508 513
 
509 514
 #### `renderCustomStats`
510 515
 

+ 2
- 0
src/packages/excalidraw/index.tsx View File

@@ -20,6 +20,7 @@ const Excalidraw = (props: ExcalidrawProps) => {
20 20
     isCollaborating,
21 21
     onPointerUpdate,
22 22
     onExportToBackend,
23
+    renderTopRight,
23 24
     renderFooter,
24 25
     langCode = defaultLang.code,
25 26
     viewModeEnabled,
@@ -72,6 +73,7 @@ const Excalidraw = (props: ExcalidrawProps) => {
72 73
         isCollaborating={isCollaborating}
73 74
         onPointerUpdate={onPointerUpdate}
74 75
         onExportToBackend={onExportToBackend}
76
+        renderTopRight={renderTopRight}
75 77
         renderFooter={renderFooter}
76 78
         langCode={langCode}
77 79
         viewModeEnabled={viewModeEnabled}

+ 1
- 0
src/types.ts View File

@@ -182,6 +182,7 @@ export interface ExcalidrawProps {
182 182
     data: ClipboardData,
183 183
     event: ClipboardEvent | null,
184 184
   ) => Promise<boolean> | boolean;
185
+  renderTopRight?: (isMobile: boolean, appState: AppState) => JSX.Element;
185 186
   renderFooter?: (isMobile: boolean) => JSX.Element;
186 187
   langCode?: Language["code"];
187 188
   viewModeEnabled?: boolean;

Loading…
Cancel
Save