Repository: gitify-app/gitify
Pull request #1289 (2024-06-20 02:46:24)

refactor: interaction button and hover group components

afonsojramos: Nice cleaning up!

Patch:
diff --git a/src/components/AccountNotifications.tsx b/src/components/AccountNotifications.tsx
index 5295b7a0..348ad95c 100644
--- a/src/components/AccountNotifications.tsx
+++ b/src/components/AccountNotifications.tsx
@@ -8,8 +8,10 @@ import { AppContext } from '../context/App';
 import { type Account, Size } from '../types';
 import type { Notification } from '../typesGitHub';
 import { openAccountProfile } from '../utils/links';
+import { HoverGroup } from './HoverGroup';
 import { NotificationRow } from './NotificationRow';
 import { RepositoryNotifications } from './RepositoryNotifications';
+import { InteractionButton } from './buttons/InteractionButton';
 import { PlatformIcon } from './icons/PlatformIcon';
 
 interface IAccountNotifications {
@@ -82,16 +84,14 @@ export const AccountNotifications: FC<IAccountNotifications> = (
               @{account.user.login}
             </button>
           </div>
-          <div className="opacity-0 transition-opacity group-hover:opacity-80">
-            <button
-              type="button"
-              className="h-full hover:text-green-500 focus:outline-none"
+          <HoverGroup>
+            <InteractionButton
               title={toggleAccountNotificationsLabel}
+              icon={ChevronIcon}
+              size={Size.SMALL}
               onClick={toggleAccountNotifications}
-            >
-              <ChevronIcon size={Size.SMALL} />
-            </button>
-          </div>
+            />
+          </HoverGroup>
         </div>
       )}
 
diff --git a/src/components/HoverGroup.tsx b/src/components/HoverGroup.tsx
new file mode 100644
index 00000000..0d238d38
--- /dev/null
+++ b/src/components/HoverGroup.tsx
@@ -0,0 +1,13 @@
+import type { FC, ReactNode } from 'react';
+
+interface IHoverGroup {
+  children: ReactNode;
+}
+
+export const HoverGroup: FC<IHoverGroup> = ({ children }: IHoverGroup) => {
+  return (
+    <div className="flex items-center justify-center gap-2 opacity-0 transition-opacity group-hover:opacity-80">
+      {children}
+    </div>
+  );
+};
diff --git a/src/components/NotificationRow.tsx b/src/components/NotificationRow.tsx
index 0d1d4ad0..964adf2d 100644
--- a/src/components/NotificationRow.tsx
+++ b/src/components/NotificationRow.tsx
@@ -35,6 +35,8 @@ import {
   openUserProfile,
 } from '../utils/links';
 import { formatReason } from '../utils/reason';
+import { HoverGroup } from './HoverGroup';
+import { InteractionButton } from './buttons/InteractionButton';
 import { PillButton } from './buttons/PillButton';
 import { AvatarIcon } from './icons/AvatarIcon';
 
@@ -255,45 +257,34 @@ export const NotificationRow: FC<INotificationRow> = ({
         </div>
       </div>
 
-      <div className="flex items-center justify-center gap-2 opacity-0 transition-opacity group-hover:opacity-80">
-        <button
-          type="button"
-          className="h-full hover:text-green-500 focus:outline-none"
+      <HoverGroup>
+        <InteractionButton
           title="Mark as Done"
+          icon={CheckIcon}
+          size={Size.MEDIUM}
           onClick={() => {
             setAnimateExit(!settings.delayNotificationState);
             setShowAsRead(settings.delayNotificationState);
             markNotificationDone(notification);
           }}
-        >
-          <CheckIcon size={Size.MEDIUM} aria-label="Mark as Done" />
-        </button>
-
-        <button
-          type="button"
-          className="h-full hover:text-green-500 focus:outline-none"
+        />
+        <InteractionButton
           title="Mark as Read"
+          icon={ReadIcon}
+          size={Size.SMALL}
           onClick={() => {
             setAnimateExit(!settings.delayNotificationState);
             setShowAsRead(settings.delayNotificationState);
             markNotificationRead(notification);
           }}
-        >
-          <ReadIcon size={Size.SMALL} aria-label="Mark as Read" />
-        </button>
-
-        <button
-          type="button"
-          className="h-full hover:text-red-500 focus:outline-none"
+        />
+        <InteractionButton
           title="Unsubscribe from Thread"
+          icon={BellSlashIcon}
+          size={Size.SMALL}
           onClick={unsubscribeFromThread}
-        >
-          <BellSlashIcon
-            size={Size.SMALL}
-            aria-label="Unsubscribe from Thread"
-          />
-        </button>
-      </div>
+        />
+      </HoverGroup>
     </div>
   );
 };
