Skip to content

Commit 6a861af

Browse files
authored
Layout (#97)
* chore: a bunch of ux/styling tweaks adjust table borders adjust table transaction expand/collapse to support click the entire row add app studio page + placeholder content reduce memory footprint by reducing cache period refine loaders add latest block/transaction animation change app call badge icon add subtle animation on loadable tweak settings page
1 parent 9b97688 commit 6a861af

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+309
-240
lines changed

src/App.routes.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { SettingsPage } from './features/settings/pages/settings-page'
1515
import { TxPage } from './features/transactions/pages/tx-page'
1616
import { IndexPage } from '@/index-page'
1717
import { NetworkPage } from '@/features/network/pages/network-page'
18+
import { AppStudioPage, appStudioPageTitle } from './features/app-studio/pages/app-studio-page'
1819

1920
export const routes = evalTemplates([
2021
{
@@ -96,7 +97,8 @@ export const routes = evalTemplates([
9697
},
9798
{
9899
template: Urls.AppStudio,
99-
element: <ErrorPage title="App Studio" />,
100+
errorElement: <ErrorPage title={appStudioPageTitle} />,
101+
element: <AppStudioPage />,
100102
},
101103
{
102104
template: Urls.Settings,

src/assets/icons/chevron-down.svg

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/assets/icons/chevron-left-line.svg

Lines changed: 0 additions & 4 deletions
This file was deleted.

src/assets/icons/chevron-left.svg

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/assets/icons/chevron-right-line.svg

Lines changed: 0 additions & 4 deletions
This file was deleted.

src/assets/icons/chevron-right.svg

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/features/accounts/pages/account-page.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { useLoadableAccount } from '../data'
99
import { AccountDetails } from '../components/account-details'
1010
import { useCallback } from 'react'
1111
import { PageTitle } from '@/features/common/components/page-title'
12+
import { PageLoader } from '@/features/common/components/page-loader'
1213

1314
export const accountPageTitle = 'Account'
1415
export const accountInvalidAddressMessage = 'Address is invalid'
@@ -36,7 +37,7 @@ export function AccountPage() {
3637
return (
3738
<>
3839
<PageTitle title={accountPageTitle} canRefreshPage={isStale} onRefresh={refresh} />
39-
<RenderLoadable loadable={loadableAccount} transformError={transformError}>
40+
<RenderLoadable loadable={loadableAccount} transformError={transformError} fallback={<PageLoader />}>
4041
{(account: Account) => <AccountDetails account={account} />}
4142
</RenderLoadable>
4243
</>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { PageTitle } from '@/features/common/components/page-title'
2+
3+
export const appStudioPageTitle = 'App Studio'
4+
5+
export function AppStudioPage() {
6+
return (
7+
<>
8+
<PageTitle title={appStudioPageTitle} />
9+
<div>
10+
<p>
11+
Comming soon!
12+
<br />
13+
In the meantime, we recommend{' '}
14+
<a href="https://app.dappflow.org/beaker-studio/" className="text-primary underline" rel="nofollow" target="_blank">
15+
Dappflow
16+
</a>{' '}
17+
for your application needs.
18+
</p>
19+
</div>
20+
</>
21+
)
22+
}

src/features/applications/pages/application-page.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { ApplicationDetails } from '../components/application-details'
88
import { is404 } from '@/utils/error'
99
import { useCallback } from 'react'
1010
import { PageTitle } from '@/features/common/components/page-title'
11+
import { PageLoader } from '@/features/common/components/page-loader'
1112

1213
const transformError = (e: Error) => {
1314
if (is404(e)) {
@@ -38,7 +39,7 @@ export function ApplicationPage() {
3839
return (
3940
<>
4041
<PageTitle title={applicationPageTitle} canRefreshPage={isStale} onRefresh={refresh} />
41-
<RenderLoadable loadable={loadableApplication} transformError={transformError}>
42+
<RenderLoadable loadable={loadableApplication} transformError={transformError} fallback={<PageLoader />}>
4243
{(application) => <ApplicationDetails application={application} />}
4344
</RenderLoadable>
4445
</>

src/features/assets/pages/asset-page.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { AssetDetails } from '../components/asset-details'
88
import { useLoadableAsset } from '../data'
99
import { useCallback } from 'react'
1010
import { PageTitle } from '@/features/common/components/page-title'
11+
import { PageLoader } from '@/features/common/components/page-loader'
1112

1213
const transformError = (e: Error) => {
1314
if (is404(e)) {
@@ -38,7 +39,7 @@ export function AssetPage() {
3839
return (
3940
<>
4041
<PageTitle title={assetPageTitle} canRefreshPage={isStale} onRefresh={refresh} />
41-
<RenderLoadable loadable={loadableAsset} transformError={transformError}>
42+
<RenderLoadable loadable={loadableAsset} transformError={transformError} fallback={<PageLoader />}>
4243
{(asset) => <AssetDetails asset={asset} />}
4344
</RenderLoadable>
4445
</>

src/features/blocks/components/latest-blocks.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export function LatestBlocks() {
1717
<ul>
1818
{latestBlocks.map((block) => (
1919
<li key={block.round} className="border-b last:border-0">
20-
<BlockLink round={block.round} className="flex p-3 text-sm hover:bg-accent">
20+
<BlockLink round={block.round} className="flex p-3.5 text-sm animate-in fade-in-0 zoom-in-90 hover:bg-accent">
2121
<Box className="hidden text-primary sm:max-lg:block xl:block" />
2222
<div className={cn('mx-2')}>
2323
<h3 className={cn('leading-none mb-2')}>{block.round}</h3>

src/features/blocks/pages/block-page.test.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ describe('block-page', () => {
132132
rows: [
133133
{
134134
cells: [
135+
'',
135136
ellipseId(transactionResult1.id),
136137
ellipseId(transactionResult1.group),
137138
ellipseAddress(transactionResult1.sender),
@@ -142,6 +143,7 @@ describe('block-page', () => {
142143
},
143144
{
144145
cells: [
146+
'',
145147
ellipseId(transactionResult2.id),
146148
ellipseId(transactionResult2.group),
147149
ellipseAddress(transactionResult2.sender),

src/features/blocks/pages/block-page.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { is404 } from '@/utils/error'
77
import { useLoadableBlock } from '../data'
88
import { isInteger } from '@/utils/is-integer'
99
import { PageTitle } from '@/features/common/components/page-title'
10+
import { PageLoader } from '@/features/common/components/page-loader'
1011

1112
const transformError = (e: Error) => {
1213
if (is404(e)) {
@@ -32,7 +33,7 @@ export function BlockPage() {
3233
return (
3334
<>
3435
<PageTitle title={blockPageTitle} />
35-
<RenderLoadable loadable={loadableBlock} transformError={transformError}>
36+
<RenderLoadable loadable={loadableBlock} transformError={transformError} fallback={<PageLoader />}>
3637
{(block) => <BlockDetails block={block} />}
3738
</RenderLoadable>
3839
</>

src/features/common/components/badge.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as React from 'react'
22
import { cva, type VariantProps } from 'class-variance-authority'
33
import { cn } from '@/features/common/utils'
4-
import { CircleDollarSign, SquareArrowRight, SquareArrowOutDownLeft, Bolt, Snowflake, ShieldCheck, Key } from 'lucide-react'
4+
import { CircleDollarSign, SquareArrowRight, Bolt, Snowflake, ShieldCheck, Key, Parentheses } from 'lucide-react'
55
import { TransactionType } from '@/features/transactions/models'
66

77
const badgeVariants = cva(
@@ -35,7 +35,7 @@ const iconClasses = 'mr-1 size-4'
3535
const transactionTypeBadgeIcon = new Map([
3636
[TransactionType.Payment.toString(), <CircleDollarSign className={iconClasses} />],
3737
[TransactionType.AssetTransfer.toString(), <SquareArrowRight className={iconClasses} />],
38-
[TransactionType.AppCall.toString(), <SquareArrowOutDownLeft className={iconClasses} />],
38+
[TransactionType.AppCall.toString(), <Parentheses className={iconClasses} />],
3939
[TransactionType.AssetConfig.toString(), <Bolt className={iconClasses} />],
4040
[TransactionType.AssetFreeze.toString(), <Snowflake className={iconClasses} />],
4141
[TransactionType.StateProof.toString(), <ShieldCheck className={iconClasses} />],

src/features/common/components/data-table-pagination.tsx

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
1-
import SvgChevronLeft from '@/features/common/components/icons/chevron-left'
2-
import SvgChevronRight from '@/features/common/components/icons/chevron-right'
3-
41
import { Table } from '@tanstack/react-table'
5-
62
import { Button } from '@/features/common/components/button'
73
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/features/common/components/select'
8-
import SvgChevronLeftLine from './icons/chevron-left-line'
9-
import SvgChevronRightLine from './icons/chevron-right-line'
4+
import { ChevronFirst, ChevronLast, ChevronLeft, ChevronRight } from 'lucide-react'
105

116
interface DataTablePaginationProps<TData> {
127
table: Table<TData>
@@ -44,29 +39,37 @@ export function DataTablePagination<TData>({ table }: DataTablePaginationProps<T
4439
<div className="flex shrink grow basis-0 items-center justify-end space-x-2">
4540
<Button
4641
variant="outline"
42+
size="icon"
4743
className="hidden size-8 p-0 lg:flex"
4844
onClick={() => table.setPageIndex(0)}
4945
disabled={!table.getCanPreviousPage()}
5046
>
5147
<span className="sr-only">Go to first page</span>
52-
<SvgChevronLeftLine className="size-4" />
48+
<ChevronFirst />
5349
</Button>
54-
<Button variant="outline" className="size-8 p-0" onClick={() => table.previousPage()} disabled={!table.getCanPreviousPage()}>
50+
<Button
51+
variant="outline"
52+
size="icon"
53+
className="size-8 p-0"
54+
onClick={() => table.previousPage()}
55+
disabled={!table.getCanPreviousPage()}
56+
>
5557
<span className="sr-only">Go to previous page</span>
56-
<SvgChevronLeft className="size-4" />
58+
<ChevronLeft />
5759
</Button>
58-
<Button variant="outline" className="size-8 p-0" onClick={() => table.nextPage()} disabled={!table.getCanNextPage()}>
60+
<Button variant="outline" size="icon" className="size-8 p-0" onClick={() => table.nextPage()} disabled={!table.getCanNextPage()}>
5961
<span className="sr-only">Go to next page</span>
60-
<SvgChevronRight className="size-4" />
62+
<ChevronRight />
6163
</Button>
6264
<Button
6365
variant="outline"
66+
size="icon"
6467
className="hidden size-8 p-0 lg:flex"
6568
onClick={() => table.setPageIndex(table.getPageCount() - 1)}
6669
disabled={!table.getCanNextPage()}
6770
>
6871
<span className="sr-only">Go to last page</span>
69-
<SvgChevronRightLine className="size-4" />
72+
<ChevronLast />
7073
</Button>
7174
</div>
7275
</div>

src/features/common/components/data-table.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export function DataTable<TData, TValue>({ columns, data, getSubRows, subRowsExp
4040

4141
return (
4242
<div>
43-
<div className="grid rounded-md border">
43+
<div className="grid border-y">
4444
<Table>
4545
<TableHeader>
4646
{table.getHeaderGroups().map((headerGroup) => (
@@ -58,7 +58,11 @@ export function DataTable<TData, TValue>({ columns, data, getSubRows, subRowsExp
5858
<TableBody>
5959
{table.getRowModel().rows?.length ? (
6060
table.getRowModel().rows.map((row) => (
61-
<TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>
61+
<TableRow
62+
key={row.id}
63+
data-state={row.getIsSelected() && 'selected'}
64+
{...(row.getCanExpand() ? { className: 'cursor-pointer', onClick: row.getToggleExpandedHandler() } : {})}
65+
>
6266
{row.getVisibleCells().map((cell) => (
6367
<TableCell key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</TableCell>
6468
))}

src/features/common/components/icons/chevron-down.tsx

Lines changed: 0 additions & 7 deletions
This file was deleted.

src/features/common/components/icons/chevron-left-line.tsx

Lines changed: 0 additions & 8 deletions
This file was deleted.

src/features/common/components/icons/chevron-left.tsx

Lines changed: 0 additions & 7 deletions
This file was deleted.

src/features/common/components/icons/chevron-right-line.tsx

Lines changed: 0 additions & 8 deletions
This file was deleted.

src/features/common/components/icons/chevron-right.tsx

Lines changed: 0 additions & 7 deletions
This file was deleted.

src/features/common/components/lazy-load-data-table/lazy-load-data-table-pagination.tsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import SvgChevronLeft from '@/features/common/components/icons/chevron-left'
2-
import SvgChevronRight from '@/features/common/components/icons/chevron-right'
31
import { Button } from '@/features/common/components/button'
42
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/features/common/components/select'
3+
import { ChevronLeft, ChevronRight } from 'lucide-react'
54

65
interface Props {
76
pageSize: number
@@ -49,13 +48,13 @@ export function LazyLoadDataTablePagination({
4948
</div>
5049
<div className="flex shrink grow basis-0 items-center justify-center text-sm font-medium">Page {currentPage}</div>
5150
<div className="flex shrink grow basis-0 items-center justify-end space-x-2">
52-
<Button variant="outline" className="size-8 p-0" onClick={() => previousPage()} disabled={!previousPageEnabled}>
51+
<Button variant="outline" size="icon" className="size-8 p-0" onClick={() => previousPage()} disabled={!previousPageEnabled}>
5352
<span className="sr-only">Go to previous page</span>
54-
<SvgChevronLeft className="size-4" />
53+
<ChevronLeft />
5554
</Button>
56-
<Button variant="outline" className="size-8 p-0" onClick={() => nextPage()} disabled={!nextPageEnabled}>
55+
<Button variant="outline" size="icon" className="size-8 p-0" onClick={() => nextPage()} disabled={!nextPageEnabled}>
5756
<span className="sr-only">Go to next page</span>
58-
<SvgChevronRight className="size-4" />
57+
<ChevronRight />
5958
</Button>
6059
</div>
6160
</div>

src/features/common/components/lazy-load-data-table/lazy-load-data-table.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export function LazyLoadDataTable<TData, TValue>({ columns, createLoadablePage,
5353

5454
return (
5555
<div>
56-
<div className="grid rounded-md border">
56+
<div className="grid border-y">
5757
<Table>
5858
<TableHeader>
5959
{table.getHeaderGroups().map((headerGroup) => (
@@ -88,7 +88,11 @@ export function LazyLoadDataTable<TData, TValue>({ columns, createLoadablePage,
8888
{loadablePage.state === 'hasData' &&
8989
table.getRowModel().rows.length > 0 &&
9090
table.getRowModel().rows.map((row) => (
91-
<TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>
91+
<TableRow
92+
key={row.id}
93+
data-state={row.getIsSelected() && 'selected'}
94+
{...(row.getCanExpand() ? { className: 'cursor-pointer', onClick: row.getToggleExpandedHandler() } : {})}
95+
>
9296
{row.getVisibleCells().map((cell) => (
9397
<TableCell key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</TableCell>
9498
))}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { Loader2 as Loader } from 'lucide-react'
2+
3+
export function PageLoader() {
4+
return (
5+
<div className="mt-10 flex flex-col items-center justify-center">
6+
<Loader className="size-16 animate-spin" />
7+
<span className="mt-2">Loading...</span>
8+
</div>
9+
)
10+
}

src/features/common/components/refresh-button.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const refreshButtonLabel = 'Refresh'
99

1010
export function RefreshButton({ onClick }: Props) {
1111
return (
12-
<Button onClick={onClick} variant="ghost" size="icon" aria-label={refreshButtonLabel} className="ml-auto">
12+
<Button onClick={onClick} variant="outline" size="icon" aria-label={refreshButtonLabel} className="ml-auto">
1313
<RefreshCw className="size-[1.2rem]" />
1414
<span className="sr-only">{refreshButtonLabel}</span>
1515
</Button>

src/features/common/components/render-loadable.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export type RenderLoadableProps<T> = {
1111

1212
export function RenderLoadable<T>({ loadable, children, fallback, transformError }: RenderLoadableProps<T>) {
1313
if (loadable.state === 'hasData') {
14-
return <>{children(loadable.data)}</>
14+
return <div className="animate-in fade-in-40">{children(loadable.data)}</div>
1515
} else if (loadable.state === 'loading') {
1616
return <>{fallback ?? <Loader className="size-10 animate-spin" />}</>
1717
}

src/features/common/data/state-cleanup.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import { applicationResultsAtom } from '@/features/applications/data'
99
import { assetMetadataResultsAtom, assetResultsAtom } from '@/features/assets/data'
1010

1111
const cleanUpIntervalMillis = 600_000 // 10 minutes
12-
const expirationMillis = 3_600_000 // 1 hour
13-
// Run every 10 minutes and cleanup data that hasn't been accessed in the last 1 hour
12+
const expirationMillis = 1_800_000 // 30 minutes
13+
// Run every 10 minutes and cleanup data that hasn't been accessed in the last 30 minutes
1414

1515
const stateCleanupEffect = atomEffect((get, set) => {
1616
const cleanup = setInterval(() => {

src/features/groups/pages/group-page.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ describe('group-page', () => {
121121
// This table has 10+ row, we only test the first 2 rows
122122
rows: [
123123
{
124-
cells: ['INDQXWQ...', '/oRSr2u...', 'AACC...EN4A', '1201559522', 'Application Call', ''],
124+
cells: ['', 'INDQXWQ...', '/oRSr2u...', 'AACC...EN4A', '1201559522', 'Application Call', ''],
125125
},
126126
],
127127
})

0 commit comments

Comments
 (0)