From f8c69533bb1c99f2f5a2a08c6c900eab754a4f45 Mon Sep 17 00:00:00 2001 From: Lucas Werey Date: Wed, 4 Sep 2024 14:25:22 +0200 Subject: [PATCH] :sparkles:feat(lld): UI of inscriptions table for ordis --- .changeset/clever-cups-sin.md | 5 ++ .../components/Inscriptions/index.tsx | 80 +++++++++++++++++ .../Inscriptions/useInscriptionsModel.tsx | 32 +++++++ .../Ordinals/components/RareSats/.gitkeep | 0 .../Ordinals/screens/Account/index.tsx | 14 +++ .../__integration__/mockedInscriptions.ts | 90 +++++++++++++++++++ .../Collection/TableRow/TokenTitle.tsx | 16 ++-- .../components/Collection/TableRow/index.tsx | 42 +++++++-- .../features/Collectibles/types/Collection.ts | 11 ++- .../Collectibles/utils/typeGuardsChecker.ts | 2 +- .../src/renderer/screens/account/index.tsx | 7 ++ 11 files changed, 283 insertions(+), 16 deletions(-) create mode 100644 .changeset/clever-cups-sin.md create mode 100644 apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/index.tsx create mode 100644 apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/useInscriptionsModel.tsx create mode 100644 apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/.gitkeep create mode 100644 apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/screens/Account/index.tsx create mode 100644 apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/mockedInscriptions.ts diff --git a/.changeset/clever-cups-sin.md b/.changeset/clever-cups-sin.md new file mode 100644 index 000000000000..e1d6967a128e --- /dev/null +++ b/.changeset/clever-cups-sin.md @@ -0,0 +1,5 @@ +--- +"ledger-live-desktop": patch +--- + +LLD ORDINALS add dummy table to display inscriptions inside BTC account screen. diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/index.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/index.tsx new file mode 100644 index 000000000000..4691340a2152 --- /dev/null +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/index.tsx @@ -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; + +type Props = { + account: Account; +}; + +export type InscriptionsItemProps = { + isLoading: boolean; + tokenName: string; + collectionName: string; + tokenIcons: OrdinalsRowProps["tokenIcons"]; + media: MediaProps; + onClick: () => void; +}; + +const Item: React.FC = ({ + isLoading, + tokenName, + collectionName, + tokenIcons, + media, + onClick, +}) => { + return ( + + ); +}; + +function View({ displayedObjects, displayShowMore, onShowMore }: ViewProps) { + return ( + + + + {/** titlekey doesn't need to be translated so we keep it hard coded */} + {displayedObjects ? ( + displayedObjects.map((item, index) => ( + + )) + ) : ( + + {"NOTHING TO SHOW"} + + )} + {displayShowMore && } + + + ); +} + +const Inscriptions: React.FC = ({ account }: Props) => { + return ; +}; + +export default Inscriptions; diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/useInscriptionsModel.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/useInscriptionsModel.tsx new file mode 100644 index 000000000000..05900b0790e9 --- /dev/null +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/useInscriptionsModel.tsx @@ -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([]); + + 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 }; +}; diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/.gitkeep b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/screens/Account/index.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/screens/Account/index.tsx new file mode 100644 index 000000000000..d404995e3d08 --- /dev/null +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/screens/Account/index.tsx @@ -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 = ({ account }) => { + return ; + // here we will add the rare sats table +}; + +export default OrdinalsAccount; diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/mockedInscriptions.ts b/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/mockedInscriptions.ts new file mode 100644 index 000000000000..9d849c33eae6 --- /dev/null +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/mockedInscriptions.ts @@ -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"), + }, +]; diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/TokenTitle.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/TokenTitle.tsx index d41eed6c96c3..2ab7c9bef6ce 100644 --- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/TokenTitle.tsx +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/TokenTitle.tsx @@ -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 = ({ tokenName, isLoading }) => { +const TokenTitle: React.FC = ({ tokenName, isLoading, collectionName }) => { return ( - - {tokenName} - + + + {tokenName} + + + {collectionName} + + ); }; diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/index.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/index.tsx index c51d8e2eab55..c930b1f9566e 100644 --- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/index.tsx +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/index.tsx @@ -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 { @@ -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 => { const mediaBox = () => { return ( @@ -37,14 +44,28 @@ const TableRow: React.FC = props => { const nftCount = () => { return ( - + <> {isNFTRow(props) && ( - - {props.numberOfNfts || 0} - + + + {props.numberOfNfts || 0} + + )} - {isOrdinalsRow(props) && null} - + {isOrdinalsRow(props) && props.tokenIcons.length != 0 && ( + + {props.tokenIcons?.map((Icon, index) => ( + + ))} + + )} + ); }; @@ -54,12 +75,17 @@ const TableRow: React.FC = props => { justifyContent="center" px={4} py={3} + maxHeight={64} display={"flex"} onClick={props.onClick} > {mediaBox()} - + {nftCount()} diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/Collection.ts b/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/Collection.ts index 29f35aa17dab..4410715c5b7b 100644 --- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/Collection.ts +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/Collection.ts @@ -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[]; @@ -35,6 +41,7 @@ export type TableHeaderActionsProps = { export enum TableHeaderTitleKey { NFTCollections = "NFT.collections.title", + Inscriptions = "Inscriptions", } export type TableHeaderProps = { diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/utils/typeGuardsChecker.ts b/apps/ledger-live-desktop/src/newArch/features/Collectibles/utils/typeGuardsChecker.ts index 2f0c838e77bc..d471caa3806e 100644 --- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/utils/typeGuardsChecker.ts +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/utils/typeGuardsChecker.ts @@ -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 { diff --git a/apps/ledger-live-desktop/src/renderer/screens/account/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/account/index.tsx index 1cfc13ee960b..26c74695c8c6 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/account/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/account/index.tsx @@ -28,6 +28,7 @@ import OperationsList from "~/renderer/components/OperationsList"; import useTheme from "~/renderer/hooks/useTheme"; import Collections from "~/renderer/screens/nft/Collections"; import NftCollections from "LLD/features/Collectibles/Nfts/Collections"; +import OrdinalsAccount from "LLD/features/Collectibles/Ordinals/screens/Account"; import BalanceSummary from "./BalanceSummary"; import AccountHeader from "./AccountHeader"; import AccountHeaderActions, { AccountHeaderSettingsButton } from "./AccountHeaderActions"; @@ -110,6 +111,9 @@ const AccountPage = ({ const nftReworked = useFeature("lldNftsGalleryNewArch"); const isNftReworkedEnabled = nftReworked?.enabled; + const ordinalsFF = useFeature("lldnewArchOrdinals"); + const isOrdinalsEnabled = ordinalsFF?.enabled; + const filterOperations = useCallback( (operation: Operation, account: AccountLike) => { // Remove operations linked to address poisoning @@ -215,6 +219,9 @@ const AccountPage = ({ ) ) : null} + {isOrdinalsEnabled && account.type === "Account" && account.currency.id === "bitcoin" ? ( + + ) : null} {account.type === "Account" ? : null}