diff --git a/apps/web/app/globals.css b/apps/web/app/globals.css
index 822d71c..cb6011d 100644
--- a/apps/web/app/globals.css
+++ b/apps/web/app/globals.css
@@ -4,6 +4,53 @@
@tailwind components;
@tailwind utilities;
+@layer base {
+ :root {
+ --background: 0 0% 100%;
+ --foreground: 0 0% 3.9%;
+ --card: 0 0% 100%;
+ --card-foreground: 0 0% 3.9%;
+ --popover: 0 0% 100%;
+ --popover-foreground: 0 0% 3.9%;
+ --primary: 0 0% 9%;
+ --primary-foreground: 0 0% 98%;
+ --secondary: 0 0% 96.1%;
+ --secondary-foreground: 0 0% 9%;
+ --muted: 0 0% 96.1%;
+ --muted-foreground: 0 0% 45.1%;
+ --accent: 0 0% 96.1%;
+ --accent-foreground: 0 0% 9%;
+ --destructive: 0 84.2% 60.2%;
+ --destructive-foreground: 0 0% 98%;
+ --border: 0 0% 89.8%;
+ --input: 0 0% 89.8%;
+ --ring: 0 0% 3.9%;
+ --radius: 0.5rem;
+ }
+
+ .dark {
+ --background: 0 0% 3.9%;
+ --foreground: 0 0% 98%;
+ --card: 0 0% 3.9%;
+ --card-foreground: 0 0% 98%;
+ --popover: 0 0% 3.9%;
+ --popover-foreground: 0 0% 98%;
+ --primary: 0 0% 98%;
+ --primary-foreground: 0 0% 9%;
+ --secondary: 0 0% 14.9%;
+ --secondary-foreground: 0 0% 98%;
+ --muted: 0 0% 14.9%;
+ --muted-foreground: 0 0% 63.9%;
+ --accent: 0 0% 14.9%;
+ --accent-foreground: 0 0% 98%;
+ --destructive: 0 62.8% 30.6%;
+ --destructive-foreground: 0 0% 98%;
+ --border: 0 0% 14.9%;
+ --input: 0 0% 14.9%;
+ --ring: 0 0% 83.1%;
+ }
+}
+
body {
font-family: 'Gowun Batang', serif;
}
diff --git a/apps/web/components.json b/apps/web/components.json
new file mode 100644
index 0000000..cd5c5fa
--- /dev/null
+++ b/apps/web/components.json
@@ -0,0 +1,20 @@
+{
+ "$schema": "https://ui.shadcn.com/schema.json",
+ "style": "default",
+ "rsc": true,
+ "tsx": true,
+ "tailwind": {
+ "config": "apps/web/tailwind.config.js",
+ "css": "apps/web/app/globals.css",
+ "baseColor": "neutral",
+ "cssVariables": true
+ },
+ "aliases": {
+ "components": "front/new-component",
+ "ui": "front/new-component/ui",
+ "utils": "front/lib/utils",
+ "lib": "front/lib",
+ "hooks": "front/hooks"
+ },
+ "iconLibrary": "lucide"
+}
diff --git a/apps/web/src/lib/utils.ts b/apps/web/src/lib/utils.ts
new file mode 100644
index 0000000..2819a83
--- /dev/null
+++ b/apps/web/src/lib/utils.ts
@@ -0,0 +1,6 @@
+import { clsx, type ClassValue } from 'clsx';
+import { twMerge } from 'tailwind-merge';
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs));
+}
diff --git a/apps/web/src/new-component/bottom.tsx b/apps/web/src/new-component/bottom.tsx
index 578eac4..21c7ea9 100644
--- a/apps/web/src/new-component/bottom.tsx
+++ b/apps/web/src/new-component/bottom.tsx
@@ -5,39 +5,40 @@ import { MdOutlinePets, MdOutlineContentPasteSearch } from 'react-icons/md';
import { FcLikePlaceholder } from 'react-icons/fc';
import { usePathname, useRouter } from 'next/navigation';
import { v4 as uuidv4 } from 'uuid';
+import { cn } from 'front/lib/utils';
export const Bottom = () => {
const pathname = usePathname();
+ const router = useRouter();
const barItem = [
- {
- name: '홈',
- path: '/',
- icon: ,
- },
- {
- name: '조회하기',
- path: '/search',
- icon: ,
- },
- {
- name: '좋아요',
- path: '/like',
- icon: ,
- },
+ { name: '홈', path: '/', icon: },
+ { name: '조회하기', path: '/search', icon: },
+ { name: '좋아요', path: '/like', icon: },
];
- const router = useRouter();
return (
-
+
+
);
};
diff --git a/apps/web/src/new-component/header.tsx b/apps/web/src/new-component/header.tsx
index 6972440..a897dc6 100644
--- a/apps/web/src/new-component/header.tsx
+++ b/apps/web/src/new-component/header.tsx
@@ -5,16 +5,21 @@ import { CountList } from 'front/new-site/home/Count';
import { initSido } from 'front/new-site/search/select/initData';
import React from 'react';
import { useRouter } from 'next/navigation';
+import { Button } from 'front/new-component/ui/button';
const Header: React.FC = () => {
const { data } = useSido({ init: initSido });
const router = useRouter();
return (
-
+
diff --git a/apps/web/src/new-component/index.ts b/apps/web/src/new-component/index.ts
index fdbc6ad..bc05af4 100644
--- a/apps/web/src/new-component/index.ts
+++ b/apps/web/src/new-component/index.ts
@@ -1,4 +1,3 @@
-export * from './form'
-export * from './header'
-export * from './sidebar'
-export * from './bottom'
\ No newline at end of file
+export * from './form';
+export * from './header';
+export * from './bottom';
diff --git a/apps/web/src/new-component/sidebar.tsx b/apps/web/src/new-component/sidebar.tsx
deleted file mode 100644
index efee1d6..0000000
--- a/apps/web/src/new-component/sidebar.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-'use client';
-
-import React, { useState } from 'react';
-import { MdOutlinePets, MdOutlineContentPasteSearch } from 'react-icons/md';
-import { FcLikePlaceholder } from 'react-icons/fc';
-import { v4 as uuidv4 } from 'uuid';
-
-const Sidebar: React.FC<{ isOpen: boolean; toggleSidebar: () => void }> = ({
- isOpen,
- toggleSidebar,
-}) => {
- const barItem = [
- {
- name: '홈',
- path: '/',
- icon:
,
- },
- {
- name: '조회하기',
- path: '/search',
- icon:
,
- },
- {
- name: '좋아요',
- path: '/like',
- icon:
,
- },
- ];
- return (
-
-
-
-
-
-
- );
-};
-
-export default Sidebar;
diff --git a/apps/web/src/new-component/ui/avatar.tsx b/apps/web/src/new-component/ui/avatar.tsx
new file mode 100644
index 0000000..37784ef
--- /dev/null
+++ b/apps/web/src/new-component/ui/avatar.tsx
@@ -0,0 +1,50 @@
+'use client';
+
+import * as React from 'react';
+import * as AvatarPrimitive from '@radix-ui/react-avatar';
+
+import { cn } from 'front/lib/utils';
+
+const Avatar = React.forwardRef<
+ React.ElementRef
,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+Avatar.displayName = AvatarPrimitive.Root.displayName;
+
+const AvatarImage = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+AvatarImage.displayName = AvatarPrimitive.Image.displayName;
+
+const AvatarFallback = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
+
+export { Avatar, AvatarImage, AvatarFallback };
diff --git a/apps/web/src/new-component/ui/button.tsx b/apps/web/src/new-component/ui/button.tsx
new file mode 100644
index 0000000..8c49db6
--- /dev/null
+++ b/apps/web/src/new-component/ui/button.tsx
@@ -0,0 +1,57 @@
+import * as React from 'react';
+import { Slot } from '@radix-ui/react-slot';
+import { cva, type VariantProps } from 'class-variance-authority';
+
+import { cn } from 'front/lib/utils';
+
+const buttonVariants = cva(
+ 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
+ {
+ variants: {
+ variant: {
+ default:
+ 'bg-primary text-primary-foreground hover:bg-primary/90',
+ destructive:
+ 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
+ outline:
+ 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
+ secondary:
+ 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
+ ghost: 'hover:bg-accent hover:text-accent-foreground',
+ link: 'text-primary underline-offset-4 hover:underline',
+ },
+ size: {
+ default: 'h-10 px-4 py-2',
+ sm: 'h-9 rounded-md px-3',
+ lg: 'h-11 rounded-md px-8',
+ icon: 'h-10 w-10',
+ },
+ },
+ defaultVariants: {
+ variant: 'default',
+ size: 'default',
+ },
+ }
+);
+
+export interface ButtonProps
+ extends React.ButtonHTMLAttributes,
+ VariantProps {
+ asChild?: boolean;
+}
+
+const Button = React.forwardRef(
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
+ const Comp = asChild ? Slot : 'button';
+ return (
+
+ );
+ }
+);
+Button.displayName = 'Button';
+
+export { Button, buttonVariants };
diff --git a/apps/web/src/new-component/ui/card.tsx b/apps/web/src/new-component/ui/card.tsx
new file mode 100644
index 0000000..8f8d272
--- /dev/null
+++ b/apps/web/src/new-component/ui/card.tsx
@@ -0,0 +1,79 @@
+import * as React from 'react';
+
+import { cn } from 'front/lib/utils';
+
+const Card = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+Card.displayName = 'Card';
+
+const CardHeader = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+CardHeader.displayName = 'CardHeader';
+
+const CardTitle = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+CardTitle.displayName = 'CardTitle';
+
+const CardDescription = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+CardDescription.displayName = 'CardDescription';
+
+const CardContent = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+CardContent.displayName = 'CardContent';
+
+const CardFooter = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+CardFooter.displayName = 'CardFooter';
+
+export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };
diff --git a/apps/web/src/new-component/ui/progress.tsx b/apps/web/src/new-component/ui/progress.tsx
new file mode 100644
index 0000000..967123d
--- /dev/null
+++ b/apps/web/src/new-component/ui/progress.tsx
@@ -0,0 +1,28 @@
+'use client';
+
+import * as React from 'react';
+import * as ProgressPrimitive from '@radix-ui/react-progress';
+
+import { cn } from 'front/lib/utils';
+
+const Progress = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, value, ...props }, ref) => (
+
+
+
+));
+Progress.displayName = ProgressPrimitive.Root.displayName;
+
+export { Progress };
diff --git a/apps/web/src/new-component/ui/skeleton.tsx b/apps/web/src/new-component/ui/skeleton.tsx
new file mode 100644
index 0000000..922d7a1
--- /dev/null
+++ b/apps/web/src/new-component/ui/skeleton.tsx
@@ -0,0 +1,15 @@
+import { cn } from 'front/lib/utils';
+
+function Skeleton({
+ className,
+ ...props
+}: React.HTMLAttributes) {
+ return (
+
+ );
+}
+
+export { Skeleton };
diff --git a/apps/web/src/new-site/home/Contents.tsx b/apps/web/src/new-site/home/Contents.tsx
index 0db5fa7..2cb1dd8 100644
--- a/apps/web/src/new-site/home/Contents.tsx
+++ b/apps/web/src/new-site/home/Contents.tsx
@@ -3,6 +3,7 @@
import React from 'react';
import './contents.scss';
import { useRouter } from 'next/navigation';
+import { Button } from 'front/new-component/ui/button';
type Props = Record;
@@ -22,12 +23,12 @@ const SearchContentsItem = () => {
당신의 책임있는 사랑이 그들의 삶을 바꿀 수 있습니다.
-
+
);
diff --git a/apps/web/src/new-site/home/Count.tsx b/apps/web/src/new-site/home/Count.tsx
index c09dbe0..35a99c4 100644
--- a/apps/web/src/new-site/home/Count.tsx
+++ b/apps/web/src/new-site/home/Count.tsx
@@ -1,9 +1,13 @@
+'use client';
+
import { useAnimalInfoSidoCount } from 'front/hooks';
import { v4 as uuidv4 } from 'uuid';
import React from 'react';
import { Sido } from '@animal-project/shared-types';
import InfiniteLoopSlider from './InfiniteLoop';
import './infinity.scss';
+import { Avatar, AvatarImage } from 'front/new-component/ui/avatar';
+import { Skeleton } from 'front/new-component/ui/skeleton';
type Props = {
items: Sido[];
@@ -14,48 +18,42 @@ export const CountList = (props: Props) => {
const query = useAnimalInfoSidoCount(items);
return (
- <>
-
- {query?.map((result) => {
- if (result.data?.sido.orgCd === '') return null;
- return (
-
-
-
-
- {result.isLoading ? null : (
-

- )}
-
-
-
-
- {result.isLoading ? null : result.data?.sido.orgdownNm}
+
+ {query?.map((result) => {
+ if (result.data?.sido.orgCd === '') return null;
+ return (
+
+
+ {result.isLoading ? (
+
+ ) : (
+
+
+
+ )}
+
+ {result.isLoading ? (
+
+ ) : (
+
+ {result.data?.sido.orgdownNm}
-
- {result.isLoading ? null : result.data?.totalCount}
+ )}
+ {result.isLoading ? (
+
+ ) : (
+
+ {result.data?.totalCount}
-
+ )}
- );
- })}
-
- >
+
+ );
+ })}
+
);
};
diff --git a/apps/web/src/new-site/search/Form.tsx b/apps/web/src/new-site/search/Form.tsx
index 1a4bfe7..4ccd812 100644
--- a/apps/web/src/new-site/search/Form.tsx
+++ b/apps/web/src/new-site/search/Form.tsx
@@ -3,6 +3,7 @@ import React from 'react';
import { DevTool } from '@hookform/devtools';
import { SubmitHandler, useForm } from 'react-hook-form';
import { Form } from 'front/new-component';
+import { Button } from 'front/new-component/ui/button';
import {
initKind,
initShelter,
@@ -63,9 +64,9 @@ export const SearchForm = (props: {
{/* 필요 시 빈 공간으로 유지 */}
-
diff --git a/apps/web/src/new-site/search/SearchView.tsx b/apps/web/src/new-site/search/SearchView.tsx
index 3edaf75..664c3f3 100644
--- a/apps/web/src/new-site/search/SearchView.tsx
+++ b/apps/web/src/new-site/search/SearchView.tsx
@@ -4,6 +4,7 @@ import { AnimalInfoRequestType } from '@animal-project/shared-types';
import { useAnimalInfoInfinity } from 'front/hooks';
import { AnimalCard } from './card';
import InfiniteScroll from 'react-infinite-scroller';
+import { Progress } from 'front/new-component/ui/progress';
type Props = {
animalInfoRequest: AnimalInfoRequestType | null;
@@ -20,7 +21,7 @@ export const SearchView = (props: Props) => {
loadMore={() => {
fetchNextPage();
}}
- loader={
}
+ loader={
}
useWindow={false}
>
diff --git a/apps/web/src/new-site/search/card/AnimalCard.tsx b/apps/web/src/new-site/search/card/AnimalCard.tsx
index 82bc98d..e0a53b5 100644
--- a/apps/web/src/new-site/search/card/AnimalCard.tsx
+++ b/apps/web/src/new-site/search/card/AnimalCard.tsx
@@ -1,8 +1,11 @@
+'use client';
+
import { AnimalInfo } from '@animal-project/shared-types';
-import React, { useState } from 'react';
+import React from 'react';
import { FaHeart } from 'react-icons/fa';
import { motion } from 'framer-motion';
import { useLike } from 'front/hooks/store';
+import { Card, CardContent } from 'front/new-component/ui/card';
type Props = {
item: AnimalInfo;
@@ -13,34 +16,33 @@ export const AnimalCard = (props: Props) => {
const { like, toggleLike } = useLike({ likeItem: { ...item, like: false } });
return (
-
+
toggleLike()}>
-
+
-
-
-
+
+
-
- | 종류 |
- {item.kindCd} |
+
+ | 종류 |
+ {item.kindCd} |
-
- | 성별 |
- {item.sexCd} |
+
+ | 성별 |
+ {item.sexCd} |
-
- | 나이 |
- {item.age} |
+
+ | 나이 |
+ {item.age} |
-
-
+
+
);
};
diff --git a/apps/web/src/new-site/search/select/Select.tsx b/apps/web/src/new-site/search/select/Select.tsx
index 089a92b..6d0af20 100644
--- a/apps/web/src/new-site/search/select/Select.tsx
+++ b/apps/web/src/new-site/search/select/Select.tsx
@@ -1,6 +1,7 @@
import { AnimalInfoRequestType } from '@animal-project/shared-types';
import React from 'react';
import { UseFormRegister, UseFormWatch } from 'react-hook-form';
+import { cn } from 'front/lib/utils';
type Props = {
children: React.ReactNode;
@@ -19,11 +20,15 @@ export type SelectWatchProps = {
export const Select = (props: Props & SelectProps) => {
const { children, labelName, register, name } = props;
return (
-