검색/필터 UI 개선, 채널 정렬, 드래그 스크롤, 지도링크 수정

- 검색바: 아이콘 내장, 모드 select 제거 (hybrid 고정), 엔터 검색
- 필터 그룹화: [음식 장르·가격] [지역 나라·시·구] + X 해제 버튼
- 채널 필터: 드롭다운 → 유튜브 아이콘 토글 카드, 드래그 스크롤
- 채널 정렬: sort_order 컬럼 추가, 백오피스 순서 편집
- 채널+필터 동시 적용: API 호출 대신 클라이언트 필터링
- 내위치 ON 시 다른 필터 초기화, 역방향도 동일
- 전체보기 버튼: 모든 필터 일괄 해제
- 네이버맵: 한국 식당만, 식당명만 검색
- 구글맵: 식당명+주소/지역 검색
- 로그인 영역 데스크톱 Row 1 우측 배치
- scrollbar-hide CSS 추가

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
joungmin
2026-03-11 20:42:25 +09:00
parent 2a0ee1d2cc
commit e85e135c8b
11 changed files with 342 additions and 175 deletions

View File

@@ -134,10 +134,11 @@ function ChannelsPanel({ isAdmin }: { isAdmin: boolean }) {
const [editingChannel, setEditingChannel] = useState<string | null>(null);
const [editDesc, setEditDesc] = useState("");
const [editTags, setEditTags] = useState("");
const [editOrder, setEditOrder] = useState<number>(99);
const handleSaveChannel = async (id: string) => {
try {
await api.updateChannel(id, { description: editDesc, tags: editTags });
await api.updateChannel(id, { description: editDesc, tags: editTags, sort_order: editOrder });
setEditingChannel(null);
load();
} catch {
@@ -210,6 +211,7 @@ function ChannelsPanel({ isAdmin }: { isAdmin: boolean }) {
<th className="text-left px-4 py-3"> </th>
<th className="text-left px-4 py-3"></th>
<th className="text-left px-4 py-3"></th>
<th className="text-center px-4 py-3"></th>
<th className="text-right px-4 py-3"> </th>
{isAdmin && <th className="text-left px-4 py-3"></th>}
<th className="text-left px-4 py-3"> </th>
@@ -238,7 +240,7 @@ function ChannelsPanel({ isAdmin }: { isAdmin: boolean }) {
) : (
<span className="text-gray-600 cursor-pointer" onClick={() => {
if (!isAdmin) return;
setEditingChannel(ch.id); setEditDesc(ch.description || ""); setEditTags(ch.tags || "");
setEditingChannel(ch.id); setEditDesc(ch.description || ""); setEditTags(ch.tags || ""); setEditOrder(ch.sort_order ?? 99);
}}>{ch.description || <span className="text-gray-400">-</span>}</span>
)}
</td>
@@ -253,10 +255,18 @@ function ChannelsPanel({ isAdmin }: { isAdmin: boolean }) {
) : (
<span className="text-gray-500 cursor-pointer" onClick={() => {
if (!isAdmin) return;
setEditingChannel(ch.id); setEditDesc(ch.description || ""); setEditTags(ch.tags || "");
setEditingChannel(ch.id); setEditDesc(ch.description || ""); setEditTags(ch.tags || ""); setEditOrder(ch.sort_order ?? 99);
}}>{ch.tags ? ch.tags.split(",").map(t => t.trim()).join(", ") : <span className="text-gray-400">-</span>}</span>
)}
</td>
<td className="px-4 py-3 text-center text-xs">
{editingChannel === ch.id ? (
<input type="number" value={editOrder} onChange={(e) => setEditOrder(Number(e.target.value))}
className="border rounded px-2 py-1 text-xs w-14 text-center bg-white text-gray-900" min={1} />
) : (
<span className="text-gray-500">{ch.sort_order ?? 99}</span>
)}
</td>
<td className="px-4 py-3 text-right font-medium">
{ch.video_count > 0 ? (
<span className="px-2 py-0.5 bg-green-50 text-green-700 rounded text-xs">{ch.video_count}</span>