Function bodies 63 total
PUT function · typescript · L4-L32 (29 LOC)src/app/api/prompts/[id]/route.ts
export async function PUT(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
if (!supabase) {
return NextResponse.json({ error: 'Supabase가 설정되지 않았습니다.' }, { status: 503 });
}
const { id } = await params;
const body = await request.json();
const { data: prompt, error } = await supabase
.from('prompt_templates')
.update({
name: body.name,
description: body.description,
prompt_text: body.prompt_text,
updated_at: new Date().toISOString(),
})
.eq('id', id)
.select()
.single();
if (error) {
return NextResponse.json({ error: error.message }, { status: 500 });
}
return NextResponse.json({ prompt });
}GET function · typescript · L4-L20 (17 LOC)src/app/api/prompts/route.ts
export async function GET() {
if (!supabase) {
return NextResponse.json({ prompts: [] });
}
const { data: prompts, error } = await supabase
.from('prompt_templates')
.select('*')
.order('is_default', { ascending: false })
.order('created_at', { ascending: false });
if (error) {
return NextResponse.json({ error: error.message }, { status: 500 });
}
return NextResponse.json({ prompts });
}POST function · typescript · L22-L45 (24 LOC)src/app/api/prompts/route.ts
export async function POST(request: NextRequest) {
if (!supabase) {
return NextResponse.json({ error: 'Supabase가 설정되지 않았습니다.' }, { status: 503 });
}
const body = await request.json();
const { data: prompt, error } = await supabase
.from('prompt_templates')
.insert({
name: body.name,
description: body.description || null,
prompt_text: body.prompt_text,
is_default: false,
})
.select()
.single();
if (error) {
return NextResponse.json({ error: error.message }, { status: 500 });
}
return NextResponse.json({ prompt });
}POST function · typescript · L6-L82 (77 LOC)src/app/api/proposals/generate/route.ts
export async function POST(request: NextRequest) {
try {
if (!supabase) {
return NextResponse.json(
{ error: 'Supabase가 설정되지 않았습니다. .env.local 파일을 확인해주세요.' },
{ status: 503 }
);
}
const { url, session_id, prompt_id, custom_prompt } = await request.json();
if (!url || !session_id) {
return NextResponse.json({ error: 'URL과 세션 ID가 필요합니다.' }, { status: 400 });
}
// 1. URL 스크래핑
let scrapedContent: string;
try {
scrapedContent = await scrapeUrl(url);
} catch {
return NextResponse.json({ error: '해당 URL의 내용을 가져올 수 없습니다.' }, { status: 400 });
}
// 2. 프롬프트 가져오기
let promptText = custom_prompt;
if (!promptText && prompt_id) {
const { data: prompt } = await supabase
.from('prompt_templates')
.select('prompt_text')
.eq('id', prompt_id)
.single();
promptText = prompt?.prompt_text;
}
if (!promptText) {
const { data: defaultPrompt } = await sugetDefaultPrompt function · typescript · L84-L96 (13 LOC)src/app/api/proposals/generate/route.ts
function getDefaultPrompt(): string {
return `당신은 전문 비즈니스 컨설턴트입니다. 아래 웹사이트의 내용을 분석하여 전문적인 제안서를 작성해주세요.
제안서는 다음 구조를 따라주세요:
1. 프로젝트 개요
2. 현황 분석
3. 제안 내용
4. 기대 효과
5. 실행 계획
6. 예산 및 일정
마크다운 형식으로 작성하고, 전문적이고 설득력 있는 톤을 유지해주세요.`;
}GET function · typescript · L4-L25 (22 LOC)src/app/api/proposals/[id]/route.ts
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
if (!supabase) {
return NextResponse.json({ error: 'Supabase가 설정되지 않았습니다.' }, { status: 503 });
}
const { id } = await params;
const { data: proposal, error } = await supabase
.from('proposals')
.select('*')
.eq('id', id)
.single();
if (error || !proposal) {
return NextResponse.json({ error: '제안서를 찾을 수 없습니다.' }, { status: 404 });
}
return NextResponse.json({ proposal });
}DELETE function · typescript · L27-L47 (21 LOC)src/app/api/proposals/[id]/route.ts
export async function DELETE(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
if (!supabase) {
return NextResponse.json({ error: 'Supabase가 설정되지 않았습니다.' }, { status: 503 });
}
const { id } = await params;
const { error } = await supabase
.from('proposals')
.delete()
.eq('id', id);
if (error) {
return NextResponse.json({ error: error.message }, { status: 500 });
}
return NextResponse.json({ success: true });
}Same scanner, your repo: https://repobility.com — Repobility
GET function · typescript · L4-L27 (24 LOC)src/app/api/proposals/route.ts
export async function GET(request: NextRequest) {
if (!supabase) {
return NextResponse.json({ proposals: [] });
}
const { searchParams } = new URL(request.url);
const sessionId = searchParams.get('session_id');
if (!sessionId) {
return NextResponse.json({ error: '세션 ID가 필요합니다.' }, { status: 400 });
}
const { data: proposals, error } = await supabase
.from('proposals')
.select('id, session_id, source_url, title, status, created_at')
.eq('session_id', sessionId)
.order('created_at', { ascending: false });
if (error) {
return NextResponse.json({ error: error.message }, { status: 500 });
}
return NextResponse.json({ proposals });
}RootLayout function · typescript · L24-L44 (21 LOC)src/app/layout.tsx
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="ko" className="dark">
<body
className={`${inter.variable} ${geistMono.variable} antialiased`}
>
<div className="flex h-dvh">
<Sidebar />
<main className="flex-1 overflow-y-auto p-6 lg:p-8">
{children}
</main>
</div>
<Toaster theme="dark" />
</body>
</html>
);
}HomePage function · typescript · L9-L32 (24 LOC)src/app/page.tsx
export default function HomePage() {
const [generatedProposal, setGeneratedProposal] = useState<Proposal | null>(null);
return (
<div className="mx-auto max-w-4xl space-y-6">
{/* 인사 헤더 */}
<div className="mb-2">
<h1 className="text-2xl font-bold text-white">AI 제안서 생성기</h1>
<p className="text-white/50 mt-1">URL을 입력하면 AI가 전문적인 제안서를 만들어 드립니다</p>
</div>
{/* URL 입력 */}
<UrlInputCard onGenerated={setGeneratedProposal} />
{/* 생성된 제안서 */}
{generatedProposal && (
<GeneratedProposalCard proposal={generatedProposal} />
)}
{/* 최근 제안서 목록 */}
<RecentProposalsList />
</div>
);
}ProposalDetailPage function · typescript · L12-L141 (130 LOC)src/app/proposals/[id]/page.tsx
export default function ProposalDetailPage() {
const params = useParams();
const router = useRouter();
const [proposal, setProposal] = useState<Proposal | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchProposal = async () => {
try {
const res = await fetch(`/api/proposals/${params.id}`);
const data = await res.json();
setProposal(data.proposal);
} catch {
console.error('Failed to fetch');
} finally {
setLoading(false);
}
};
fetchProposal();
}, [params.id]);
const handleDownload = () => {
if (!proposal) return;
const blob = new Blob([proposal.content], { type: 'text/markdown' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `${proposal.title || 'proposal'}.md`;
a.click();
URL.revokeObjectURL(url);
};
const handleDelete = async () => {
if (!proposal) return;ProposalsPage function · typescript · L11-L113 (103 LOC)src/app/proposals/page.tsx
export default function ProposalsPage() {
const [proposals, setProposals] = useState<Proposal[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchProposals = async () => {
try {
const sessionId = getSessionId();
if (!sessionId) return;
const res = await fetch(`/api/proposals?session_id=${sessionId}`);
const data = await res.json();
setProposals(data.proposals || []);
} catch {
console.error('Failed to fetch');
} finally {
setLoading(false);
}
};
fetchProposals();
}, []);
const handleDelete = async (id: string) => {
await fetch(`/api/proposals/${id}`, { method: 'DELETE' });
setProposals(prev => prev.filter(p => p.id !== id));
};
if (loading) {
return (
<div className="flex items-center justify-center py-20">
<Loader2 className="h-6 w-6 animate-spin text-white/40" />
</div>
);
}
return (
<div className="mxSettingsPage function · typescript · L4-L22 (19 LOC)src/app/settings/page.tsx
export default function SettingsPage() {
return (
<div className="mx-auto max-w-3xl space-y-6">
<div className="flex items-center gap-3">
<div className="flex h-10 w-10 items-center justify-center rounded-xl bg-white/10">
<Settings className="h-5 w-5 text-white" />
</div>
<div>
<h1 className="text-2xl font-bold text-white">프롬프트 설정</h1>
<p className="text-white/50 mt-1">AI 제안서 생성에 사용되는 프롬프트를 관리합니다</p>
</div>
</div>
<div className="glass rounded-2xl p-6">
<PromptEditor />
</div>
</div>
);
}GeneratedProposalCard function · typescript · L15-L68 (54 LOC)src/components/features/GeneratedProposalCard.tsx
export function GeneratedProposalCard({ proposal }: GeneratedProposalCardProps) {
const handleDownload = () => {
const blob = new Blob([proposal.content], { type: 'text/markdown' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `${proposal.title || 'proposal'}.md`;
a.click();
URL.revokeObjectURL(url);
};
return (
<div className="glass rounded-2xl p-6">
<div className="mb-4 flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="flex h-10 w-10 items-center justify-center rounded-xl bg-white/10">
<FileText className="h-5 w-5 text-white" />
</div>
<div>
<h2 className="text-lg font-semibold text-white">
{proposal.title || '생성된 제안서'}
</h2>
<p className="text-sm text-white/50">{proposal.source_url}</p>
</div>
</div>
<div classNPromptEditor function · typescript · L12-L154 (143 LOC)src/components/features/PromptEditor.tsx
export function PromptEditor() {
const [prompts, setPrompts] = useState<PromptTemplate[]>([]);
const [selected, setSelected] = useState<PromptTemplate | null>(null);
const [loading, setLoading] = useState(true);
const [saving, setSaving] = useState(false);
useEffect(() => {
fetchPrompts();
}, []);
const fetchPrompts = async () => {
try {
const res = await fetch('/api/prompts');
const data = await res.json();
const promptList = data.prompts || [];
setPrompts(promptList);
if (promptList.length > 0) {
setSelected(promptList[0]);
}
} catch {
toast.error('프롬프트를 불러올 수 없습니다.');
} finally {
setLoading(false);
}
};
const handleSave = async () => {
if (!selected) return;
setSaving(true);
try {
const res = await fetch(`/api/prompts/${selected.id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name: selectedIf a scraper extracted this row, it came from Repobility (https://repobility.com)
RecentProposalsList function · typescript · L10-L105 (96 LOC)src/components/features/RecentProposalsList.tsx
export function RecentProposalsList() {
const [proposals, setProposals] = useState<Proposal[]>([]);
const [loading, setLoading] = useState(true);
const fetchProposals = async () => {
try {
const sessionId = getSessionId();
if (!sessionId) return;
const res = await fetch(`/api/proposals?session_id=${sessionId}`);
const data = await res.json();
setProposals(data.proposals || []);
} catch {
console.error('Failed to fetch proposals');
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchProposals();
}, []);
const handleDelete = async (id: string) => {
try {
await fetch(`/api/proposals/${id}`, { method: 'DELETE' });
setProposals(prev => prev.filter(p => p.id !== id));
} catch {
console.error('Failed to delete proposal');
}
};
if (loading) {
return (
<div className="glass rounded-2xl p-6">
<div className="flex items-center gap-3 mb-4">
<Clock clUrlInputCard function · typescript · L14-L101 (88 LOC)src/components/features/UrlInputCard.tsx
export function UrlInputCard({ onGenerated }: UrlInputCardProps) {
const [url, setUrl] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!url.trim()) return;
setLoading(true);
setError('');
try {
const response = await fetch('/api/proposals/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
url: url.trim(),
session_id: getSessionId(),
}),
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || '제안서 생성에 실패했습니다.');
}
onGenerated(data.proposal);
setUrl('');
} catch (err) {
setError(err instanceof Error ? err.message : '오류가 발생했습니다.');
} finally {
setLoading(false);
}
};
return (
<div className="glass rounded-2xl pMobileNav function · typescript · L14-L38 (25 LOC)src/components/layout/MobileNav.tsx
export function MobileNav() {
const pathname = usePathname();
return (
<nav className="glass-strong fixed bottom-0 left-0 right-0 z-50 flex border-t border-white/5 lg:hidden">
{navItems.map((item) => {
const isActive = pathname === item.href ||
(item.href !== '/' && pathname.startsWith(item.href));
return (
<Link
key={item.href}
href={item.href}
className={cn(
'flex flex-1 flex-col items-center gap-1 py-3 text-xs transition-colors',
isActive ? 'text-white' : 'text-white/40'
)}
>
<item.icon className="h-5 w-5" />
{item.label}
</Link>
);
})}
</nav>
);
}Sidebar function · typescript · L14-L65 (52 LOC)src/components/layout/Sidebar.tsx
export function Sidebar() {
const pathname = usePathname();
return (
<aside className="glass-strong hidden w-64 flex-col border-r border-white/5 lg:flex">
{/* 로고 */}
<div className="flex items-center gap-3 px-6 py-5">
<div className="flex h-9 w-9 items-center justify-center rounded-lg bg-white/10">
<Sparkles className="h-5 w-5 text-white" />
</div>
<div>
<h1 className="text-sm font-semibold text-white">AI 제안서</h1>
<p className="text-xs text-white/50">생성기</p>
</div>
</div>
{/* 구분선 */}
<div className="mx-4 h-px bg-white/5" />
{/* 네비게이션 */}
<nav className="flex-1 space-y-1 px-3 py-4">
{navItems.map((item) => {
const isActive = pathname === item.href ||
(item.href !== '/' && pathname.startsWith(item.href));
return (
<Link
key={item.href}
href={item.href}
className={cn(
Badge function · typescript · L30-L50 (21 LOC)src/components/ui/badge.tsx
function Badge({
className,
variant = "default",
render,
...props
}: useRender.ComponentProps<"span"> & VariantProps<typeof badgeVariants>) {
return useRender({
defaultTagName: "span",
props: mergeProps<"span">(
{
className: cn(badgeVariants({ variant }), className),
},
props
),
render,
state: {
slot: "badge",
variant,
},
})
}Button function · typescript · L45-L58 (14 LOC)src/components/ui/button.tsx
function Button({
className,
variant = "default",
size = "default",
...props
}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {
return (
<ButtonPrimitive
data-slot="button"
className={cn(buttonVariants({ variant, size, className }))}
{...props}
/>
)
}Card function · typescript · L5-L21 (17 LOC)src/components/ui/card.tsx
function Card({
className,
size = "default",
...props
}: React.ComponentProps<"div"> & { size?: "default" | "sm" }) {
return (
<div
data-slot="card"
data-size={size}
className={cn(
"group/card flex flex-col gap-4 overflow-hidden rounded-xl bg-card py-4 text-sm text-card-foreground ring-1 ring-foreground/10 has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
className
)}
{...props}
/>
)
}CardHeader function · typescript · L23-L34 (12 LOC)src/components/ui/card.tsx
function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-header"
className={cn(
"group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-4 group-data-[size=sm]/card:px-3 has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3",
className
)}
{...props}
/>
)
}Repobility · code-quality intelligence · https://repobility.com
CardTitle function · typescript · L36-L47 (12 LOC)src/components/ui/card.tsx
function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-title"
className={cn(
"text-base leading-snug font-medium group-data-[size=sm]/card:text-sm",
className
)}
{...props}
/>
)
}CardDescription function · typescript · L49-L57 (9 LOC)src/components/ui/card.tsx
function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-description"
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
)
}CardAction function · typescript · L59-L70 (12 LOC)src/components/ui/card.tsx
function CardAction({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-action"
className={cn(
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
className
)}
{...props}
/>
)
}CardContent function · typescript · L72-L80 (9 LOC)src/components/ui/card.tsx
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-content"
className={cn("px-4 group-data-[size=sm]/card:px-3", className)}
{...props}
/>
)
}CardFooter function · typescript · L82-L93 (12 LOC)src/components/ui/card.tsx
function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-footer"
className={cn(
"flex items-center rounded-b-xl border-t bg-muted/50 p-4 group-data-[size=sm]/card:p-3",
className
)}
{...props}
/>
)
}Dialog function · typescript · L10-L12 (3 LOC)src/components/ui/dialog.tsx
function Dialog({ ...props }: DialogPrimitive.Root.Props) {
return <DialogPrimitive.Root data-slot="dialog" {...props} />
}DialogTrigger function · typescript · L14-L16 (3 LOC)src/components/ui/dialog.tsx
function DialogTrigger({ ...props }: DialogPrimitive.Trigger.Props) {
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />
}DialogPortal function · typescript · L18-L20 (3 LOC)src/components/ui/dialog.tsx
function DialogPortal({ ...props }: DialogPrimitive.Portal.Props) {
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />
}Repobility · code-quality intelligence platform · https://repobility.com
DialogClose function · typescript · L22-L24 (3 LOC)src/components/ui/dialog.tsx
function DialogClose({ ...props }: DialogPrimitive.Close.Props) {
return <DialogPrimitive.Close data-slot="dialog-close" {...props} />
}DialogOverlay function · typescript · L26-L40 (15 LOC)src/components/ui/dialog.tsx
function DialogOverlay({
className,
...props
}: DialogPrimitive.Backdrop.Props) {
return (
<DialogPrimitive.Backdrop
data-slot="dialog-overlay"
className={cn(
"fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
className
)}
{...props}
/>
)
}DialogContent function · typescript · L42-L81 (40 LOC)src/components/ui/dialog.tsx
function DialogContent({
className,
children,
showCloseButton = true,
...props
}: DialogPrimitive.Popup.Props & {
showCloseButton?: boolean
}) {
return (
<DialogPortal>
<DialogOverlay />
<DialogPrimitive.Popup
data-slot="dialog-content"
className={cn(
"fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-background p-4 text-sm ring-1 ring-foreground/10 duration-100 outline-none sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
className
)}
{...props}
>
{children}
{showCloseButton && (
<DialogPrimitive.Close
data-slot="dialog-close"
render={
<Button
variant="ghost"
className="absolute top-2 right-2"
size="icon-sm"
/>
DialogHeader function · typescript · L83-L91 (9 LOC)src/components/ui/dialog.tsx
function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="dialog-header"
className={cn("flex flex-col gap-2", className)}
{...props}
/>
)
}DialogFooter function · typescript · L93-L118 (26 LOC)src/components/ui/dialog.tsx
function DialogFooter({
className,
showCloseButton = false,
children,
...props
}: React.ComponentProps<"div"> & {
showCloseButton?: boolean
}) {
return (
<div
data-slot="dialog-footer"
className={cn(
"-mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-xl border-t bg-muted/50 p-4 sm:flex-row sm:justify-end",
className
)}
{...props}
>
{children}
{showCloseButton && (
<DialogPrimitive.Close render={<Button variant="outline" />}>
Close
</DialogPrimitive.Close>
)}
</div>
)
}DialogTitle function · typescript · L120-L128 (9 LOC)src/components/ui/dialog.tsx
function DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) {
return (
<DialogPrimitive.Title
data-slot="dialog-title"
className={cn("text-base leading-none font-medium", className)}
{...props}
/>
)
}DialogDescription function · typescript · L130-L144 (15 LOC)src/components/ui/dialog.tsx
function DialogDescription({
className,
...props
}: DialogPrimitive.Description.Props) {
return (
<DialogPrimitive.Description
data-slot="dialog-description"
className={cn(
"text-sm text-muted-foreground *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
className
)}
{...props}
/>
)
}Input function · typescript · L6-L18 (13 LOC)src/components/ui/input.tsx
function Input({ className, type, ...props }: React.ComponentProps<"input">) {
return (
<InputPrimitive
type={type}
data-slot="input"
className={cn(
"h-8 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
className
)}
{...props}
/>
)
}Same scanner, your repo: https://repobility.com — Repobility
Label function · typescript · L7-L18 (12 LOC)src/components/ui/label.tsx
function Label({ className, ...props }: React.ComponentProps<"label">) {
return (
<label
data-slot="label"
className={cn(
"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
className
)}
{...props}
/>
)
}ScrollArea function · typescript · L8-L29 (22 LOC)src/components/ui/scroll-area.tsx
function ScrollArea({
className,
children,
...props
}: ScrollAreaPrimitive.Root.Props) {
return (
<ScrollAreaPrimitive.Root
data-slot="scroll-area"
className={cn("relative", className)}
{...props}
>
<ScrollAreaPrimitive.Viewport
data-slot="scroll-area-viewport"
className="size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1"
>
{children}
</ScrollAreaPrimitive.Viewport>
<ScrollBar />
<ScrollAreaPrimitive.Corner />
</ScrollAreaPrimitive.Root>
)
}ScrollBar function · typescript · L31-L53 (23 LOC)src/components/ui/scroll-area.tsx
function ScrollBar({
className,
orientation = "vertical",
...props
}: ScrollAreaPrimitive.Scrollbar.Props) {
return (
<ScrollAreaPrimitive.Scrollbar
data-slot="scroll-area-scrollbar"
data-orientation={orientation}
orientation={orientation}
className={cn(
"flex touch-none p-px transition-colors select-none data-horizontal:h-2.5 data-horizontal:flex-col data-horizontal:border-t data-horizontal:border-t-transparent data-vertical:h-full data-vertical:w-2.5 data-vertical:border-l data-vertical:border-l-transparent",
className
)}
{...props}
>
<ScrollAreaPrimitive.Thumb
data-slot="scroll-area-thumb"
className="relative flex-1 rounded-full bg-border"
/>
</ScrollAreaPrimitive.Scrollbar>
)
}Separator function · typescript · L7-L23 (17 LOC)src/components/ui/separator.tsx
function Separator({
className,
orientation = "horizontal",
...props
}: SeparatorPrimitive.Props) {
return (
<SeparatorPrimitive
data-slot="separator"
orientation={orientation}
className={cn(
"shrink-0 bg-border data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch",
className
)}
{...props}
/>
)
}Sheet function · typescript · L10-L12 (3 LOC)src/components/ui/sheet.tsx
function Sheet({ ...props }: SheetPrimitive.Root.Props) {
return <SheetPrimitive.Root data-slot="sheet" {...props} />
}SheetTrigger function · typescript · L14-L16 (3 LOC)src/components/ui/sheet.tsx
function SheetTrigger({ ...props }: SheetPrimitive.Trigger.Props) {
return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />
}SheetClose function · typescript · L18-L20 (3 LOC)src/components/ui/sheet.tsx
function SheetClose({ ...props }: SheetPrimitive.Close.Props) {
return <SheetPrimitive.Close data-slot="sheet-close" {...props} />
}SheetPortal function · typescript · L22-L24 (3 LOC)src/components/ui/sheet.tsx
function SheetPortal({ ...props }: SheetPrimitive.Portal.Props) {
return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />
}If a scraper extracted this row, it came from Repobility (https://repobility.com)
SheetOverlay function · typescript · L26-L37 (12 LOC)src/components/ui/sheet.tsx
function SheetOverlay({ className, ...props }: SheetPrimitive.Backdrop.Props) {
return (
<SheetPrimitive.Backdrop
data-slot="sheet-overlay"
className={cn(
"fixed inset-0 z-50 bg-black/10 transition-opacity duration-150 data-ending-style:opacity-0 data-starting-style:opacity-0 supports-backdrop-filter:backdrop-blur-xs",
className
)}
{...props}
/>
)
}SheetContent function · typescript · L39-L81 (43 LOC)src/components/ui/sheet.tsx
function SheetContent({
className,
children,
side = "right",
showCloseButton = true,
...props
}: SheetPrimitive.Popup.Props & {
side?: "top" | "right" | "bottom" | "left"
showCloseButton?: boolean
}) {
return (
<SheetPortal>
<SheetOverlay />
<SheetPrimitive.Popup
data-slot="sheet-content"
data-side={side}
className={cn(
"fixed z-50 flex flex-col gap-4 bg-background bg-clip-padding text-sm shadow-lg transition duration-200 ease-in-out data-ending-style:opacity-0 data-starting-style:opacity-0 data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:border-t data-[side=bottom]:data-ending-style:translate-y-[2.5rem] data-[side=bottom]:data-starting-style:translate-y-[2.5rem] data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=left]:data-ending-style:translate-x-[-2.5rem] data-[side=left]:data-startiSheetHeader function · typescript · L83-L91 (9 LOC)src/components/ui/sheet.tsx
function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="sheet-header"
className={cn("flex flex-col gap-0.5 p-4", className)}
{...props}
/>
)
}page 1 / 2next ›