From 681f8d17cd652e4c962605d247220e7f6460b37b Mon Sep 17 00:00:00 2001 From: recoma96 Date: Wed, 8 Apr 2026 09:45:29 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=EA=B2=80=EC=83=89=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EB=A6=AC=EB=89=B4=EC=96=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 테이블 -> 카드형으로 전환 필터 리셋 버튼 추기 --- .../components/client/CourseSearchList.tsx | 66 +++++----- web/src/components/client/SearchBar.tsx | 117 +++++++++++------- web/src/pages/courses/[id].astro | 2 +- web/src/pages/courses/index.astro | 5 +- 4 files changed, 106 insertions(+), 84 deletions(-) diff --git a/web/src/components/client/CourseSearchList.tsx b/web/src/components/client/CourseSearchList.tsx index d39ef24..51a8a12 100644 --- a/web/src/components/client/CourseSearchList.tsx +++ b/web/src/components/client/CourseSearchList.tsx @@ -57,44 +57,42 @@ const CourseSearchList: React.FC = () => { const paginationItems = getPaginationItems(currentPage, totalPages); return ( -
- - - - - - - - - - - - {courses.map((course, index) => ( - - - - - - - - ))} - -
코스명주소코스 스타일난이도
{((currentPage - 1) * (searchResult?.pageSize || 10)) + index + 1}{course.name} - {course.roadAddresses.length > 0 ? ( - course.roadAddresses[0] - ) : ( - course.loadAddresses[0] - )} - {course.courseStyle.name}
Lv.{course.difficulty.level}
- +
+ {/* Course Card List */} +
+ {courses.map((course) => ( + + {/* Difficulty Badge */} +
+ Lv.{course.difficulty.level} +
+ + {/* Course Info */} +
+
{course.name}
+
+ {course.roadAddresses.length > 0 ? course.roadAddresses[0] : course.loadAddresses[0]} +
+
+ + {/* Course Style Tag */} +
{course.courseStyle.name}
+
+ ))} +
+ {/* Pagination */}
{paginationItems.map((page, index) => ( - + )}
-
- {/* Search Input and Button */} -
-
- setSearchWord(e.target.value)} - onKeyDown={(e) => e.key === 'Enter' && handleSearch()} - /> - + {/* Divider */} +
+ + {/* Search Input and Button */} +
+
+ setSearchWord(e.target.value)} + onKeyDown={(e) => e.key === 'Enter' && handleSearch()} + /> + +
diff --git a/web/src/pages/courses/[id].astro b/web/src/pages/courses/[id].astro index f7e7396..1d3de11 100644 --- a/web/src/pages/courses/[id].astro +++ b/web/src/pages/courses/[id].astro @@ -15,7 +15,7 @@ const { id } = Astro.params; let isNotFound = false; -const course: CourseDetailSchemaResponse | null = await fetch(`${import.meta.env.API_ENDPOINT}/v1/courses/${id}`).then(async (res) => { +const course: CourseDetailSchemaResponse | null = await fetch(`${import.meta.env.PUBLIC_API_ENDPOINT}/v1/courses/${id}`).then(async (res) => { if (res.ok) { return res.json() as Promise; } else { diff --git a/web/src/pages/courses/index.astro b/web/src/pages/courses/index.astro index caf83bc..87bc428 100644 --- a/web/src/pages/courses/index.astro +++ b/web/src/pages/courses/index.astro @@ -7,7 +7,10 @@ import CourseSearchList from "@/components/client/CourseSearchList"; --- -

Trailine

+
+

Trailine 코스 찾기

+

나에게 맞는 트레킹 코스를 검색해 보세요

+
\ No newline at end of file From 1181ca4f1cda3debfd249ed690895a04a260c482 Mon Sep 17 00:00:00 2001 From: recoma96 Date: Wed, 8 Apr 2026 10:33:59 +0900 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20=EC=83=81=EC=84=B8=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EB=A6=AC=EB=89=B4=EC=96=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 목록 돌아가기 링크 추가 — 좌측 상단에 ← 코스 목록으로 돌아가기 네비게이션 코스명 스타일링 — text-2xl font-bold 적용 코스 스타일 뱃지 추가 — 코스명 바로 아래에 badge-outline으로 표시 주소에 위치 아이콘 추가 — 맵 핀 SVG + text-base-content/60 보조 색상 난이도/길이/시간 카드로 감싸기 — card border border-base-content/10 적용 난이도/길이/시간 반응형 처리 — 모바일: 길이|시간(위) + 난이도(아래) 세로 배치, 데스크톱: 가로 배치 bg-gray-100 → bg-base-200 — DaisyUI 테마 색상으로 통일 코스 설명 박스 개선 — bg-base-200 배경 + "코스 소개" 라벨 추가 이미지 슬라이더 반응형 높이 — 고정 700px → 모바일 250px / 데스크톱 700px --- .../client/CourseIntervalDetail.tsx | 23 +++++--- web/src/components/client/ImageSlider.tsx | 14 ++--- web/src/pages/courses/[id].astro | 58 +++++++++++++------ web/src/types/responses/course-detail.ts | 2 +- web/src/vars/colors.ts | 6 +- 5 files changed, 66 insertions(+), 37 deletions(-) diff --git a/web/src/components/client/CourseIntervalDetail.tsx b/web/src/components/client/CourseIntervalDetail.tsx index 4da53aa..3c06184 100644 --- a/web/src/components/client/CourseIntervalDetail.tsx +++ b/web/src/components/client/CourseIntervalDetail.tsx @@ -49,25 +49,32 @@ const CourseIntervalDetail: React.FC = ({courseId} : Props) => { return (
-
    +
      {intervals.map((interval, idx) => (
    • -
      { - idx + 1}. {interval.name} [{interval.difficulty.name}] ({interval.length} km, {minutesToKoreanDuration(interval.duration)}) +
      +
      + {interval.difficulty.name} +
      +
      +

      {idx + 1}. {interval.name}

      +

      {interval.length} km · {minutesToKoreanDuration(interval.duration)}

      +
      -
      +
      +

      {interval.description}

      {interval.images && interval.images.length > 0 && ( ({ url: image.url, title: image.title ?? "", description: image.description, - }))} className="max-w-full mx-auto mb-4" height={400} /> + }))} className="max-w-full mx-auto" heightClassName="h-[200px] lg:h-[400px]" /> )} -

      {interval.description}

    • diff --git a/web/src/components/client/ImageSlider.tsx b/web/src/components/client/ImageSlider.tsx index 15922ae..0574a69 100644 --- a/web/src/components/client/ImageSlider.tsx +++ b/web/src/components/client/ImageSlider.tsx @@ -19,11 +19,10 @@ type Image = { interface ImageSliderProps { images: Image[]; className?: string; - height: number; + heightClassName?: string; } -const ImageSlider: React.FC = ({ images, className, height }) => { - if (className === undefined) className = ""; +const ImageSlider: React.FC = ({ images, className = "", heightClassName = "h-[250px] lg:h-[700px]" }) => { return (
      = ({ images, className, height })
      {image.title}
      - {image.title}
      diff --git a/web/src/pages/courses/[id].astro b/web/src/pages/courses/[id].astro index 1d3de11..a563e80 100644 --- a/web/src/pages/courses/[id].astro +++ b/web/src/pages/courses/[id].astro @@ -53,35 +53,59 @@ const difficultyBackgroundColor = course ? COURSE_DIFFICULTY_COLORS[course.diffi + + + + + + 코스 목록으로 돌아가기 + +
      -

      {course?.name}

      -

      {mainAddress}

      +

      {course?.name}

      +
      {course?.courseStyle?.name}
      +

      + + + + + {mainAddress} +

      - -
      -
      -

      Lv. {course?.difficulty?.level} | {course?.difficulty?.code}

      -

      {course?.difficulty?.name}

      -
      -
      -

      총 길이

      -

      {course?.length} km

      -
      -
      -

      소요 시간

      -

      {minutesToKoreanDuration(course?.duration || 0)}

      + +
      +
      + +
      +
      +

      총 길이

      +

      {course?.length} km

      +
      +
      +

      소요 시간

      +

      {minutesToKoreanDuration(course?.duration || 0)}

      +
      +
      + +
      +

      Lv. {course?.difficulty?.level} | {course?.difficulty?.code}

      +

      {course?.difficulty?.name}

      +
      {course?.images && course.images.length > 0 && ( - + )} -
      +
      +

      코스 소개

      +
      +
      diff --git a/web/src/types/responses/course-detail.ts b/web/src/types/responses/course-detail.ts index 444dd7f..1faaffd 100644 --- a/web/src/types/responses/course-detail.ts +++ b/web/src/types/responses/course-detail.ts @@ -24,7 +24,7 @@ export interface CourseDetailSchemaResponse { loadAddresses: string[]; roadAddresses: string[]; difficulty: Difficulty; - styles: Style; + courseStyle: Style; images: Image[]; length: number; duration: number; diff --git a/web/src/vars/colors.ts b/web/src/vars/colors.ts index a1cd394..efa551f 100644 --- a/web/src/vars/colors.ts +++ b/web/src/vars/colors.ts @@ -1,10 +1,10 @@ export const INTERVAL_DIFFICULTY_COLORS = [ // index = difficulty level '#777777', // unknown '#58b947', // easy - '#3c86c6', // normal - '#f68820', // advanced + '#f68820', // normal '#bf2327', // hard - '#010101', // expert + '#57187D', // very hard + '#010101', // exporting ]; export const COURSE_DIFFICULTY_COLORS = [ From 252f8376c6756d2d7bf3f6c4c8d919a98926b9b3 Mon Sep 17 00:00:00 2001 From: recoma96 Date: Wed, 8 Apr 2026 13:11:49 +0900 Subject: [PATCH 3/4] =?UTF-8?q?fix:=20SSR=20=EB=B6=80=EB=B6=84=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EB=B0=B1=EC=97=94=EB=93=9C=20API=20=ED=98=B8?= =?UTF-8?q?=EC=B6=9C=20=EC=95=88=EB=90=98=EB=8A=94=20=EC=9D=B4=EC=8A=88=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/package-lock.json | 46 +++++++++++++++----------------- web/package.json | 2 +- web/src/pages/courses/[id].astro | 2 +- 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 8a6ca38..a2499f0 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -8,7 +8,7 @@ "name": "trailine-web", "version": "0.2.0", "dependencies": { - "@astrojs/node": "^10.0.0", + "@astrojs/node": "^9.5.1", "@astrojs/react": "^4.4.2", "@tailwindcss/vite": "^4.1.17", "@types/navermaps": "^3.9.1", @@ -34,13 +34,10 @@ "license": "MIT" }, "node_modules/@astrojs/internal-helpers": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.8.0.tgz", - "integrity": "sha512-J56GrhEiV+4dmrGLPNOl2pZjpHXAndWVyiVDYGDuw6MWKpBSEMLdFxHzeM/6sqaknw9M+HFfHZAcvi3OfT3D/w==", - "license": "MIT", - "dependencies": { - "picomatch": "^4.0.3" - } + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.7.6.tgz", + "integrity": "sha512-GOle7smBWKfMSP8osUIGOlB5kaHdQLV3foCsf+5Q9Wsuu+C6Fs3Ez/ttXmhjZ1HkSgsogcM1RXSjjOVieHq16Q==", + "license": "MIT" }, "node_modules/@astrojs/markdown-remark": { "version": "6.3.11", @@ -71,24 +68,18 @@ "vfile": "^6.0.3" } }, - "node_modules/@astrojs/markdown-remark/node_modules/@astrojs/internal-helpers": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.7.6.tgz", - "integrity": "sha512-GOle7smBWKfMSP8osUIGOlB5kaHdQLV3foCsf+5Q9Wsuu+C6Fs3Ez/ttXmhjZ1HkSgsogcM1RXSjjOVieHq16Q==", - "license": "MIT" - }, "node_modules/@astrojs/node": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@astrojs/node/-/node-10.0.0.tgz", - "integrity": "sha512-MYz73s+U1CxdSLoYlbB9lrgA2ryi6K8ULH2rM3SBQDFbWtXuTFiBAfG8c5BHy75tsSRn2p0rc7jdFiQAzuZOyw==", + "version": "9.5.5", + "resolved": "https://registry.npmjs.org/@astrojs/node/-/node-9.5.5.tgz", + "integrity": "sha512-rtU2BGU5u3SfGURpANfMxVzCIoR86MkaN05ncza9rbtuMKJ/XnRJt/BbyVknDbOJ71hoci0SIsJwKcJR8vvi/A==", "license": "MIT", "dependencies": { - "@astrojs/internal-helpers": "0.8.0", + "@astrojs/internal-helpers": "0.7.6", "send": "^1.2.1", "server-destroy": "^1.0.1" }, "peerDependencies": { - "astro": "^6.0.0-alpha.0" + "astro": "^5.17.3" } }, "node_modules/@astrojs/prism": { @@ -169,6 +160,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -2257,6 +2249,7 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.2.tgz", "integrity": "sha512-WOhQTZ4G8xZ1tjJTvKOpyEVSGgOTvJAfDK3FNFgELyaTpzhdgHVHeqW8V+UJvzF5BT+/B54T/1S2K6gd9c7bbA==", "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -2266,6 +2259,7 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -2275,6 +2269,7 @@ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -2573,6 +2568,7 @@ "resolved": "https://registry.npmjs.org/astro/-/astro-5.18.1.tgz", "integrity": "sha512-m4VWilWZ+Xt6NPoYzC4CgGZim/zQUO7WFL0RHCH0AiEavF1153iC3+me2atDvXpf/yX4PyGUeD8wZLq1cirT3g==", "license": "MIT", + "peer": true, "dependencies": { "@astrojs/compiler": "^2.13.0", "@astrojs/internal-helpers": "0.7.6", @@ -2654,12 +2650,6 @@ "sharp": "^0.34.0" } }, - "node_modules/astro/node_modules/@astrojs/internal-helpers": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.7.6.tgz", - "integrity": "sha512-GOle7smBWKfMSP8osUIGOlB5kaHdQLV3foCsf+5Q9Wsuu+C6Fs3Ez/ttXmhjZ1HkSgsogcM1RXSjjOVieHq16Q==", - "license": "MIT" - }, "node_modules/astro/node_modules/@esbuild/aix-ppc64": { "version": "0.27.7", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", @@ -3198,6 +3188,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -5837,6 +5828,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.1.tgz", "integrity": "sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -5846,6 +5838,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.1.tgz", "integrity": "sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -6107,6 +6100,7 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.1.tgz", "integrity": "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==", "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -6928,6 +6922,7 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", @@ -7227,6 +7222,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/web/package.json b/web/package.json index 1e8af53..b420ebd 100644 --- a/web/package.json +++ b/web/package.json @@ -11,7 +11,7 @@ "test:run": "vitest run" }, "dependencies": { - "@astrojs/node": "^10.0.0", + "@astrojs/node": "^9.5.1", "@astrojs/react": "^4.4.2", "@tailwindcss/vite": "^4.1.17", "@types/navermaps": "^3.9.1", diff --git a/web/src/pages/courses/[id].astro b/web/src/pages/courses/[id].astro index a563e80..7c5e3e0 100644 --- a/web/src/pages/courses/[id].astro +++ b/web/src/pages/courses/[id].astro @@ -15,7 +15,7 @@ const { id } = Astro.params; let isNotFound = false; -const course: CourseDetailSchemaResponse | null = await fetch(`${import.meta.env.PUBLIC_API_ENDPOINT}/v1/courses/${id}`).then(async (res) => { +const course: CourseDetailSchemaResponse | null = await fetch(`${import.meta.env.API_ENDPOINT}/v1/courses/${id}`).then(async (res) => { if (res.ok) { return res.json() as Promise; } else { From 212b09ffa2662341294ab646fb644e025601f4b1 Mon Sep 17 00:00:00 2001 From: recoma96 Date: Wed, 8 Apr 2026 13:13:06 +0900 Subject: [PATCH 4/4] =?UTF-8?q?version:=20=EB=B2=84=EC=A0=84=20=EB=AA=85?= =?UTF-8?q?=EC=8B=9C=20-=200.3.0=20alpha?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/package-lock.json | 4 ++-- web/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index a2499f0..d5292e5 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,12 +1,12 @@ { "name": "trailine-web", - "version": "0.2.0", + "version": "0.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "trailine-web", - "version": "0.2.0", + "version": "0.3.0", "dependencies": { "@astrojs/node": "^9.5.1", "@astrojs/react": "^4.4.2", diff --git a/web/package.json b/web/package.json index b420ebd..28fc4ec 100644 --- a/web/package.json +++ b/web/package.json @@ -1,7 +1,7 @@ { "name": "trailine-web", "type": "module", - "version": "0.2.0", + "version": "0.3.0", "scripts": { "dev": "astro dev", "build": "astro build",