Extract documents page layout into a tv variant
The results container hand-wrote its layout classes and toggled the dimmed state with a string-interpolated conditional. Move both the page shell and the busy/dimmed state into a documentsLayout tv variant, and reuse it in the skeleton so the loading and loaded layouts share one source of truth. Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
@@ -38,6 +38,7 @@ import { TrustCenterFileListItem } from "./_components/TrustCenterFileListItem";
|
||||
import { groupByField } from "./_lib/groupByField";
|
||||
import { toQueryVariables } from "./_lib/toQueryVariables";
|
||||
import { useDocumentTab } from "./_lib/useDocumentTab";
|
||||
import { documentsLayout } from "./variants";
|
||||
|
||||
export const documentsPageQuery = graphql`
|
||||
query DocumentsPageQuery($visibility: TrustCenterVisibility) {
|
||||
@@ -129,16 +130,15 @@ export function DocumentsPage({ queryRef }: DocumentsPageProps) {
|
||||
const fileGroups = groupByField(fileNodes, node => node.category)
|
||||
.sort((a, b) => a.key.localeCompare(b.key));
|
||||
|
||||
const { page, results } = documentsLayout({ busy: isRefetching });
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageHeader title={t("title")} count={total} flushBottomSpace>
|
||||
<DocumentsToolbar />
|
||||
</PageHeader>
|
||||
<div className="flex w-full flex-col items-center px-8 py-8">
|
||||
<div
|
||||
aria-busy={isRefetching}
|
||||
className={`flex w-full max-w-5xl flex-col gap-8 transition-opacity duration-150 ${isRefetching ? "opacity-60" : ""}`}
|
||||
>
|
||||
<div className={page()}>
|
||||
<div aria-busy={isRefetching} className={results()}>
|
||||
<ListErrorBoundary
|
||||
onRetry={done => startTransition(() => {
|
||||
refetch(toQueryVariables(tab), { fetchPolicy: "network-only", onComplete: done });
|
||||
|
||||
@@ -24,10 +24,14 @@ import { TextSkeleton } from "@probo/ui/src/v2/typography/TextSkeleton";
|
||||
|
||||
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();
|
||||
|
||||
return (
|
||||
<>
|
||||
<HeaderBand flushBottomSpace>
|
||||
@@ -36,8 +40,8 @@ export function DocumentsPageSkeleton() {
|
||||
<TabsSkeleton />
|
||||
</div>
|
||||
</HeaderBand>
|
||||
<div className="flex w-full flex-col items-center px-8 py-8">
|
||||
<div className="flex w-full max-w-5xl flex-col gap-8">
|
||||
<div className={page()}>
|
||||
<div className={results()}>
|
||||
{SECTION_PLACEHOLDERS.map(section => (
|
||||
<div key={section} className="flex flex-col gap-3">
|
||||
<TextSkeleton size={3} className="w-40" />
|
||||
|
||||
39
apps/compliance-portal/src/pages/documents/variants.ts
Normal file
39
apps/compliance-portal/src/pages/documents/variants.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2026 Probo Inc <hello@probo.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
import { tv } from "tailwind-variants/lite";
|
||||
|
||||
// Documents page shell: a centered content column below the header band. The
|
||||
// `busy` variant dims the current results while a filtered slice refetches.
|
||||
export const documentsLayout = tv({
|
||||
slots: {
|
||||
page: "flex w-full flex-col items-center px-8 py-8",
|
||||
results: "flex w-full max-w-5xl flex-col gap-8 transition-opacity duration-150",
|
||||
},
|
||||
variants: {
|
||||
busy: {
|
||||
true: { results: "opacity-60" },
|
||||
false: {},
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
busy: false,
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user