From 1c28f63555dea5c797bcf1cfee48511cd9b91170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89mile=20R=C3=A9?= Date: Mon, 20 Jul 2026 14:27:51 +0200 Subject: [PATCH] Extract bordered list into UI List MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Documents and data requests duplicated the same card and row chrome. A shared List primitive keeps those surfaces consistent across the portal. Signed-off-by: Émile Ré --- .../pages/documents/DocumentsPageSkeleton.tsx | 8 +- .../documents/_components/DocumentEntry.tsx | 13 ++-- .../documents/_components/DocumentSection.tsx | 5 +- .../pages/documents/_components/variants.ts | 13 +--- .../src/pages/requests/RequestsPage.tsx | 7 +- .../pages/requests/RequestsPageSkeleton.tsx | 14 +--- .../_components/RightsRequestListItem.tsx | 12 +-- .../pages/requests/_components/variants.ts | 7 +- packages/ui/src/v2/List/List.stories.tsx | 73 +++++++++++++++++++ packages/ui/src/v2/List/List.tsx | 34 +++++++++ packages/ui/src/v2/List/ListItem.tsx | 34 +++++++++ packages/ui/src/v2/List/ListItemContent.tsx | 33 +++++++++ packages/ui/src/v2/List/ListItemSkeleton.tsx | 34 +++++++++ packages/ui/src/v2/List/ListSkeleton.tsx | 46 ++++++++++++ packages/ui/src/v2/List/variants.ts | 32 ++++++++ 15 files changed, 313 insertions(+), 52 deletions(-) create mode 100644 packages/ui/src/v2/List/List.stories.tsx create mode 100644 packages/ui/src/v2/List/List.tsx create mode 100644 packages/ui/src/v2/List/ListItem.tsx create mode 100644 packages/ui/src/v2/List/ListItemContent.tsx create mode 100644 packages/ui/src/v2/List/ListItemSkeleton.tsx create mode 100644 packages/ui/src/v2/List/ListSkeleton.tsx create mode 100644 packages/ui/src/v2/List/variants.ts diff --git a/apps/compliance-portal/src/pages/documents/DocumentsPageSkeleton.tsx b/apps/compliance-portal/src/pages/documents/DocumentsPageSkeleton.tsx index eed51dab9..6af78fcc2 100644 --- a/apps/compliance-portal/src/pages/documents/DocumentsPageSkeleton.tsx +++ b/apps/compliance-portal/src/pages/documents/DocumentsPageSkeleton.tsx @@ -18,6 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +import { ListSkeleton } from "@probo/ui/src/v2/List/ListSkeleton"; import { TabsSkeleton } from "@probo/ui/src/v2/Tabs/TabsSkeleton"; import { HeadingSkeleton } from "@probo/ui/src/v2/typography/HeadingSkeleton"; import { TextSkeleton } from "@probo/ui/src/v2/typography/TextSkeleton"; @@ -27,7 +28,6 @@ import { HeaderBand } from "#/components/HeaderBand/HeaderBand"; import { documentsLayout } from "./variants"; const SECTION_PLACEHOLDERS = ["a", "b"]; -const ROW_PLACEHOLDERS = ["x", "y", "z"]; export function DocumentsPageSkeleton() { const { page, results } = documentsLayout(); @@ -45,11 +45,7 @@ export function DocumentsPageSkeleton() { {SECTION_PLACEHOLDERS.map(section => (
-
- {ROW_PLACEHOLDERS.map(row => ( -
- ))} -
+
))}
diff --git a/apps/compliance-portal/src/pages/documents/_components/DocumentEntry.tsx b/apps/compliance-portal/src/pages/documents/_components/DocumentEntry.tsx index e96567e6c..6bccef884 100644 --- a/apps/compliance-portal/src/pages/documents/_components/DocumentEntry.tsx +++ b/apps/compliance-portal/src/pages/documents/_components/DocumentEntry.tsx @@ -18,11 +18,12 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +import { ListItem } from "@probo/ui/src/v2/List/ListItem"; +import { ListItemContent } from "@probo/ui/src/v2/List/ListItemContent"; import { Text } from "@probo/ui/src/v2/typography/Text"; import type { ReactNode } from "react"; import { DocumentAccessAction } from "./DocumentAccessAction"; -import { documentListItem } from "./variants"; interface DocumentEntryProps { // Primary line (document title, file name, or framework name). @@ -53,18 +54,16 @@ export function DocumentEntry({ onGetAccess, isRequesting, }: DocumentEntryProps) { - const { root, content } = documentListItem(); - return ( -
-
+ + {title} {meta} -
+ -
+ ); } diff --git a/apps/compliance-portal/src/pages/documents/_components/DocumentSection.tsx b/apps/compliance-portal/src/pages/documents/_components/DocumentSection.tsx index a332a1b82..80b841aa1 100644 --- a/apps/compliance-portal/src/pages/documents/_components/DocumentSection.tsx +++ b/apps/compliance-portal/src/pages/documents/_components/DocumentSection.tsx @@ -18,6 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +import { List } from "@probo/ui/src/v2/List/List"; import { Text } from "@probo/ui/src/v2/typography/Text"; import type { ReactNode } from "react"; @@ -32,7 +33,7 @@ interface DocumentSectionProps { // One category group: a localized header above a bordered list of rows. export function DocumentSection({ title, description, children }: DocumentSectionProps) { - const { root, header, list } = documentSection(); + const { root, header } = documentSection(); return (
@@ -46,7 +47,7 @@ export function DocumentSection({ title, description, children }: DocumentSectio )} -
{children}
+ {children}
); } diff --git a/apps/compliance-portal/src/pages/documents/_components/variants.ts b/apps/compliance-portal/src/pages/documents/_components/variants.ts index b9baa8f13..6700cb482 100644 --- a/apps/compliance-portal/src/pages/documents/_components/variants.ts +++ b/apps/compliance-portal/src/pages/documents/_components/variants.ts @@ -20,22 +20,13 @@ import { tv } from "tailwind-variants/lite"; -// Document list: category sections, each a titled block above a bordered list. -// Entries share a common layout (title + accent metadata + trailing access -// action). +// Document list: category section chrome (title + description). The bordered +// list surface and row layout live in @probo/ui List. export const documentSection = tv({ slots: { root: "flex flex-col gap-3", header: "flex flex-col gap-0.5", - list: "overflow-hidden rounded-4 border border-sand-a4 bg-sand-1", - }, -}); - -export const documentListItem = tv({ - slots: { - root: "flex items-center gap-4 border-b border-sand-a3 px-4 py-3 last:border-b-0", - content: "flex min-w-0 flex-1 flex-col gap-0.5", }, }); diff --git a/apps/compliance-portal/src/pages/requests/RequestsPage.tsx b/apps/compliance-portal/src/pages/requests/RequestsPage.tsx index cc4232afa..45fc20976 100644 --- a/apps/compliance-portal/src/pages/requests/RequestsPage.tsx +++ b/apps/compliance-portal/src/pages/requests/RequestsPage.tsx @@ -20,6 +20,7 @@ import { NoteIcon, PlusIcon } from "@phosphor-icons/react"; import { Button } from "@probo/ui/src/v2/Button/Button"; +import { List } from "@probo/ui/src/v2/List/List"; import { useEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import type { PreloadedQuery } from "react-relay"; @@ -37,7 +38,6 @@ import type { RequestsPageQuery } from "./__generated__/RequestsPageQuery.graphq import type { RequestsPageRefetchQuery } from "./__generated__/RequestsPageRefetchQuery.graphql"; import { NewRequestDialog } from "./_components/NewRequestDialog"; import { RightsRequestListItem } from "./_components/RightsRequestListItem"; -import { rightsRequestList } from "./_components/variants"; import { requestsLayout } from "./variants"; export const requestsPageQuery = graphql` @@ -116,7 +116,6 @@ export function RequestsPage({ queryRef }: RequestsPageProps) { }; const { page, results, loadMore } = requestsLayout(); - const { card } = rightsRequestList(); const newRequestButton = (