diff --git a/landing/components/registry/RegistryRestore.vue b/landing/components/registry/RegistryRestore.vue index 2066b17e0..61978cdfb 100644 --- a/landing/components/registry/RegistryRestore.vue +++ b/landing/components/registry/RegistryRestore.vue @@ -10,14 +10,8 @@ const { t } = useI18n(); dir="auto" >
{{ t('shell.restore.eyebrow') }}
+{{ t('shell.restore.intro') }}
-- {{ t('shell.restore.availability') }} - {{ t('shell.restore.releaseNote') }} -
{{ t('shell.restore.guide') }} ++ + {{ t('shell.restore.from') }} +
+uap.toml
+
+
+
+ uap.lock
+
+ uap.toml
+ uap.lock
+ + + {{ t('shell.restore.to') }} +
+uap.toml
- uap.lock
- {{ t('shell.restore.directory') }}
-{{ t('shell.restore.requirements') }} {{ t('shell.restore.excludes') }}
@@ -53,87 +88,276 @@ const { t } = useI18n(); padding-block: 32px 48px; &__panel { - display: grid; - grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); - gap: 24px 40px; + position: relative; padding: clamp(20px, 4vw, 36px); border: 1px solid var(--line-strong); border-radius: 16px; background: var(--surface); + overflow: hidden; + + &::before { + content: ''; + position: absolute; + inset-inline: 0; + top: 0; + height: 2px; + background: linear-gradient(90deg, var(--cyan), var(--primary-bright)); + opacity: 0.8; + } + } + + &__header { + display: flex; + flex-wrap: wrap; + align-items: baseline; + justify-content: space-between; + gap: 14px 24px; + margin-block-end: 26px; } h2 { - margin-block: 8px 12px; + margin: 0; font-size: clamp(1.5rem, 3vw, 2rem); line-height: 1.2; letter-spacing: -0.035em; text-wrap: balance; } - p { - margin-block: 0 14px; - color: var(--muted); + &__guide { + color: var(--primary-bright); font-size: 0.9rem; - line-height: 1.65; + text-decoration: underline; + text-underline-offset: 3px; } - .eyebrow { - color: var(--cyan); + &__flow { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(220px, 250px) minmax(0, 1fr); + align-items: stretch; + gap: 16px; + padding-block-end: 30px; } - &__availability { - display: grid; - gap: 6px; + &__machine { + position: relative; + min-width: 0; + padding: 12px 12px 26px; + border: 1px solid var(--line-strong); + border-radius: 18px; + background: var(--surface-raised); + box-shadow: 0 12px 28px color-mix(in srgb, var(--text) 9%, transparent); - strong { - width: fit-content; - padding: 3px 9px; - border: 1px solid var(--line-strong); - border-radius: 6px; - color: var(--text); - background: var(--surface-raised); - font-size: 0.8rem; + &::before { + content: ''; + position: absolute; + top: 5px; + left: 50%; + translate: -50% 0; + width: 4px; + height: 4px; + border-radius: 50%; + background: var(--line-strong); + } + + &::after { + content: ''; + position: absolute; + bottom: 9px; + left: 50%; + translate: -50% 0; + width: 5px; + height: 5px; + border-radius: 50%; + background: var(--cyan); + box-shadow: 0 0 8px color-mix(in srgb, var(--cyan) 75%, transparent); } } - &__guide { - color: var(--primary-bright); - font-size: 0.9rem; - text-decoration: underline; - text-underline-offset: 3px; + &__screen { + // A monitor screen keeps the dark display palette in every theme. + --surface-solid: #101522; + --surface-raised: #172033; + --text: #e0e6ff; + --muted: #9aa6c5; + --subtle: #7f8dac; + --line: rgba(203, 211, 255, 0.12); + --cyan: #00f0ff; + + overflow: hidden; + border-radius: 10px; + background: + linear-gradient(155deg, color-mix(in srgb, var(--cyan) 7%, transparent), transparent 48%), + var(--surface-solid); + box-shadow: + inset 0 0 0 1px var(--line), + inset 0 0 30px color-mix(in srgb, var(--cyan) 6%, transparent); } - &__steps { - min-width: 0; + &__stage-label { + display: flex; + align-items: center; + gap: 9px; + margin: 0; + padding: 9px 13px; + border-block-end: 1px solid var(--line); + background: color-mix(in srgb, var(--surface-raised) 55%, transparent); + color: var(--muted); + font-size: 0.68rem; + font-weight: 750; + letter-spacing: 0.09em; + text-transform: uppercase; + } + + &__step { + color: color-mix(in srgb, var(--text) 38%, transparent); + font-size: 1.35rem; + font-weight: 450; + letter-spacing: -0.05em; + line-height: 1; + font-variant-numeric: tabular-nums; + } - p { - margin-block: 12px; - font-size: 0.8rem; + &__screen-body { + padding: 15px 13px 17px; + + // Flat on the screen: no card chrome, just the command row. + :deep(.command-snippet.command-snippet--inline) { + border: 0; + border-radius: 0; + background: transparent; } - code { - color: var(--text); + :deep(.command-snippet__header) { + min-height: 0; + padding: 0; + border: 0; + background: transparent; + } + + :deep(.command-snippet button) { + padding: 2px 4px; + color: var(--muted); } :deep(pre) { direction: ltr; text-align: left; - overflow-wrap: anywhere; + white-space: pre-wrap; + overflow-wrap: break-word; + padding: 0; } } - .registry-restore__boundary { - grid-column: 1 / -1; - margin: 0; + &__stand { + position: absolute; + top: 100%; + left: 50%; + translate: -50% 0; + width: 92px; + height: 18px; + background: var(--line-strong); + clip-path: polygon(38% 0, 62% 0, 66% 58%, 94% 58%, 100% 100%, 0 100%, 6% 58%, 34% 58%); + } + + &__handoff { + position: relative; + display: grid; + grid-template-rows: 1fr auto 1fr; + justify-items: center; + min-width: 0; + } + + &__files { + position: absolute; + left: 50%; + bottom: calc(50% + 27px); + translate: -50% 0; + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 8px; + width: max-content; + max-width: 100%; + } + + &__file { + display: inline-flex; + align-items: center; + gap: 7px; + padding: 8px 11px; + border: 1px solid var(--line-strong); + border-radius: 10px; + background: color-mix(in srgb, var(--surface-solid) 55%, var(--surface-raised)); + font-size: 0.76rem; + + svg { + width: 13px; + height: 13px; + flex: 0 0 13px; + color: var(--primary-bright); + stroke: currentColor; + stroke-width: 1.8; + stroke-linecap: round; + stroke-linejoin: round; + } + + code { + color: var(--text); + } + } + + &__arrow { + grid-row: 2; + width: calc(100% + 32px); + margin-inline: -16px; + height: 36px; + color: var(--cyan); + stroke: currentColor; + stroke-width: 2; + stroke-linecap: round; + stroke-linejoin: round; + } + + :dir(rtl) &__arrow { + transform: scaleX(-1); + } + + &__boundary { + margin: 22px 0 0; padding-block-start: 16px; border-block-start: 1px solid var(--line); - font-size: 0.8rem; + color: var(--muted); + font-size: 0.78rem; + line-height: 1.6; } } -@media (max-width: 720px) { - .registry-restore__panel { +@media (max-width: 980px) { + .registry-restore__flow { grid-template-columns: minmax(0, 1fr); + padding-block-end: 26px; + } + + .registry-restore__handoff { + grid-template-rows: auto auto; + gap: 12px; + padding-block: 4px; + } + + .registry-restore__files { + position: static; + translate: none; + width: auto; + } + + .registry-restore__arrow, + :dir(rtl) .registry-restore__arrow { + transform: rotate(90deg); + width: 92px; + height: 36px; + // Rotation does not affect layout: reserve the full 92px visual height. + margin-block: 28px; + margin-inline: 0; } } diff --git a/landing/locales/ar.json b/landing/locales/ar.json index ee9da2f85..1ac278f39 100644 --- a/landing/locales/ar.json +++ b/landing/locales/ar.json @@ -209,16 +209,11 @@ }, "shell": { "restore": { - "eyebrow": "بيئات إضافات قابلة لإعادة الإنشاء", "title": "إصدارات الإضافات نفسها على حاسوبك القادم", - "intro": "احفظ مجموعة الإضافات العامة وتبعياتها، ثم استعد الإصدارات المسجلة بدقة على حاسوب آخر.", - "availability": "متاح في الإصدار 0.1.86", - "releaseNote": "مضمّن في إصدارات npm وHomebrew والملفات التنفيذية الأصلية بدءًا من الإصدار 0.1.86.", - "guide": "دليل الاستعادة (بالإنجليزية)", + "guide": "الدليل", "from": "على هذا الحاسوب", "to": "على حاسوبك القادم", "transfer": "انسخ {manifest} و{lockfile} إلى الحاسوب الآخر بين تنفيذ هذين الأمرين.", - "directory": "يستخدم الأمران المجلد الحالي عند عدم تحديد مجلد.", "requirements": "تتطلب الاستعادة بقاء المصادر المسجلة متاحة وعملاء تدعمهم إدارة التبعيات.", "excludes": "لا تُنقل عمليات تسجيل الدخول أو الأسرار أو الإعدادات أو بيانات الإضافات." }, diff --git a/landing/locales/en.json b/landing/locales/en.json index 34fb6e2ac..4be6ab008 100644 --- a/landing/locales/en.json +++ b/landing/locales/en.json @@ -363,16 +363,11 @@ }, "shell": { "restore": { - "eyebrow": "Reproducible plugin environments", "title": "Same plugin versions on your next machine", - "intro": "Save your global plugin set and its dependencies, then restore the exact recorded versions on another computer.", - "availability": "Available in 0.1.86", - "releaseNote": "Included in npm, Homebrew and native releases from version 0.1.86.", - "guide": "Restore guide (English)", + "guide": "Guide", "from": "On this computer", "to": "On your next computer", "transfer": "Copy {manifest} and {lockfile} to the other computer between these commands.", - "directory": "Both commands use the current directory when no directory is specified.", "requirements": "Restoration requires the recorded sources to remain available and clients supported by dependency management.", "excludes": "Sign-ins, secrets, settings and plugin data are not transferred." }, diff --git a/landing/locales/es.json b/landing/locales/es.json index 073b3a836..f280868e0 100644 --- a/landing/locales/es.json +++ b/landing/locales/es.json @@ -346,16 +346,11 @@ }, "shell": { "restore": { - "eyebrow": "Entornos de plugins reproducibles", "title": "Las mismas versiones de plugins en tu próximo equipo", - "intro": "Guarda tu conjunto global de plugins y sus dependencias, y restaura las versiones exactas registradas en otro equipo.", - "availability": "Disponible en 0.1.86", - "releaseNote": "Incluido en las versiones de npm, Homebrew y los binarios nativos a partir de la versión 0.1.86.", - "guide": "Guía de restauración (en inglés)", + "guide": "Guía", "from": "En este equipo", "to": "En tu próximo equipo", "transfer": "Copia {manifest} y {lockfile} al otro equipo entre estos comandos.", - "directory": "Si no se especifica un directorio, ambos comandos usan el directorio actual.", "requirements": "La restauración requiere que las fuentes registradas sigan disponibles y que los clientes sean compatibles con la gestión de dependencias.", "excludes": "No se transfieren sesiones, secretos, ajustes ni datos de plugins." }, diff --git a/landing/locales/fr.json b/landing/locales/fr.json index e15e6f599..46ab372ed 100644 --- a/landing/locales/fr.json +++ b/landing/locales/fr.json @@ -346,16 +346,11 @@ }, "shell": { "restore": { - "eyebrow": "Environnements de plugins reproductibles", "title": "Les mêmes versions de plugins sur votre prochain ordinateur", - "intro": "Enregistrez votre ensemble global de plugins et leurs dépendances, puis restaurez les versions exactes enregistrées sur un autre ordinateur.", - "availability": "Disponible dans la version 0.1.86", - "releaseNote": "Inclus dans les versions npm, Homebrew et les binaires natifs à partir de la version 0.1.86.", - "guide": "Guide de restauration (en anglais)", + "guide": "Guide", "from": "Sur cet ordinateur", "to": "Sur votre prochain ordinateur", "transfer": "Copiez {manifest} et {lockfile} sur l’autre ordinateur entre ces commandes.", - "directory": "Sans répertoire indiqué, les deux commandes utilisent le répertoire courant.", "requirements": "La restauration nécessite des sources enregistrées toujours disponibles et des clients compatibles avec la gestion des dépendances.", "excludes": "Les connexions aux comptes, secrets, réglages et données des plugins ne sont pas transférés." }, diff --git a/landing/locales/hi.json b/landing/locales/hi.json index 632614ced..192e320a1 100644 --- a/landing/locales/hi.json +++ b/landing/locales/hi.json @@ -346,16 +346,11 @@ }, "shell": { "restore": { - "eyebrow": "दोबारा बनाए जा सकने वाले प्लगइन परिवेश", "title": "अगले कंप्यूटर पर भी प्लगइन के वही संस्करण", - "intro": "अपने वैश्विक प्लगइन समूह और उसकी निर्भरताओं को सहेजें, फिर दूसरे कंप्यूटर पर दर्ज किए गए उन्हीं संस्करणों को बहाल करें।", - "availability": "0.1.86 में उपलब्ध", - "releaseNote": "संस्करण 0.1.86 से npm, Homebrew और नेटिव रिलीज़ में शामिल है।", - "guide": "बहाली की गाइड (अंग्रेज़ी में)", + "guide": "गाइड", "from": "इस कंप्यूटर पर", "to": "अगले कंप्यूटर पर", "transfer": "इन दोनों कमांड के बीच {manifest} और {lockfile} को दूसरे कंप्यूटर पर कॉपी करें।", - "directory": "डायरेक्टरी न देने पर दोनों कमांड वर्तमान डायरेक्टरी का उपयोग करती हैं।", "requirements": "बहाली के लिए दर्ज स्रोतों का उपलब्ध रहना और निर्भरता प्रबंधन द्वारा समर्थित क्लाइंट आवश्यक हैं।", "excludes": "साइन-इन, सीक्रेट, सेटिंग और प्लगइन डेटा स्थानांतरित नहीं होते।" }, diff --git a/landing/locales/pt.json b/landing/locales/pt.json index 0d62decb8..51b8d2799 100644 --- a/landing/locales/pt.json +++ b/landing/locales/pt.json @@ -209,16 +209,11 @@ }, "shell": { "restore": { - "eyebrow": "Ambientes de plugins reproduzíveis", "title": "As mesmas versões de plugins no seu próximo computador", - "intro": "Salve seu conjunto global de plugins e suas dependências e restaure as versões exatas registradas em outro computador.", - "availability": "Disponível na versão 0.1.86", - "releaseNote": "Incluído nas versões npm, Homebrew e nos binários nativos a partir da versão 0.1.86.", - "guide": "Guia de restauração (em inglês)", + "guide": "Guia", "from": "Neste computador", "to": "No próximo computador", "transfer": "Copie {manifest} e {lockfile} para o outro computador entre estes comandos.", - "directory": "Sem um diretório especificado, ambos os comandos usam o diretório atual.", "requirements": "A restauração exige que as fontes registradas continuem disponíveis e que os clientes sejam compatíveis com o gerenciamento de dependências.", "excludes": "Logins, segredos, configurações e dados dos plugins não são transferidos." }, diff --git a/landing/locales/ru.json b/landing/locales/ru.json index e35a790a2..9161f7318 100644 --- a/landing/locales/ru.json +++ b/landing/locales/ru.json @@ -346,16 +346,11 @@ }, "shell": { "restore": { - "eyebrow": "Воспроизводимое окружение плагинов", "title": "Те же версии плагинов на другом компьютере", - "intro": "Сохраните глобальный набор плагинов и их зависимостей, затем восстановите точно зафиксированные версии на другом компьютере.", - "availability": "Доступно в 0.1.86", - "releaseNote": "Входит в выпуски npm, Homebrew и нативные сборки начиная с версии 0.1.86.", - "guide": "Инструкция по восстановлению (на английском)", + "guide": "Инструкция", "from": "На этом компьютере", "to": "На другом компьютере", "transfer": "Между этими командами скопируйте {manifest} и {lockfile} на другой компьютер.", - "directory": "Если каталог не указан, обе команды используют текущий каталог.", "requirements": "Для восстановления нужны доступные зафиксированные источники и клиенты, поддерживаемые системой управления зависимостями.", "excludes": "Входы в аккаунты, секреты, настройки и данные плагинов не переносятся." }, diff --git a/landing/locales/uk.json b/landing/locales/uk.json index 3bad1a286..67b1d7004 100644 --- a/landing/locales/uk.json +++ b/landing/locales/uk.json @@ -346,16 +346,11 @@ }, "shell": { "restore": { - "eyebrow": "Відтворюване середовище плагінів", "title": "Ті самі версії плагінів на іншому компʼютері", - "intro": "Збережіть глобальний набір плагінів та їхніх залежностей, а потім відновіть точно зафіксовані версії на іншому компʼютері.", - "availability": "Доступно у 0.1.86", - "releaseNote": "Входить до випусків npm, Homebrew і нативних збірок починаючи з версії 0.1.86.", - "guide": "Інструкція з відновлення (англійською)", + "guide": "Інструкція", "from": "На цьому компʼютері", "to": "На іншому компʼютері", "transfer": "Між цими командами скопіюйте {manifest} і {lockfile} на інший компʼютер.", - "directory": "Якщо каталог не вказано, обидві команди використовують поточний каталог.", "requirements": "Для відновлення потрібні доступні зафіксовані джерела та клієнти, підтримувані системою керування залежностями.", "excludes": "Входи в облікові записи, секрети, налаштування та дані плагінів не переносяться." }, diff --git a/landing/locales/zh.json b/landing/locales/zh.json index 5688376e2..9aef9e280 100644 --- a/landing/locales/zh.json +++ b/landing/locales/zh.json @@ -346,16 +346,11 @@ }, "shell": { "restore": { - "eyebrow": "可复现的插件环境", "title": "在下一台电脑上使用相同的插件版本", - "intro": "保存全局插件集及其依赖,然后在另一台电脑上恢复所记录的确切版本。", - "availability": "已在 0.1.86 中发布", - "releaseNote": "自 0.1.86 版本起,已包含在 npm、Homebrew 和原生发行版中。", - "guide": "恢复指南(英文)", + "guide": "指南", "from": "在当前电脑上", "to": "在下一台电脑上", "transfer": "在运行这两条命令之间,将 {manifest} 和 {lockfile} 复制到另一台电脑。", - "directory": "未指定目录时,两条命令均使用当前目录。", "requirements": "恢复需要记录的源仍可访问,并且客户端支持依赖管理。", "excludes": "不会传输登录状态、机密信息、设置或插件数据。" }, diff --git a/landing/scripts/check-i18n.mjs b/landing/scripts/check-i18n.mjs index b76c104dc..ab40a8f1a 100644 --- a/landing/scripts/check-i18n.mjs +++ b/landing/scripts/check-i18n.mjs @@ -111,6 +111,7 @@ const reviewedCaptions = { 'shell.header.faq': 'FAQ', 'shell.navigation.plugins': 'Plugins', 'shell.navigation.faq': 'FAQ', + 'shell.restore.guide': 'Guide', 'registryUi.catalog.source': 'Source', 'registryUi.catalog.agent': 'Agent', 'registryUi.card.installable': 'installable', diff --git a/landing/tests/browser/i18n-integration.spec.ts b/landing/tests/browser/i18n-integration.spec.ts index e7b52c10a..2229b2273 100644 --- a/landing/tests/browser/i18n-integration.spec.ts +++ b/landing/tests/browser/i18n-integration.spec.ts @@ -36,8 +36,7 @@ for (const locale of publishedLocales) { ).shell.restore as Record