feat(desktop): PC·업데이트 팝업 Apple/Windows 브랜드 아이콘

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Macbook
2026-06-15 17:03:07 +09:00
parent a5e14ba676
commit 0768ec37b9
5 changed files with 130 additions and 9 deletions
+10 -8
View File
@@ -4,6 +4,7 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import QRCode from 'qrcode';
import DraggableModalFrame from './DraggableModalFrame';
import { PlatformBrandIcon } from './icons/PlatformBrandIcons';
import {
loadDesktopAppBuildReadiness,
loadDesktopAppBuildStatus,
@@ -161,17 +162,18 @@ const PlatformCard: React.FC<{
mobile?: MobileAppReleaseInfoDto | null;
}> = ({ platform, release, mobile }) => {
const configs = {
mac: { label: 'macOS (Apple Silicon · Intel)', icon: '🍎', ext: '.dmg', isLink: false },
windows: { label: 'Windows (64-bit)', icon: '🪟', ext: '.exe', isLink: false },
android: { label: 'Android (패드 · 폰 · 별도 버전)', icon: '🤖', ext: '.apk', isLink: false },
mac: { label: 'macOS (Apple Silicon · Intel)', ext: '.dmg', isLink: false },
windows: { label: 'Windows (64-bit)', ext: '.exe', isLink: false },
android: { label: 'Android (패드 · 폰 · 별도 버전)', ext: '.apk', isLink: false },
} as const;
const { label, icon, ext } = configs[platform];
const { label, ext } = configs[platform];
const brandIcon = <PlatformBrandIcon platform={platform} />;
if (platform === 'android') {
if (!mobile?.available || !mobile.downloadUrl) {
return (
<div className="app-download-pc-card app-download-pc-card--empty">
<div className="app-download-pc-icon" aria-hidden>{icon}</div>
{brandIcon}
<div>
<strong>{label}</strong>
<p className="app-download-muted"> ({ext})</p>
@@ -181,7 +183,7 @@ const PlatformCard: React.FC<{
}
return (
<div className="app-download-pc-card">
<div className="app-download-pc-icon" aria-hidden>{icon}</div>
{brandIcon}
<div className="app-download-pc-body">
<strong>{label}</strong>
<p className="app-download-meta">
@@ -207,7 +209,7 @@ const PlatformCard: React.FC<{
if (!release?.available || !release.downloadUrl) {
return (
<div className="app-download-pc-card app-download-pc-card--empty">
<div className="app-download-pc-icon" aria-hidden>{icon}</div>
{brandIcon}
<div>
<strong>{label}</strong>
<p className="app-download-muted"> ({ext})</p>
@@ -218,7 +220,7 @@ const PlatformCard: React.FC<{
return (
<div className="app-download-pc-card">
<div className="app-download-pc-icon" aria-hidden>{icon}</div>
{brandIcon}
<div className="app-download-pc-body">
<strong>{label}</strong>
<p className="app-download-meta">
@@ -10,6 +10,7 @@ import {
type DesktopUpdateProgress,
} from '../utils/desktopBridge';
import { isMacDesktop, isWindowsDesktop } from '../utils/platform';
import { PlatformBrandIcon, type PlatformBrandIconId } from './icons/PlatformBrandIcons';
interface Props {
open: boolean;
@@ -84,6 +85,12 @@ const DesktopUpdateModal: React.FC<Props> = ({ open, onClose, autoStart = true }
? 100
: progress?.downloadPercent;
const platformBrand: PlatformBrandIconId | null = isMacDesktop()
? 'mac'
: isWindowsDesktop()
? 'windows'
: null;
return (
<DraggableModalFrame
title="PC 프로그램 업데이트"
@@ -93,6 +100,11 @@ const DesktopUpdateModal: React.FC<Props> = ({ open, onClose, autoStart = true }
dialogClassName="sp-modal desktop-update-modal"
>
<div className="desktop-update-modal-body">
{platformBrand && (
<div className="desktop-update-platform-brand">
<PlatformBrandIcon platform={platformBrand} />
</div>
)}
<p className="desktop-update-version">
<strong>v{progress?.currentVersion ?? appVersion}</strong>
{progress?.newVersion && progress.newVersion !== progress.currentVersion && (
@@ -0,0 +1,64 @@
import React from 'react';
/** Apple 실루엣 로고 — 흰색 (다크 배경용) */
export const AppleLogoWhite: React.FC<{ size?: number; className?: string }> = ({
size = 22,
className,
}) => (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="#ffffff"
className={className}
aria-hidden
>
<path d="M17.05 20.28c-.98.95-2.05.88-3.08.4-1.09-.5-2.08-.48-3.24 0-1.44.62-2.2.44-3.06-.4C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09l.01-.01zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z" />
</svg>
);
/** Microsoft Windows 4-pane 로고 */
export const WindowsLogo: React.FC<{ size?: number; className?: string }> = ({
size = 22,
className,
}) => (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
className={className}
aria-hidden
>
<path fill="#f25022" d="M3 3h8.5v8.5H3V3z" />
<path fill="#7fba00" d="M12.5 3H21v8.5h-8.5V3z" />
<path fill="#00a4ef" d="M3 12.5h8.5V21H3v-8.5z" />
<path fill="#ffb900" d="M12.5 12.5H21V21h-8.5v-8.5z" />
</svg>
);
export type PlatformBrandIconId = 'mac' | 'windows' | 'android';
export const PlatformBrandIcon: React.FC<{
platform: PlatformBrandIconId;
className?: string;
}> = ({ platform, className }) => {
if (platform === 'mac') {
return (
<span className={`app-download-pc-icon app-download-pc-icon--mac${className ? ` ${className}` : ''}`}>
<AppleLogoWhite size={22} />
</span>
);
}
if (platform === 'windows') {
return (
<span className={`app-download-pc-icon app-download-pc-icon--windows${className ? ` ${className}` : ''}`}>
<WindowsLogo size={22} />
</span>
);
}
return (
<span className={`app-download-pc-icon app-download-pc-icon--android${className ? ` ${className}` : ''}`} aria-hidden>
🤖
</span>
);
};