React
Result Section
데이터 로딩 결과, 사용자의 액션 완료 여부 등 사용자에 액션에 대한 결과를 제공하는 템플릿입니다. 주로 전체 화면이나 특정 영역을 차지하여 다음 액션을 유도하거나 현재 상황을 안내하는 역할을 합니다.
import { IconDiamond } from "@karrotmarket/react-multicolor-icon";
import { VStack, Icon, Box } from "@seed-design/react";
import { ResultSection } from "seed-design/ui/result-section";
export default function ResultSectionPreview() {
return (
<VStack minHeight="480px" width="320px" borderWidth={1} borderColor="stroke.neutralMuted">
<ResultSection
asset={
<Box pb="x4">
<Icon svg={<IconDiamond />} size="x10" />
</Box>
}
title="결과 타이틀"
description="부가 설명을 적어주세요"
primaryActionProps={{
children: "Primary Action",
onClick: () => window.alert("Primary Action Clicked"),
}}
secondaryActionProps={{
children: "Secondary Action",
onClick: () => window.alert("Secondary Action Clicked"),
}}
/>
</VStack>
);
}Installation
npx @seed-design/cli@latest add ui:result-sectionpnpm dlx @seed-design/cli@latest add ui:result-sectionyarn dlx @seed-design/cli@latest add ui:result-sectionbun x @seed-design/cli@latest add ui:result-section의존성 설치
npm install @seed-design/reactyarn add @seed-design/reactpnpm add @seed-design/reactbun add @seed-design/react아래 코드를 복사 후 붙여넣고 사용하세요
/**
* @file ui:result-section
* @requires @seed-design/react@^2.0.0
* @requires @seed-design/css@^2.0.0
**/
"use client";
import * as React from "react";
import { Text, VStack, type TextProps, type VStackProps } from "@seed-design/react";
import { ActionButton, type ActionButtonProps } from "./action-button";
export interface ResultSectionProps
extends Omit<React.HTMLAttributes<HTMLDivElement>, "title" | "children"> {
/**
* @default "large"
*/
size?: "large" | "medium";
asset?: React.ReactNode;
title?: React.ReactNode;
description?: React.ReactNode;
primaryActionProps?: ActionButtonProps;
secondaryActionProps?: ActionButtonProps;
}
const textStyles = {
title: {
large: "t8Bold",
medium: "t5Bold",
},
description: {
large: "t5Regular",
medium: "t4Regular",
},
} as const satisfies Record<
string,
Record<NonNullable<ResultSectionProps["size"]>, NonNullable<TextProps["textStyle"]>>
>;
const textContainerProperties = {
large: {
gap: "x3",
pb: "x7",
},
medium: {
gap: "x2",
pb: "x6",
},
} as const satisfies Record<NonNullable<ResultSectionProps["size"]>, VStackProps>;
/**
* @see https://seed-design.io/react/components/result-section
*/
export const ResultSection = React.forwardRef<HTMLDivElement, ResultSectionProps>((props, ref) => {
const {
size = "large",
asset,
title,
description,
primaryActionProps,
secondaryActionProps,
...otherProps
} = props;
return (
<VStack ref={ref} justify="center" align="center" px="x12" py="x4" grow {...otherProps}>
{asset}
<VStack {...textContainerProperties[size]}>
<Text
align="center"
whiteSpace="pre-line"
color="fg.neutral"
textStyle={textStyles.title[size]}
>
{title}
</Text>
<Text
align="center"
whiteSpace="pre-line"
color="fg.neutralMuted"
textStyle={textStyles.description[size]}
>
{description}
</Text>
</VStack>
{(primaryActionProps || secondaryActionProps) && (
<VStack align="center" gap="x5">
{primaryActionProps && (
<ActionButton variant="neutralWeak" size="medium" {...primaryActionProps} />
)}
{secondaryActionProps && (
<ActionButton
variant="ghost"
size="small"
color="fg.neutral"
fontWeight="bold"
bleedX="asPadding"
bleedY="asPadding"
{...secondaryActionProps}
/>
)}
</VStack>
)}
</VStack>
);
});
ResultSection.displayName = "ResultSection";
/**
* This file is a snippet from SEED Design, helping you get started quickly with @seed-design/* packages.
* You can extend this snippet however you want.
*/
Props
Prop
Type
asset?React.ReactNodetitle?React.ReactNodedescription?React.ReactNodeprimaryActionProps?ActionButtonProps | undefinedsecondaryActionProps?ActionButtonProps | undefinedExamples
Sizes
Large
import { VStack } from "@seed-design/react";
import { ResultSection } from "seed-design/ui/result-section";
export default function ResultSectionLarge() {
return (
<VStack minHeight="480px" width="320px" borderWidth={1} borderColor="stroke.neutralMuted">
<ResultSection
size="large"
title="cupidatat ad consequat"
description="Lorem ipsum dolor sit amet consectetur adipisicing elit."
primaryActionProps={{
children: "Primary Action",
}}
secondaryActionProps={{
children: "Secondary Action",
}}
/>
</VStack>
);
}Medium
import { VStack } from "@seed-design/react";
import { ResultSection } from "seed-design/ui/result-section";
export default function ResultSectionMedium() {
return (
<VStack minHeight="480px" width="320px" borderWidth={1} borderColor="stroke.neutralMuted">
<ResultSection
size="medium"
title="cupidatat ad consequat"
description="Lorem ipsum dolor sit amet consectetur adipisicing elit."
primaryActionProps={{
children: "Primary Action",
}}
secondaryActionProps={{
children: "Secondary Action",
}}
/>
</VStack>
);
}With CTA & Progress Circle
import { ActionButton } from "seed-design/ui/action-button";
import { AppBar, AppBarMain } from "seed-design/ui/app-bar";
import { AppScreen, AppScreenContent } from "seed-design/ui/app-screen";
import { ProgressCircle } from "seed-design/ui/progress-circle";
import { ResultSection } from "seed-design/ui/result-section";
import { IconExclamationmarkCircleFill } from "@karrotmarket/react-monochrome-icon";
import { Box, Flex, Icon, VStack } from "@seed-design/react";
import { type StaticActivityComponentType } from "@stackflow/react/future";
import { useEffect, useState, type ComponentProps } from "react";
declare module "@stackflow/config" {
interface Register {
ActivityResultSectionCtaProgressCircle: {};
}
}
type RefundStatus = "in-progress" | "failed";
const resultSectionProperties = {
"in-progress": {
title: "환불을 요청하고 있어요",
description: "잠시만 기다려주세요",
asset: (
<Box pb="x4">
<ProgressCircle size="40" />
</Box>
),
},
failed: {
title: "다시 시도해주세요",
description: "환불 요청에 실패했어요",
asset: (
<Box pb="x4">
<Icon svg={<IconExclamationmarkCircleFill />} size="x10" color="fg.critical" />
</Box>
),
},
} satisfies Record<RefundStatus, ComponentProps<typeof ResultSection>>;
const ActivityResultSectionCtaProgressCircle: StaticActivityComponentType<
"ActivityResultSectionCtaProgressCircle"
> = () => {
const [refundStatus, setRefundStatus] = useState<RefundStatus>("in-progress");
useEffect(() => {
const timer = setTimeout(() => setRefundStatus("failed"), 3000);
return () => clearTimeout(timer);
}, []);
return (
<AppScreen>
<AppBar>
<AppBarMain title="환불 요청" />
</AppBar>
<AppScreenContent>
<VStack grow gap="x4" height="full" pb="safeArea">
<ResultSection {...resultSectionProperties[refundStatus]} />
<Flex p="x4" px="spacingX.globalGutter" pt="x3" pb="x2">
<ActionButton
flexGrow
size="large"
variant="neutralSolid"
disabled={refundStatus === "in-progress"}
loading={refundStatus === "in-progress"}
onClick={() => {
setRefundStatus("in-progress");
setTimeout(() => setRefundStatus("failed"), 3000);
}}
>
다시 시도
</ActionButton>
</Flex>
</VStack>
</AppScreenContent>
</AppScreen>
);
};
export default ActivityResultSectionCtaProgressCircle;Success Example
Result Section 에셋 영역에서 다크 모드와 라이트 모드에서 서로 다른 Lottie 애니메이션을 사용하는 예시입니다.
클라이언트에서 현재 테마 정보 감지하는 방법을 참고하여 테마에 맞는 Lottie 애니메이션을 Result Section에 적용할 수 있습니다.
import dynamic from "next/dynamic";
import { VStack, Box } from "@seed-design/react";
import { ResultSection } from "seed-design/ui/result-section";
import { useTheme } from "@/hooks/useTheme";
const Player = dynamic(() => import("@lottiefiles/react-lottie-player").then((mod) => mod.Player), {
ssr: false,
});
const LOTTIE_URLS = {
light:
"https://asset-town.krrt.io/production/motion/bd9f3c71-5b81-40b0-8eea-eeebd668edae/c17fa891bb007b9e4e6b281e483b5491cb905703.json",
dark: "https://asset-town.krrt.io/production/motion/19bf4654-5286-4def-a651-c674a20ce1ee/89c9e404edc356cf143dab80b627fde01ed8a8fb.json",
};
export default function ResultSectionSuccessWithLottie() {
const { userColorScheme } = useTheme();
const lottieUrl = LOTTIE_URLS[userColorScheme];
return (
<VStack minHeight="480px" width="320px" borderWidth={1} borderColor="stroke.neutralMuted">
<ResultSection
asset={
<Box pb="x4">
<Player
src={lottieUrl}
autoplay
loop={false}
keepLastFrame
style={{ width: 70, height: 70 }}
/>
</Box>
}
title="성공했어요"
description="요청이 성공적으로 완료되었습니다"
primaryActionProps={{
children: "확인",
onClick: () => window.alert("확인 클릭"),
}}
/>
</VStack>
);
}Last updated on