feat(pop-profile): 앱 모드(풀스크린) 메뉴 항목 추가

POP 프로필 팝오버에 "앱 모드" 메뉴를 추가한다.
Fullscreen API로 브라우저를 전체화면 전환하여 앱처럼 사용 가능.
- showAppMode 설정 옵션 추가 (기본 활성화)
- 풀스크린 진입: document.documentElement.requestFullscreen()
- 풀스크린 해제: document.exitFullscreen()
- 상태에 따라 아이콘/텍스트 전환 (Maximize2/Minimize2, 앱 모드/앱 모드 해제)
- fullscreenchange 이벤트 리스너로 상태 동기화
- 디자이너 설정 패널에 "앱 모드 (풀스크린)" 토글 추가
This commit is contained in:
SeongHyun Kim 2026-03-25 15:54:26 +09:00
parent 6262ddb76b
commit dd3b226917
1 changed files with 54 additions and 2 deletions

View File

@ -1,6 +1,6 @@
"use client";
import React, { useState, useMemo } from "react";
import React, { useState, useMemo, useEffect, useCallback } from "react";
import { useRouter } from "next/navigation";
import { cn } from "@/lib/utils";
import { Label } from "@/components/ui/label";
@ -17,7 +17,7 @@ import {
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { Monitor, LayoutGrid, LogOut, UserCircle } from "lucide-react";
import { Monitor, LayoutGrid, LogOut, UserCircle, Maximize2, Minimize2 } from "lucide-react";
import { PopComponentRegistry } from "@/lib/registry/PopComponentRegistry";
import { useAuth } from "@/hooks/useAuth";
@ -31,6 +31,7 @@ export interface PopProfileConfig {
avatarSize?: AvatarSize;
showDashboardLink?: boolean;
showPcMode?: boolean;
showAppMode?: boolean;
showLogout?: boolean;
}
@ -38,6 +39,7 @@ const DEFAULT_CONFIG: PopProfileConfig = {
avatarSize: "md",
showDashboardLink: true,
showPcMode: true,
showAppMode: true,
showLogout: true,
};
@ -67,6 +69,33 @@ function PopProfileComponent({ config: rawConfig }: PopProfileComponentProps) {
const router = useRouter();
const { user, isLoggedIn, logout } = useAuth();
const [open, setOpen] = useState(false);
const [isFullscreen, setIsFullscreen] = useState(false);
// 풀스크린 상태 변경 감지
useEffect(() => {
const handleFullscreenChange = () => {
setIsFullscreen(!!document.fullscreenElement);
};
document.addEventListener("fullscreenchange", handleFullscreenChange);
// 초기 상태 동기화
setIsFullscreen(!!document.fullscreenElement);
return () => {
document.removeEventListener("fullscreenchange", handleFullscreenChange);
};
}, []);
const handleAppMode = useCallback(async () => {
setOpen(false);
try {
if (document.fullscreenElement) {
await document.exitFullscreen();
} else {
await document.documentElement.requestFullscreen();
}
} catch {
// 풀스크린 API 미지원 또는 사용자 거부
}
}, []);
const config = useMemo(() => ({
...DEFAULT_CONFIG,
@ -180,6 +209,20 @@ function PopProfileComponent({ config: rawConfig }: PopProfileComponentProps) {
PC
</button>
)}
{config.showAppMode && (
<button
onClick={handleAppMode}
className="flex w-full items-center gap-3 rounded-md px-3 py-3 text-sm transition-colors hover:bg-accent"
style={{ minHeight: 48 }}
>
{isFullscreen ? (
<Minimize2 className="h-4 w-4 text-muted-foreground" />
) : (
<Maximize2 className="h-4 w-4 text-muted-foreground" />
)}
{isFullscreen ? "앱 모드 해제" : "📱 앱 모드"}
</button>
)}
{config.showLogout && (
<>
<div className="mx-2 my-1 border-t" />
@ -276,6 +319,14 @@ function PopProfileConfigPanel({ config: rawConfig, onUpdate }: PopProfileConfig
/>
</div>
<div className="flex items-center justify-between">
<Label className="text-xs text-muted-foreground"> ()</Label>
<Switch
checked={config.showAppMode ?? true}
onCheckedChange={(v) => updateConfig({ showAppMode: v })}
/>
</div>
<div className="flex items-center justify-between">
<Label className="text-xs text-muted-foreground"></Label>
<Switch
@ -325,6 +376,7 @@ PopComponentRegistry.registerComponent({
avatarSize: "md",
showDashboardLink: true,
showPcMode: true,
showAppMode: true,
showLogout: true,
},
connectionMeta: {