pc 앱 배포,다운로드 기능

This commit is contained in:
Macbook
2026-06-14 10:33:53 +09:00
parent 92f67580e3
commit 407e746822
14 changed files with 640 additions and 86 deletions
@@ -22,6 +22,8 @@ interface Props {
onUpdateSlots: (slots: WidgetSlot[]) => void;
onUpdateSize: (width: number, height: number) => void;
onUpdateGridFr: (rowFr: number[], colFr: number[]) => void;
/** Tauri OS 창 — 네이티브 타이틀·리사이즈 사용, 내부 플로팅 크롬 숨김 */
nativeShell?: boolean;
}
const FloatingWidgetWindow: React.FC<Props> = ({
@@ -32,6 +34,7 @@ const FloatingWidgetWindow: React.FC<Props> = ({
onUpdateSlots,
onUpdateSize,
onUpdateGridFr,
nativeShell = false,
}) => {
const [pickSlotId, setPickSlotId] = useState<string | null>(null);
const bodyRef = useRef<HTMLDivElement>(null);
@@ -146,37 +149,49 @@ const FloatingWidgetWindow: React.FC<Props> = ({
const title = `위젯 ${instance.rows}×${instance.cols}`;
return createPortal(
const windowClass = [
'fw-window',
focused ? 'fw-window--focused' : '',
nativeShell ? 'fw-window--native' : '',
].filter(Boolean).join(' ');
const windowStyle = nativeShell
? undefined
: {
...panelStyle,
width: instance.width,
height: instance.height,
zIndex: instance.zIndex,
cursor: dragging ? 'grabbing' : undefined,
};
const content = (
<>
<div
ref={panelRef}
className={`fw-window${focused ? ' fw-window--focused' : ''}`}
style={{
...panelStyle,
width: instance.width,
height: instance.height,
zIndex: instance.zIndex,
cursor: dragging ? 'grabbing' : undefined,
}}
onMouseDown={onFocus}
className={windowClass}
style={windowStyle}
onMouseDown={nativeShell ? undefined : onFocus}
>
<div
className="fw-window-head"
onPointerDown={onHeaderPointerDown}
style={{ cursor: headerCursor, ...headerTouchStyle }}
>
<span className="fw-window-title">{title}</span>
<button
type="button"
className="fw-window-close"
title="위젯 창 닫기"
aria-label="위젯 창 닫기"
onPointerDown={e => e.stopPropagation()}
onClick={onClose}
{!nativeShell && (
<div
className="fw-window-head"
onPointerDown={onHeaderPointerDown}
style={{ cursor: headerCursor, ...headerTouchStyle }}
>
</button>
</div>
<span className="fw-window-title">{title}</span>
<button
type="button"
className="fw-window-close"
title="위젯 창 닫기"
aria-label="위젯 창 닫기"
onPointerDown={e => e.stopPropagation()}
onClick={onClose}
>
</button>
</div>
)}
<div className="fw-window-body-wrap">
<div
@@ -227,20 +242,22 @@ const FloatingWidgetWindow: React.FC<Props> = ({
)}
</div>
<div className="fw-window-resize-layer">
<div
className="fw-window-resize-handle fw-window-resize-handle--sw"
role="separator"
aria-label="위젯 창 크기 조절 (좌하단)"
onPointerDown={onResizeSwPointerDown}
/>
<div
className="fw-window-resize-handle fw-window-resize-handle--se"
role="separator"
aria-label="위젯 창 크기 조절 (우하단)"
onPointerDown={onResizeSePointerDown}
/>
</div>
{!nativeShell && (
<div className="fw-window-resize-layer">
<div
className="fw-window-resize-handle fw-window-resize-handle--sw"
role="separator"
aria-label="위젯 창 크기 조절 (좌하단)"
onPointerDown={onResizeSwPointerDown}
/>
<div
className="fw-window-resize-handle fw-window-resize-handle--se"
role="separator"
aria-label="위젯 창 크기 조절 (우하단)"
onPointerDown={onResizeSePointerDown}
/>
</div>
)}
</div>
<WidgetPickerModal
@@ -249,9 +266,10 @@ const FloatingWidgetWindow: React.FC<Props> = ({
onClose={() => setPickSlotId(null)}
onSelect={applyWidgetType}
/>
</>,
document.body,
</>
);
return nativeShell ? content : createPortal(content, document.body);
};
export default FloatingWidgetWindow;