From 1da3d252e8f4ed7e1a6573f87e6275ead403b1c1 Mon Sep 17 00:00:00 2001
From: Ajay Bura <32841439+ajbura@users.noreply.github.com>
Date: Thu, 11 Aug 2022 16:13:53 +0530
Subject: [PATCH] Add navigation bar to sticker board

---
 src/app/organisms/emoji-board/EmojiBoard.jsx  | 104 +++++++++---------
 src/app/organisms/emoji-board/EmojiBoard.scss |   9 +-
 .../organisms/sticker-board/StickerBoard.jsx  |  31 +++++-
 .../organisms/sticker-board/StickerBoard.scss |  16 +++
 4 files changed, 103 insertions(+), 57 deletions(-)

diff --git a/src/app/organisms/emoji-board/EmojiBoard.jsx b/src/app/organisms/emoji-board/EmojiBoard.jsx
index b97cab0a..d9762323 100644
--- a/src/app/organisms/emoji-board/EmojiBoard.jsx
+++ b/src/app/organisms/emoji-board/EmojiBoard.jsx
@@ -252,6 +252,58 @@ function EmojiBoard({ onSelect, searchRef }) {
 
   return (
     <div id="emoji-board" className="emoji-board">
+      <ScrollView invisible>
+        <div className="emoji-board__nav">
+          {recentEmojis.length > 0 && (
+            <IconButton
+              onClick={() => openGroup(0)}
+              src={RecentClockIC}
+              tooltip="Recent"
+              tooltipPlacement="left"
+            />
+          )}
+          <div className="emoji-board__nav-custom">
+            {
+              availableEmojis.map((pack) => {
+                const src = initMatrix.matrixClient
+                  .mxcUrlToHttp(pack.avatarUrl ?? pack.getEmojis()[0].mxc);
+                return (
+                  <IconButton
+                    onClick={() => openGroup(recentOffset + pack.packIndex)}
+                    src={src}
+                    key={pack.packIndex}
+                    tooltip={pack.displayName ?? 'Unknown'}
+                    tooltipPlacement="left"
+                    isImage
+                  />
+                );
+              })
+            }
+          </div>
+          <div className="emoji-board__nav-twemoji">
+            {
+              [
+                [0, EmojiIC, 'Smilies'],
+                [1, DogIC, 'Animals'],
+                [2, CupIC, 'Food'],
+                [3, BallIC, 'Activities'],
+                [4, PhotoIC, 'Travel'],
+                [5, BulbIC, 'Objects'],
+                [6, PeaceIC, 'Symbols'],
+                [7, FlagIC, 'Flags'],
+              ].map(([indx, ico, name]) => (
+                <IconButton
+                  onClick={() => openGroup(recentOffset + availableEmojis.length + indx)}
+                  key={indx}
+                  src={ico}
+                  tooltip={name}
+                  tooltipPlacement="left"
+                />
+              ))
+            }
+          </div>
+        </div>
+      </ScrollView>
       <div className="emoji-board__content">
         <div className="emoji-board__content__search">
           <RawIcon size="small" src={SearchIC} />
@@ -285,58 +337,6 @@ function EmojiBoard({ onSelect, searchRef }) {
           <Text>:slight_smile:</Text>
         </div>
       </div>
-      <ScrollView invisible>
-        <div className="emoji-board__nav">
-          {recentEmojis.length > 0 && (
-            <IconButton
-              onClick={() => openGroup(0)}
-              src={RecentClockIC}
-              tooltip="Recent"
-              tooltipPlacement="right"
-            />
-          )}
-          <div className="emoji-board__nav-custom">
-            {
-              availableEmojis.map((pack) => {
-                const src = initMatrix.matrixClient
-                  .mxcUrlToHttp(pack.avatarUrl ?? pack.getEmojis()[0].mxc);
-                return (
-                  <IconButton
-                    onClick={() => openGroup(recentOffset + pack.packIndex)}
-                    src={src}
-                    key={pack.packIndex}
-                    tooltip={pack.displayName ?? 'Unknown'}
-                    tooltipPlacement="right"
-                    isImage
-                  />
-                );
-              })
-            }
-          </div>
-          <div className="emoji-board__nav-twemoji">
-            {
-              [
-                [0, EmojiIC, 'Smilies'],
-                [1, DogIC, 'Animals'],
-                [2, CupIC, 'Food'],
-                [3, BallIC, 'Activities'],
-                [4, PhotoIC, 'Travel'],
-                [5, BulbIC, 'Objects'],
-                [6, PeaceIC, 'Symbols'],
-                [7, FlagIC, 'Flags'],
-              ].map(([indx, ico, name]) => (
-                <IconButton
-                  onClick={() => openGroup(recentOffset + availableEmojis.length + indx)}
-                  key={indx}
-                  src={ico}
-                  tooltip={name}
-                  tooltipPlacement="right"
-                />
-              ))
-            }
-          </div>
-        </div>
-      </ScrollView>
     </div>
   );
 }
diff --git a/src/app/organisms/emoji-board/EmojiBoard.scss b/src/app/organisms/emoji-board/EmojiBoard.scss
index 6883e18e..7bdaa066 100644
--- a/src/app/organisms/emoji-board/EmojiBoard.scss
+++ b/src/app/organisms/emoji-board/EmojiBoard.scss
@@ -26,7 +26,7 @@
     min-height: 100%;
     padding: 4px 6px;
     background-color: var(--bg-surface-low);
-    @include dir.side(border, 1px solid var(--bg-surface-border), none);
+    @include dir.side(border, none, 1px solid var(--bg-surface-border));
 
     position: relative;
     
@@ -122,8 +122,11 @@
     @include dir.side(margin, var(--left-margin), var(--right-margin));
   }
   & .emoji {
-    width: 38px;
-    height: 38px;
+    max-width: 38px;
+    max-height: 38px;
+    width: 100%;
+    height: 100%;
+    overflow: hidden;
     object-fit: contain;
     padding: var(--emoji-padding);
     cursor: pointer;
diff --git a/src/app/organisms/sticker-board/StickerBoard.jsx b/src/app/organisms/sticker-board/StickerBoard.jsx
index 53b75635..91e25918 100644
--- a/src/app/organisms/sticker-board/StickerBoard.jsx
+++ b/src/app/organisms/sticker-board/StickerBoard.jsx
@@ -1,6 +1,6 @@
 /* eslint-disable jsx-a11y/click-events-have-key-events */
 /* eslint-disable jsx-a11y/no-static-element-interactions */
-import React from 'react';
+import React, { useRef } from 'react';
 import PropTypes from 'prop-types';
 import './StickerBoard.scss';
 
@@ -9,10 +9,12 @@ import { getRelevantPacks } from '../emoji-board/custom-emoji';
 
 import Text from '../../atoms/text/Text';
 import ScrollView from '../../atoms/scroll/ScrollView';
+import IconButton from '../../atoms/button/IconButton';
 
 function StickerBoard({ roomId, onSelect }) {
   const mx = initMatrix.matrixClient;
   const room = mx.getRoom(roomId);
+  const scrollRef = useRef(null);
 
   const parentIds = initMatrix.roomList.getAllParentSpaces(room.roomId);
   const parentRooms = [...parentIds].map((id) => mx.getRoom(id));
@@ -38,6 +40,11 @@ function StickerBoard({ roomId, onSelect }) {
     onSelect(stickerData);
   };
 
+  const openGroup = (groupIndex) => {
+    const scrollContent = scrollRef.current.firstElementChild;
+    scrollContent.children[groupIndex].scrollIntoView();
+  };
+
   const renderPack = (pack) => (
     <div className="sticker-board__pack" key={pack.id}>
       <Text className="sticker-board__pack-header" variant="b2" weight="bold">{pack.displayName ?? 'Unknown'}</Text>
@@ -50,6 +57,7 @@ function StickerBoard({ roomId, onSelect }) {
             alt={sticker.shortcode}
             title={sticker.body ?? sticker.shortcode}
             data-mx-sticker={sticker.mxc}
+            loading="lazy"
           />
         ))}
       </div>
@@ -58,8 +66,27 @@ function StickerBoard({ roomId, onSelect }) {
 
   return (
     <div className="sticker-board">
+      {packs.length > 0 && (
+        <ScrollView invisible>
+          <div className="sticker-board__sidebar">
+            {packs.map((pack, index) => {
+              const src = mx.mxcUrlToHttp(pack.avatarUrl ?? pack.getStickers()[0].mxc);
+              return (
+                <IconButton
+                  key={pack.id}
+                  onClick={() => openGroup(index)}
+                  src={src}
+                  tooltip={pack.displayName || 'Unknown'}
+                  tooltipPlacement="left"
+                  isImage
+                />
+              );
+            })}
+          </div>
+        </ScrollView>
+      )}
       <div className="sticker-board__container">
-        <ScrollView autoHide>
+        <ScrollView autoHide ref={scrollRef}>
           <div
             onClick={handleOnSelect}
             className="sticker-board__content"
diff --git a/src/app/organisms/sticker-board/StickerBoard.scss b/src/app/organisms/sticker-board/StickerBoard.scss
index be8ad35a..524ceeae 100644
--- a/src/app/organisms/sticker-board/StickerBoard.scss
+++ b/src/app/organisms/sticker-board/StickerBoard.scss
@@ -5,6 +5,22 @@
   --sticker-board-width: 286px;
   display: flex;
   height: var(--sticker-board-height);
+  display: flex;
+
+  & > .scrollbar {
+    width: initial;    
+    height: var(--sticker-board-height);
+  }
+
+  &__sidebar {
+    display: flex;
+    flex-direction: column;
+    min-height: 100%;
+    padding: 4px 6px;
+
+    background-color: var(--bg-surface-low);
+    @include dir.side(border, none, 1px solid var(--bg-surface-border));
+  }
 
   &__container {
     flex-grow: 1;