Toast
임시 알림 메시지를 표시하는 토스트 컴포넌트입니다.
개요
Toast는 화면 모서리에 나타났다 자동으로 사라지는 알림 컴포넌트입니다. iCignal Toast는 iCignal 브랜드 컬러가 적용되어 있으며, 분석 작업과 데이터 처리 상태를 간결하게 전달합니다. sonner 라이브러리를 사용하며, Foundation Toast의 모든 기능을 상속합니다.
주요 특징:
- 4가지 Variant (success, warning, danger, info)
- 위치 조절 (top-right, bottom-right 등)
- 자동 닫기
- Promise 기반 API
- iCignal 브랜드 스타일 적용
사용 사례:
- iCignal 데이터 저장 완료 알림
- 분석 작업 시작/완료 알림
- 리포트 다운로드 알림
- 캠페인 설정 저장 알림
설치
npx @vortex/cli add sonner --package icignal기본 사용법
import "@vortex/ui-icignal/theme"; // iCignal 테마 적용
import { toast } from "sonner";
import { Button } from "@vortex/ui-icignal";
export default function Example() {
return <Button onClick={() => toast("알림 메시지")}>토스트 표시</Button>;
}Variants (변형)
toast.success("데이터 저장 완료!");
toast.error("분석 실패");
toast.warning("데이터 품질 경고");
toast.info("리포트 생성 중...");iCignal 브랜딩
iCignal 특화 사용 가이드
데이터 저장 알림:
import { toast } from "sonner";
import { Button } from "@vortex/ui-icignal";
<Button
onClick={() => {
const saveData = async () => {
await api.saveAnalytics();
};
toast.promise(saveData(), {
loading: "데이터 저장 중...",
success: "분석 데이터가 저장되었습니다.",
error: "데이터 저장에 실패했습니다.",
});
}}
>
데이터 저장
</Button>;리포트 생성 알림:
import { toast } from "sonner";
import { FileText } from "lucide-react";
const handleGenerateReport = () => {
const generateReport = async () => {
await api.generateReport();
return { reportId: "12345" };
};
toast.promise(generateReport(), {
loading: "리포트 생성 중...",
success: (data) => `리포트가 생성되었습니다. (ID: ${data.reportId})`,
error: "리포트 생성에 실패했습니다.",
});
};
<Button variant="primary" onClick={handleGenerateReport}>
<FileText size={16} className="mr-xs" />
리포트 생성
</Button>;대시보드 필터 적용:
import { toast } from "sonner";
const applyFilters = () => {
toast.success("필터가 적용되었습니다.", {
description: "최근 30일 데이터를 표시합니다.",
duration: 3000,
});
};
<Button variant="outline" onClick={applyFilters}>
필터 적용
</Button>;캠페인 시작 알림:
import { toast } from "sonner";
import { Play, CheckCircle } from "lucide-react";
const startCampaign = async () => {
toast.loading("캠페인 시작 중...", { id: "campaign" });
try {
await api.startCampaign();
toast.success("캠페인이 시작되었습니다.", {
id: "campaign",
description: "실시간 모니터링이 활성화되었습니다.",
icon: <CheckCircle size={16} />,
});
} catch (error) {
toast.error("캠페인 시작 실패", { id: "campaign" });
}
};
<Button variant="primary" onClick={startCampaign}>
<Play size={16} className="mr-xs" />
캠페인 시작
</Button>;Foundation과의 차이점
| 속성 | Foundation | iCignal |
|---|---|---|
| 색상 | 중립적 | iCignal 브랜드 컬러 |
| 브랜드 적용 | 없음 | iCignal 분석 작업 맥락 |
| 사용 맥락 | 범용 | Analytics/Dashboard 특화 |
| 메시지 | 일반적 | 데이터/분석 관련 |
| 테마 | 중립적 테마 | iCignal 테마 (@vortex/ui-icignal/theme) |
사용 패턴 차이:
// Foundation - 범용 알림
toast.success("저장 완료");
// iCignal - Analytics 맥락
toast.promise(saveAnalytics(), {
loading: "분석 데이터 저장 중...",
success: "45,231건의 데이터가 저장되었습니다.",
error: "데이터베이스 연결 실패",
});Props API
| Prop | Type | Default | Description |
|---|---|---|---|
| position | string | ’bottom-right’ | 토스트 위치 |
| duration | number | 4000 | 표시 시간 (ms) |
예제
예제 1: iCignal 데이터 처리 워크플로우
import "@vortex/ui-icignal/theme";
import { toast } from "sonner";
import { Button } from "@vortex/ui-icignal";
import { Play, Download, RefreshCw } from "lucide-react";
export default function DataProcessing() {
const handleAnalyze = async () => {
const analyze = async () => {
// Step 1: 데이터 로드
toast.loading("데이터 로드 중...", { id: "analyze" });
await sleep(1000);
// Step 2: 데이터 분석
toast.loading("데이터 분석 중... (45,231건)", { id: "analyze" });
await sleep(2000);
// Step 3: 완료
return { count: 45231, insights: 12 };
};
toast.promise(analyze(), {
loading: "분석 시작...",
success: (data) =>
`분석 완료! ${data.count}건의 데이터에서 ${data.insights}개의 인사이트를 발견했습니다.`,
error: "분석 실패. 잠시 후 다시 시도해주세요.",
});
};
const handleExport = async () => {
toast.promise(exportData(), {
loading: "데이터 내보내기 중...",
success: "데이터가 다운로드되었습니다.",
error: "내보내기 실패",
});
};
const handleSync = () => {
toast.success("데이터 동기화 완료", {
description: "최신 데이터로 업데이트되었습니다.",
duration: 3000,
});
};
return (
<div className="flex gap-md p-lg">
<Button variant="primary" onClick={handleAnalyze}>
<Play size={16} className="mr-xs" />
데이터 분석
</Button>
<Button variant="outline" onClick={handleExport}>
<Download size={16} className="mr-xs" />
데이터 내보내기
</Button>
<Button variant="ghost" onClick={handleSync}>
<RefreshCw size={16} className="mr-xs" />
동기화
</Button>
</div>
);
}예제 2: iCignal 리포트 관리
import "@vortex/ui-icignal/theme";
import { toast } from "sonner";
import { Button } from "@vortex/ui-icignal";
import { FileText, Share2, Trash2 } from "lucide-react";
export default function ReportActions() {
const handleCreate = async () => {
const create = async () => {
await api.createReport();
return { id: "12345", name: "월간 분석 리포트" };
};
toast.promise(create(), {
loading: "리포트 생성 중...",
success: (data) => `${data.name}이 생성되었습니다.`,
error: "리포트 생성 실패",
});
};
const handleShare = () => {
toast.success("리포트 공유 링크 복사됨", {
description: "https://icignal.com/reports/12345",
duration: 5000,
});
};
const handleDelete = async () => {
const confirmDelete = confirm("정말 삭제하시겠습니까?");
if (!confirmDelete) return;
toast.promise(api.deleteReport(), {
loading: "리포트 삭제 중...",
success: "리포트가 삭제되었습니다.",
error: "삭제 실패",
});
};
return (
<div className="flex gap-sm p-lg">
<Button variant="primary" onClick={handleCreate}>
<FileText size={16} className="mr-xs" />
리포트 생성
</Button>
<Button variant="outline" onClick={handleShare}>
<Share2 size={16} className="mr-xs" />
공유
</Button>
<Button variant="destructive" onClick={handleDelete}>
<Trash2 size={16} className="mr-xs" />
삭제
</Button>
</div>
);
}예제 3: iCignal 캠페인 관리
import "@vortex/ui-icignal/theme";
import { toast } from "sonner";
import { Button, Badge } from "@vortex/ui-icignal";
import { Play, Pause, Stop } from "lucide-react";
export default function CampaignControl() {
const handleStart = async () => {
toast.promise(api.startCampaign(), {
loading: "캠페인 시작 중...",
success: "캠페인이 활성화되었습니다.",
error: "캠페인 시작 실패",
});
};
const handlePause = () => {
toast.info("캠페인 일시정지", {
description: "언제든 다시 시작할 수 있습니다.",
});
};
const handleStop = async () => {
const confirm = window.confirm("캠페인을 종료하시겠습니까?");
if (!confirm) return;
toast.promise(api.stopCampaign(), {
loading: "캠페인 종료 중...",
success: "캠페인이 종료되었습니다.",
error: "종료 실패",
});
};
return (
<Card>
<CardHeader>
<div className="flex justify-between items-center">
<h3 className="font-semibold">이메일 캠페인</h3>
<Badge variant="success">실행 중</Badge>
</div>
</CardHeader>
<CardContent>
<div className="flex gap-sm">
<Button variant="primary" size="sm" onClick={handleStart}>
<Play size={16} className="mr-xs" />
시작
</Button>
<Button variant="outline" size="sm" onClick={handlePause}>
<Pause size={16} className="mr-xs" />
일시정지
</Button>
<Button variant="destructive" size="sm" onClick={handleStop}>
<Stop size={16} className="mr-xs" />
종료
</Button>
</div>
</CardContent>
</Card>
);
}관련 컴포넌트
- Foundation Toast - 기본 버전 참조
- Alert - 알림 메시지
- Dialog - 모달 대화상자
- Button - 액션 트리거
Last updated on