Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/[locale]/layer-2/networks/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type { ExtendedRollup, Lang, PageParams } from "@/lib/types"
import CalloutSSR from "@/components/CalloutSSR"
import { ContentHero, type ContentHeroProps } from "@/components/Hero"
import I18nProvider from "@/components/I18nProvider"
import Layer2NetworksTable from "@/components/Layer2NetworksTable/lazy"
import Layer2NetworksTable from "@/components/Layer2NetworksTable"
import MainArticle from "@/components/MainArticle"
import NetworkMaturity from "@/components/NetworkMaturity"
import { ButtonLink } from "@/components/ui/buttons/Button"
Expand Down
2 changes: 1 addition & 1 deletion app/[locale]/wallets/find-wallet/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
import type { Lang, PageParams } from "@/lib/types"

import Breadcrumbs from "@/components/Breadcrumbs"
import FindWalletProductTable from "@/components/FindWalletProductTable/lazy"
import FindWalletProductTable from "@/components/FindWalletProductTable"
import I18nProvider from "@/components/I18nProvider"
import MainArticle from "@/components/MainArticle"

Expand Down
113 changes: 113 additions & 0 deletions src/components/FindWalletProductTable/List.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { memo, useCallback, useRef, useState } from "react"

import type { WalletRow } from "@/lib/types"

import { cn } from "@/lib/utils/cn"
import { trackCustomEvent } from "@/lib/utils/matomo"

import WalletInfo from "./WalletInfo"

type RowProps = {
wallet: WalletRow
index: number
open: boolean
visible: boolean
onOpenChange: (open: boolean, wallet: WalletRow) => void
children?: React.ReactNode
}

const Row = memo(function Row({
wallet,
index,
open,
visible,
onOpenChange,
children,
}: RowProps) {
const handleToggle = useCallback(
(e: React.SyntheticEvent<HTMLDetailsElement>) => {
onOpenChange(e.currentTarget.open, wallet)
},
[onOpenChange, wallet]
)
return (
<details
data-index={index}
open={open}
onToggle={handleToggle}
className={cn(
"group/collapsible flex w-full flex-col border-b open:bg-background-highlight hover:bg-background-highlight",
!visible && "hidden"
)}
>
<summary className="cursor-pointer list-none p-4 focus-visible:outline focus-visible:-outline-offset-1 focus-visible:outline-primary-hover [&::-webkit-details-marker]:hidden">
<WalletInfo wallet={wallet} />
</summary>
{open && <div className="p-4">{children}</div>}
</details>
)
})

type ListProps = {
data: WalletRow[]
// Rows whose id is not in `matchedIds` are display:none. Avoids
// mount/unmount churn on filter changes.
matchedIds: Set<string>
renderSubComponent: (wallet: WalletRow, listIdx: number) => React.ReactNode
matomoEventCategory: string
}

const List = ({
data,
matchedIds,
renderSubComponent,
matomoEventCategory,
...rest
}: ListProps) => {
const [expanded, setExpanded] = useState<Record<string, boolean>>({})
const previousExpandedRef = useRef<Record<string, boolean>>({})

const handleOpenChange = useCallback(
(open: boolean, wallet: WalletRow) => {
setExpanded((prev) => ({ ...prev, [wallet.id]: open }))

if (!open) return

const expandedOnce = previousExpandedRef.current[wallet.id]
if (!expandedOnce) {
trackCustomEvent({
eventCategory: matomoEventCategory,
eventAction: "expanded",
eventName: wallet.id,
})
}
previousExpandedRef.current = {
...previousExpandedRef.current,
[wallet.id]: true,
}
},
[matomoEventCategory]
)

return (
<div {...rest}>
{data.map((wallet, index) => {
const open = !!expanded[wallet.id]
return (
<Row
key={wallet.id}
wallet={wallet}
index={index}
open={open}
visible={matchedIds.has(wallet.id)}
onOpenChange={handleOpenChange}
>
{open && renderSubComponent(wallet, index)}
</Row>
)
})}
</div>
)
}

