diff --git a/src/pages/Kernel.tsx b/src/pages/Kernel.tsx index 54b28df..c05bc59 100644 --- a/src/pages/Kernel.tsx +++ b/src/pages/Kernel.tsx @@ -2,7 +2,23 @@ import { useEffect, useRef, useState } from 'react'; import { getVersion } from '@tauri-apps/api/app'; import { invoke } from '@tauri-apps/api/core'; import { listen } from '@tauri-apps/api/event'; -import { AlertCircle, Check, Copy, ExternalLink, Eye, EyeOff, Info } from 'lucide-react'; +import { + AlertCircle, + AppWindow, + ArrowRight, + Box, + Check, + Copy, + Database, + Download, + ExternalLink, + Eye, + EyeOff, + Info, + PackageOpen, + RefreshCw, + RotateCcw, +} from 'lucide-react'; import { type CoreStatus, useCoreRuntime } from '../coreRuntime'; import openaiIcon from '../assets/icons/openai-light.svg'; import claudeIcon from '../assets/icons/claude.svg'; @@ -668,6 +684,22 @@ export function KernelPage({ view = 'home' }: { view?: KernelView }) { const currentAppVersion = resolvedAppVersion ? displayAppVersion(resolvedAppVersion) : t('common.detecting'); + const appVersionStatusLabel = appUpdateTask.running + ? t(`appUpdate.phase.${appUpdateTask.phase}` as Parameters[0]) + : appUpdateError + ? t('kernel.update.failed') + : appUpdate?.updateAvailable + ? t('appUpdate.available', { version: displayAppVersion(appUpdate.latestVersion) }) + : appUpdate + ? t('appUpdate.upToDate') + : t('appUpdate.phase.checking'); + const appVersionStatusTone = appUpdateError + ? 'error' + : appUpdate?.updateAvailable + ? 'update' + : appUpdate + ? 'success' + : ''; const latestLabel = checkingLatest ? t('kernel.update.checking') : latestVersion || (latestError ? t('kernel.update.failed') : t('kernel.update.notChecked')); @@ -746,6 +778,51 @@ export function KernelPage({ view = 'home' }: { view?: KernelView }) { return (
+ {view === 'versions' ? ( +
+
+ +
+

{t('app.nav.versions')}

+

{t('kernel.versions.offlineHint')}

+
+
+ +
+
+
+ + {versionSourceError ?

{versionSourceError}

: null} +
+
+ ) : null} +
{view === 'home' ? (
@@ -822,85 +899,36 @@ export function KernelPage({ view = 'home' }: { view?: KernelView }) { ) : null} {view === 'versions' ? ( -
-
-
+ ) : null} {view === 'versions' ? ( -
-
-
-

{t('kernel.versions.title')}

- - {t('kernel.versions.offlineHint')} +
+
+
+ +

{t('kernel.versions.title')}

+
+ + {versionStatusLabel} + +
+ +
+
+ {t('kernel.versions.current')} + {currentVersion || t('kernel.status.notInstalled')} +
+
+ {t('kernel.versions.latest')} + {latestLabel} +
+
+ {t('kernel.versions.bundled')} + + {bundledCore?.version ?? (bundledCoreError ? t('common.detectionFailed') : t('kernel.versions.notIncluded'))} +
-
-
-
{t('kernel.versions.current')}
-
{currentVersion || t('kernel.status.notInstalled')}
+
+
+
+ + + ) : null}
diff --git a/src/styles.css b/src/styles.css index 33de52b..5ba5b39 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1011,6 +1011,69 @@ textarea:focus-visible { gap: 18px; } +.version-management-page { + gap: 20px; +} + +.version-page-header { + display: grid; + grid-template-columns: minmax(0, 1fr); + align-items: center; + gap: 24px; + min-width: 0; + padding: 22px 24px; + border: 1px solid var(--theme-e3e1db); + border-radius: 14px; + background: + linear-gradient(135deg, color-mix(in srgb, var(--ui-accent-soft) 62%, transparent), transparent 48%), + var(--theme-fffdf8); + box-shadow: var(--ui-panel-shadow); +} + +.version-page-title { + display: flex; + min-width: 0; + align-items: center; + gap: 14px; +} + +.version-page-title-icon, +.version-product-icon { + display: grid; + flex: none; + place-items: center; + color: var(--ui-accent-strong); + background: var(--ui-accent-soft); +} + +.version-page-title-icon { + width: 46px; + height: 46px; + border: 1px solid color-mix(in srgb, var(--ui-accent) 22%, transparent); + border-radius: 13px; +} + +.version-page-title > div { + min-width: 0; +} + +.version-page-title h1 { + margin: 0; + color: var(--theme-2d2a26); + font-size: 24px; + line-height: var(--line-height-tight); +} + +.version-page-title p { + margin: 5px 0 0; + overflow: hidden; + color: var(--theme-7a746c); + font-size: var(--font-size-meta); + line-height: var(--line-height-body); + text-overflow: ellipsis; + white-space: nowrap; +} + .config-subpage-panel { display: grid; min-width: 0; @@ -1025,14 +1088,16 @@ textarea:focus-visible { grid-column: auto; } -.version-source-panel { - display: flex; - min-height: 68px; - flex-wrap: wrap; +.version-source-control { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; align-items: center; - justify-content: space-between; - gap: 20px; - padding-block: 14px; + gap: 12px 18px; + min-width: 0; + padding: 12px 14px; + border: 1px solid color-mix(in srgb, var(--ui-accent) 17%, var(--theme-e3e1db)); + border-radius: 10px; + background: color-mix(in srgb, var(--theme-fffdf8) 82%, var(--ui-accent-soft)); } .version-source-copy { @@ -1044,6 +1109,8 @@ textarea:focus-visible { .version-source-copy > svg { flex: none; + align-self: flex-start; + margin-top: 2px; color: var(--ui-accent); } @@ -1055,45 +1122,200 @@ textarea:focus-visible { .version-source-copy strong { color: var(--theme-39352f); - font-size: var(--font-size-body); + font-size: var(--font-size-label); } .version-source-copy span { + display: -webkit-box; + overflow: hidden; color: var(--theme-7a746c); - font-size: var(--font-size-meta); - line-height: var(--line-height-body); + font-size: var(--font-size-caption); + line-height: 1.4; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; } .version-source-error { - width: 100%; + grid-column: 1 / -1; margin: 0; font-size: var(--font-size-meta); } -.version-heading-inline { +.version-product-card { + display: grid; + grid-template-rows: auto auto auto minmax(0, 1fr) auto; + align-content: start; + gap: 18px; + padding: 26px; + overflow: hidden; +} + +.version-product-heading { display: flex; min-width: 0; - align-items: baseline; - gap: 10px; + align-items: center; + justify-content: space-between; + gap: 14px; } -.version-heading-inline h2 { +.version-product-identity { + display: flex; + min-width: 0; + align-items: center; + gap: 11px; +} + +.version-product-icon { + width: 38px; + height: 38px; + border-radius: 10px; +} + +.version-product-icon.core { + color: var(--theme-554075); + background: var(--theme-f1ecfb); +} + +.version-product-identity h2 { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.version-product-heading .state-pill { + min-width: 0; + max-width: 52%; flex: none; + overflow: hidden; + text-overflow: ellipsis; } -.version-offline-hint { +.version-comparison { + display: grid; + grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); + align-items: center; + gap: 16px; + min-height: 118px; + padding: 20px; + border: 1px solid var(--theme-e3e1db); + border-radius: 12px; + background: var(--theme-f4f1ea); +} + +.version-comparison-arrow { + color: var(--theme-9a958d); +} + +.version-value-block { + display: grid; + min-width: 0; + gap: 7px; +} + +.version-value-block span { + color: var(--theme-8a847c); + font-size: var(--font-size-meta); + font-weight: 700; +} + +.version-value-block strong { min-width: 0; overflow: hidden; - color: var(--theme-8a847c); - font-size: var(--font-size-caption); - font-weight: 400; + color: var(--theme-2d2a26); + font-size: var(--font-size-metric-compact); line-height: var(--line-height-tight); text-overflow: ellipsis; white-space: nowrap; } -.kernel-layout > .version-panel > .panel-heading { - padding-bottom: 10px; +.version-value-block.latest strong { + color: var(--ui-accent-strong); +} + +.version-core-values { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + min-height: 118px; + border: 1px solid var(--theme-e3e1db); + border-radius: 12px; + background: var(--theme-f4f1ea); +} + +.version-core-values .version-value-block { + align-content: center; + padding: 18px; +} + +.version-core-values .version-value-block + .version-value-block { + border-left: 1px solid var(--theme-e3e1db); +} + +.version-core-values .version-value-block strong { + font-size: 20px; +} + +.version-card-support { + display: flex; + min-width: 0; + align-items: center; + gap: 11px; + min-height: 58px; + padding: 11px 13px; + border: 1px solid var(--theme-e3e1db); + border-radius: 10px; + background: var(--theme-faf8f2); +} + +.version-card-support > svg { + flex: none; + color: var(--theme-7a746c); +} + +.version-card-support > div { + display: grid; + min-width: 0; + gap: 2px; +} + +.version-card-support strong, +.version-card-support span { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.version-card-support strong { + color: var(--theme-39352f); + font-size: var(--font-size-meta); +} + +.version-card-support span { + color: var(--theme-7a746c); + font-size: var(--font-size-caption); +} + +.version-card-support span.success { + color: var(--theme-2f6b3f); +} + +.version-card-support span.error { + color: var(--theme-9f2d20); +} + +.version-card-note { + align-self: start; + margin: 0; + color: var(--theme-7a746c); + font-size: var(--font-size-caption); + line-height: var(--line-height-body); +} + +.version-card-note-slot { + min-height: 0; +} + +.version-card-note.error { + color: var(--theme-9f2d20); } .client-api-panel { @@ -1295,6 +1517,14 @@ textarea:focus-visible { grid-template-rows: repeat(3, auto); } +.version-management-layout > .version-product-card { + grid-template-rows: auto auto auto minmax(0, 1fr) auto; +} + +.version-management-layout > .version-product-card > .panel-action-row { + padding-top: 0; +} + .kernel-layout > .panel > .panel-heading { min-height: 0; height: auto; @@ -1399,10 +1629,10 @@ textarea:focus-visible { } .button-row.version-action-row { - grid-template-columns: repeat(4, minmax(0, 1fr)); + grid-template-columns: repeat(2, minmax(0, 1fr)); grid-auto-flow: row; grid-auto-columns: unset; - grid-auto-rows: 38px; + grid-auto-rows: 40px; align-items: stretch; gap: 10px; } @@ -1421,30 +1651,23 @@ textarea:focus-visible { white-space: normal; } -.software-update-details { - align-content: start; -} - -.software-update-details .panel-detail-row { - grid-template-columns: 120px minmax(0, 1fr); -} - -.software-update-details .panel-detail-row dt { - white-space: nowrap; -} - .software-update-actions { - grid-template-columns: repeat(auto-fit, minmax(min(120px, 100%), 1fr)); + grid-template-columns: repeat(2, minmax(0, 1fr)); grid-auto-flow: row; - grid-auto-rows: 38px; + grid-auto-rows: 40px; align-items: stretch; } +.software-update-actions > button:last-child:nth-child(3) { + grid-column: 1 / -1; +} + .software-update-actions > button, .version-action-row > button { width: 100%; - height: 38px; - min-height: 38px; + height: 40px; + min-height: 40px; + gap: 7px; padding: 0 10px; line-height: normal; overflow-wrap: normal; @@ -1452,11 +1675,11 @@ textarea:focus-visible { white-space: nowrap; } -.software-update-panel .panel-heading p { - white-space: normal; -} - @container workspace (min-width: 840px) { + .version-page-header { + grid-template-columns: minmax(260px, 0.8fr) minmax(360px, 1.2fr); + } + .home-page { grid-template-columns: minmax(320px, 0.8fr) minmax(0, 1.2fr); grid-auto-rows: 1fr; @@ -1502,45 +1725,58 @@ textarea:focus-visible { .version-management-layout { grid-template-columns: repeat(2, minmax(0, 1fr)); - grid-template-rows: auto minmax(0, 1fr); align-items: stretch; } - .version-management-layout > .version-source-panel { - grid-column: 1 / -1; - grid-row: 1; - } - .version-management-layout > .panel { height: 100%; align-self: stretch; - grid-template-rows: auto minmax(0, 1fr) auto; - row-gap: clamp(12px, 2vh, 22px); - } - - .version-management-layout > .version-source-panel { - height: auto; - grid-template-rows: none; - row-gap: 8px; - } - - .version-management-layout > .software-update-panel, - .version-management-layout > .version-panel { - grid-row: 2; } .home-page > .home-layout > .control-panel > .panel-detail-grid, - .version-management-layout > .panel > .panel-detail-grid, .home-page > .client-api-panel > .client-api-grid { align-content: space-evenly; } - .home-page > .home-layout > .control-panel > .panel-action-row, - .version-management-layout > .panel > .panel-action-row { + .home-page > .home-layout > .control-panel > .panel-action-row { padding-top: 0; } } +@container workspace (max-width: 700px) { + .version-page-header { + gap: 18px; + } + + .version-page-title p { + overflow: visible; + text-overflow: clip; + white-space: normal; + } + + .version-product-heading { + align-items: flex-start; + flex-direction: column; + } + + .version-product-heading .state-pill { + max-width: 100%; + } + + .version-core-values { + grid-template-columns: minmax(0, 1fr); + } + + .version-core-values .version-value-block { + padding: 14px 18px; + } + + .version-core-values .version-value-block + .version-value-block { + border-top: 1px solid var(--theme-e3e1db); + border-left: 0; + } +} + .info-list { display: grid; gap: 10px;