Skip to content

Commit

Permalink
✨feat(lld): UI of inscriptions table for ordis (#7745)
Browse files Browse the repository at this point in the history
  • Loading branch information
LucasWerey authored Sep 5, 2024
1 parent d7163a7 commit 917045c
Show file tree
Hide file tree
Showing 11 changed files with 283 additions and 16 deletions.
5 changes: 5 additions & 0 deletions .changeset/clever-cups-sin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ledger-live-desktop": patch
---

LLD ORDINALS add dummy table to display inscriptions inside BTC account screen.
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React from "react";
import { Account } from "@ledgerhq/types-live";
import { Box, Flex } from "@ledgerhq/react-ui";
import { useInscriptionsModel } from "./useInscriptionsModel";
import TableContainer from "~/renderer/components/TableContainer";
import TableHeader from "LLD/features/Collectibles/components/Collection/TableHeader";
import { OrdinalsRowProps, TableHeaderTitleKey } from "LLD/features/Collectibles/types/Collection";
import TableRow from "LLD/features/Collectibles/components/Collection/TableRow";
import ShowMore from "LLD/features/Collectibles/components/Collection/ShowMore";
import { MediaProps } from "LLD/features/Collectibles/types/Media";

type ViewProps = ReturnType<typeof useInscriptionsModel>;

type Props = {
account: Account;
};

export type InscriptionsItemProps = {
isLoading: boolean;
tokenName: string;
collectionName: string;
tokenIcons: OrdinalsRowProps["tokenIcons"];
media: MediaProps;
onClick: () => void;
};

const Item: React.FC<InscriptionsItemProps> = ({
isLoading,
tokenName,
collectionName,
tokenIcons,
media,
onClick,
}) => {
return (
<TableRow
isLoading={isLoading}
tokenName={tokenName}
collectionName={collectionName}
tokenIcons={tokenIcons}
media={media}
onClick={onClick}
/>
);
};

function View({ displayedObjects, displayShowMore, onShowMore }: ViewProps) {
return (
<Box>
<TableContainer id="oridinals-inscriptions">
<TableHeader titleKey={TableHeaderTitleKey.Inscriptions} />
{/** titlekey doesn't need to be translated so we keep it hard coded */}
{displayedObjects ? (
displayedObjects.map((item, index) => (
<Item
key={index}
isLoading={item.isLoading}
tokenName={item.tokenName}
collectionName={item.collectionName}
tokenIcons={item.tokenIcons}
media={item.media}
onClick={item.onClick}
/>
))
) : (
<Flex justifyContent={"center"} my={12}>
{"NOTHING TO SHOW"}
</Flex>
)}
{displayShowMore && <ShowMore onShowMore={onShowMore} />}
</TableContainer>
</Box>
);
}

const Inscriptions: React.FC<Props> = ({ account }: Props) => {
return <View {...useInscriptionsModel({ account })} />;
};

export default Inscriptions;
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { useEffect, useMemo, useState } from "react";
import { Account } from "@ledgerhq/types-live";
import { InscriptionsItemProps } from "./index";
import { mockedItems as InscriptionsMocked } from "LLD/features/Collectibles/__integration__/mockedInscriptions";
type Props = {
account: Account;
};

export const useInscriptionsModel = ({ account }: Props) => {
const [displayShowMore, setDisplayShowMore] = useState(false);
const [displayedObjects, setDisplayedObjects] = useState<InscriptionsItemProps[]>([]);

const mockedItems: InscriptionsItemProps[] = useMemo(() => [...InscriptionsMocked], []);

useEffect(() => {
if (mockedItems.length > 3) setDisplayShowMore(true);
setDisplayedObjects(mockedItems.slice(0, 3));
}, [mockedItems]);

const onShowMore = () => {
setDisplayedObjects(prevDisplayedObjects => {
const newDisplayedObjects = [
...prevDisplayedObjects,
...mockedItems.slice(prevDisplayedObjects.length, prevDisplayedObjects.length + 3),
];
if (newDisplayedObjects.length === mockedItems.length) setDisplayShowMore(false);
return newDisplayedObjects;
});
};

return { account, displayedObjects, displayShowMore, onShowMore };
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from "react";
import { Account } from "@ledgerhq/types-live";
import Inscriptions from "../../components/Inscriptions";

type Props = {
account: Account;
};

const OrdinalsAccount: React.FC<Props> = ({ account }) => {
return <Inscriptions account={account} />;
// here we will add the rare sats table
};

export default OrdinalsAccount;
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { Icons } from "@ledgerhq/react-ui";
import { InscriptionsItemProps } from "../Ordinals/components/Inscriptions";

export const mockedItems: InscriptionsItemProps[] = [
{
isLoading: false,
tokenName: "NodeMonke#5673",
collectionName: "NodeMonkes",
tokenIcons: [Icons.OrdinalsAlpha, Icons.OrdinalsPaliblockPalindrome],
media: {
uri: "https://www.cryptoslam.io/_next/image?url=https%3A%2F%2Fd6rvidx1ucs57.cloudfront.net%2Fcryptoslam-token-images.s3.amazonaws.com%2FBitcoin%2Fnodemonkes%2Fimage%2Ff976d219206858d782cccd90d25882cc77cafd3d6c159728f0d3407e25961ab0i0.png%3Fd%3D354%26u%3Dhttps%253A%252F%252Fcryptoslam-token-images.s3.amazonaws.com%252FBitcoin%252Fnodemonkes%252Fimage%252Ff976d219206858d782cccd90d25882cc77cafd3d6c159728f0d3407e25961ab0i0.png&w=1920&q=75",
previewUri:
"https://www.cryptoslam.io/_next/image?url=https%3A%2F%2Fd6rvidx1ucs57.cloudfront.net%2Fcryptoslam-token-images.s3.amazonaws.com%2FBitcoin%2Fnodemonkes%2Fimage%2Ff976d219206858d782cccd90d25882cc77cafd3d6c159728f0d3407e25961ab0i0.png%3Fd%3D354%26u%3Dhttps%253A%252F%252Fcryptoslam-token-images.s3.amazonaws.com%252FBitcoin%252Fnodemonkes%252Fimage%252Ff976d219206858d782cccd90d25882cc77cafd3d6c159728f0d3407e25961ab0i0.png&w=1920&q=75",
mediaType: "image",
isLoading: false,
useFallback: true,
contentType: "image",
},
onClick: () => console.log("clicked"),
},
{
isLoading: false,
tokenName: "NodeMonke#5673#22",
collectionName: "NodeMonkes#2",
tokenIcons: [Icons.OrdinalsAlpha, Icons.OrdinalsPaliblockPalindrome],
media: {
uri: "https://www.cryptoslam.io/_next/image?url=https%3A%2F%2Fd6rvidx1ucs57.cloudfront.net%2Fcryptoslam-token-images.s3.amazonaws.com%2FBitcoin%2Fnodemonkes%2Fimage%2F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png%3Fd%3D354%26u%3Dhttps%253A%252F%252Fcryptoslam-token-images.s3.amazonaws.com%252FBitcoin%252Fnodemonkes%252Fimage%252F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png&w=1920&q=75",
previewUri:
"https://www.cryptoslam.io/_next/image?url=https%3A%2F%2Fd6rvidx1ucs57.cloudfront.net%2Fcryptoslam-token-images.s3.amazonaws.com%2FBitcoin%2Fnodemonkes%2Fimage%2F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png%3Fd%3D354%26u%3Dhttps%253A%252F%252Fcryptoslam-token-images.s3.amazonaws.com%252FBitcoin%252Fnodemonkes%252Fimage%252F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png&w=1920&q=75",
mediaType: "image",
isLoading: false,
useFallback: true,
contentType: "image",
},
onClick: () => console.log("clicked"),
},
{
isLoading: false,
tokenName: "NodeMonke#5673#33",
collectionName: "NodeMonkes#2",
tokenIcons: [],
media: {
uri: "https://www.cryptoslam.io/_next/image?url=https%3A%2F%2Fd6rvidx1ucs57.cloudfront.net%2Fcryptoslam-token-images.s3.amazonaws.com%2FBitcoin%2Fnodemonkes%2Fimage%2F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png%3Fd%3D354%26u%3Dhttps%253A%252F%252Fcryptoslam-token-images.s3.amazonaws.com%252FBitcoin%252Fnodemonkes%252Fimage%252F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png&w=1920&q=75",
previewUri:
"https://www.cryptoslam.io/_next/image?url=https%3A%2F%2Fd6rvidx1ucs57.cloudfront.net%2Fcryptoslam-token-images.s3.amazonaws.com%2FBitcoin%2Fnodemonkes%2Fimage%2F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png%3Fd%3D354%26u%3Dhttps%253A%252F%252Fcryptoslam-token-images.s3.amazonaws.com%252FBitcoin%252Fnodemonkes%252Fimage%252F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png&w=1920&q=75",
mediaType: "image",
isLoading: false,
useFallback: true,
contentType: "image",
},
onClick: () => console.log("clicked"),
},
{
isLoading: false,
tokenName: "NodeMonke#5673#44",
collectionName: "NodeMonkes#2",
tokenIcons: [Icons.OrdinalsBlackLegendary],
media: {
uri: "https://www.cryptoslam.io/_next/image?url=https%3A%2F%2Fd6rvidx1ucs57.cloudfront.net%2Fcryptoslam-token-images.s3.amazonaws.com%2FBitcoin%2Fnodemonkes%2Fimage%2F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png%3Fd%3D354%26u%3Dhttps%253A%252F%252Fcryptoslam-token-images.s3.amazonaws.com%252FBitcoin%252Fnodemonkes%252Fimage%252F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png&w=1920&q=75",
previewUri:
"https://www.cryptoslam.io/_next/image?url=https%3A%2F%2Fd6rvidx1ucs57.cloudfront.net%2Fcryptoslam-token-images.s3.amazonaws.com%2FBitcoin%2Fnodemonkes%2Fimage%2F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png%3Fd%3D354%26u%3Dhttps%253A%252F%252Fcryptoslam-token-images.s3.amazonaws.com%252FBitcoin%252Fnodemonkes%252Fimage%252F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png&w=1920&q=75",
mediaType: "image",
isLoading: false,
useFallback: true,
contentType: "image",
},
onClick: () => console.log("clicked"),
},
{
isLoading: false,
tokenName: "NodeMonke#5673#55",
collectionName: "NodeMonkes#2",
tokenIcons: [
Icons.OrdinalsBlock9450X,
Icons.OrdinalsPaliblockPalindrome,
Icons.OrdinalsBlock9,
Icons.OrdinalsHitman,
],
media: {
uri: "https://www.cryptoslam.io/_next/image?url=https%3A%2F%2Fd6rvidx1ucs57.cloudfront.net%2Fcryptoslam-token-images.s3.amazonaws.com%2FBitcoin%2Fnodemonkes%2Fimage%2F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png%3Fd%3D354%26u%3Dhttps%253A%252F%252Fcryptoslam-token-images.s3.amazonaws.com%252FBitcoin%252Fnodemonkes%252Fimage%252F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png&w=1920&q=75",
previewUri:
"https://www.cryptoslam.io/_next/image?url=https%3A%2F%2Fd6rvidx1ucs57.cloudfront.net%2Fcryptoslam-token-images.s3.amazonaws.com%2FBitcoin%2Fnodemonkes%2Fimage%2F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png%3Fd%3D354%26u%3Dhttps%253A%252F%252Fcryptoslam-token-images.s3.amazonaws.com%252FBitcoin%252Fnodemonkes%252Fimage%252F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png&w=1920&q=75",
mediaType: "image",
isLoading: false,
useFallback: true,
contentType: "image",
},
onClick: () => console.log("clicked"),
},
];
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
import React from "react";
import { Skeleton } from "../../Skeleton";
import { Text } from "@ledgerhq/react-ui";
import { Flex, Text } from "@ledgerhq/react-ui";

type Props = {
tokenName: string | string[];
isLoading: boolean;
collectionName?: string;
};

const TokenTitle: React.FC<Props> = ({ tokenName, isLoading }) => {
const TokenTitle: React.FC<Props> = ({ tokenName, isLoading, collectionName }) => {
return (
<Skeleton width={136} minHeight={24} barHeight={10} show={isLoading}>
<Text ff="Inter|SemiBold" color="palette.text.shade100" fontSize={4}>
{tokenName}
</Text>
<Flex flexDirection="column" alignItems="flex-start">
<Text ff="Inter|SemiBold" color="palette.text.shade100" fontSize={4}>
{tokenName}
</Text>
<Text ff="Inter|SemiBold" color={"opacityDefault.c50"} fontSize={3}>
{collectionName}
</Text>
</Flex>
</Skeleton>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";
import { Media, Skeleton } from "../../index";
import { Box, Text } from "@ledgerhq/react-ui";
import { Box, Flex, Text } from "@ledgerhq/react-ui";
import { rgba } from "~/renderer/styles/helpers";
import styled from "styled-components";
import {
Expand All @@ -25,6 +25,13 @@ const Container = styled(Box)`
}
`;

const SatsIconContainer = styled(Flex)`
border-radius: 8px;
background: ${p => p.theme.colors.opacityDefault.c05};
border: 1px solid ${p => p.theme.colors.opacityDefault.c10};
padding: 8px;
`;

const TableRow: React.FC<Props> = props => {
const mediaBox = () => {
return (
Expand All @@ -37,14 +44,28 @@ const TableRow: React.FC<Props> = props => {

const nftCount = () => {
return (
<Skeleton width={42} minHeight={24} barHeight={10} show={props.isLoading}>
<>
{isNFTRow(props) && (
<Text ff="Inter|SemiBold" color="palette.text.shade100" fontSize={4} textAlign="right">
{props.numberOfNfts || 0}
</Text>
<Skeleton width={42} minHeight={24} barHeight={10} show={props.isLoading}>
<Text ff="Inter|SemiBold" color="palette.text.shade100" fontSize={4} textAlign="right">
{props.numberOfNfts || 0}
</Text>
</Skeleton>
)}
{isOrdinalsRow(props) && null}
</Skeleton>
{isOrdinalsRow(props) && props.tokenIcons.length != 0 && (
<SatsIconContainer
p={"8px"}
alignItems={"center"}
justifyContent={"center"}
flexDirection={"row"}
columnGap={"12px"}
>
{props.tokenIcons?.map((Icon, index) => (
<Icon key={index} size={"XS"} color={"neutral.c100"} />
))}
</SatsIconContainer>
)}
</>
);
};

Expand All @@ -54,12 +75,17 @@ const TableRow: React.FC<Props> = props => {
justifyContent="center"
px={4}
py={3}
maxHeight={64}
display={"flex"}
onClick={props.onClick}
>
{mediaBox()}
<Box ml={3} flex={1}>
<TokenTitle tokenName={props.tokenName} isLoading={props.isLoading} />
<TokenTitle
tokenName={props.tokenName}
isLoading={props.isLoading}
collectionName={isOrdinalsRow(props) ? props.collectionName : undefined}
/>
</Box>
{nftCount()}
</Container>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,22 @@ export type NftRowProps = {
onClick: () => void;
};

export interface IconProps {
size: "S" | "XS" | "M" | "L" | "XL" | undefined;
color: string;
style?: React.CSSProperties;
}

export type OrdinalsRowProps = {
media: MediaProps;
tokenName: string;
collectionName: string;
tokenIcons: string[];
tokenIcons: Array<({ size, color, style }: IconProps) => JSX.Element>;
onClick: () => void;
};

export type RareSatsRowProps = {
tokenIcons: string[];
tokenIcons: Array<({ size, color, style }: IconProps) => JSX.Element>;
tokenName: string[];
numberOfSats: number[];
yearOfCreation: number[];
Expand All @@ -35,6 +41,7 @@ export type TableHeaderActionsProps = {

export enum TableHeaderTitleKey {
NFTCollections = "NFT.collections.title",
Inscriptions = "Inscriptions",
}

export type TableHeaderProps = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
} from "../types/Collection";

export function isNFTRow(props: Props): props is Props & NftRowProps {
return "media" in props;
return "media" in props && !("collectionName" in props);
}

export function isOrdinalsRow(props: Props): props is Props & OrdinalsRowProps {
Expand Down
Loading

0 comments on commit 917045c

Please sign in to comment.