diff --git a/src/components/RepositoryNotifications.tsx b/src/components/RepositoryNotifications.tsx
index fa664c98..ab4769e6 100644
--- a/src/components/RepositoryNotifications.tsx
+++ b/src/components/RepositoryNotifications.tsx
@@ -16,7 +16,9 @@ import { AppContext } from '../context/App';
 import { Size } from '../types';
 import type { Notification } from '../typesGitHub';
 import { openRepository } from '../utils/links';
+import { HoverGroup } from './HoverGroup';
 import { NotificationRow } from './NotificationRow';
+import { InteractionButton } from './buttons/InteractionButton';
 import { AvatarIcon } from './icons/AvatarIcon';
 
 interface IRepositoryNotifications {
@@ -81,37 +83,26 @@ export const RepositoryNotifications: FC<IRepositoryNotifications> = ({
           </span>
         </div>
 
-        <div className="flex items-center justify-center gap-2 opacity-0 transition-opacity group-hover:opacity-80">
-          <button
-            type="button"
-            className="h-full hover:text-green-500 focus:outline-none"
+        <HoverGroup>
+          <InteractionButton
             title="Mark Repository as Done"
+            icon={CheckIcon}
+            size={Size.MEDIUM}
             onClick={markRepoAsDone}
-          >
-            <CheckIcon
-              size={Size.MEDIUM}
-              aria-label="Mark Repository as Done"
-            />
-          </button>
-
-          <button
-            type="button"
-            className="h-full hover:text-green-500 focus:outline-none"
+          />
+          <InteractionButton
             title="Mark Repository as Read"
+            icon={ReadIcon}
+            size={Size.SMALL}
             onClick={markRepoAsRead}
-          >
-            <ReadIcon size={Size.SMALL} aria-label="Mark Repository as Read" />
-          </button>
-
-          <button
-            type="button"
-            className="h-full hover:text-green-500 focus:outline-none"
+          />
+          <InteractionButton
             title={toggleRepositoryNotificationsLabel}
+            icon={ChevronIcon}
+            size={Size.SMALL}
             onClick={toggleRepositoryNotifications}
-          >
-            <ChevronIcon size={Size.SMALL} />
-          </button>
-        </div>
+          />
+        </HoverGroup>
       </div>
 
       {showRepositoryNotifications &&
diff --git a/src/components/buttons/InteractionButton.tsx b/src/components/buttons/InteractionButton.tsx
new file mode 100644
index 00000000..94bd9745
--- /dev/null
+++ b/src/components/buttons/InteractionButton.tsx
@@ -0,0 +1,25 @@
+import type { Icon } from '@primer/octicons-react';
+import type { FC, MouseEvent } from 'react';
+import type { Size } from '../../types';
+
+export interface IInteractionButton {
+  title: string;
+  icon: Icon;
+  size: Size;
+  onClick: (event?: MouseEvent<HTMLElement>) => void;
+}
+
+export const InteractionButton: FC<IInteractionButton> = (
+  props: IInteractionButton,
+) => {
+  return (
+    <button
+      type="button"
+      className="h-full hover:text-green-500 focus:outline-none"
+      title={props.title}
+      onClick={props.onClick}
+    >
+      <props.icon size={props.size} aria-label={props.title} />
+    </button>
+  );
+};


Test patch:
diff --git a/src/components/HoverGroup.test.tsx b/src/components/HoverGroup.test.tsx
new file mode 100644
index 00000000..ea3573f6
--- /dev/null
+++ b/src/components/HoverGroup.test.tsx
@@ -0,0 +1,9 @@
+import { render } from '@testing-library/react';
+import { HoverGroup } from './HoverGroup';
+
+describe('components/HoverGroup.tsx', () => {
+  it('should render', () => {
+    const tree = render(<HoverGroup>Hover Group</HoverGroup>);
+    expect(tree).toMatchSnapshot();
+  });
+});
diff --git a/src/components/__snapshots__/AccountNotifications.test.tsx.snap b/src/components/__snapshots__/AccountNotifications.test.tsx.snap
index 33f51f6e..8f120478 100644
--- a/src/components/__snapshots__/AccountNotifications.test.tsx.snap
+++ b/src/components/__snapshots__/AccountNotifications.test.tsx.snap
@@ -40,7 +40,7 @@ exports[`components/AccountNotifications.tsx should render itself (github.com wi
           </button>
         </div>
         <div
-          class="opacity-0 transition-opacity group-hover:opacity-80"
+          class="flex items-center justify-center gap-2 opacity-0 transition-opacity group-hover:opacity-80"
         >
           <button
             class="h-full hover:text-green-500 focus:outline-none"
@@ -48,11 +48,12 @@ exports[`components/AccountNotifications.tsx should render itself (github.com wi
             type="button"
           >
             <svg
-              aria-hidden="true"
+              aria-label="Hide account notifications"
               class="octicon octicon-chevron-down"
               fill="currentColor"
               focusable="false"
               height="14"
+              role="img"
               style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
               viewBox="0 0 12 12"
               width="14"
@@ -239,7 +240,7 @@ exports[`components/AccountNotifications.tsx should render itself (github.com wi
             </svg>
           </button>
           <button
-            class="h-full hover:text-red-500 focus:outline-none"
+            class="h-full hover:text-green-500 focus:outline-none"
             title="Unsubscribe from Thread"
             type="button"
           >
@@ -396,7 +397,7 @@ exports[`components/AccountNotifications.tsx should render itself (github.com wi
             </svg>
           </button>
           <button
-            class="h-full hover:text-red-500 focus:outline-none"
+            class="h-full hover:text-green-500 focus:outline-none"
             title="Unsubscribe from Thread"
             type="button"
           >
@@ -456,7 +457,7 @@ exports[`components/AccountNotifications.tsx should render itself (github.com wi
         </button>
       </div>
       <div
-        class="opacity-0 transition-opacity group-hover:opacity-80"
+        class="flex items-center justify-center gap-2 opacity-0 transition-opacity group-hover:opacity-80"
       >
         <button
           class="h-full hover:text-green-500 focus:outline-none"
@@ -464,11 +465,12 @@ exports[`components/AccountNotifications.tsx should render itself (github.com wi
           type="button"
         >
           <svg
-            aria-hidden="true"
+            aria-label="Hide account notifications"
             class="octicon octicon-chevron-down"
             fill="currentColor"
             focusable="false"
             height="14"
+            role="img"
             style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
             viewBox="0 0 12 12"
             width="14"
@@ -655,7 +657,7 @@ exports[`components/AccountNotifications.tsx should render itself (github.com wi
           </svg>
         </button>
         <button
-          class="h-full hover:text-red-500 focus:outline-none"
+          class="h-full hover:text-green-500 focus:outline-none"
           title="Unsubscribe from Thread"
           type="button"
         >
@@ -812,7 +814,7 @@ exports[`components/AccountNotifications.tsx should render itself (github.com wi
           </svg>
         </button>
         <button
-          class="h-full hover:text-red-500 focus:outline-none"
+          class="h-full hover:text-green-500 focus:outline-none"
           title="Unsubscribe from Thread"
           type="button"
         >
@@ -929,7 +931,7 @@ exports[`components/AccountNotifications.tsx should render itself (github.com wi
           </button>
         </div>
         <div
-          class="opacity-0 transition-opacity group-hover:opacity-80"
+          class="flex items-center justify-center gap-2 opacity-0 transition-opacity group-hover:opacity-80"
         >
           <button
             class="h-full hover:text-green-500 focus:outline-none"
@@ -937,11 +939,12 @@ exports[`components/AccountNotifications.tsx should render itself (github.com wi
             type="button"
           >
             <svg
-              aria-hidden="true"
+              aria-label="Hide account notifications"
               class="octicon octicon-chevron-down"
               fill="currentColor"
               focusable="false"
               height="14"
+              role="img"
               style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
               viewBox="0 0 12 12"
               width="14"
@@ -994,7 +997,7 @@ exports[`components/AccountNotifications.tsx should render itself (github.com wi
         </button>
       </div>
       <div
-        class="opacity-0 transition-opacity group-hover:opacity-80"
+        class="flex items-center justify-center gap-2 opacity-0 transition-opacity group-hover:opacity-80"
       >
         <button
           class="h-full hover:text-green-500 focus:outline-none"
@@ -1002,11 +1005,12 @@ exports[`components/AccountNotifications.tsx should render itself (github.com wi
           type="button"
         >
           <svg
-            aria-hidden="true"
+            aria-label="Hide account notifications"
             class="octicon octicon-chevron-down"
             fill="currentColor"
             focusable="false"
             height="14"
+            role="img"
             style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
             viewBox="0 0 12 12"
             width="14"
@@ -1116,7 +1120,7 @@ exports[`components/AccountNotifications.tsx should render itself (github.com wi
           </button>
         </div>
         <div
-          class="opacity-0 transition-opacity group-hover:opacity-80"
+          class="flex items-center justify-center gap-2 opacity-0 transition-opacity group-hover:opacity-80"
         >
           <button
             class="h-full hover:text-green-500 focus:outline-none"
@@ -1124,11 +1128,12 @@ exports[`components/AccountNotifications.tsx should render itself (github.com wi
             type="button"
           >
             <svg
-              aria-hidden="true"
+              aria-label="No notifications for account"
               class="octicon octicon-chevron-left"
               fill="currentColor"
               focusable="false"
               height="14"
+              role="img"
               style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
               viewBox="0 0 12 12"
               width="14"
@@ -1178,7 +1183,7 @@ exports[`components/AccountNotifications.tsx should render itself (github.com wi
         </button>
       </div>
       <div
-        class="opacity-0 transition-opacity group-hover:opacity-80"
+        class="flex items-center justify-center gap-2 opacity-0 transition-opacity group-hover:opacity-80"
       >
         <button
           class="h-full hover:text-green-500 focus:outline-none"
@@ -1186,11 +1191,12 @@ exports[`components/AccountNotifications.tsx should render itself (github.com wi
           type="button"
         >
           <svg
-            aria-hidden="true"
+            aria-label="No notifications for account"
             class="octicon octicon-chevron-left"
             fill="currentColor"
             focusable="false"
             height="14"
+            role="img"
             style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
             viewBox="0 0 12 12"
             width="14"
@@ -1297,7 +1303,7 @@ exports[`components/AccountNotifications.tsx should toggle account notifications
           </button>
         </div>
         <div
-          class="opacity-0 transition-opacity group-hover:opacity-80"
+          class="flex items-center justify-center gap-2 opacity-0 transition-opacity group-hover:opacity-80"
         >
           <button
             class="h-full hover:text-green-500 focus:outline-none"
@@ -1305,11 +1311,12 @@ exports[`components/AccountNotifications.tsx should toggle account notifications
             type="button"
           >
             <svg
-              aria-hidden="true"
+              aria-label="Show account notifications"
               class="octicon octicon-chevron-up"
               fill="currentColor"
               focusable="false"
               height="14"
+              role="img"
               style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
               viewBox="0 0 12 12"
               width="14"
@@ -1358,7 +1365,7 @@ exports[`components/AccountNotifications.tsx should toggle account notifications
           </button>
         </div>
         <div
-          class="opacity-0 transition-opacity group-hover:opacity-80"
+          class="flex items-center justify-center gap-2 opacity-0 transition-opacity group-hover:opacity-80"
         >
           <button
             class="h-full hover:text-green-500 focus:outline-none"
@@ -1366,11 +1373,12 @@ exports[`components/AccountNotifications.tsx should toggle account notifications
             type="button"
           >
             <svg
-              aria-hidden="true"
+              aria-label="Hide account notifications"
               class="octicon octicon-chevron-down"
               fill="currentColor"
               focusable="false"
               height="14"
+              role="img"
               style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
               viewBox="0 0 12 12"
               width="14"
@@ -1423,7 +1431,7 @@ exports[`components/AccountNotifications.tsx should toggle account notifications
         </button>
       </div>
       <div
-        class="opacity-0 transition-opacity group-hover:opacity-80"
+        class="flex items-center justify-center gap-2 opacity-0 transition-opacity group-hover:opacity-80"
       >
         <button
           class="h-full hover:text-green-500 focus:outline-none"
@@ -1431,11 +1439,12 @@ exports[`components/AccountNotifications.tsx should toggle account notifications
           type="button"
         >
           <svg
-            aria-hidden="true"
+            aria-label="Hide account notifications"
             class="octicon octicon-chevron-down"
             fill="currentColor"
             focusable="false"
             height="14"
+            role="img"
             style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
             viewBox="0 0 12 12"
             width="14"
diff --git a/src/components/__snapshots__/HoverGroup.test.tsx.snap b/src/components/__snapshots__/HoverGroup.test.tsx.snap
new file mode 100644
index 00000000..100f475e
--- /dev/null
+++ b/src/components/__snapshots__/HoverGroup.test.tsx.snap
@@ -0,0 +1,74 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`components/HoverGroup.tsx should render 1`] = `
+{
+  "asFragment": [Function],
+  "baseElement": <body>
+    <div>
+      <div
+        class="flex items-center justify-center gap-2 opacity-0 transition-opacity group-hover:opacity-80"
+      >
+        Hover Group
+      </div>
+    </div>
+  </body>,
+  "container": <div>
+    <div
+      class="flex items-center justify-center gap-2 opacity-0 transition-opacity group-hover:opacity-80"
+    >
+      Hover Group
+    </div>
+  </div>,
+  "debug": [Function],
+  "findAllByAltText": [Function],
+  "findAllByDisplayValue": [Function],
+  "findAllByLabelText": [Function],
+  "findAllByPlaceholderText": [Function],
+  "findAllByRole": [Function],
+  "findAllByTestId": [Function],
+  "findAllByText": [Function],
+  "findAllByTitle": [Function],
+  "findByAltText": [Function],
+  "findByDisplayValue": [Function],
+  "findByLabelText": [Function],
+  "findByPlaceholderText": [Function],
+  "findByRole": [Function],
+  "findByTestId": [Function],
+  "findByText": [Function],
+  "findByTitle": [Function],
+  "getAllByAltText": [Function],
+  "getAllByDisplayValue": [Function],
+  "getAllByLabelText": [Function],
+  "getAllByPlaceholderText": [Function],
+  "getAllByRole": [Function],
+  "getAllByTestId": [Function],
+  "getAllByText": [Function],
+  "getAllByTitle": [Function],
+  "getByAltText": [Function],
+  "getByDisplayValue": [Function],
+  "getByLabelText": [Function],
+  "getByPlaceholderText": [Function],
+  "getByRole": [Function],
+  "getByTestId": [Function],
+  "getByText": [Function],
+  "getByTitle": [Function],
+  "queryAllByAltText": [Function],
+  "queryAllByDisplayValue": [Function],
+  "queryAllByLabelText": [Function],
+  "queryAllByPlaceholderText": [Function],
+  "queryAllByRole": [Function],
+  "queryAllByTestId": [Function],
+  "queryAllByText": [Function],
+  "queryAllByTitle": [Function],
+  "queryByAltText": [Function],
+  "queryByDisplayValue": [Function],
+  "queryByLabelText": [Function],
+  "queryByPlaceholderText": [Function],
+  "queryByRole": [Function],
+  "queryByTestId": [Function],
+  "queryByText": [Function],
+  "queryByTitle": [Function],
+  "rerender": [Function],
+  "unmount": [Function],
+}
+`;
diff --git a/src/components/__snapshots__/NotificationRow.test.tsx.snap b/src/components/__snapshots__/NotificationRow.test.tsx.snap
index 649fef6d..0db30480 100644
--- a/src/components/__snapshots__/NotificationRow.test.tsx.snap
+++ b/src/components/__snapshots__/NotificationRow.test.tsx.snap
@@ -214,7 +214,7 @@ exports[`components/NotificationRow.tsx notification pills / metrics comment pil
             </svg>
           </button>
           <button
-            class="h-full hover:text-red-500 focus:outline-none"
+            class="h-full hover:text-green-500 focus:outline-none"
             title="Unsubscribe from Thread"
             type="button"
           >
@@ -448,7 +448,7 @@ exports[`components/NotificationRow.tsx notification pills / metrics comment pil
           </svg>
         </button>
         <button
-          class="h-full hover:text-red-500 focus:outline-none"
+          class="h-full hover:text-green-500 focus:outline-none"
           title="Unsubscribe from Thread"
           type="button"
         >
@@ -739,7 +739,7 @@ exports[`components/NotificationRow.tsx notification pills / metrics comment pil
             </svg>
           </button>
           <button
-            class="h-full hover:text-red-500 focus:outline-none"
+            class="h-full hover:text-green-500 focus:outline-none"
             title="Unsubscribe from Thread"
             type="button"
           >
@@ -973,7 +973,7 @@ exports[`components/NotificationRow.tsx notification pills / metrics comment pil
           </svg>
         </button>
         <button
-          class="h-full hover:text-red-500 focus:outline-none"
+          class="h-full hover:text-green-500 focus:outline-none"
           title="Unsubscribe from Thread"
           type="button"
         >
@@ -1242,7 +1242,7 @@ exports[`components/NotificationRow.tsx notification pills / metrics comment pil
             </svg>
           </button>
           <button
-            class="h-full hover:text-red-500 focus:outline-none"
+            class="h-full hover:text-green-500 focus:outline-none"
             title="Unsubscribe from Thread"
             type="button"
           >
@@ -1454,7 +1454,7 @@ exports[`components/NotificationRow.tsx notification pills / metrics comment pil
           </svg>
         </button>
         <button
-          class="h-full hover:text-red-500 focus:outline-none"
+          class="h-full hover:text-green-500 focus:outline-none"
           title="Unsubscribe from Thread"
           type="button"
         >
@@ -1769,7 +1769,7 @@ exports[`components/NotificationRow.tsx notification pills / metrics label pills
             </svg>
           </button>
           <button
-            class="h-full hover:text-red-500 focus:outline-none"
+            class="h-full hover:text-green-500 focus:outline-none"
             title="Unsubscribe from Thread"
             type="button"
           >
@@ -2027,7 +2027,7 @@ exports[`components/NotificationRow.tsx notification pills / metrics label pills
           </svg>
         </button>
         <button
-          class="h-full hover:text-red-500 focus:outline-none"
+          class="h-full hover:text-green-500 focus:outline-none"
           title="Unsubscribe from Thread"
           type="button"
         >
@@ -2296,7 +2296,7 @@ exports[`components/NotificationRow.tsx notification pills / metrics linked issu
             </svg>
           </button>
           <button
-            class="h-full hover:text-red-500 focus:outline-none"
+            class="h-full hover:text-green-500 focus:outline-none"
             title="Unsubscribe from Thread"
             type="button"
           >
@@ -2508,7 +2508,7 @@ exports[`components/NotificationRow.tsx notification pills / metrics linked issu
           </svg>
         </button>
         <button
-          class="h-full hover:text-red-500 focus:outline-none"
+          class="h-full hover:text-green-500 focus:outline-none"
           title="Unsubscribe from Thread"
           type="button"
         >
@@ -2777,7 +2777,7 @@ exports[`components/NotificationRow.tsx notification pills / metrics linked issu
             </svg>
           </button>
           <button
-            class="h-full hover:text-red-500 focus:outline-none"
+            class="h-full hover:text-green-500 focus:outline-none"
             title="Unsubscribe from Thread"
             type="button"
           >
@@ -2989,7 +2989,7 @@ exports[`components/NotificationRow.tsx notification pills / metrics linked issu
           </svg>
         </button>
         <button
-          class="h-full hover:text-red-500 focus:outline-none"
+          class="h-full hover:text-green-500 focus:outline-none"
           title="Unsubscribe from Thread"
           type="button"
         >
@@ -3325,7 +3325,7 @@ exports[`components/NotificationRow.tsx notification pills / metrics milestone p
             </svg>
           </button>
           <button
-            class="h-full hover:text-red-500 focus:outline-none"
+            class="h-full hover:text-green-500 focus:outline-none"
             title="Unsubscribe from Thread"
             type="button"
           >
@@ -3604,7 +3604,7 @@ exports[`components/NotificationRow.tsx notification pills / metrics milestone p
           </svg>
         </button>
         <button
-          class="h-full hover:text-red-500 focus:outline-none"
+          class="h-full hover:text-green-500 focus:outline-none"
           title="Unsubscribe from Thread"
           type="button"
         >
@@ -3940,7 +3940,7 @@ exports[`components/NotificationRow.tsx notification pills / metrics milestone p
             </svg>
           </button>
           <button
-            class="h-full hover:text-red-500 focus:outline-none"
+            class="h-full hover:text-green-500 focus:outline-none"
             title="Unsubscribe from Thread"
             type="button"
           >
@@ -4219,7 +4219,7 @@ exports[`components/NotificationRow.tsx notification pills / metrics milestone p
           </svg>
         </button>
         <button
-          class="h-full hover:text-red-500 focus:outline-none"
+          class="h-full hover:text-green-500 focus:outline-none"
           title="Unsubscribe from Thread"
           type="button"
         >
@@ -4415,7 +4415,7 @@ exports[`components/NotificationRow.tsx notification pills / metrics showPills d
             </svg>
           </button>
           <button
-            class="h-full hover:text-red-500 focus:outline-none"
+            class="h-full hover:text-green-500 focus:outline-none"
             title="Unsubscribe from Thread"
             type="button"
           >
@@ -4554,7 +4554,7 @@ exports[`components/NotificationRow.tsx notification pills / metrics showPills d
           </svg>
         </button>
         <button
-          class="h-full hover:text-red-500 focus:outline-none"
+          class="h-full hover:text-green-500 focus:outline-none"
           title="Unsubscribe from Thread"
           type="button"
         >
@@ -4811,7 +4811,7 @@ exports[`components/NotificationRow.tsx should render itself & its children - gr
             </svg>
           </button>
           <button
-            class="h-full hover:text-red-500 focus:outline-none"
+            class="h-full hover:text-green-500 focus:outline-none"
             title="Unsubscribe from Thread"
             type="button"
           >
@@ -5011,7 +5011,7 @@ exports[`components/NotificationRow.tsx should render itself & its children - gr
           </svg>
         </button>
         <button
-          class="h-full hover:text-red-500 focus:outline-none"
+          class="h-full hover:text-green-500 focus:outline-none"
           title="Unsubscribe from Thread"
           type="button"
         >
@@ -5250,7 +5250,7 @@ exports[`components/NotificationRow.tsx should render itself & its children - gr
             </svg>
           </button>
           <button
-            class="h-full hover:text-red-500 focus:outline-none"
+            class="h-full hover:text-green-500 focus:outline-none"
             title="Unsubscribe from Thread"
             type="button"
           >
@@ -5432,7 +5432,7 @@ exports[`components/NotificationRow.tsx should render itself & its children - gr
           </svg>
         </button>
         <button
-          class="h-full hover:text-red-500 focus:outline-none"
+          class="h-full hover:text-green-500 focus:outline-none"
           title="Unsubscribe from Thread"
           type="button"
         >
@@ -5671,7 +5671,7 @@ exports[`components/NotificationRow.tsx should render itself & its children when
             </svg>
           </button>
           <button
-            class="h-full hover:text-red-500 focus:outline-none"
+            class="h-full hover:text-green-500 focus:outline-none"
             title="Unsubscribe from Thread"
             type="button"
           >
@@ -5853,7 +5853,7 @@ exports[`components/NotificationRow.tsx should render itself & its children when
           </svg>
         </button>
         <button
-          class="h-full hover:text-red-500 focus:outline-none"
+          class="h-full hover:text-green-500 focus:outline-none"
           title="Unsubscribe from Thread"
           type="button"
         >
@@ -6097,7 +6097,7 @@ exports[`components/NotificationRow.tsx should render itself & its children with
             </svg>
           </button>
           <button
-            class="h-full hover:text-red-500 focus:outline-none"
+            class="h-full hover:text-green-500 focus:outline-none"
             title="Unsubscribe from Thread"
             type="button"
           >
@@ -6284,7 +6284,7 @@ exports[`components/NotificationRow.tsx should render itself & its children with
           </svg>
         </button>
         <button
-          class="h-full hover:text-red-500 focus:outline-none"
+          class="h-full hover:text-green-500 focus:outline-none"
           title="Unsubscribe from Thread"
           type="button"
         >
diff --git a/src/components/__snapshots__/RepositoryNotifications.test.tsx.snap b/src/components/__snapshots__/RepositoryNotifications.test.tsx.snap
index a294a63c..f9d7f0d8 100644
--- a/src/components/__snapshots__/RepositoryNotifications.test.tsx.snap
+++ b/src/components/__snapshots__/RepositoryNotifications.test.tsx.snap
@@ -73,11 +73,12 @@ exports[`components/Repository.tsx should render itself & its children 1`] = `
             type="button"
           >
             <svg
-              aria-hidden="true"
+              aria-label="Hide repository notifications"
               class="octicon octicon-chevron-down"
               fill="currentColor"
               focusable="false"
               height="14"
+              role="img"
               style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
               viewBox="0 0 12 12"
               width="14"
@@ -166,11 +167,12 @@ exports[`components/Repository.tsx should render itself & its children 1`] = `
           type="button"
         >
           <svg
-            aria-hidden="true"
+            aria-label="Hide repository notifications"
             class="octicon octicon-chevron-down"
             fill="currentColor"
             focusable="false"
             height="14"
+            role="img"
             style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
             viewBox="0 0 12 12"
             width="14"
@@ -325,11 +327,12 @@ exports[`components/Repository.tsx should toggle account notifications visibilit
             type="button"
           >
             <svg
-              aria-hidden="true"
+              aria-label="Show repository notifications"
               class="octicon octicon-chevron-up"
               fill="currentColor"
               focusable="false"
               height="14"
+              role="img"
               style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
               viewBox="0 0 12 12"
               width="14"
@@ -420,11 +423,12 @@ exports[`components/Repository.tsx should toggle account notifications visibilit
             type="button"
           >
             <svg
-              aria-hidden="true"
+              aria-label="Hide repository notifications"
               class="octicon octicon-chevron-down"
               fill="currentColor"
               focusable="false"
               height="14"
+              role="img"
               style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
               viewBox="0 0 12 12"
               width="14"
@@ -522,11 +526,12 @@ exports[`components/Repository.tsx should toggle account notifications visibilit
           type="button"
         >
           <svg
-            aria-hidden="true"
+            aria-label="Hide repository notifications"
             class="octicon octicon-chevron-down"
             fill="currentColor"
             focusable="false"
             height="14"
+            role="img"
             style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
             viewBox="0 0 12 12"
             width="14"
@@ -681,11 +686,12 @@ exports[`components/Repository.tsx should use default repository icon when avata
             type="button"
           >
             <svg
-              aria-hidden="true"
+              aria-label="Hide repository notifications"
               class="octicon octicon-chevron-down"
               fill="currentColor"
               focusable="false"
               height="14"
+              role="img"
               style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
               viewBox="0 0 12 12"
               width="14"
@@ -783,11 +789,12 @@ exports[`components/Repository.tsx should use default repository icon when avata
           type="button"
         >
           <svg
-            aria-hidden="true"
+            aria-label="Hide repository notifications"
             class="octicon octicon-chevron-down"
             fill="currentColor"
             focusable="false"
             height="14"
+            role="img"
             style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
             viewBox="0 0 12 12"
             width="14"
diff --git a/src/components/buttons/InteractionButton.test.tsx b/src/components/buttons/InteractionButton.test.tsx
new file mode 100644
index 00000000..9891c0fb
--- /dev/null
+++ b/src/components/buttons/InteractionButton.test.tsx
@@ -0,0 +1,20 @@
+import { MarkGithubIcon } from '@primer/octicons-react';
+import { render } from '@testing-library/react';
+import { Size } from '../../types';
+import {
+  type IInteractionButton,
+  InteractionButton,
+} from './InteractionButton';
+
+describe('components/buttons/InteractionButton.tsx', () => {
+  it('should render', () => {
+    const props: IInteractionButton = {
+      title: 'Mock Interaction Button',
+      icon: MarkGithubIcon,
+      size: Size.SMALL,
+      onClick: () => () => {},
+    };
+    const tree = render(<InteractionButton {...props} />);
+    expect(tree).toMatchSnapshot();
+  });
+});
diff --git a/src/components/buttons/SidebarButton.test.tsx b/src/components/buttons/SidebarButton.test.tsx
index 53bb475d..7fb2f317 100644
--- a/src/components/buttons/SidebarButton.test.tsx
+++ b/src/components/buttons/SidebarButton.test.tsx
@@ -24,7 +24,7 @@ describe('components/buttons/SidebarButton.tsx', () => {
     expect(tree).toMatchSnapshot();
   });
 
-  it('should render - medium', () => {
+  it('should render - with specific size', () => {
     const props: ISidebarButton = {
       title: 'Mock Sidebar Button',
       metric: 0,
diff --git a/src/components/buttons/__snapshots__/InteractionButton.test.tsx.snap b/src/components/buttons/__snapshots__/InteractionButton.test.tsx.snap
new file mode 100644
index 00000000..e944ff59
--- /dev/null
+++ b/src/components/buttons/__snapshots__/InteractionButton.test.tsx.snap
@@ -0,0 +1,106 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`components/buttons/InteractionButton.tsx should render 1`] = `
+{
+  "asFragment": [Function],
+  "baseElement": <body>
+    <div>
+      <button
+        class="h-full hover:text-green-500 focus:outline-none"
+        title="Mock Interaction Button"
+        type="button"
+      >
+        <svg
+          aria-label="Mock Interaction Button"
+          class="octicon octicon-mark-github"
+          fill="currentColor"
+          focusable="false"
+          height="14"
+          role="img"
+          style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+          viewBox="0 0 16 16"
+          width="14"
+        >
+          <path
+            d="M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z"
+          />
+        </svg>
+      </button>
+    </div>
+  </body>,
+  "container": <div>
+    <button
+      class="h-full hover:text-green-500 focus:outline-none"
+      title="Mock Interaction Button"
+      type="button"
+    >
+      <svg
+        aria-label="Mock Interaction Button"
+        class="octicon octicon-mark-github"
+        fill="currentColor"
+        focusable="false"
+        height="14"
+        role="img"
+        style="display: inline-block; user-select: none; vertical-align: text-bottom; overflow: visible;"
+        viewBox="0 0 16 16"
+        width="14"
+      >
+        <path
+          d="M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z"
+        />
+      </svg>
+    </button>
+  </div>,
+  "debug": [Function],
+  "findAllByAltText": [Function],
+  "findAllByDisplayValue": [Function],
+  "findAllByLabelText": [Function],
+  "findAllByPlaceholderText": [Function],
+  "findAllByRole": [Function],
+  "findAllByTestId": [Function],
+  "findAllByText": [Function],
+  "findAllByTitle": [Function],
+  "findByAltText": [Function],
+  "findByDisplayValue": [Function],
+  "findByLabelText": [Function],
+  "findByPlaceholderText": [Function],
+  "findByRole": [Function],
+  "findByTestId": [Function],
+  "findByText": [Function],
+  "findByTitle": [Function],
+  "getAllByAltText": [Function],
+  "getAllByDisplayValue": [Function],
+  "getAllByLabelText": [Function],
+  "getAllByPlaceholderText": [Function],
+  "getAllByRole": [Function],
+  "getAllByTestId": [Function],
+  "getAllByText": [Function],
+  "getAllByTitle": [Function],
+  "getByAltText": [Function],
+  "getByDisplayValue": [Function],
+  "getByLabelText": [Function],
+  "getByPlaceholderText": [Function],
+  "getByRole": [Function],
+  "getByTestId": [Function],
+  "getByText": [Function],
+  "getByTitle": [Function],
+  "queryAllByAltText": [Function],
+  "queryAllByDisplayValue": [Function],
+  "queryAllByLabelText": [Function],
+  "queryAllByPlaceholderText": [Function],
+  "queryAllByRole": [Function],
+  "queryAllByTestId": [Function],
+  "queryAllByText": [Function],
+  "queryAllByTitle": [Function],
+  "queryByAltText": [Function],
+  "queryByDisplayValue": [Function],
+  "queryByLabelText": [Function],
+  "queryByPlaceholderText": [Function],
+  "queryByRole": [Function],
+  "queryByTestId": [Function],
+  "queryByText": [Function],
+  "queryByTitle": [Function],
+  "rerender": [Function],
+  "unmount": [Function],
+}
+`;
diff --git a/src/components/buttons/__snapshots__/SidebarButton.test.tsx.snap b/src/components/buttons/__snapshots__/SidebarButton.test.tsx.snap
index d4318b53..8275f94c 100644
--- a/src/components/buttons/__snapshots__/SidebarButton.test.tsx.snap
+++ b/src/components/buttons/__snapshots__/SidebarButton.test.tsx.snap
@@ -1,6 +1,6 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`components/buttons/SidebarButton.tsx should render - medium 1`] = `
+exports[`components/buttons/SidebarButton.tsx should render - with specific size 1`] = `
 {
   "asFragment": [Function],
   "baseElement": <body>