diff --git a/src/app/(main)/map/_components/useMobileRouteView.tsx b/src/app/(main)/map/_components/useMobileRouteView.tsx index 51e30d53..eadc8e74 100644 --- a/src/app/(main)/map/_components/useMobileRouteView.tsx +++ b/src/app/(main)/map/_components/useMobileRouteView.tsx @@ -459,34 +459,34 @@ export function useMobileRouteView({
{/* 펼치면 X·일차 탭은 사라지고 카드가 그 자리까지 커진다 */}
-
+
+
-
{/* 접힘: 가장 긴 카드에 맞춰 모든 카드가 같은 높이 / 펼침: 지도의 70% */}
diff --git a/src/app/(main)/plan/_components/itinerary/PlanPlaceCard.tsx b/src/app/(main)/plan/_components/itinerary/PlanPlaceCard.tsx index eded7da1..842af452 100644 --- a/src/app/(main)/plan/_components/itinerary/PlanPlaceCard.tsx +++ b/src/app/(main)/plan/_components/itinerary/PlanPlaceCard.tsx @@ -311,9 +311,7 @@ export function PlanPlaceCard({ className={cn( "w-full select-none transition-colors", PLAN_PLACE_CARD_TW.article, - // 고른 카드는 계속 켜져 있으므로 배경은 그대로 두고 테두리와 옅게 번지는 파란 그림자로만 표시한다 - // (그림자 토큰이 없어 파랑 원시 토큰으로 지정) - focused && "border-primary shadow-[0_0_12px_var(--blue-200)]", + focused && "border-primary", dragDisabled ? "cursor-default" : "cursor-grab active:cursor-grabbing", diff --git a/src/app/(main)/plan/_components/mobile/MobilePlanPlaceCard.tsx b/src/app/(main)/plan/_components/mobile/MobilePlanPlaceCard.tsx index 6bbba996..2f4b88c7 100644 --- a/src/app/(main)/plan/_components/mobile/MobilePlanPlaceCard.tsx +++ b/src/app/(main)/plan/_components/mobile/MobilePlanPlaceCard.tsx @@ -1,6 +1,6 @@ "use client"; -import { useId, useState, type PointerEvent as ReactPointerEvent } from "react"; +import { useEffect, useId, useRef, useState, type PointerEvent as ReactPointerEvent } from "react"; import { ChevronDownIcon, @@ -10,6 +10,7 @@ import { TimeClockIcon, WriteIcon, } from "@/assets/icons"; +import { useOnClickOutside } from "@/hooks/useOnClickOutside"; import { formatScheduleTimeRange } from "@/lib/plan/scheduleTime"; import type { PlanPlace } from "@/lib/plan/types"; import { renderTextWithLinks } from "@/lib/text/renderTextWithLinks"; @@ -104,7 +105,7 @@ export function MobilePlanPlaceCard({

{place.title}

- {meta ?

{meta}

: null} + {meta ? : null}
@@ -139,6 +140,57 @@ export function MobilePlanPlaceCard({ ); } +/** 분류·주소 줄 — 좁은 화면에서 잘렸을 때만 눌러서 전체 주소를 아래 드롭다운으로 보여 준다 */ +function PlaceMeta({ place, meta }: Readonly<{ place: PlanPlace; meta: string }>) { + const wrapRef = useRef(null); + const textRef = useRef(null); + const addressId = useId(); + const [truncated, setTruncated] = useState(false); + const [open, setOpen] = useState(false); + useOnClickOutside(wrapRef, () => setOpen(false)); + + // 카드 폭(회전·넘겨 보기 칸)이 바뀌면 잘렸는지 다시 잰다 + useEffect(() => { + const el = textRef.current; + if (!el || typeof ResizeObserver === "undefined") return; + const measure = () => setTruncated(el.scrollWidth > el.clientWidth); + measure(); + const observer = new ResizeObserver(measure); + observer.observe(el); + return () => observer.disconnect(); + }, [meta]); + + const expandable = truncated && Boolean(place.subtitle); + return ( +
+

{meta}

+ {expandable ? ( + // 잘리지 않았으면 버튼을 두지 않아 이 줄을 눌러도 카드 본문(열기)이 눌린다 +
+ ); +} + function PlaceTimeAndExpense({ place, expenseSummary, addWhenEmpty, onEditTime, onOpenExpenses }: Pick) { const summaryId = useId(); @@ -268,7 +320,7 @@ function PlaceMemo({ place, addWhenEmpty, onEditMemo }:
) : null} {!memo && addMemo ? ( - // 메모가 있을 때와 같은 줄(구분선·아이콘·꺾쇠)을 흐리게 — 누르면 메모 시트 + // 메모가 있을 때와 같은 줄(구분선·아이콘)을 흐리게 — 펼칠 내용이 없어 꺾쇠는 두지 않는다. 누르면 메모 시트
) : null} diff --git a/src/app/(main)/room-settings/page.tsx b/src/app/(main)/room-settings/page.tsx deleted file mode 100644 index e002c4fa..00000000 --- a/src/app/(main)/room-settings/page.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { MainSettingsPageLayout } from "@/components/layout/MainSettingsPageLayout"; - -import { RoomTripSettingsSection } from "./_components/RoomTripSettingsSection"; - -export default function RoomSettingsPage() { - return ( - - - - ); -} diff --git a/src/components/layout/MainSettingsPageLayout.tsx b/src/components/layout/MainSettingsPageLayout.tsx index 220a1709..9c9cbd00 100644 --- a/src/components/layout/MainSettingsPageLayout.tsx +++ b/src/components/layout/MainSettingsPageLayout.tsx @@ -2,7 +2,7 @@ import type { ReactNode } from "react"; import { SetSectionMaxWidth } from "@/contexts/SectionWidthContext"; -/** member-settings·room-settings 등 s1 본문 폭 설정 탭 공통 레이아웃 */ +/** member-settings 등 s1 본문 폭 설정 탭 공통 레이아웃 */ export function MainSettingsPageLayout({ children }: { children: ReactNode }) { return (
diff --git a/src/components/map/Map.tsx b/src/components/map/Map.tsx index c012f57c..88ccf57e 100644 --- a/src/components/map/Map.tsx +++ b/src/components/map/Map.tsx @@ -5,7 +5,9 @@ import { usePathname } from "next/navigation"; import { Bookmark } from "lucide-react"; import { AdvancedMarker, + ControlPosition, Map as GoogleMap, + MapControl, useMap, useMapsLibrary, type MapCameraChangedEvent, @@ -465,6 +467,27 @@ export default function TripMap({ clearPlanFocus(); }; + const bookmarkToggle = ( + + ); + return (
@@ -519,6 +542,13 @@ export default function TripMap({ )} {!routeView && } + + {/* PC는 확대·축소(+/−) 바로 위 — 같은 오른쪽 아래 컨트롤 자리에 넣으면 지도가 +/− 위로 쌓아 준다 */} + {routeView || isMobileDevice ? null : ( + +
{bookmarkToggle}
+
+ )} )}
@@ -537,36 +567,21 @@ export default function TripMap({ {!bootstrap.ready || routeView ? null : ( <> -
- {onOpenRouteView ? ( - - ) : null} - -
+ {isMobileDevice ? ( +
+ {onOpenRouteView ? ( + + ) : null} + {bookmarkToggle} +
+ ) : null} )}
diff --git a/src/components/rooms/RoomTripEditDialog.tsx b/src/components/rooms/RoomTripEditDialog.tsx index 164468c5..59025560 100644 --- a/src/components/rooms/RoomTripEditDialog.tsx +++ b/src/components/rooms/RoomTripEditDialog.tsx @@ -3,14 +3,18 @@ import { RoomTripDeleteButton, RoomTripSettingsSection, -} from "@/app/(main)/room-settings/_components/RoomTripSettingsSection"; +} from "@/components/rooms/RoomTripSettingsSection"; import { SettingsDialog } from "@/components/settings/SettingsDialog"; export function RoomTripEditDialog({ onClose }: { onClose: () => void }) { return ( - }> +
- + +
+ {/* 여행 삭제는 적용하기 아래 모달 오른쪽 끝 — 방장이 아니면 버튼이 없어 줄째 숨긴다 */} +
+
); diff --git a/src/components/rooms/RoomTripEditForm.tsx b/src/components/rooms/RoomTripEditForm.tsx index 2d82f4c5..0131f340 100644 --- a/src/components/rooms/RoomTripEditForm.tsx +++ b/src/components/rooms/RoomTripEditForm.tsx @@ -28,7 +28,6 @@ import { type Props = { room: RoomTripFormSource; readOnly?: boolean; - onCancel?: () => void; onSaved?: () => void; }; @@ -36,7 +35,7 @@ export function RoomTripEditForm(props: Props) { return ; } -function RoomTripEditSession({ room, readOnly = false, onCancel, onSaved }: Props) { +function RoomTripEditSession({ room, readOnly = false, onSaved }: Props) { const saved = toTripFormValues(room); const [title, setTitle] = useState(saved.title); @@ -124,16 +123,6 @@ function RoomTripEditSession({ room, readOnly = false, onCancel, onSaved }: Prop onSaved, ]); - function handleCancel() { - const next = toTripFormValues(room); - setTitle(next.title); - setDestinations(next.destinations); - setStartDate(next.startDate); - setEndDate(next.endDate); - setShrinkConfirmOpen(false); - onCancel?.(); - } - function handleApply() { if (!canApply) return; @@ -176,15 +165,7 @@ function RoomTripEditSession({ room, readOnly = false, onCancel, onSaved }: Prop )} {!readOnly && ( - - - 취소 - +