Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Sidebar UI #3457

Closed
wants to merge 68 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
cb74b6e
Cleaned up Sidebar
tlesicka Sep 10, 2024
747eefc
Moved Payees and Rules from Menu to Action Items
tlesicka Sep 11, 2024
6309a8c
Remove unused imports and variables; changed budget name margin
tlesicka Sep 12, 2024
08f3bd8
Update ActionButtons and BottomButtons
tlesicka Sep 14, 2024
b3258e1
ActionButtons and BottomButtons list moved to Sidebar
tlesicka Sep 14, 2024
9395780
Convert List of Accounts to Expandable Groups
tlesicka Sep 15, 2024
bf7f146
Collapsible Account Groups
tlesicka Sep 15, 2024
198ab61
Fixed AccoundGroupName highlighting when selected
tlesicka Sep 16, 2024
abab4dd
Merge branch 'actualbudget:master' into sidebar
tlesicka Sep 16, 2024
c1dcc5c
Merge branch 'sidebar' of https://github.com/tlesicka/actual into sid…
tlesicka Sep 16, 2024
0e88e75
Cleanup Code
tlesicka Sep 16, 2024
469ffac
Toggle visibility of budget name pencil
tlesicka Sep 16, 2024
71c649d
Removed Console Warnings
tlesicka Sep 16, 2024
5e802df
Fixed error
tlesicka Sep 16, 2024
a0437f1
Fixed Minimum Sidebar issue
tlesicka Sep 17, 2024
f9f8a0b
Merge branch 'actualbudget:master' into sidebar
tlesicka Sep 17, 2024
7ab35b9
Create 3457.md
tlesicka Sep 17, 2024
3d755bb
Merge branch 'actualbudget:master' into sidebar
tlesicka Sep 17, 2024
ea7be1e
Code cleanup as recommended by CodeRabbit
tlesicka Sep 18, 2024
c100c44
Merge branch 'actualbudget:master' into sidebar
tlesicka Sep 18, 2024
12b4b2d
Implement changes requested on PR
tlesicka Sep 18, 2024
a719da6
Merge branch 'sidebar' of https://github.com/tlesicka/actual into sid…
tlesicka Sep 18, 2024
51eea88
Merge branch 'actualbudget:master' into sidebar
tlesicka Sep 19, 2024
240084a
Fixed a few lint issues
tlesicka Sep 19, 2024
d233162
Fixed more lint issues
tlesicka Sep 19, 2024
1030f80
More lint cleanup
tlesicka Sep 20, 2024
f49cee6
Fixed more lint errors
tlesicka Sep 20, 2024
b4c9200
Merge branch 'actualbudget:master' into sidebar
tlesicka Sep 20, 2024
a940d41
Merge branch 'sidebar' of https://github.com/tlesicka/actual into sid…
tlesicka Sep 20, 2024
552feb2
Fixed lint warnings
tlesicka Sep 20, 2024
ed68db3
Fixed one more lint issue
tlesicka Sep 20, 2024
802a318
Change 2 lowercase word to First letter capital
tlesicka Sep 21, 2024
605e541
Merge branch 'master' into sidebar
tlesicka Sep 21, 2024
4bd350c
Merge branch 'sidebar' of https://github.com/tlesicka/actual into sid…
tlesicka Sep 21, 2024
7744738
Fixed error
tlesicka Sep 21, 2024
c628673
Fixed TS parse error
tlesicka Sep 21, 2024
75b8de5
Fixed account dragging issue
tlesicka Sep 22, 2024
8caa1ee
Merge branch 'actualbudget:master' into sidebar
tlesicka Sep 22, 2024
e2bba88
Merge branch 'actualbudget:master' into sidebar
tlesicka Sep 23, 2024
e0407b0
Merge branch 'actualbudget:master' into sidebar
tlesicka Sep 24, 2024
a4c1cf6
Merge branch 'actualbudget:master' into sidebar
tlesicka Sep 24, 2024
711c012
Merge branch 'actualbudget:master' into sidebar
tlesicka Sep 25, 2024
3a54e18
Merge branch 'actualbudget:master' into sidebar
tlesicka Sep 25, 2024
4de497e
Updated VRT snapshots
tlesicka Sep 25, 2024
9393e2e
Merge branch 'actualbudget:master' into sidebar
tlesicka Sep 25, 2024
208859c
Update VRT snapshots
tlesicka Sep 25, 2024
e395dc8
Merge branch 'actualbudget:master' into sidebar
tlesicka Sep 26, 2024
2659e75
Fixed typo and budget name input box width
tlesicka Sep 27, 2024
3673533
Merge branch 'actualbudget:master' into sidebar
tlesicka Sep 27, 2024
1ede421
Merge remote-tracking branch 'upstream/master' into sidebar
tlesicka Sep 27, 2024
7501237
Update VRT
tlesicka Sep 28, 2024
32642b9
Merge branch 'actualbudget:master' into sidebar
tlesicka Sep 28, 2024
ae47b1f
Merge branch 'actualbudget:master' into sidebar
tlesicka Sep 28, 2024
20c5a4e
Merge branch 'actualbudget:master' into sidebar
tlesicka Sep 29, 2024
e3aaf6d
Sidebar text is no longer user selectable.
tlesicka Sep 29, 2024
a57a926
Remove empty account groups from sidebar
tlesicka Sep 29, 2024
5c6d593
Fix Lint error
tlesicka Sep 30, 2024
6a89fd4
Merge branch 'actualbudget:master' into sidebar
tlesicka Sep 30, 2024
7bd5535
Adjusted position of account group expand/collapse chevron
tlesicka Sep 30, 2024
c984483
Update VRT snapshots
tlesicka Sep 30, 2024
1a375b1
Merge branch 'sidebar' of https://github.com/tlesicka/actual into sid…
tlesicka Sep 30, 2024
73e7f2d
Added transition time to ActionButtons
tlesicka Sep 30, 2024
30bdd47
Fixed Lint errors in ActionButtons
tlesicka Sep 30, 2024
a8b8d2c
Added :hover highlighting to Account Group expand/collapse chevrons
tlesicka Sep 30, 2024
2d47b7d
Merge branch 'actualbudget:master' into sidebar
tlesicka Oct 1, 2024
b9137cf
Update Action Button expand/collapse speed
tlesicka Oct 1, 2024
b88a9c7
Merge branch 'actualbudget:master' into sidebar
tlesicka Oct 2, 2024
2488c82
Merge branch 'actualbudget:master' into sidebar
tlesicka Oct 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions packages/desktop-client/e2e/page-models/navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ export class Navigation {
}

