Skip to content

Commit

Permalink
Extract cell components from TokensTableRow (#4909)
Browse files Browse the repository at this point in the history
# Motivation

We want to try to reuse the tokens table structure and style for the
neurons table.
The `TokensTable` component is currently very specific to the tokens
table.
By extracting tokens specific subcomponents, I'm hoping to separate the
generic table structure from the tokens specific rendering.
And this should make it easier to subsequently create a generic table
component and use that for both the tokens table and the neurons table.

# Changes

1. Create `TokenTitleCell`, `TokenBalanceCell` and `TokenActionsCell`
component.
2. Use those components in `TokensTableRow.svelte`

# Tests

All tokens table functionality continues to be covered by
`src/tests/lib/components/tokens/TokensTable.spec.ts`.

# Todos

- [ ] Add entry to changelog (if necessary).
not necessary
  • Loading branch information
dskloetd authored May 23, 2024
1 parent aeaaf8b commit 4b8179b
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 84 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<script lang="ts">
import GoToDetailIcon from "./actions/GoToDetailIcon.svelte";
import ReceiveButton from "./actions/ReceiveButton.svelte";
import SendButton from "./actions/SendButton.svelte";
import {
UserTokenAction,
type UserTokenData,
type UserTokenLoading,
} from "$lib/types/tokens-page";
import { isUserTokenData } from "$lib/utils/user-token.utils";
import { nonNullish } from "@dfinity/utils";
import type { SvelteComponent, ComponentType } from "svelte";
export let userTokenData: UserTokenData | UserTokenLoading;
const actionMapper: Record<
UserTokenAction,
ComponentType<SvelteComponent<{ userToken: UserTokenData }>>
> = {
[UserTokenAction.GoToDetail]: GoToDetailIcon,
[UserTokenAction.Receive]: ReceiveButton,
[UserTokenAction.Send]: SendButton,
};
let userToken: UserTokenData | undefined;
$: userToken = isUserTokenData(userTokenData) ? userTokenData : undefined;
</script>

{#if nonNullish(userToken)}
{#each userToken.actions as action}
<svelte:component this={actionMapper[action]} {userToken} on:nnsAction />
{/each}
{/if}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<script lang="ts">
import type { UserTokenData, UserTokenLoading } from "$lib/types/tokens-page";
import AmountDisplay from "$lib/components/ic/AmountDisplay.svelte";
import { Spinner } from "@dfinity/gix-components";
import { UnavailableTokenAmount } from "$lib/utils/token.utils";
export let userTokenData: UserTokenData | UserTokenLoading;
</script>

{#if userTokenData.balance instanceof UnavailableTokenAmount}
<span data-tid="token-value-label"
>{`-/- ${userTokenData.balance.token.symbol}`}</span
>
{:else if userTokenData.balance === "loading"}
<span data-tid="token-value-label" class="balance-spinner"
><Spinner inline size="tiny" /></span
>
{:else}
<AmountDisplay singleLine amount={userTokenData.balance} />
{/if}

<style lang="scss">
.balance-spinner {
display: flex;
align-items: center;
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<script lang="ts">
import type { UserTokenData, UserTokenLoading } from "$lib/types/tokens-page";
import Logo from "../../ui/Logo.svelte";
import { nonNullish } from "@dfinity/utils";
export let userTokenData: UserTokenData | UserTokenLoading;
</script>

<div class="title-logo-wrapper">
<Logo
src={userTokenData.logo}
alt={userTokenData.title}
size="medium"
framed
/>
<div class="title-wrapper">
<h5 data-tid="project-name">{userTokenData.title}</h5>
{#if nonNullish(userTokenData.subtitle)}
<span data-tid="project-subtitle" class="description"
>{userTokenData.subtitle}</span
>
{/if}
</div>
</div>

<style lang="scss">
h5 {
margin: 0;
}
.title-logo-wrapper {
display: flex;
align-items: center;
gap: var(--padding);
.title-wrapper {
display: flex;
flex-direction: column;
gap: var(--padding-0_5x);
}
}
</style>
Original file line number Diff line number Diff line change
@@ -1,35 +1,12 @@
<script lang="ts">
import {
UserTokenAction,
type UserTokenData,
type UserTokenLoading,
} from "$lib/types/tokens-page";
import type { SvelteComponent, ComponentType } from "svelte";
import Logo from "../../ui/Logo.svelte";
import GoToDetailIcon from "./actions/GoToDetailIcon.svelte";
import ReceiveButton from "./actions/ReceiveButton.svelte";
import SendButton from "./actions/SendButton.svelte";
import { UnavailableTokenAmount } from "$lib/utils/token.utils";
import AmountDisplay from "$lib/components/ic/AmountDisplay.svelte";
import { nonNullish } from "@dfinity/utils";
import type { UserTokenData, UserTokenLoading } from "$lib/types/tokens-page";
import TokenTitleCell from "./TokenTitleCell.svelte";
import TokenBalanceCell from "./TokenBalanceCell.svelte";
import TokenActionsCell from "./TokenActionsCell.svelte";
import { i18n } from "$lib/stores/i18n";
import { Spinner } from "@dfinity/gix-components";
import { isUserTokenData } from "$lib/utils/user-token.utils";
export let userTokenData: UserTokenData | UserTokenLoading;
const actionMapper: Record<
UserTokenAction,
ComponentType<SvelteComponent<{ userToken: UserTokenData }>>
> = {
[UserTokenAction.GoToDetail]: GoToDetailIcon,
[UserTokenAction.Receive]: ReceiveButton,
[UserTokenAction.Send]: SendButton,
};
let userToken: UserTokenData | undefined;
$: userToken = isUserTokenData(userTokenData) ? userTokenData : undefined;
// Should be the same as the area in the classes `rows-count-X`.
const cellAreaName = (index: number) => `cell-${index}`;
// This will allow us to have different number of rows depending on the number of columns.
Expand All @@ -49,47 +26,15 @@
data-title={userTokenData.title}
>
<div role="cell" class="title-cell">
<div class="title-logo-wrapper">
<Logo
src={userTokenData.logo}
alt={userTokenData.title}
size="medium"
framed
/>
<div class="title-wrapper">
<h5 data-tid="project-name">{userTokenData.title}</h5>
{#if nonNullish(userTokenData.subtitle)}
<span data-tid="project-subtitle" class="description"
>{userTokenData.subtitle}</span
>
{/if}
</div>
</div>
<TokenTitleCell {userTokenData} />
</div>

<div role="cell" class={`mobile-row-cell left-cell ${cellAreaName(0)}`}>
<span class="mobile-only">{$i18n.tokens.balance_header}</span>
{#if userTokenData.balance instanceof UnavailableTokenAmount}
<span data-tid="token-value-label"
>{`-/- ${userTokenData.balance.token.symbol}`}</span
>
{:else if userTokenData.balance === "loading"}
<span data-tid="token-value-label" class="balance-spinner"
><Spinner inline size="tiny" /></span
>
{:else}
<AmountDisplay singleLine amount={userTokenData.balance} />
{/if}
<TokenBalanceCell {userTokenData} />
</div>
<div role="cell" class="actions-cell actions">
{#if nonNullish(userToken)}
{#each userToken.actions as action}
<svelte:component
this={actionMapper[action]}
{userToken}
on:nnsAction
/>
{/each}
{/if}
<TokenActionsCell {userTokenData} on:nnsAction />
</div>
</a>

Expand All @@ -98,10 +43,6 @@
@use "@dfinity/gix-components/dist/styles/mixins/media";
@use "../../../themes/mixins/grid-table";
h5 {
margin: 0;
}
[role="row"] {
@include interaction.tappable;
Expand Down Expand Up @@ -195,23 +136,6 @@
}
}
.title-logo-wrapper {
display: flex;
align-items: center;
gap: var(--padding);
.title-wrapper {
display: flex;
flex-direction: column;
gap: var(--padding-0_5x);
}
}
.balance-spinner {
display: flex;
align-items: center;
}
.actions {
:global(svg) {
color: var(--primary);
Expand Down

0 comments on commit 4b8179b

Please sign in to comment.