From 0768ec37b9e754f510f194edc1aa952d8d1fce7c Mon Sep 17 00:00:00 2001 From: Macbook Date: Mon, 15 Jun 2026 17:03:07 +0900 Subject: [PATCH] =?UTF-8?q?feat(desktop):=20PC=C2=B7=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8=20=ED=8C=9D=EC=97=85=20Apple/Windows=20?= =?UTF-8?q?=EB=B8=8C=EB=9E=9C=EB=93=9C=20=EC=95=84=EC=9D=B4=EC=BD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- desktop/src/StartupUpdateGate.tsx | 13 ++++ frontend/src/App.css | 32 +++++++++- frontend/src/components/AppDownloadModal.tsx | 18 +++--- .../src/components/DesktopUpdateModal.tsx | 12 ++++ .../components/icons/PlatformBrandIcons.tsx | 64 +++++++++++++++++++ 5 files changed, 130 insertions(+), 9 deletions(-) create mode 100644 frontend/src/components/icons/PlatformBrandIcons.tsx diff --git a/desktop/src/StartupUpdateGate.tsx b/desktop/src/StartupUpdateGate.tsx index 7fd36b1..615ca24 100644 --- a/desktop/src/StartupUpdateGate.tsx +++ b/desktop/src/StartupUpdateGate.tsx @@ -5,6 +5,8 @@ import { type DesktopUpdateProgress, } from './bridge/updater'; import { scheduleMainWindowTitleSync } from './setMainWindowTitle'; +import { PlatformBrandIcon, type PlatformBrandIconId } from '@frontend/components/icons/PlatformBrandIcons'; +import { isMacDesktop, isWindowsDesktop } from '@frontend/utils/platform'; import '@frontend/App.css'; const PHASE_LABEL: Record = { @@ -35,9 +37,20 @@ function StartupUpdateSplash({ progress }: { progress: DesktopUpdateProgress | n ? 'desktop-update-progress--active' : ''; + const platformBrand: PlatformBrandIconId | null = isMacDesktop() + ? 'mac' + : isWindowsDesktop() + ? 'windows' + : null; + return (
+ {platformBrand && ( +
+ +
+ )}

GoldenChart

{progress?.currentVersion ? `현재 v${progress.currentVersion}` : '시작 중…'} diff --git a/frontend/src/App.css b/frontend/src/App.css index 097b768..89ca154 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -13429,6 +13429,14 @@ html.theme-light .tam-disclaimer { color: #90a4ae; } margin: 8px 0 0; font-size: 12px; color: #4ade80; line-height: 1.45; } .desktop-update-modal-body { padding: 4px 2px 0; } +.desktop-update-platform-brand { + display: flex; + justify-content: center; + margin-bottom: 12px; +} +.desktop-update-platform-brand--startup { + margin-bottom: 10px; +} .desktop-update-version { margin: 0 0 12px; font-size: 13px; color: var(--text2); } @@ -13598,7 +13606,29 @@ html.theme-light .tam-disclaimer { color: #90a4ae; } background: var(--bg2); border: 1px solid var(--border); } .app-download-pc-card--empty { opacity: 0.75; } -.app-download-pc-icon { font-size: 28px; flex-shrink: 0; width: 36px; text-align: center; } +.app-download-pc-icon { + display: inline-flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + width: 40px; + height: 40px; + border-radius: 10px; + box-sizing: border-box; +} +.app-download-pc-icon--mac { + background: #1d1d1f; + box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08); +} +.app-download-pc-icon--windows { + background: #0078d4; + box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12); +} +.app-download-pc-icon--android { + font-size: 24px; + background: var(--bg3); + border: 1px solid var(--border); +} .app-download-pc-body { flex: 1; min-width: 0; } .app-download-pc-body strong { display: block; font-size: 14px; margin-bottom: 4px; } .app-download-pc-btn { diff --git a/frontend/src/components/AppDownloadModal.tsx b/frontend/src/components/AppDownloadModal.tsx index f1c93cf..cd285c6 100644 --- a/frontend/src/components/AppDownloadModal.tsx +++ b/frontend/src/components/AppDownloadModal.tsx @@ -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 = ; if (platform === 'android') { if (!mobile?.available || !mobile.downloadUrl) { return (

-
{icon}
+ {brandIcon}
{label}

설치 파일 준비 중 ({ext})

@@ -181,7 +183,7 @@ const PlatformCard: React.FC<{ } return (
-
{icon}
+ {brandIcon}
{label}

@@ -207,7 +209,7 @@ const PlatformCard: React.FC<{ if (!release?.available || !release.downloadUrl) { return (

-
{icon}
+ {brandIcon}
{label}

설치 파일 준비 중 ({ext})

@@ -218,7 +220,7 @@ const PlatformCard: React.FC<{ return (
-
{icon}
+ {brandIcon}
{label}

diff --git a/frontend/src/components/DesktopUpdateModal.tsx b/frontend/src/components/DesktopUpdateModal.tsx index 7ba0bfa..b93e633 100644 --- a/frontend/src/components/DesktopUpdateModal.tsx +++ b/frontend/src/components/DesktopUpdateModal.tsx @@ -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 = ({ open, onClose, autoStart = true } ? 100 : progress?.downloadPercent; + const platformBrand: PlatformBrandIconId | null = isMacDesktop() + ? 'mac' + : isWindowsDesktop() + ? 'windows' + : null; + return ( = ({ open, onClose, autoStart = true } dialogClassName="sp-modal desktop-update-modal" >

+ {platformBrand && ( +
+ +
+ )}

현재 버전 v{progress?.currentVersion ?? appVersion} {progress?.newVersion && progress.newVersion !== progress.currentVersion && ( diff --git a/frontend/src/components/icons/PlatformBrandIcons.tsx b/frontend/src/components/icons/PlatformBrandIcons.tsx new file mode 100644 index 0000000..146b8c2 --- /dev/null +++ b/frontend/src/components/icons/PlatformBrandIcons.tsx @@ -0,0 +1,64 @@ +import React from 'react'; + +/** Apple 실루엣 로고 — 흰색 (다크 배경용) */ +export const AppleLogoWhite: React.FC<{ size?: number; className?: string }> = ({ + size = 22, + className, +}) => ( + + + +); + +/** Microsoft Windows 4-pane 로고 */ +export const WindowsLogo: React.FC<{ size?: number; className?: string }> = ({ + size = 22, + className, +}) => ( + + + + + + +); + +export type PlatformBrandIconId = 'mac' | 'windows' | 'android'; + +export const PlatformBrandIcon: React.FC<{ + platform: PlatformBrandIconId; + className?: string; +}> = ({ platform, className }) => { + if (platform === 'mac') { + return ( + + + + ); + } + if (platform === 'windows') { + return ( + + + + ); + } + return ( + + 🤖 + + ); +};