From 1278746ff2b3a783be176f0d3cb0308a9b98c6bd Mon Sep 17 00:00:00 2001
From: Jed Fox <git@jedfox.com>
Date: Wed, 11 Jan 2023 17:21:52 -0500
Subject: [PATCH] Further iteration on the sidebar design (#440)

---
 .../src/components/SidebarWithData.js         |   1 +
 .../loot-design/src/components/sidebar.js     | 263 ++++++++++--------
 2 files changed, 150 insertions(+), 114 deletions(-)

diff --git a/packages/desktop-client/src/components/SidebarWithData.js b/packages/desktop-client/src/components/SidebarWithData.js
index 0c35a02b3..831c7f03d 100644
--- a/packages/desktop-client/src/components/SidebarWithData.js
+++ b/packages/desktop-client/src/components/SidebarWithData.js
@@ -94,6 +94,7 @@ function SidebarWithData({
       failedAccounts={failedAccounts}
       updatedAccounts={updatedAccounts}
       getBalanceQuery={queries.accountBalance}
+      getAllAccountBalance={queries.allAccountBalance}
       getOnBudgetBalance={queries.budgetedAccountBalance}
       getOffBudgetBalance={queries.offbudgetAccountBalance}
       onFloat={() => saveGlobalPrefs({ floatingSidebar: !floatingSidebar })}
diff --git a/packages/loot-design/src/components/sidebar.js b/packages/loot-design/src/components/sidebar.js
index 163ecc337..290b5801e 100644
--- a/packages/loot-design/src/components/sidebar.js
+++ b/packages/loot-design/src/components/sidebar.js
@@ -1,23 +1,25 @@
-import React, { useState, useMemo, useCallback } from 'react';
+import React, { useState, useMemo, useCallback, useEffect } from 'react';
 import { RectButton } from 'react-native-gesture-handler';
 import { useDispatch } from 'react-redux';
-import { useLocation, useHistory } from 'react-router';
+import { useLocation } from 'react-router';
 import { withRouter } from 'react-router-dom';
 
 import { css } from 'glamor';
 
 import { closeBudget } from 'loot-core/src/client/actions/budgets';
 import Platform from 'loot-core/src/client/platform';
-import PiggyBank from 'loot-design/src/svg/v1/PiggyBank';
 
 import { styles, colors } from '../style';
 import Add from '../svg/v1/Add';
-import ChevronRight from '../svg/v1/CheveronRight';
+import CheveronDown from '../svg/v1/CheveronDown';
+import CheveronRight from '../svg/v1/CheveronRight';
 import Cog from '../svg/v1/Cog';
 import DotsHorizontalTriple from '../svg/v1/DotsHorizontalTriple';
+import LoadBalancer from '../svg/v1/LoadBalancer';
 import Reports from '../svg/v1/Reports';
+import StoreFrontIcon from '../svg/v1/StoreFront';
+import TuningIcon from '../svg/v1/Tuning';
 import Wallet from '../svg/v1/Wallet';
-import Wrench from '../svg/v1/Wrench';
 import ArrowButtonLeft1 from '../svg/v2/ArrowButtonLeft1';
 import CalendarIcon from '../svg/v2/Calendar';
 import {
@@ -35,9 +37,11 @@ import CellValue from './spreadsheet/CellValue';
 
 export const SIDEBAR_WIDTH = 240;
 
+const fontWeight = 600;
+
 function Item({
   children,
-  icon,
+  Icon,
   title,
   style,
   indent = 0,
@@ -79,7 +83,7 @@ function Item({
         height: 20
       }}
     >
-      {icon}
+      <Icon width={15} height={15} style={{ color: 'inherit' }} />
       <Block style={{ marginLeft: 8 }}>{title}</Block>
       <View style={{ flex: 1 }} />
       {button}
@@ -108,6 +112,70 @@ function Item({
   );
 }
 
+function SecondaryItem({
+  Icon,
+  title,
+  style,
+  to,
+  exact,
+  onClick,
+  bold,
+  indent = 0
+}) {
+  const hoverStyle = {
+    backgroundColor: colors.n2
+  };
+  const activeStyle = {
+    borderLeft: '4px solid ' + colors.p8,
+    paddingLeft: 14 - 4 + indent,
+    color: colors.p8,
+    fontWeight: bold ? fontWeight : null
+  };
+  const linkStyle = [
+    accountNameStyle,
+    {
+      color: colors.n9,
+      paddingLeft: 14 + indent,
+      fontWeight: bold ? fontWeight : null
+    },
+    { ':hover': hoverStyle }
+  ];
+
+  const content = (
+    <View
+      style={{
+        flexDirection: 'row',
+        alignItems: 'center',
+        height: 16
+      }}
+    >
+      {Icon && <Icon width={12} height={12} style={{ color: 'inherit' }} />}
+      <Block style={{ marginLeft: Icon ? 8 : 0, color: 'inherit' }}>
+        {title}
+      </Block>
+    </View>
+  );
+
+  return (
+    <View style={[{ flexShrink: 0 }, style]}>
+      {onClick ? (
+        <RectButton onClick={onClick}>
+          <View style={linkStyle}>{content}</View>
+        </RectButton>
+      ) : (
+        <AnchorLink
+          style={linkStyle}
+          to={to}
+          exact={exact}
+          activeStyle={activeStyle}
+        >
+          {content}
+        </AnchorLink>
+      )}
+    </View>
+  );
+}
+
 let accountNameStyle = [
   {
     marginTop: -2,
@@ -179,7 +247,7 @@ function Account({
               // has unread transactions. The system does mark is read and
               // unbolds it, but it still "flashes" bold so this just
               // ignores it if it's active
-              fontWeight: 'normal',
+              fontWeight: (style && style.fontWeight) || 'normal',
               '& .dot': {
                 backgroundColor: colors.p8,
                 transform: 'translateX(-4.5px)'
@@ -218,7 +286,7 @@ function Account({
               }
             />
           </AnchorLink>
-        </View>{' '}
+        </View>
       </View>
     </View>
   );
@@ -229,9 +297,11 @@ function Accounts({
   failedAccounts,
   updatedAccounts,
   getAccountPath,
+  allAccountsPath,
   budgetedAccountPath,
   offBudgetAccountPath,
   getBalanceQuery,
+  getAllAccountBalance,
   getOnBudgetBalance,
   getOffBudgetBalance,
   showClosedAccounts,
@@ -269,22 +339,25 @@ function Accounts({
         paddingTop: isDragging ? 15 : 0,
         marginTop: isDragging ? -15 : 0
       };
-    } else if (i === length - 1) {
-      return {
-        paddingBottom: 15
-      };
     }
     return null;
   };
 
   return (
     <View>
+      <Account
+        name="All accounts"
+        to={allAccountsPath}
+        query={getAllAccountBalance()}
+        style={{ fontWeight, marginTop: 15 }}
+      />
+
       {budgetedAccounts.length > 0 && (
         <Account
           name="For budget"
           to={budgetedAccountPath}
           query={getOnBudgetBalance()}
-          style={{ marginTop: 15, color: colors.n6 }}
+          style={{ fontWeight, marginTop: 13 }}
         />
       )}
 
@@ -309,7 +382,7 @@ function Accounts({
           name="Off budget"
           to={offBudgetAccountPath}
           query={getOffBudgetBalance()}
-          style={{ color: colors.n6 }}
+          style={{ fontWeight, marginTop: 13 }}
         />
       )}
 
@@ -330,22 +403,12 @@ function Accounts({
       ))}
 
       {closedAccounts.length > 0 && (
-        <View
-          style={[
-            accountNameStyle,
-            {
-              marginTop: 15,
-              color: colors.n6,
-              flexDirection: 'row',
-              userSelect: 'none',
-              alignItems: 'center',
-              flexShrink: 0
-            }
-          ]}
+        <SecondaryItem
+          style={{ marginTop: 15 }}
+          title={'Closed accounts' + (showClosedAccounts ? '' : '...')}
           onClick={onToggleClosedAccounts}
-        >
-          {'Closed Accounts' + (showClosedAccounts ? '' : '...')}
-        </View>
+          bold
+        />
       )}
 
       {showClosedAccounts &&
@@ -360,6 +423,16 @@ function Accounts({
             onDrop={onReorder}
           />
         ))}
+
+      <SecondaryItem
+        style={{
+          marginTop: 15,
+          marginBottom: 9
+        }}
+        onClick={onAddAccount}
+        Icon={Add}
+        title="Add account"
+      />
     </View>
   );
 }
@@ -431,64 +504,49 @@ const MenuButton = withRouter(function MenuButton({ history }) {
 
 function Tools() {
   let [isOpen, setOpen] = useState(false);
-  let location = useLocation();
-  let history = useHistory();
   let onToggle = useCallback(() => setOpen(open => !open), []);
+  let location = useLocation();
 
-  let items = [
-    { name: 'payees', text: 'Payees' },
-    { name: 'rules', text: 'Rules' },
-    { name: 'repair-splits', text: 'Repair split transactions' }
-  ];
-
-  let onMenuSelect = useCallback(
-    type => {
-      switch (type) {
-        case 'payees':
-          history.push('/payees');
-          break;
-        case 'rules':
-          history.push('/rules');
-          break;
-        case 'repair-splits':
-          history.push('/tools/fix-splits', { locationPtr: history.location });
-          break;
-        default:
-      }
-      setOpen(false);
-    },
-    [history]
+  const isActive = ['/payees', '/rules', '/tools'].some(route =>
+    location.pathname.startsWith(route)
   );
 
+  useEffect(() => {
+    if (isActive) {
+      setOpen(true);
+    }
+  }, [location.pathname]);
+
   return (
     <View style={{ flexShrink: 0 }}>
       <Item
-        title="More Tools"
-        icon={<Wrench width={15} height={15} style={{ color: 'inherit' }} />}
-        exact={true}
+        title="More"
+        Icon={isOpen ? CheveronDown : CheveronRight}
         onClick={onToggle}
-        style={{ pointerEvents: isOpen ? 'none' : 'auto' }}
-        forceHover={isOpen}
-        forceActive={['/payees', '/rules', '/tools'].some(route =>
-          location.pathname.startsWith(route)
-        )}
-        button={
-          <ChevronRight
-            width={12}
-            height={12}
-            style={{ color: colors.n6, marginRight: 6 }}
-          />
-        }
+        style={{ marginBottom: isOpen ? 8 : 0 }}
+        forceActive={!isOpen && isActive}
       />
       {isOpen && (
-        <Tooltip
-          position="right"
-          offset={-8}
-          style={{ padding: 0 }}
-          onClose={onToggle}
-        >
-          <Menu onMenuSelect={onMenuSelect} items={items} />
-        </Tooltip>
+        <>
+          <SecondaryItem
+            title="Payees"
+            Icon={StoreFrontIcon}
+            to="/payees"
+            indent={15}
+          />
+          <SecondaryItem
+            title="Rules"
+            Icon={TuningIcon}
+            to="/rules"
+            indent={15}
+          />
+          <SecondaryItem
+            title="Repair split transactions"
+            Icon={LoadBalancer}
+            to="/tools/fix-splits"
+            indent={15}
+          />
+        </>
       )}
     </View>
   );
@@ -501,6 +559,7 @@ export function Sidebar({
   failedAccounts,
   updatedAccounts,
   getBalanceQuery,
+  getAllAccountBalance,
   getOnBudgetBalance,
   getOffBudgetBalance,
   showClosedAccounts,
@@ -589,46 +648,20 @@ export function Sidebar({
       </View>
 
       <View style={{ overflow: 'auto' }}>
-        <Item
-          title="Budget"
-          icon={<Wallet width={15} height={15} style={{ color: 'inherit' }} />}
-          to="/budget"
-        />
-        <Item
-          title="Reports"
-          icon={<Reports width={15} height={15} style={{ color: 'inherit' }} />}
-          to="/reports"
-        />
+        <Item title="Budget" Icon={Wallet} to="/budget" />
+        <Item title="Reports" Icon={Reports} to="/reports" />
 
-        <Item
-          title="Schedules"
-          icon={
-            <CalendarIcon width={15} height={15} style={{ color: 'inherit' }} />
-          }
-          to="/schedules"
-        />
+        <Item title="Schedules" Icon={CalendarIcon} to="/schedules" />
 
         <Tools />
 
-        <Item
-          title="Accounts"
-          to="/accounts"
-          icon={
-            <PiggyBank width={15} height={15} style={{ color: 'inherit' }} />
-          }
-          exact={true}
-          button={
-            <Button
-              bare
-              onClick={e => {
-                e.stopPropagation();
-                e.preventDefault();
-                onAddAccount();
-              }}
-            >
-              <Add width={12} height={12} style={{ color: colors.n6 }} />
-            </Button>
-          }
+        <View
+          style={{
+            height: 1,
+            backgroundColor: colors.n3,
+            marginTop: 15,
+            flexShrink: 0
+          }}
         />
 
         <Accounts
@@ -636,9 +669,11 @@ export function Sidebar({
           failedAccounts={failedAccounts}
           updatedAccounts={updatedAccounts}
           getAccountPath={account => `/accounts/${account.id}`}
+          allAccountsPath="/accounts"
           budgetedAccountPath="/accounts/budgeted"
           offBudgetAccountPath="/accounts/offbudget"
           getBalanceQuery={getBalanceQuery}
+          getAllAccountBalance={getAllAccountBalance}
           getOnBudgetBalance={getOnBudgetBalance}
           getOffBudgetBalance={getOffBudgetBalance}
           showClosedAccounts={showClosedAccounts}
-- 
GitLab