async goToSettingsPage() {
const settingsLink = this.page.getByRole('link', { name: 'Settings' });
const settingsLink = this.page.getByRole('button', { name: 'Settings' });

// Expand the "more" menu only if it is not already expanded
// Expand the menu only if it is not already expanded
if (!(await settingsLink.isVisible())) {
await this.page.getByRole('button', { name: 'More' }).click();
await this.page.getByRole('button', { name: 'Test Budget' }).click();
tlesicka marked this conversation as resolved.
Show resolved Hide resolved
}

await settingsLink.click();
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
120 changes: 56 additions & 64 deletions packages/desktop-client/src/components/sidebar/Account.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,74 +92,66 @@ export function Account<FieldName extends SheetFields<'account'>>({

const accountRow = (
<View innerRef={dropRef} style={{ flexShrink: 0, ...outerStyle }}>
<View>
<DropHighlight pos={dropPos} />
<View innerRef={dragRef}>
<Link
variant="internal"
to={to}
<DropHighlight pos={dropPos} />
<View innerRef={dragRef}>
<Link
variant="internal"
to={to}
style={{
...accountNameStyle,
...style,
position: 'relative',
borderLeft: '4px solid transparent',
...(updated && { fontWeight: 700 }),
}}
activeStyle={{
borderColor: theme.sidebarItemAccentSelected,
color: theme.sidebarItemTextSelected,
// This is kind of a hack, but we don't ever want the account
// that the user is looking at to be "bolded" which means it
// 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: (style && style.fontWeight) || 'normal',
'& .dot': {
backgroundColor: theme.sidebarItemAccentSelected,
transform: 'translateX(-4.5px)',
},
}}
>
<View
style={{
...accountNameStyle,
...style,
position: 'relative',
borderLeft: '4px solid transparent',
...(updated && { fontWeight: 700 }),
}}
activeStyle={{
borderColor: theme.sidebarItemAccentSelected,
color: theme.sidebarItemTextSelected,
// This is kind of a hack, but we don't ever want the account
// that the user is looking at to be "bolded" which means it
// 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: (style && style.fontWeight) || 'normal',
'& .dot': {
backgroundColor: theme.sidebarItemAccentSelected,
transform: 'translateX(-4.5px)',
},
position: 'absolute',
left: 0,
top: 0,
bottom: 0,
flexDirection: 'row',
alignItems: 'center',
}}
>
<View
style={{
position: 'absolute',
left: 0,
top: 0,
bottom: 0,
flexDirection: 'row',
alignItems: 'center',
}}
>
<div
className={`dot ${css({
marginRight: 3,
width: 5,
height: 5,
borderRadius: 5,
backgroundColor: pending
? theme.sidebarItemBackgroundPending
: failed
? theme.sidebarItemBackgroundFailed
: theme.sidebarItemBackgroundPositive,
marginLeft: 2,
transition: 'transform .3s',
opacity: connected ? 1 : 0,
})}`}
/>
</View>

<AlignedText
style={
(name === 'Off budget' || name === 'For budget') && {
borderBottom: `1.5px solid rgba(255,255,255,0.4)`,
paddingBottom: '3px',
}
}
left={name}
right={<CellValue binding={query} type="financial" />}
<div
className={`dot ${css({
marginRight: 3,
width: 5,
height: 5,
borderRadius: 5,
backgroundColor: pending
? theme.sidebarItemBackgroundPending
: failed
? theme.sidebarItemBackgroundFailed
: theme.sidebarItemBackgroundPositive,
marginLeft: 2,
transition: 'transform .3s',
opacity: connected ? 1 : 0,
})}`}
/>
</Link>
</View>
</View>

<AlignedText
left={name}
right={<CellValue binding={query} type="financial" />}
/>
</Link>
</View>
</View>
);
Expand Down
101 changes: 101 additions & 0 deletions packages/desktop-client/src/components/sidebar/AccountGroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// @ts-strict-ignore
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';

import * as queries from 'loot-core/src/client/queries';
import { type State } from 'loot-core/src/client/state-types';
import { type AccountEntity } from 'loot-core/types/models';

import { useFailedAccounts } from '../../hooks/useFailedAccounts';
import { useLocalPref } from '../../hooks/useLocalPref';
import { useUpdatedAccounts } from '../../hooks/useUpdatedAccounts';
import { type CSSProperties } from '../../style';
import { View } from '../common/View';
import { type OnDropCallback } from '../sort';
import { type SheetFields, type Binding } from '../spreadsheet';

import { Account } from './Account';
import { AccountGroupName } from './AccountGroupName';

type AccountGroupProps<FieldName extends SheetFields<'account'>> = {
groupName: string;
groupQuery?: Binding<'account', FieldName>;
groupTo?: string;
accountList?: AccountEntity[];
onReorder?: OnDropCallback;
style?: CSSProperties;
};

export function AccountGroup<FieldName extends SheetFields<'account'>>({
groupName,
groupQuery,
groupTo,
accountList,
onReorder,
style,
}: AccountGroupProps<FieldName>) {
const { t } = useTranslation();
const failedAccounts = useFailedAccounts();
const updatedAccounts = useUpdatedAccounts();
const syncingAccountIds = useSelector(
(state: State) => state.account.accountsSyncing,
);

const getAccountPath = (account: AccountEntity) => `/accounts/${account.id}`;

function onDragChange() {}

const [collapsed, setCollapsedGroupsPref] = useLocalPref(
'ui.collapsedAccountGroups',
);

const toggleAccounts = () => {
const c = collapsed ? { ...collapsed } : {};
c[groupName.replace(/\s/g, '')] =
!collapsed || !Object.hasOwn(collapsed, groupName.replace(/\s/g, ''))
? true
: !collapsed[groupName.replace(/\s/g, '')];
setCollapsedGroupsPref(c);
};

/*
const accountGroupStyle = {
background: 'var(--color-tableBackground)',
borderRadius: '10px',
margin: '10px',
border: '2px solid var(--color-tableBorder)',
};
*/

return (
accountList?.length > 0 && (
<View style={{ flexShrink: 0, padding: '5px 0', ...style }}>
<AccountGroupName
groupName={t(groupName)}
to={groupTo}
query={groupQuery}
toggleAccounts={toggleAccounts}
collapsed={collapsed?.[groupName.replace(/\s/g, '')]}
/>

{!collapsed?.[groupName.replace(/\s/g, '')] &&
accountList?.map(account => (
<Account
key={account.id}
name={account.name}
account={account}
connected={!!account.bank}
pending={syncingAccountIds.includes(account.id)}
failed={failedAccounts?.has(account.id)}
updated={updatedAccounts?.includes(account.id)}
to={getAccountPath(account)}
query={queries.accountBalance(account)}
onDragChange={onDragChange}
onDrop={onReorder}
/>
))}
</View>
)
);
}
147 changes: 147 additions & 0 deletions packages/desktop-client/src/components/sidebar/AccountGroupName.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// @ts-strict-ignore
import React from 'react';

import { css } from 'glamor';

import { SvgExpandArrow } from '../../icons/v0';
import { styles, theme, type CSSProperties } from '../../style';
import { AlignedText } from '../common/AlignedText';
import { Link } from '../common/Link';
import { View } from '../common/View';
import { type SheetFields, type Binding } from '../spreadsheet';
import { CellValue } from '../spreadsheet/CellValue';

type AccountGroupNameProps<FieldName extends SheetFields<'account'>> = {
groupName: string;
to?: string;
query?: Binding<'account', FieldName>;
connected?: boolean;
pending?: boolean;
failed?: boolean;
updated?: boolean;
style?: CSSProperties;
outerStyle?: CSSProperties;
toggleAccounts?: () => void;
collapsed?: boolean;
};

export function AccountGroupName<FieldName extends SheetFields<'account'>>({
groupName,
to,
query,
connected,
pending,
failed,
updated,
style,
outerStyle,
toggleAccounts,
collapsed,
}: AccountGroupNameProps<FieldName>) {
const accountNameStyle: CSSProperties = {
marginTop: -2,
marginBottom: 2,
paddingTop: 4,
paddingBottom: 4,
paddingRight: 15,
paddingLeft: toggleAccounts ? 25 : 10,
textDecoration: 'none',
color: theme.sidebarItemText,
':hover': { backgroundColor: theme.sidebarItemBackgroundHover },
...styles.smallText,
};

return (
<View style={{ flexShrink: 0, ...outerStyle }}>
<View
style={{
flexDirection: 'row',
alignItems: 'center',
position: 'relative',
}}
>
{toggleAccounts && (
<SvgExpandArrow
width={12}
height={12}
onClick={toggleAccounts}
className={`${css({
position: 'absolute',
borderRadius: 5,
zIndex: 99999,
marginTop: collapsed ? 2 : -2,
marginBottom: 5,
marginLeft: 7,
width: 16,
height: 16,
padding: 3,
transition: 'transform .1s',
transform: collapsed ? 'rotate(-90deg)' : '',
':hover': { backgroundColor: theme.sidebarItemBackgroundHover },
})}`}
/>
)}
<Link
variant="internal"
to={to || '#'}
style={{
...accountNameStyle,
...style,
flex: 1,
fontWeight: 600,
position: 'relative',
borderLeft: '4px solid transparent',
...(updated && { fontWeight: 700 }),
}}
activeStyle={{
borderColor: theme.sidebarItemAccentSelected,
color: theme.sidebarItemTextSelected,
'& .dot': {
backgroundColor: theme.sidebarItemAccentSelected,
transform: 'translateX(-4.5px)',
},
}}
>
<View
style={{
position: 'absolute',
left: 0,
top: 0,
bottom: 0,
flexDirection: 'row',
alignItems: 'center',
}}
>
<div
className={`dot ${css({
marginRight: 3,
width: 5,
height: 5,
borderRadius: 5,
backgroundColor: pending
? theme.sidebarItemBackgroundPending
: failed
? theme.sidebarItemBackgroundFailed
: theme.sidebarItemBackgroundPositive,
marginLeft: 2,
transition: 'transform .3s',
opacity: connected ? 1 : 0,
})}`}
/>
</View>

<AlignedText
style={
!collapsed && {
borderBottom: `1.5px solid rgba(255,255,255,0.4)`,
paddingBottom: '3px',
}
}
left={groupName}
right={query && <CellValue binding={query} type="financial" />}
/>
</Link>
</View>
</View>
);
}
Loading
Loading