Bladeren bron

V1.1.6外观修改

liuq 3 weken geleden
bovenliggende
commit
808dff3bf5

+ 4 - 4
src/main/index.ts

@@ -1051,8 +1051,8 @@ function createWindow(): void {
     autoHideMenuBar: true,
     titleBarStyle: 'hidden', // Hide title bar
     titleBarOverlay: {
-      color: '#ffffff', // Match login background
-      symbolColor: '#747474', // Match control color
+      color: '#f7f9fc', // Match refreshed app shell
+      symbolColor: '#64748b', // Match refreshed control color
       height: 30
     },
     webPreferences: {
@@ -1158,8 +1158,8 @@ function createInternalBrowserWindow(targetUrl: string, appId?: string): void {
     autoHideMenuBar: true, // Show menu bar for navigation
     titleBarStyle: 'hidden',
     titleBarOverlay: {
-      color: '#e2e2e2',
-      symbolColor: '#333',
+      color: '#f7f9fc',
+      symbolColor: '#64748b',
       height: 38
     },
     webPreferences: {

+ 58 - 57
src/renderer/src/App.tsx

@@ -450,8 +450,8 @@ function App(): JSX.Element {
       return (
         <>
           <div className="search-bar" style={{ WebkitAppRegion: 'drag', position: 'relative', zIndex: 1 } as React.CSSProperties}>
-            <div style={{ backgroundColor: '#e2e2e2', borderRadius: '4px', padding: '6px 8px', fontSize: '12px', color: '#666', display: 'flex', alignItems: 'center', WebkitAppRegion: 'no-drag', position: 'relative' } as React.CSSProperties}>
-              <BsSearch style={{ marginRight: '5px' }} />
+            <div style={{ backgroundColor: 'var(--im-surface)', border: '1px solid var(--im-border)', borderRadius: 'var(--im-radius)', padding: '9px 11px', fontSize: '13px', color: 'var(--im-text-muted)', display: 'flex', alignItems: 'center', WebkitAppRegion: 'no-drag', position: 'relative', boxShadow: 'var(--im-shadow-sm)' } as React.CSSProperties}>
+              <BsSearch style={{ marginRight: '8px', color: 'var(--im-text-subtle)', fontSize: '15px' }} />
               <input
                 type="text"
                 placeholder="搜索聊天记录"
@@ -482,8 +482,8 @@ function App(): JSX.Element {
                   outline: 'none',
                   backgroundColor: 'transparent',
                   flex: 1,
-                  fontSize: '12px',
-                  color: '#666'
+                  fontSize: '13px',
+                  color: 'var(--im-text)'
                 }}
               />
               {searchQuery && (
@@ -492,7 +492,7 @@ function App(): JSX.Element {
                     e.stopPropagation()
                     setSearchQuery('')
                   }}
-                  style={{ cursor: 'pointer', marginLeft: '5px', fontSize: '14px' }}
+                  style={{ cursor: 'pointer', marginLeft: '8px', fontSize: '16px', color: 'var(--im-text-subtle)' }}
                 >
                 </span>
@@ -507,13 +507,13 @@ function App(): JSX.Element {
                   left: '10px',
                   right: '10px',
                   backgroundColor: '#fff',
-                  border: '1px solid #e7e7e7',
-                  borderRadius: '4px',
+                  border: '1px solid var(--im-border)',
+                  borderRadius: 'var(--im-radius)',
                   maxHeight: '300px',
                   overflowY: 'auto',
                   zIndex: 10000,
                   marginTop: '4px',
-                  boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
+                  boxShadow: 'var(--im-shadow-md)',
                   WebkitAppRegion: 'no-drag'
                 } as React.CSSProperties}
               >
@@ -540,26 +540,26 @@ function App(): JSX.Element {
                     style={{
                       padding: '8px 12px',
                       cursor: 'pointer',
-                      borderBottom: '1px solid #f0f0f0',
+                      borderBottom: '1px solid var(--im-border)',
                       fontSize: '12px'
                     }}
                     onMouseEnter={(e) => {
-                      e.currentTarget.style.backgroundColor = '#f5f5f5'
+                      e.currentTarget.style.backgroundColor = '#f8fafc'
                     }}
                     onMouseLeave={(e) => {
                       e.currentTarget.style.backgroundColor = '#fff'
                     }}
                   >
                     <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '4px' }}>
-                      <div style={{ color: '#666', fontSize: '11px', fontWeight: '500' }}>
+                      <div style={{ color: 'var(--im-text-muted)', fontSize: '11px', fontWeight: '600' }}>
                         {result.contactName}
                       </div>
-                      <div style={{ color: '#999', fontSize: '10px' }}>
+                      <div style={{ color: 'var(--im-text-subtle)', fontSize: '10px' }}>
                         {formatFullDateTime(result.message.timestamp)}
                       </div>
                     </div>
                     <div style={{ 
-                      color: '#333',
+                      color: 'var(--im-text)',
                       overflow: 'hidden',
                       textOverflow: 'ellipsis',
                       whiteSpace: 'nowrap'
@@ -579,11 +579,11 @@ function App(): JSX.Element {
                   left: '10px',
                   right: '10px',
                   backgroundColor: '#fff',
-                  border: '1px solid #e7e7e7',
-                  borderRadius: '4px',
+                  border: '1px solid var(--im-border)',
+                  borderRadius: 'var(--im-radius)',
                   padding: '12px',
                   textAlign: 'center',
-                  color: '#999',
+                  color: 'var(--im-text-subtle)',
                   fontSize: '12px',
                   zIndex: 10000,
                   marginTop: '4px',
@@ -594,7 +594,7 @@ function App(): JSX.Element {
               </div>
             )}
           </div>
-          <div style={{ flex: 1, overflowY: 'auto' }}>
+          <div style={{ flex: 1, overflowY: 'auto', backgroundColor: 'var(--im-panel)' }}>
             {contacts.map(contact => {
               const remarkLabel = formatConversationRemark(contact.remarks)
               return (
@@ -606,14 +606,15 @@ function App(): JSX.Element {
                 }}
                 style={{
                   display: 'flex',
-                  padding: '12px',
+                  minHeight: '68px',
+                  padding: '12px 14px',
                   cursor: 'pointer',
-                  backgroundColor: contact.id === activeContactId ? '#c6c6c6' : '#e6e6e6',
+                  backgroundColor: contact.id === activeContactId ? 'var(--im-brand-soft)' : 'var(--im-panel)',
                   transition: 'background-color 0.2s',
-                  borderBottom: '1px solid #d6d6d6'
+                  borderBottom: '1px solid var(--im-border)'
                 }}
               >
-                <div style={{ position: 'relative', marginRight: '10px', flexShrink: 0 }}>
+                <div style={{ position: 'relative', marginRight: '12px', flexShrink: 0 }}>
                   <div
                     style={{
                       width: '40px',
@@ -628,7 +629,7 @@ function App(): JSX.Element {
                   {contact.unreadCount > 0 && (
                     <div style={{
                       position: 'absolute', top: '-5px', right: '-5px',
-                      backgroundColor: '#ff3b30', color: 'white',
+                      backgroundColor: 'var(--im-danger)', color: 'white',
                       borderRadius: '10px', padding: '0 5px', fontSize: '10px',
                       minWidth: '14px', height: '14px', lineHeight: '14px', textAlign: 'center'
                     }}>
@@ -639,14 +640,14 @@ function App(): JSX.Element {
                 <div style={{ flex: 1, overflow: 'hidden', display: 'flex', flexDirection: 'column', justifyContent: 'center' }}>
                   <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '4px' }}>
                     <div style={{ display: 'flex', alignItems: 'center', flex: 1, marginRight: '8px', flexWrap: 'wrap' }}>
-                      <span style={{ fontWeight: '500', fontSize: '14px', color: '#000' }}>
+                      <span style={{ fontWeight: '600', fontSize: '14px', color: 'var(--im-text)' }}>
                         {contact.name}
                       </span>
                       {remarkLabel && (
                         <span
                           style={{
                             fontSize: '11px',
-                            color: '#d97706',
+                            color: '#b7791f',
                             marginLeft: '2px',
                             whiteSpace: 'nowrap',
                             display: 'inline-block'
@@ -657,9 +658,9 @@ function App(): JSX.Element {
                         </span>
                       )}
                     </div>
-                    <span style={{ fontSize: '10px', color: '#999' }}>{contact.lastMessageTime}</span>
+                    <span style={{ fontSize: '10px', color: 'var(--im-text-subtle)' }}>{contact.lastMessageTime}</span>
                   </div>
-                  <div style={{ fontSize: '12px', color: '#888', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
+                  <div style={{ fontSize: '12px', color: 'var(--im-text-muted)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
                     {contact.lastMessage}
                   </div>
                 </div>
@@ -709,8 +710,8 @@ function App(): JSX.Element {
           display: 'flex',
           alignItems: 'center',
           justifyContent: 'center',
-          backgroundColor: '#f5f5f5',
-          color: '#666',
+          backgroundColor: 'var(--im-bg)',
+          color: 'var(--im-text-muted)',
           fontSize: 15
         }}
       >
@@ -740,7 +741,7 @@ function App(): JSX.Element {
         </div>
       )}
 
-      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', backgroundColor: '#f5f5f5', minWidth: 0, overflow: 'hidden' }}>
+      <div className="content-panel">
         {activeTab === 'chat' ? (
           isLoadingContacts ? (
             <div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#999' }}>
@@ -779,71 +780,71 @@ function App(): JSX.Element {
           )
         ) : activeTab === 'contact' ? (
           selectedContactDetail ? (
-            <div style={{ flex: 1, display: 'flex', flexDirection: 'column', backgroundColor: '#f5f5f5' }}>
-              <div style={{ padding: '0 20px', height: '60px', display: 'flex', alignItems: 'center', borderBottom: '1px solid #e7e7e7', justifyContent: 'space-between', WebkitAppRegion: 'drag', backgroundColor: '#fff' } as React.CSSProperties}>
-                <div style={{ fontWeight: 'bold', fontSize: '16px', WebkitAppRegion: 'no-drag' } as React.CSSProperties}>
+            <div style={{ flex: 1, display: 'flex', flexDirection: 'column', backgroundColor: 'var(--im-bg)' }}>
+              <div style={{ padding: '0 28px', height: 'var(--im-topbar-height)', display: 'flex', alignItems: 'center', borderBottom: '1px solid var(--im-border)', justifyContent: 'space-between', WebkitAppRegion: 'drag', backgroundColor: 'var(--im-panel)' } as React.CSSProperties}>
+                <div style={{ fontWeight: '700', fontSize: '17px', color: 'var(--im-text)', WebkitAppRegion: 'no-drag' } as React.CSSProperties}>
                   联系人详情
                 </div>
               </div>
               
-              <div style={{ flex: 1, overflowY: 'auto', padding: '40px 20px', display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
-                <div style={{ width: '100px', height: '100px', borderRadius: '50%', backgroundColor: 'transparent', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '100px', marginBottom: '30px', border: '1px solid #e7e7e7', boxShadow: '0 2px 4px rgba(0,0,0,0.1)', overflow: 'hidden' }}>
+              <div style={{ flex: 1, overflowY: 'auto', padding: '54px 24px 44px', display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
+                <div style={{ width: '104px', height: '104px', borderRadius: '50%', backgroundColor: 'transparent', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '100px', marginBottom: '24px', border: '1px solid rgba(255,255,255,0.9)', boxShadow: '0 10px 30px rgba(15, 23, 42, 0.14)', overflow: 'hidden' }}>
                   {getDefaultAvatar(selectedContactDetail.id, selectedContactDetail.name || selectedContactDetail.english_name, { sizePx: 100 })}
                 </div>
                 
-                <div style={{ fontSize: '20px', fontWeight: 'bold', marginBottom: '40px', color: '#333' }}>
+                <div style={{ fontSize: '22px', fontWeight: '700', marginBottom: '36px', color: 'var(--im-text)' }}>
                   {selectedContactDetail.name || selectedContactDetail.english_name || `用户${selectedContactDetail.id}`}
                 </div>
                 
-                <div style={{ width: '100%', maxWidth: '500px', backgroundColor: '#fff', borderRadius: '8px', padding: '20px', boxShadow: '0 2px 4px rgba(0,0,0,0.05)' }}>
+                <div style={{ width: '100%', maxWidth: '560px', backgroundColor: 'var(--im-panel)', borderRadius: 'var(--im-radius)', padding: '8px 24px', border: '1px solid var(--im-border)', boxShadow: 'var(--im-shadow-sm)' }}>
                   {selectedContactDetail.name && (
-                    <div style={{ padding: '15px 0', borderBottom: '1px solid #f0f0f0', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
-                      <span style={{ color: '#999', fontSize: '14px' }}>中文名</span>
-                      <span style={{ color: '#333', fontSize: '14px', fontWeight: '500' }}>{selectedContactDetail.name}</span>
+                    <div style={{ padding: '17px 0', borderBottom: '1px solid var(--im-border)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
+                      <span style={{ color: 'var(--im-text-muted)', fontSize: '14px' }}>中文名</span>
+                      <span style={{ color: 'var(--im-text)', fontSize: '14px', fontWeight: '600' }}>{selectedContactDetail.name}</span>
                     </div>
                   )}
                   
                   {selectedContactDetail.english_name && (
-                    <div style={{ padding: '15px 0', borderBottom: '1px solid #f0f0f0', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
-                      <span style={{ color: '#999', fontSize: '14px' }}>英文名</span>
-                      <span style={{ color: '#333', fontSize: '14px', fontWeight: '500' }}>{selectedContactDetail.english_name}</span>
+                    <div style={{ padding: '17px 0', borderBottom: '1px solid var(--im-border)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
+                      <span style={{ color: 'var(--im-text-muted)', fontSize: '14px' }}>英文名</span>
+                      <span style={{ color: 'var(--im-text)', fontSize: '14px', fontWeight: '600' }}>{selectedContactDetail.english_name}</span>
                     </div>
                   )}
                   
                   {selectedContactDetail.status && (
-                    <div style={{ padding: '15px 0', borderBottom: '1px solid #f0f0f0', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
-                      <span style={{ color: '#999', fontSize: '14px' }}>状态</span>
-                      <span style={{ color: '#333', fontSize: '14px', fontWeight: '500' }}>{selectedContactDetail.status}</span>
+                    <div style={{ padding: '17px 0', borderBottom: '1px solid var(--im-border)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
+                      <span style={{ color: 'var(--im-text-muted)', fontSize: '14px' }}>状态</span>
+                      <span style={{ color: 'var(--im-text)', fontSize: '14px', fontWeight: '600' }}>{selectedContactDetail.status}</span>
                     </div>
                   )}
                   
-                  <div style={{ padding: '15px 0', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
-                    <span style={{ color: '#999', fontSize: '14px' }}>用户ID</span>
-                    <span style={{ color: '#333', fontSize: '14px', fontWeight: '500' }}>{selectedContactDetail.id}</span>
+                  <div style={{ padding: '17px 0', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
+                    <span style={{ color: 'var(--im-text-muted)', fontSize: '14px' }}>用户ID</span>
+                    <span style={{ color: 'var(--im-text)', fontSize: '14px', fontWeight: '600' }}>{selectedContactDetail.id}</span>
                   </div>
                 </div>
                 
-                <div style={{ marginTop: '50px', width: '100%', maxWidth: '500px', padding: '0 20px' }}>
+                <div style={{ marginTop: '44px', width: '100%', maxWidth: '560px', padding: '0 20px' }}>
                   <button
                     onClick={() => handleSendMessageFromContact(selectedContactDetail)}
                     style={{
                       width: '100%',
-                      padding: '14px',
-                      backgroundColor: '#1aad19',
+                      padding: '13px 16px',
+                      backgroundColor: '#20b86f',
                       color: 'white',
                       border: 'none',
-                      borderRadius: '6px',
+                      borderRadius: 'var(--im-radius)',
                       fontSize: '16px',
-                      fontWeight: '500',
+                      fontWeight: '600',
                       cursor: 'pointer',
-                      transition: 'background-color 0.2s',
-                      boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
+                      transition: 'background-color 0.18s ease, box-shadow 0.18s ease',
+                      boxShadow: '0 8px 18px rgba(32, 184, 111, 0.22)'
                     }}
                     onMouseEnter={(e) => {
-                      e.currentTarget.style.backgroundColor = '#179b16'
+                      e.currentTarget.style.backgroundColor = '#18a764'
                     }}
                     onMouseLeave={(e) => {
-                      e.currentTarget.style.backgroundColor = '#1aad19'
+                      e.currentTarget.style.backgroundColor = '#20b86f'
                     }}
                   >
                     发消息

+ 5 - 3
src/renderer/src/BrowserWindow.tsx

@@ -96,9 +96,9 @@ const BrowserWindow: React.FC = () => {
   }
 
   return (
-    <div className="browser-window" style={{ display: 'flex', flexDirection: 'column', height: '100vh', width: '100vw', backgroundColor: '#f5f5f5', overflow: 'hidden' }}>
+    <div className="browser-window" style={{ display: 'flex', flexDirection: 'column', height: '100vh', width: '100vw', backgroundColor: 'var(--im-bg)', overflow: 'hidden' }}>
       {/* Title Bar / Tab Bar */}
-      <div className="browser-header" style={{ height: '38px', display: 'flex', alignItems: 'flex-end', backgroundColor: '#e2e2e2', paddingLeft: '80px', WebkitAppRegion: 'drag' } as any}>
+      <div className="browser-header" style={{ height: '38px', display: 'flex', alignItems: 'flex-end', backgroundColor: '#f7f9fc', borderBottom: '1px solid var(--im-border)', paddingLeft: '80px', WebkitAppRegion: 'drag' } as any}>
         <div style={{ display: 'flex', overflowX: 'auto', height: '100%', alignItems: 'flex-end', WebkitAppRegion: 'no-drag' } as any}>
           {tabs.map(tab => (
             <div
@@ -109,6 +109,8 @@ const BrowserWindow: React.FC = () => {
                 height: '30px',
                 width: '180px',
                 backgroundColor: activeTabId === tab.id ? '#ffffff' : 'transparent',
+                border: activeTabId === tab.id ? '1px solid var(--im-border)' : '1px solid transparent',
+                borderBottomColor: activeTabId === tab.id ? '#ffffff' : 'transparent',
                 borderTopLeftRadius: '6px',
                 borderTopRightRadius: '6px',
                 display: 'flex',
@@ -118,7 +120,7 @@ const BrowserWindow: React.FC = () => {
                 marginRight: '2px',
                 position: 'relative',
                 userSelect: 'none',
-                color: '#333'
+                color: activeTabId === tab.id ? 'var(--im-text)' : 'var(--im-text-muted)'
               }}
               title={tab.title}
             >

+ 63 - 153
src/renderer/src/components/AppMappingList.tsx

@@ -326,121 +326,58 @@ const AppMappingList: React.FC<AppMappingListProps> = ({ token, currentUserId })
   )
 
   return (
-    <div
-      style={{
-        flex: 1,
-        minHeight: 0,
-        padding: '40px',
-        overflow: 'hidden',
-        display: 'flex',
-        flexDirection: 'column',
-      }}
-    >
-      <div style={{ flexShrink: 0 }}>
-      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '30px' }}>
-        <h2 style={{ margin: 0, color: '#333', WebkitAppRegion: 'drag' } as React.CSSProperties}>应用中心</h2>
-        <div style={{ display: 'flex', alignItems: 'center', gap: '8px', WebkitAppRegion: 'no-drag' } as React.CSSProperties}>
-          <button
-            title={openInSystemBrowser ? '在应用内打开' : '用系统浏览器打开'}
-            onClick={() => {
-              setOpenInSystemBrowser(prev => {
-                const next = !prev
-                try {
-                  localStorage.setItem(OPEN_IN_SYSTEM_BROWSER_KEY, next ? 'true' : 'false')
-                } catch (_) {}
-                return next
-              })
-            }}
-            style={{
-              display: 'flex',
-              alignItems: 'center',
-              justifyContent: 'center',
-              width: '36px',
-              height: '36px',
-              padding: 0,
-              borderRadius: '6px',
-              border: '1px solid #e0e0e0',
-              backgroundColor: openInSystemBrowser ? '#1890ff' : '#f5f5f5',
-              color: openInSystemBrowser ? '#fff' : '#666',
-              cursor: 'pointer',
-              fontSize: '16px',
-              transition: 'all 0.2s',
-            } as React.CSSProperties}
-          >
-            <BsGlobe style={{ fontSize: '18px' }} />
-          </button>
-          <button
-            onClick={() => {
-              setShowCategory(prev => {
-                const next = !prev
-                try {
-                  localStorage.setItem(SHOW_CATEGORY_KEY, JSON.stringify(next))
-                } catch (_) {}
-                return next
-              })
-            }}
-            style={{
-              display: 'flex',
-              alignItems: 'center',
-              gap: '6px',
-              padding: '6px 14px',
-              borderRadius: '6px',
-              border: '1px solid #e0e0e0',
-              backgroundColor: showCategory ? '#1890ff' : '#f5f5f5',
-              color: showCategory ? '#fff' : '#666',
-              cursor: 'pointer',
-              fontSize: '13px',
-              transition: 'all 0.2s',
-            } as React.CSSProperties}
-          >
-            <BsGrid3X3Gap style={{ fontSize: '14px' }} />
-            {showCategory ? '取消分类' : '显示分类'}
-          </button>
+    <div className="launchpad-page">
+      <div className="launchpad-fixed">
+        <div className="launchpad-header">
+          <h2 className="app-page-title" style={{ WebkitAppRegion: 'drag' } as React.CSSProperties}>应用中心</h2>
+          <div className="launchpad-actions">
+            <button
+              title={openInSystemBrowser ? '在应用内打开' : '用系统浏览器打开'}
+              className={`launchpad-action-button launchpad-action-button--icon ${openInSystemBrowser ? 'is-active' : ''}`}
+              onClick={() => {
+                setOpenInSystemBrowser(prev => {
+                  const next = !prev
+                  try {
+                    localStorage.setItem(OPEN_IN_SYSTEM_BROWSER_KEY, next ? 'true' : 'false')
+                  } catch (_) {}
+                  return next
+                })
+              }}
+            >
+              <BsGlobe style={{ fontSize: '18px' }} />
+            </button>
+            <button
+              className={`launchpad-action-button launchpad-action-button--text ${showCategory ? 'is-active' : ''}`}
+              onClick={() => {
+                setShowCategory(prev => {
+                  const next = !prev
+                  try {
+                    localStorage.setItem(SHOW_CATEGORY_KEY, JSON.stringify(next))
+                  } catch (_) {}
+                  return next
+                })
+              }}
+            >
+              <BsGrid3X3Gap style={{ fontSize: '14px' }} />
+              {showCategory ? '取消分类' : '显示分类'}
+            </button>
+          </div>
         </div>
-      </div>
       
       {/* 搜索框 */}
-      <div style={{ marginBottom: '20px' }}>
-        <div style={{ 
-          position: 'relative', 
-          display: 'flex', 
-          alignItems: 'center',
-          backgroundColor: '#f5f5f5',
-          borderRadius: '8px',
-          padding: '10px 12px',
-          border: '1px solid #e0e0e0'
-        }}>
-          <BsSearch style={{ color: '#999', marginRight: '8px', fontSize: '16px' }} />
+      <div className="launchpad-search-block">
+        <div className="launchpad-search-field">
+          <BsSearch />
           <input
             type="text"
             placeholder="搜索应用名称"
             value={searchKeyword}
             onChange={(e) => setSearchKeyword(e.target.value)}
-            style={{
-              flex: 1,
-              border: 'none',
-              outline: 'none',
-              fontSize: '14px',
-              color: '#333',
-              background: 'transparent'
-            }}
           />
           {searchKeyword && (
             <button
+              className="launchpad-clear-button"
               onClick={() => setSearchKeyword('')}
-              style={{
-                background: 'none',
-                border: 'none',
-                color: '#999',
-                cursor: 'pointer',
-                fontSize: '20px',
-                padding: 0,
-                width: '24px',
-                height: '24px',
-                display: 'flex',
-                alignItems: 'center',
-                justifyContent: 'center'
-              }}
             >
               ×
             </button>
@@ -450,21 +387,11 @@ const AppMappingList: React.FC<AppMappingListProps> = ({ token, currentUserId })
 
       {/* 最近打开:仅显示 5 条,与全部应用用分隔线隔开 */}
       {recentApps.length > 0 && (
-        <div style={{ marginBottom: '24px', paddingBottom: '24px', borderBottom: '1px solid #eee' }}>
-          <div style={{
-            fontSize: '15px',
-            fontWeight: 'bold',
-            color: '#333',
-            marginBottom: '12px',
-            paddingBottom: '8px',
-            borderBottom: '1px solid #eee',
-            display: 'flex',
-            alignItems: 'center',
-            gap: '8px',
-          }}>
+        <div className="launchpad-section launchpad-section--recent">
+          <div className="launchpad-section-title">
             最近打开
           </div>
-          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(5, minmax(0, 1fr))', gap: '12px' }}>
+          <div className="launchpad-recent-grid">
             {recentApps.map((item) => {
               const mappingForIcon =
                 mappings.find(m => m.app_id === item.app_id && (m.mapped_key ?? '') === item.mapped_key) ??
@@ -488,10 +415,10 @@ const AppMappingList: React.FC<AppMappingListProps> = ({ token, currentUserId })
                     sizePx={38}
                     extraStyle={{ marginRight: 8 }}
                   />
-                  <div style={{ minWidth: 0 }}>
-                    <div style={{ fontWeight: 'bold', fontSize: '13px' }}>{item.app_name}</div>
+                  <div className="launchpad-card-text">
+                    <div className="launchpad-card-title">{item.app_name}</div>
                     {loginLoading[item.app_id] && (
-                      <div style={{ fontSize: '11px', color: '#888', marginTop: '2px' }}>
+                      <div className="launchpad-card-loading">
                         {recentLoadingText(item)}
                       </div>
                     )}
@@ -509,49 +436,32 @@ const AppMappingList: React.FC<AppMappingListProps> = ({ token, currentUserId })
       <div
         ref={scrollContainerRef}
         onScroll={handleScroll}
-        style={
-          {
-            flex: 1,
-            minHeight: 0,
-            overflowY: 'auto',
-            WebkitAppRegion: 'no-drag',
-          } as React.CSSProperties
-        }
+        className="launchpad-scroll"
       >
         {/* 下拉刷新提示 */}
         {isRefreshing && (
-          <div style={{ textAlign: 'center', padding: '20px', color: '#999' }}>
+          <div className="launchpad-tip">
             正在刷新...
           </div>
         )}
 
         {/* 错误提示 */}
         {error && (
-          <div style={{ textAlign: 'center', padding: '20px', color: '#f44336' }}>
+          <div className="launchpad-tip launchpad-tip--error">
             {error}
           </div>
         )}
 
         {showCategory ? (
           categorizedApps.map((group) => (
-            <div key={group.categoryId ?? 'uncategorized'} style={{ marginBottom: '28px' }}>
-              <div style={{
-                fontSize: '15px',
-                fontWeight: 'bold',
-                color: '#333',
-                marginBottom: '12px',
-                paddingBottom: '8px',
-                borderBottom: '1px solid #eee',
-                display: 'flex',
-                alignItems: 'center',
-                gap: '8px',
-              }}>
+            <div key={group.categoryId ?? 'uncategorized'} className="launchpad-section">
+              <div className="launchpad-section-title">
                 {group.categoryName}
-                <span style={{ fontSize: '12px', color: '#999', fontWeight: '400' }}>
+                <span className="launchpad-section-count">
                   ({group.apps.length})
                 </span>
               </div>
-              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(240px, 1fr))', gap: '20px' }}>
+              <div className="launchpad-grid">
                 {group.apps.map((mapping) => {
                   const rowBusy = !canOpenLaunch(mapping) || loginLoading[mapping.app_id]
                   return (
@@ -576,10 +486,10 @@ const AppMappingList: React.FC<AppMappingListProps> = ({ token, currentUserId })
                         sizePx={52}
                         extraStyle={{ marginRight: 10 }}
                       />
-                      <div>
-                        <div style={{ fontWeight: 'bold' }}>{mapping.app_name}</div>
+                      <div className="launchpad-card-text">
+                        <div className="launchpad-card-title">{mapping.app_name}</div>
                         {loginLoading[mapping.app_id] && (
-                          <div style={{ fontSize: '12px', color: '#888', marginTop: '4px' }}>
+                          <div className="launchpad-card-loading">
                             {launchLoadingLabel(mapping.protocol_type)}
                           </div>
                         )}
@@ -591,7 +501,7 @@ const AppMappingList: React.FC<AppMappingListProps> = ({ token, currentUserId })
             </div>
           ))
         ) : (
-          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(240px, 1fr))', gap: '20px' }}>
+          <div className="launchpad-grid">
             {displayedMappings.map((mapping) => {
               const rowBusy = !canOpenLaunch(mapping) || loginLoading[mapping.app_id]
               return (
@@ -616,10 +526,10 @@ const AppMappingList: React.FC<AppMappingListProps> = ({ token, currentUserId })
                     sizePx={52}
                     extraStyle={{ marginRight: 10 }}
                   />
-                  <div>
-                    <div style={{ fontWeight: 'bold' }}>{mapping.app_name}</div>
+                  <div className="launchpad-card-text">
+                    <div className="launchpad-card-title">{mapping.app_name}</div>
                     {loginLoading[mapping.app_id] && (
-                      <div style={{ fontSize: '12px', color: '#888', marginTop: '4px' }}>
+                      <div className="launchpad-card-loading">
                         {launchLoadingLabel(mapping.protocol_type)}
                       </div>
                     )}
@@ -632,9 +542,9 @@ const AppMappingList: React.FC<AppMappingListProps> = ({ token, currentUserId })
 
         {/* 空状态 */}
         {!isLoading && displayedMappings.length === 0 && !error && (
-          <div style={{ textAlign: 'center', padding: '60px 20px', color: '#999' }}>
-            <div style={{ fontSize: '64px', marginBottom: '16px', opacity: 0.5 }}>📱</div>
-            <div style={{ fontSize: '16px' }}>{searchKeyword.trim() ? '未找到匹配的应用' : '暂无应用'}</div>
+          <div className="launchpad-empty">
+            <div className="launchpad-empty-icon">📱</div>
+            <div className="launchpad-empty-text">{searchKeyword.trim() ? '未找到匹配的应用' : '暂无应用'}</div>
           </div>
         )}
       </div>

+ 62 - 69
src/renderer/src/components/ContactList.css

@@ -2,175 +2,169 @@
   display: flex;
   flex-direction: column;
   height: 100%;
-  background-color: #ffffff;
-  /* 确保可以滚动 */
+  background-color: var(--im-panel);
   overflow: hidden;
   position: relative;
 }
 
-/* 搜索框 */
 .contact-search-box {
-  padding: 20px 10px 10px 10px;
-  background-color: #f7f7f7;
-  border-bottom: 1px solid #e7e7e7;
+  height: var(--im-topbar-height);
+  padding: 20px 12px 12px;
+  background-color: var(--im-panel-muted);
+  border-bottom: 1px solid var(--im-border);
 }
 
 .search-input-wrapper {
   position: relative;
   display: flex;
   align-items: center;
-  background-color: #e2e2e2;
-  border: none;
-  border-radius: 4px;
-  padding: 6px 8px;
-  transition: border-color 0.2s;
+  background-color: var(--im-surface);
+  border: 1px solid var(--im-border);
+  border-radius: var(--im-radius);
+  padding: 9px 11px;
+  box-shadow: var(--im-shadow-sm);
+  transition: border-color 0.18s ease, box-shadow 0.18s ease, background-color 0.18s ease;
 }
 
 .search-input-wrapper:focus-within {
-  border: none;
+  border-color: rgba(37, 99, 235, 0.45);
+  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.08);
+  background-color: #ffffff;
 }
 
 .search-icon {
-  color: #666;
-  margin-right: 5px;
-  font-size: 12px;
+  color: var(--im-text-subtle);
+  margin-right: 8px;
+  font-size: 15px;
 }
 
 .search-input {
   flex: 1;
+  min-width: 0;
   border: none;
   outline: none;
-  font-size: 12px;
-  color: #666;
+  font-size: 13px;
+  line-height: 18px;
+  font-weight: 400;
+  letter-spacing: 0;
+  color: var(--im-text);
   background: transparent;
 }
 
 .search-input::placeholder {
-  color: #666;
+  color: var(--im-text-muted);
+  opacity: 1;
 }
 
 .search-clear-btn {
-  background: none;
+  background: transparent;
   border: none;
-  color: #909399;
-  font-size: 20px;
+  color: var(--im-text-subtle);
+  font-size: 18px;
   cursor: pointer;
   padding: 0;
   margin-left: 8px;
-  width: 20px;
-  height: 20px;
+  width: 22px;
+  height: 22px;
+  border-radius: 50%;
   display: flex;
   align-items: center;
   justify-content: center;
-  transition: color 0.2s;
+  transition: color 0.18s ease, background-color 0.18s ease;
 }
 
 .search-clear-btn:hover {
-  color: #303133;
+  color: var(--im-text);
+  background-color: #eef2f7;
 }
 
-/* 联系人列表 */
 .contact-list {
   flex: 1;
   overflow-y: auto !important;
   overflow-x: hidden;
-  padding: 8px 0;
+  padding: 6px 0;
   -webkit-overflow-scrolling: touch;
-  /* 确保可以滚动 */
   min-height: 0;
-  /* 确保可以交互 */
   pointer-events: auto;
   touch-action: pan-y;
 }
 
-/* 刷新提示 */
-.refresh-tip {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  padding: 16px;
-  color: #909399;
-  font-size: 14px;
-  gap: 8px;
-}
-
-/* 加载更多提示 */
+.refresh-tip,
 .load-more-tip {
   display: flex;
   align-items: center;
   justify-content: center;
   padding: 16px;
-  color: #909399;
-  font-size: 14px;
+  color: var(--im-text-muted);
+  font-size: 13px;
   gap: 8px;
 }
 
-/* 没有更多提示 */
 .no-more-tip {
   text-align: center;
   padding: 16px;
-  color: #c0c4cc;
-  font-size: 13px;
+  color: var(--im-text-subtle);
+  font-size: 12px;
 }
 
-/* 错误提示 */
 .error-tip {
   text-align: center;
   padding: 16px;
-  color: #f56c6c;
-  font-size: 14px;
+  color: var(--im-danger);
+  font-size: 13px;
 }
 
-/* 空状态 */
 .empty-state {
   display: flex;
   flex-direction: column;
   align-items: center;
   justify-content: center;
   padding: 60px 20px;
-  color: #909399;
+  color: var(--im-text-muted);
 }
 
 .empty-icon {
-  font-size: 60px;
-  margin-bottom: 16px;
-  opacity: 0.3;
+  font-size: 56px;
+  margin-bottom: 14px;
+  opacity: 0.22;
 }
 
 .empty-text {
-  font-size: 14px;
-  color: #c0c4cc;
+  font-size: 13px;
+  color: var(--im-text-subtle);
 }
 
-/* 联系人项 */
 .contact-item {
   display: flex;
   align-items: center;
-  padding: 12px 16px;
+  min-height: 64px;
+  padding: 10px 14px;
   cursor: pointer;
-  transition: background-color 0.2s;
-  border-bottom: 1px solid #f5f7fa;
+  transition: background-color 0.18s ease;
+  border-bottom: 1px solid var(--im-border);
+  background-color: var(--im-panel);
 }
 
 .contact-item:hover {
-  background-color: #f5f7fa;
+  background-color: var(--im-panel-muted);
 }
 
 .contact-item:active {
-  background-color: #e4e7ed;
+  background-color: #eef4ff;
 }
 
 .contact-avatar {
   margin-right: 12px;
-  color: #909399;
+  color: var(--im-text-subtle);
   display: flex;
   align-items: center;
   justify-content: center;
-  flex-shrink: 0; /* 防止头像被压缩 */
+  flex-shrink: 0;
   width: 40px;
   height: 40px;
   border-radius: 50%;
   overflow: hidden;
+  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.9);
 }
 
 .contact-info {
@@ -183,20 +177,19 @@
 
 .contact-name {
   font-size: 14px;
-  color: #000;
-  font-weight: 500;
+  color: var(--im-text);
+  font-weight: 600;
   overflow: hidden;
   text-overflow: ellipsis;
   white-space: nowrap;
   line-height: 1.5;
 }
 
-/* 加载动画 */
 .loading-spinner {
   width: 16px;
   height: 16px;
-  border: 2px solid #e4e7ed;
-  border-top-color: #409eff;
+  border: 2px solid #dbe4f0;
+  border-top-color: var(--im-info);
   border-radius: 50%;
   animation: spin 0.8s linear infinite;
 }

+ 387 - 79
src/renderer/src/index.css

@@ -1,10 +1,46 @@
+:root {
+  --im-bg: #f6f8fb;
+  --im-panel: #ffffff;
+  --im-panel-muted: #f8fafc;
+  --im-surface: #ffffff;
+  --im-sidebar: #202733;
+  --im-sidebar-hover: rgba(255, 255, 255, 0.08);
+  --im-sidebar-active: rgba(36, 193, 115, 0.16);
+  --im-border: #e5eaf0;
+  --im-border-strong: #d8dee8;
+  --im-text: #1f2937;
+  --im-text-muted: #64748b;
+  --im-text-subtle: #94a3b8;
+  --im-brand: #20b86f;
+  --im-brand-hover: #18a764;
+  --im-brand-soft: #e7f8ef;
+  --im-info: #2563eb;
+  --im-info-soft: #eef4ff;
+  --im-danger: #ef4444;
+  --im-radius: 8px;
+  --im-radius-sm: 6px;
+  --im-shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.06);
+  --im-shadow-md: 0 8px 24px rgba(15, 23, 42, 0.08);
+  --im-topbar-height: 72px;
+}
+
+* {
+  box-sizing: border-box;
+}
+
 body {
   margin: 0;
   font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
-  background-color: #f5f5f5;
+  background-color: var(--im-bg);
+  color: var(--im-text);
   height: 100vh;
   overflow: hidden;
-  user-select: none; /* 防止意外选中文本 */
+  user-select: none;
+}
+
+button,
+input {
+  font: inherit;
 }
 
 #root {
@@ -12,79 +48,93 @@ body {
   display: flex;
 }
 
-/* --- 新增布局样式 --- */
 .app-container {
   display: flex;
   width: 100vw;
   height: 100vh;
   overflow: hidden;
+  background: var(--im-bg);
 }
 
-/* 1. 最左侧主导航栏 */
 .main-nav {
   width: 60px;
-  background-color: #2e2e2e;
+  background: linear-gradient(180deg, #202733 0%, #1d2430 100%);
+  border-right: 1px solid rgba(255, 255, 255, 0.06);
   display: flex;
   flex-direction: column;
   align-items: center;
-  padding-top: 30px;
-  padding-bottom: 20px;
-  -webkit-app-region: drag; /* 允许拖动窗口 */
+  padding-top: 28px;
+  padding-bottom: 22px;
+  -webkit-app-region: drag;
 }
 
 .nav-avatar {
-  width: 36px;
-  height: 36px;
+  width: 40px;
+  height: 40px;
   border-radius: 50%;
   overflow: hidden;
-  margin-bottom: 30px;
+  margin-bottom: 28px;
   cursor: pointer;
   -webkit-app-region: no-drag;
   display: flex;
   align-items: center;
   justify-content: center;
+  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.08);
 }
 
 .nav-icon {
-  width: 36px;
-  height: 36px;
-  margin-bottom: 20px;
+  width: 40px;
+  height: 40px;
+  margin-bottom: 14px;
   display: flex;
   align-items: center;
   justify-content: center;
   font-size: 20px;
-  color: #979797;
+  color: #9aa6b8;
   cursor: pointer;
-  border-radius: 4px;
+  border-radius: 50%;
   position: relative;
   -webkit-app-region: no-drag;
-  transition: color 0.2s;
+  transition: background-color 0.18s ease, color 0.18s ease, transform 0.18s ease;
 }
 
 .nav-icon:hover {
-  color: #d6d6d6;
+  background-color: var(--im-sidebar-hover);
+  color: #ffffff;
 }
 
 .nav-icon.active {
-  color: #07c160; /* 微信绿 */
+  background-color: var(--im-sidebar-active);
+  color: var(--im-brand);
+}
+
+.nav-icon.active::before {
+  content: '';
+  position: absolute;
+  left: -10px;
+  width: 3px;
+  height: 18px;
+  border-radius: 99px;
+  background-color: var(--im-brand);
 }
 
 .nav-icon .badge {
   position: absolute;
-  top: -5px;
-  right: -5px;
-  background-color: #ff3b30;
-  color: white;
-  border-radius: 10px;
-  padding: 0 4px;
+  top: 1px;
+  right: 1px;
+  background-color: var(--im-danger);
+  color: #ffffff;
+  border: 2px solid var(--im-sidebar);
+  border-radius: 999px;
+  padding: 0 5px;
   font-size: 10px;
-  min-width: 14px;
-  height: 14px;
+  min-width: 18px;
+  height: 18px;
   line-height: 14px;
   text-align: center;
+  font-weight: 600;
 }
 
-/* 底部设置图标 */
 .nav-bottom {
   margin-top: auto;
   display: flex;
@@ -93,26 +143,33 @@ body {
   -webkit-app-region: no-drag;
 }
 
-/* 2. 中间列表栏 */
 .list-panel {
   width: 250px;
-  background-color: #e6e6e6;
-  border-right: 1px solid #d6d6d6;
+  background-color: var(--im-panel);
+  border-right: 1px solid var(--im-border);
+  display: flex;
+  flex-direction: column;
+}
+
+.content-panel {
+  flex: 1;
   display: flex;
   flex-direction: column;
+  background-color: var(--im-bg);
+  min-width: 0;
+  overflow: hidden;
 }
 
-/* 搜索框美化 */
 .search-bar {
-  padding: 20px 10px 10px 10px;
-  background-color: #f7f7f7;
-  border-bottom: 1px solid #e7e7e7;
+  height: var(--im-topbar-height);
+  padding: 20px 12px 12px;
+  background-color: var(--im-panel-muted);
+  border-bottom: 1px solid var(--im-border);
 }
 
-/* 自定义滚动条 */
 ::-webkit-scrollbar {
-  width: 6px;
-  height: 6px;
+  width: 8px;
+  height: 8px;
 }
 
 ::-webkit-scrollbar-track {
@@ -120,15 +177,18 @@ body {
 }
 
 ::-webkit-scrollbar-thumb {
-  background: #c1c1c1;
-  border-radius: 3px;
+  background: #cbd5e1;
+  border: 2px solid transparent;
+  border-radius: 999px;
+  background-clip: content-box;
 }
 
 ::-webkit-scrollbar-thumb:hover {
-  background: #a8a8a8;
+  background: #94a3b8;
+  border: 2px solid transparent;
+  background-clip: content-box;
 }
 
-/* 消息气泡箭头 - 顶部对齐以对准头像(像微信一样) */
 .bubble-self::after {
   content: '';
   position: absolute;
@@ -153,86 +213,334 @@ body {
   border-color: transparent #ffffff transparent transparent;
 }
 
-/* 图片和视频消息的气泡箭头 - 顶部对齐以对准头像(像微信一样) */
-.bubble-self.bubble-media::after {
-  top: 0;
-}
-
+.bubble-self.bubble-media::after,
 .bubble-other.bubble-media::after {
   top: 0;
 }
 
-/* 确保图片和视频消息的气泡容器能够正确计算高度 */
 .bubble-media {
   display: inline-block;
 }
 
-/* 工具栏图标悬停效果 */
 .toolbar-icon {
+  box-sizing: content-box;
+  width: 24px;
+  height: 24px;
   cursor: pointer;
-  padding: 4px;
-  border-radius: 4px;
-  transition: background-color 0.2s;
-  font-size: 20px;
-  color: #666;
+  padding: 7px;
+  border-radius: var(--im-radius-sm);
+  transition: background-color 0.18s ease, color 0.18s ease;
+  font-size: 24px;
+  color: var(--im-text-muted);
 }
 
 .toolbar-icon:hover {
-  background-color: #e0e0e0;
+  background-color: var(--im-info-soft);
+  color: var(--im-info);
 }
 
-/* 联系人列表项悬停/选中效果 */
 .contact-item:hover {
-  background-color: #d9d8d8 !important;
+  background-color: var(--im-panel-muted) !important;
 }
 
 .contact-item.active {
-  background-color: #c6c6c6 !important;
+  background-color: var(--im-brand-soft) !important;
 }
 
-/* 模拟右键菜单 */
 .context-menu {
   position: fixed;
-  background: white;
-  border: 1px solid #ccc;
-  box-shadow: 2px 2px 5px rgba(0,0,0,0.2);
+  background: var(--im-panel);
+  border: 1px solid var(--im-border);
+  box-shadow: var(--im-shadow-md);
   z-index: 1000;
-  border-radius: 4px;
-  padding: 5px 0;
+  border-radius: var(--im-radius);
+  padding: 6px;
   min-width: 120px;
 }
 
 .context-menu-item {
-  padding: 8px 15px;
+  padding: 8px 12px;
   cursor: pointer;
   font-size: 14px;
-  color: #333;
+  color: var(--im-text);
+  border-radius: var(--im-radius-sm);
 }
 
 .context-menu-item:hover {
-  background-color: #f0f0f0;
+  background-color: var(--im-panel-muted);
 }
 
-/* 浏览器导航卡片 */
 .browser-card {
-  padding: 10px;
-  background-color: white;
-  border-radius: 6px;
-  margin-bottom: 10px;
+  min-height: 76px;
+  padding: 14px 16px;
+  background-color: var(--im-surface);
+  border-radius: var(--im-radius);
+  margin-bottom: 0;
   cursor: pointer;
   display: flex;
   align-items: center;
-  transition: background-color 0.2s;
-  border: 1px solid #e0e0e0;
+  border: 1px solid var(--im-border);
+  box-shadow: var(--im-shadow-sm);
+  transition: border-color 0.18s ease, box-shadow 0.18s ease, transform 0.18s ease, background-color 0.18s ease;
 }
 
 .browser-card:hover {
-  background-color: #f0f0f0;
-  border-color: #d0d0d0;
+  background-color: #ffffff;
+  border-color: #cbd5e1;
+  box-shadow: 0 10px 24px rgba(15, 23, 42, 0.08);
+  transform: translateY(-1px);
+}
+
+.browser-card.disabled,
+.browser-card.disabled:hover {
+  transform: none;
+  box-shadow: var(--im-shadow-sm);
 }
 
-/* 最近打开小卡片:一行 5 个 */
 .browser-card--recent {
-  padding: 6px 8px;
-  margin-bottom: 0;
+  min-height: 58px;
+  padding: 10px 12px;
+}
+
+.app-page-title {
+  margin: 0;
+  color: var(--im-text);
+  font-size: 28px;
+  line-height: 1.25;
+  font-weight: 700;
+  letter-spacing: 0;
+}
+
+.launchpad-page {
+  flex: 1;
+  min-height: 0;
+  padding: 36px 40px 32px;
+  overflow: hidden;
+  display: flex;
+  flex-direction: column;
+  background: var(--im-bg);
+}
+
+.launchpad-fixed {
+  flex-shrink: 0;
+}
+
+.launchpad-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 26px;
+}
+
+.launchpad-actions {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  -webkit-app-region: no-drag;
+}
+
+.launchpad-action-button {
+  height: 38px;
+  border-radius: var(--im-radius);
+  border: 1px solid var(--im-border);
+  background-color: var(--im-surface);
+  color: var(--im-text-muted);
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  box-shadow: var(--im-shadow-sm);
+  transition: border-color 0.18s ease, background-color 0.18s ease, color 0.18s ease, box-shadow 0.18s ease;
+}
+
+.launchpad-action-button:hover {
+  border-color: #cbd5e1;
+  background-color: #ffffff;
+  color: var(--im-info);
+}
+
+.launchpad-action-button.is-active {
+  border-color: rgba(37, 99, 235, 0.25);
+  background-color: var(--im-info-soft);
+  color: var(--im-info);
+}
+
+.launchpad-action-button--icon {
+  width: 38px;
+  padding: 0;
+}
+
+.launchpad-action-button--text {
+  gap: 7px;
+  padding: 0 14px;
+  font-size: 13px;
+  font-weight: 600;
+}
+
+.launchpad-search-block {
+  margin-bottom: 22px;
+}
+
+.launchpad-search-field {
+  position: relative;
+  display: flex;
+  align-items: center;
+  background-color: var(--im-surface);
+  border-radius: var(--im-radius);
+  padding: 12px 14px;
+  border: 1px solid var(--im-border);
+  box-shadow: var(--im-shadow-sm);
+  transition: border-color 0.18s ease, box-shadow 0.18s ease;
+}
+
+.launchpad-search-field:focus-within {
+  border-color: rgba(37, 99, 235, 0.45);
+  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.08);
+}
+
+.launchpad-search-field svg {
+  color: var(--im-text-subtle);
+  margin-right: 10px;
+  font-size: 17px;
+}
+
+.launchpad-search-field input {
+  flex: 1;
+  min-width: 0;
+  border: none;
+  outline: none;
+  font-size: 14px;
+  color: var(--im-text);
+  background: transparent;
+}
+
+.launchpad-search-field input::placeholder {
+  color: var(--im-text-subtle);
+}
+
+.launchpad-clear-button {
+  background: transparent;
+  border: none;
+  color: var(--im-text-subtle);
+  cursor: pointer;
+  font-size: 18px;
+  padding: 0;
+  width: 24px;
+  height: 24px;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  transition: color 0.18s ease, background-color 0.18s ease;
+}
+
+.launchpad-clear-button:hover {
+  color: var(--im-text);
+  background-color: #eef2f7;
+}
+
+.launchpad-section {
+  margin-bottom: 28px;
+}
+
+.launchpad-section--recent {
+  margin-bottom: 26px;
+  padding-bottom: 24px;
+  border-bottom: 1px solid var(--im-border);
+}
+
+.launchpad-section-title {
+  font-size: 15px;
+  font-weight: 700;
+  color: var(--im-text);
+  margin-bottom: 14px;
+  padding-bottom: 10px;
+  border-bottom: 1px solid var(--im-border);
+  display: flex;
+  align-items: center;
+  gap: 8px;
+}
+
+.launchpad-section-count {
+  font-size: 12px;
+  color: var(--im-text-subtle);
+  font-weight: 500;
+}
+
+.launchpad-recent-grid {
+  display: grid;
+  grid-template-columns: repeat(5, minmax(0, 1fr));
+  gap: 12px;
+}
+
+.launchpad-grid {
+  display: grid;
+  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
+  gap: 18px;
+}
+
+.launchpad-scroll {
+  flex: 1;
+  min-height: 0;
+  overflow-y: auto;
+  padding-right: 6px;
+  -webkit-app-region: no-drag;
+}
+
+.launchpad-card-text {
+  min-width: 0;
+}
+
+.launchpad-card-title {
+  color: var(--im-text);
+  font-weight: 700;
+  font-size: 15px;
+  line-height: 1.35;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+}
+
+.browser-card--recent .launchpad-card-title {
+  font-size: 13px;
+  -webkit-line-clamp: 1;
+}
+
+.launchpad-card-loading {
+  font-size: 12px;
+  color: var(--im-text-muted);
+  margin-top: 4px;
+}
+
+.browser-card--recent .launchpad-card-loading {
+  font-size: 11px;
+  margin-top: 2px;
+}
+
+.launchpad-tip {
+  text-align: center;
+  padding: 20px;
+  color: var(--im-text-subtle);
+}
+
+.launchpad-tip--error {
+  color: var(--im-danger);
+}
+
+.launchpad-empty {
+  text-align: center;
+  padding: 60px 20px;
+  color: var(--im-text-subtle);
+}
+
+.launchpad-empty-icon {
+  font-size: 60px;
+  margin-bottom: 14px;
+  opacity: 0.32;
+}
+
+.launchpad-empty-text {
+  font-size: 15px;
 }

+ 2 - 2
src/renderer/src/pages/ChatPage.tsx

@@ -256,9 +256,9 @@ export const ChatPage: React.FC<ChatPageProps> = ({
       onDragOver={handleChatDragOver}
       onDrop={handleChatDrop}
     >
-      <div style={{ padding: '0 20px', height: '60px', display: 'flex', alignItems: 'center', borderBottom: '1px solid #e7e7e7', WebkitAppRegion: 'drag' } as React.CSSProperties}>
+      <div style={{ padding: '0 24px', height: 'var(--im-topbar-height)', display: 'flex', alignItems: 'center', borderBottom: '1px solid var(--im-border)', backgroundColor: 'var(--im-panel)', WebkitAppRegion: 'drag' } as React.CSSProperties}>
         <div style={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap', WebkitAppRegion: 'no-drag' } as React.CSSProperties}>
-          <span style={{ fontWeight: 'bold', fontSize: '16px' }}>
+          <span style={{ fontWeight: '700', fontSize: '16px', color: 'var(--im-text)' }}>
             {activeContact.name}
           </span>
           {headerRemark && (