Skip to content

Commit

Permalink
✨(lld): add details drawer for inscriptions (#7908)
Browse files Browse the repository at this point in the history
✨(lld): add detaildrawer for inscriptions
  • Loading branch information
LucasWerey authored Sep 27, 2024
1 parent 03c3a22 commit 6cf1258
Show file tree
Hide file tree
Showing 24 changed files with 2,550 additions and 1,084 deletions.
6 changes: 6 additions & 0 deletions .changeset/dry-otters-shop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"ledger-live-desktop": patch
"@ledgerhq/live-nft": patch
---

Add detail drawers for inscriptions of ordinals protocol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from "react";
import { Flex, Icons, IconsLegacy, Text } from "@ledgerhq/react-ui";
import Button from "~/renderer/components/Button";
import { useTranslation } from "react-i18next";

const Actions = () => {
const { t } = useTranslation();
return (
<Flex alignItems="center" columnGap={12}>
<Button
outlineGrey
style={{ flex: 1, justifyContent: "center" }}
my={4}
onClick={() => {
/* TODO */
}}
center
>
<Flex columnGap={1}>
<Icons.Eye color="neutral.c100" />
<Text variant="bodyLineHeight" fontWeight="600" fontSize={14} color="neutral.c100">
{t("ordinals.inscriptions.detailsDrawer.hide")}
</Text>
</Flex>
</Button>
<Button outlineGrey>
<IconsLegacy.OthersMedium />
</Button>
</Flex>
);
};
export default Actions;
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from "react";
import { Flex, Text } from "@ledgerhq/react-ui";
import IconContainer from "LLD/features/Collectibles/components/Collection/TableRow/IconContainer";
import { IconProps } from "LLD/features/Collectibles/types/Collection";
import { MappingKeys } from "LLD/features/Collectibles/types/Ordinals";
import { useTranslation } from "react-i18next";

type Props = {
icons: (({ size, color, style }: IconProps) => JSX.Element)[];
names: MappingKeys[];
};

const SubTitle: React.FC<Props> = ({ icons, names }) => {
const { t } = useTranslation();
return (
<Flex mb={20} alignItems="center" columnGap={12}>
<IconContainer icons={icons} iconNames={names} />
<Text variant="bodyLineHeight" fontSize={14} color="neutral.c70">
{t("ordinals.inscriptions.detailsDrawer.storedOnChain")}
</Text>
</Flex>
);
};

export default SubTitle;
Original file line number Diff line number Diff line change
@@ -1,18 +1,66 @@
import React from "react";
import { SideDrawer } from "~/renderer/components/SideDrawer";
import { SimpleHashNft } from "@ledgerhq/live-nft/api/types";
import { DetailDrawer } from "LLD/features/Collectibles/components";
import { CollectibleTypeEnum } from "LLD/features/Collectibles/types/enum/Collectibles";
import useInscriptionDetailDrawer from "./useInscriptionDetailDrawer";
import Actions from "./Actions";
import SubTitle from "./SubTitle";

type ViewProps = ReturnType<typeof useInscriptionDetailDrawer> & {
onClose: () => void;
};

type Props = {
inscription: SimpleHashNft;
correspondingRareSat: SimpleHashNft | null | undefined;
isLoading: boolean;
onClose: () => void;
};
const InscriptionDetailsDrawer: React.FC<Props> = ({ inscription, onClose }) => {
// will be replaced by DetailsDrawer from collectibles

const View: React.FC<ViewProps> = ({ data, rareSat, onClose }) => (
<DetailDrawer
collectibleType={CollectibleTypeEnum.NFT}
areFieldsLoading={data.areFieldsLoading}
collectibleName={data.collectibleName}
contentType={data.contentType}
collectionName={data.collectionName}
details={data.details}
previewUri={data.previewUri}
originalUri={data.originalUri}
isPanAndZoomOpen={data.isPanAndZoomOpen}
mediaType={data.mediaType}
tags={data.tags}
useFallback={data.useFallback}
tokenId={data.tokenId}
isOpened={true}
closeCollectiblesPanAndZoom={data.closeCollectiblesPanAndZoom}
handleRequestClose={onClose}
openCollectiblesPanAndZoom={data.openCollectiblesPanAndZoom}
setUseFallback={data.setUseFallback}
>
{rareSat?.icons && (
<DetailDrawer.Subtitle>
<SubTitle icons={Object.values(rareSat.icons)} names={rareSat.names} />
</DetailDrawer.Subtitle>
)}
<DetailDrawer.Actions>
<Actions />
</DetailDrawer.Actions>
</DetailDrawer>
);

const InscriptionDetailDrawer = ({
inscription,
isLoading,
correspondingRareSat,
onClose,
}: Props) => {
return (
<SideDrawer direction={"left"} isOpen={!!inscription} onRequestClose={onClose}>
{inscription.name || inscription.contract.name}
</SideDrawer>
<View
onClose={onClose}
{...useInscriptionDetailDrawer({ isLoading, inscription, correspondingRareSat })}
/>
);
};

export default InscriptionDetailsDrawer;
export default InscriptionDetailDrawer;
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { useMemo, useState } from "react";
import { SimpleHashNft } from "@ledgerhq/live-nft/api/types";
import useCollectibles from "LLD/features/Collectibles/hooks/useCollectibles";
import { createDetails } from "LLD/features/Collectibles/utils/createInscriptionDetailsArrays";
import { useCalendarFormatted } from "~/renderer/hooks/useDateFormatter";
import { Tag } from "LLD/features/Collectibles/types/DetailDrawer";
import { processRareSat } from "../helpers";

type Props = {
isLoading: boolean;
inscription: SimpleHashNft;
correspondingRareSat: SimpleHashNft | null | undefined;
};

const useInscriptionDetailDrawer = ({ isLoading, inscription, correspondingRareSat }: Props) => {
const [useFallback, setUseFallback] = useState(false);
const imageUri =
inscription.video_url || inscription.previews?.image_large_url || inscription.image_url;

const isVideo = !!inscription.video_url;

const contentType = isVideo ? "video" : imageUri ? "image" : "";

const { isPanAndZoomOpen, openCollectiblesPanAndZoom, closeCollectiblesPanAndZoom } =
useCollectibles();

const createdDateFromTimestamp = new Date(inscription.first_created?.timestamp || 0);
const formattedCreatedDate = useCalendarFormatted(createdDateFromTimestamp);
const createdDate = createdDateFromTimestamp === new Date(0) ? "" : formattedCreatedDate;
const details = createDetails(inscription, createdDate);

const tags: Tag[] =
inscription.extra_metadata?.attributes?.map(attr => ({
key: attr.trait_type,
value: attr.value,
})) || [];

const rareSat = useMemo(() => {
if (correspondingRareSat) return processRareSat(correspondingRareSat);
}, [correspondingRareSat]);

const data = {
areFieldsLoading: isLoading,
collectibleName: inscription.name || inscription.contract.name || "",
contentType,
collectionName: inscription.collection.name || "",
details: details,
previewUri: imageUri,
originalUri: imageUri,
isPanAndZoomOpen,
mediaType: inscription.video_properties?.mime_type || "image",
tags: tags,
useFallback: useFallback,
tokenId: inscription.nft_id,
isOpened: true,
closeCollectiblesPanAndZoom,
openCollectiblesPanAndZoom,
setUseFallback: setUseFallback,
};

return { inscription, data, rareSat };
};

export default useInscriptionDetailDrawer;
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import Switch from "~/renderer/components/Switch";
import { hasProtectedOrdinalsAssetsSelector } from "~/renderer/reducers/settings";
import { setHasProtectedOrdinalsAssets } from "~/renderer/actions/settings";
import { useDispatch, useSelector } from "react-redux";
import { t } from "i18next";
import { useTranslation } from "react-i18next";

const ProtectBox: React.FC = () => {
const { t } = useTranslation();
const dispatch = useDispatch();
const hasProtectedOrdinals = useSelector(hasProtectedOrdinalsAssetsSelector);

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React, { useMemo } from "react";
import { InscriptionsItemProps } from "LLD/features/Collectibles/types/Inscriptions";
import TableRow from "LLD/features/Collectibles/components/Collection/TableRow";
import { GroupedNftOrdinals } from "@ledgerhq/live-nft-react/index";
import { findCorrespondingSat } from "LLD/features/Collectibles/utils/findCorrespondingSat";
import { processRareSat } from "../helpers";

type ItemProps = {
isLoading: boolean;
inscriptionsGroupedWithRareSats: GroupedNftOrdinals[];
} & InscriptionsItemProps;

const Item: React.FC<ItemProps> = ({
isLoading,
tokenName,
collectionName,
media,
nftId,
inscriptionsGroupedWithRareSats,
onClick,
}) => {
const correspondingRareSat = findCorrespondingSat(inscriptionsGroupedWithRareSats, nftId);
const rareSat = useMemo(() => {
if (correspondingRareSat) return processRareSat(correspondingRareSat.rareSat);
}, [correspondingRareSat]);

return (
<TableRow
isLoading={isLoading}
tokenName={tokenName}
collectionName={collectionName}
tokenIcons={rareSat?.icons || []}
media={media}
rareSatName={rareSat?.names || []}
onClick={onClick}
/>
);
};

export default Item;
Original file line number Diff line number Diff line change
@@ -1,40 +1,14 @@
import { SimpleHashNft } from "@ledgerhq/live-nft/api/types";
import { IconProps } from "LLD/features/Collectibles/types/Collection";
import { mappingKeysWithIconAndName } from "../Icons";
import { MappingKeys } from "LLD/features/Collectibles/types/Ordinals";

function matchCorrespondingIcon(
rareSats: SimpleHashNft[],
): Array<SimpleHashNft & { icons: Array<({ size, color, style }: IconProps) => JSX.Element> }> {
return rareSats.map(rareSat => {
const iconKeys: string[] = [];
const rarity = rareSat.extra_metadata?.ordinal_details?.sat_rarity?.toLowerCase();

if (rarity && rarity !== "common") {
iconKeys.push(rarity.replace(" ", "_"));
}

const icons = iconKeys
.map(
iconKey =>
mappingKeysWithIconAndName[iconKey as keyof typeof mappingKeysWithIconAndName]?.icon,
)
.filter(Boolean) as Array<({ size, color, style }: IconProps) => JSX.Element>;

return { ...rareSat, icons };
});
}
import { createRareSatObject, matchCorrespondingIcon } from "../helpers";

export function getInscriptionsData(
inscriptions: SimpleHashNft[],
onInscriptionClick: (inscription: SimpleHashNft) => void,
) {
const inscriptionsWithIcons = matchCorrespondingIcon(inscriptions);
return inscriptionsWithIcons.map(item => ({
return inscriptions.map(item => ({
tokenName: item.name || item.contract.name || "",
nftId: item.nft_id,
collectionName: item.collection.name,
tokenIcons: item.icons,
rareSatName: [item.extra_metadata?.ordinal_details?.sat_rarity] as MappingKeys[],
media: {
uri: item.image_url || item.previews?.image_small_url,
isLoading: false,
Expand All @@ -45,3 +19,9 @@ export function getInscriptionsData(
onClick: () => onInscriptionClick(item),
}));
}

export function processRareSat(inscription: SimpleHashNft) {
const matchedRareSatsIcons = matchCorrespondingIcon(inscription);
const rareSatObject = createRareSatObject({ rareSat: matchedRareSatsIcons });
return rareSatObject.rareSat[0];
}
Loading

0 comments on commit 6cf1258

Please sign in to comment.