export default List
173 changes: 65 additions & 108 deletions src/components/FindWalletProductTable/WalletInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@ import { DevicesIcon, LanguagesIcon } from "@/components/icons/wallets"
import { Image } from "@/components/Image"
import { SupportedLanguagesTooltip } from "@/components/SupportedLanguagesTooltip"

import { breakpointAsNumber } from "@/lib/utils/screen"
import { formatStringList, getWalletPersonas } from "@/lib/utils/wallets"

import { NUMBER_OF_SUPPORTED_LANGUAGES_SHOWN } from "@/lib/constants"

import MediaQuery from "../MediaQuery"
import { ButtonLink } from "../ui/buttons/Button"
import { TagsInlineText } from "../ui/tag"

Expand Down Expand Up @@ -59,120 +57,79 @@ const WalletInfo = ({ wallet }: WalletInfoProps) => {
}, [wallet.supportedLanguages])

return (
<div className="flex flex-col gap-4">
<div className="relative flex flex-col gap-4">
{/* Open-state stripe (desktop only), sits in the image-column gutter. */}
<div
aria-hidden
className={`pointer-events-none absolute inset-s-7 top-16 -bottom-9 hidden w-1 -translate-x-1/2 lg:group-[[open]]/collapsible:block rtl:translate-x-1/2 ${wallet.twBackgroundColor}`}
/>

<div className="flex flex-row items-center justify-between gap-4">
<div className="flex flex-col gap-4">
{/* Desktop layout */}
<MediaQuery queries={[`(min-width: ${breakpointAsNumber.lg}px)`]}>
<div className="hidden flex-row gap-4 lg:flex">
<Image
src={wallet.image}
alt=""
style={{ objectFit: "contain", width: "56px", height: "56px" }}
/>
<div className="flex flex-col gap-2">
<p className="text-xl font-bold">{wallet.name}</p>

<PersonaTags walletPersonas={walletPersonas} />

<div
className={`ms-2 ${walletPersonas.length === 0 ? "mb-4" : ""} mt-1`}
>
<ChainImages
chains={wallet.supported_chains as ChainName[]}
className={`ms-2 ${walletPersonas.length === 0 ? "mb-4" : ""}`}
/>
</div>
</div>
</div>
</MediaQuery>

{/* Mobile layout */}
<MediaQuery queries={[`(max-width: ${breakpointAsNumber.lg - 1}px)`]}>
<div className="flex flex-col gap-4 lg:hidden">
<div className="flex flex-row items-center gap-4">
<Image
src={wallet.image}
alt=""
style={{
objectFit: "contain",
width: "24px",
height: "24px",
}}
/>
<p className="text-xl font-bold">{wallet.name}</p>
</div>
<div>
<PersonaTags walletPersonas={walletPersonas} />
</div>
<ChainImages
chains={wallet.supported_chains as ChainName[]}
className={walletPersonas.length === 0 ? "mb-4" : ""}
/>
<div className="grid flex-1 grid-cols-[auto_1fr] items-start gap-x-4 gap-y-2">
<Image
src={wallet.image}
alt=""
className="size-6 self-center object-contain lg:row-span-full lg:size-14 lg:self-start"
/>

<p className="self-center text-xl font-bold lg:self-start">
{wallet.name}
</p>

{walletPersonas.length > 0 && (
<div className="col-span-2 lg:col-span-1 lg:col-start-2">
<PersonaTags walletPersonas={walletPersonas} />
</div>
</MediaQuery>
)}

<div className="col-span-2 lg:col-span-1 lg:col-start-2">
<ChainImages chains={wallet.supported_chains as ChainName[]} />
</div>

<div className="flex flex-row gap-4">
<div className="relative hidden w-14 lg:block">
<div
className={`absolute -top-0 -bottom-9 left-1/2 hidden w-1 -translate-x-1/2 transform group-data-[state=open]/collapsible:block ${wallet.twBackgroundColor}`}
/>
{deviceLabels.length > 0 && (
<div className="col-span-2 flex flex-row gap-2 lg:col-span-1 lg:col-start-2">
<DevicesIcon className="size-6" />
<TagsInlineText list={deviceLabels} />
</div>
<div
className={`flex flex-col gap-2 ${walletPersonas.length === 0 ? "-mt-4" : ""}`}
>
{deviceLabels.length > 0 && (
<div className="flex flex-row gap-2">
<DevicesIcon className="size-6" />
<TagsInlineText list={deviceLabels} />
</div>
)}

<div className="col-span-2 flex flex-row gap-2 lg:col-span-1 lg:col-start-2">
<LanguagesIcon className="size-6" />
<p className="text-md">
{formattedLanguages}{" "}
{hasExtraLanguages && (
<SupportedLanguagesTooltip
supportedLanguages={wallet.supportedLanguages}
/>
)}
<div className="flex flex-row gap-2">
<LanguagesIcon className="size-6" />
<p className="text-md">
{formattedLanguages}{" "}
{hasExtraLanguages && (
<SupportedLanguagesTooltip
supportedLanguages={wallet.supportedLanguages}
/>
)}
</p>
</div>
</div>
</p>
</div>
</div>
<div>
<button className="text-primary">
<ChevronUp className="text-2xl group-data-[state=closed]/collapsible:hidden" />
<ChevronDown className="text-2xl group-data-[state=open]/collapsible:hidden" />
</button>
</div>

<span className="text-primary">
<ChevronUp className="text-2xl group-[&:not([open])]/collapsible:hidden" />
<ChevronDown className="text-2xl group-[[open]]/collapsible:hidden" />
</span>
</div>
<div className="flex flex-row gap-4">
<div className="relative hidden w-14 lg:block">
<div
className={`absolute -top-0 -bottom-9 left-1/2 hidden w-1 -translate-x-1/2 transform group-data-[state=open]/collapsible:block ${wallet.twBackgroundColor}`}
/>
</div>
<div className="flex flex-1">
<ButtonLink
href={wallet.url}
variant="outline"
className="p-2 max-sm:w-full"
size="sm"
customEventOptions={{
eventCategory: "WalletExternalLinkList",
eventAction: "Tap main button",
eventName: `${wallet.name}`,
}}
onClick={(e) => {
// Prevent expanding the wallet more info section when clicking on the "Visit website" button
e.stopPropagation()
}}
>
{t("page-find-wallet-visit-website")}
</ButtonLink>
</div>

<div className="lg:ps-18">
<ButtonLink
href={wallet.url}
variant="outline"
className="p-2 max-sm:w-full"
size="sm"
customEventOptions={{
eventCategory: "WalletExternalLinkList",
eventAction: "Tap main button",
eventName: `${wallet.name}`,
}}
onClick={(e) => {
// Prevent expanding the wallet more info section when clicking on the "Visit website" button
e.stopPropagation()
}}
>
{t("page-find-wallet-visit-website")}
</ButtonLink>
</div>
</div>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import InlineLink from "@/components/ui/Link"

import { cn } from "@/lib/utils/cn"
import { getLocaleFormattedDate } from "@/lib/utils/date"
import { trackCustomEvent } from "@/lib/utils/matomo"

import { useTranslation } from "@/hooks/useTranslation"

Expand Down Expand Up @@ -55,12 +54,6 @@ const WalletSubComponent = ({
wallet.last_updated
)

trackCustomEvent({
eventCategory: "WalletMoreInfo",
eventAction: "More info wallet",
eventName: `More info ${wallet.name}`,
})

return (
<div className="flex flex-row gap-2">
<div className="w-1 md:w-14">
Expand Down
Loading
Loading