From ce963b43aef76e5503f61bab5e095551cd0fde9f Mon Sep 17 00:00:00 2001 From: Yukon <126093594+baseGame@users.noreply.github.com> Date: Wed, 7 Oct 2026 02:05:24 +0800 Subject: [PATCH 1/2] Clarify Text Edit empty states and path hints Add stage-aware empty hints, a file-path placeholder, Enter-to-open, clearer Open tips, and plain Text metadata labeling so first-time users know the next step. --- src/i18n/locales/de-DE.ts | 5 ++++ src/i18n/locales/en-US.ts | 5 +++- src/i18n/locales/es-ES.ts | 6 +++- src/i18n/locales/fr-FR.ts | 7 ++++- src/i18n/locales/ja-JP.ts | 5 +++- src/i18n/locales/ko-KR.ts | 5 +++- src/i18n/locales/zh-CN.ts | 5 +++- src/i18n/locales/zh-TW.ts | 5 +++- src/views/TextEditView.test.ts | 31 ++++++++++++++++++++ src/views/TextEditView.vue | 52 +++++++++++++++++++++++++++++----- 10 files changed, 112 insertions(+), 14 deletions(-) diff --git a/src/i18n/locales/de-DE.ts b/src/i18n/locales/de-DE.ts index 9135954b..4a6989c3 100644 --- a/src/i18n/locales/de-DE.ts +++ b/src/i18n/locales/de-DE.ts @@ -977,6 +977,11 @@ export const deDE: LanguagePack = { 'ui.pictureEmptyReadyHint': 'Drücken Sie Enter oder klicken Sie auf Vergleichen, um diese Bilder zu vergleichen.', 'ui.pictureIdenticalHint': 'Diese Bilder stimmen überein. Keine Pixelunterschiede.', + 'ui.textEditEmptyHint': + 'Wählen Sie eine Datei mit Durchsuchen (oder fügen Sie einen Pfad ein), dann auf Öffnen klicken.', + 'ui.textEditEmptyReadyHint': + 'Drücken Sie Enter oder klicken Sie auf Öffnen, um diese Datei zu laden.', + 'ui.textEditNeedsPath': 'Wählen Sie zuerst einen Dateipfad.', 'ui.registryExportHint': 'Compare exported .reg files, offline REGF hive files (SYSTEM/SOFTWARE/NTUSER.DAT), or live HKLM/HKCU keys on Windows.', 'ui.nextConflict': 'Next Conflict', diff --git a/src/i18n/locales/en-US.ts b/src/i18n/locales/en-US.ts index 25aefb84..d1b0193a 100644 --- a/src/i18n/locales/en-US.ts +++ b/src/i18n/locales/en-US.ts @@ -319,7 +319,7 @@ export const enUS: LanguagePack = { 'ui.off': 'Off', 'ui.open': 'Open', 'ui.openAll': 'Open All', - 'ui.openATextFileToBeginEditing': 'Open a text file to begin editing', + 'ui.openATextFileToBeginEditing': 'Browse or paste a path, then Open to begin editing', 'ui.openClipboard': 'Open Clipboard', 'ui.openSuggestedView': 'Open Suggested View', 'ui.openTextMerge': 'Open Text Merge', @@ -945,6 +945,9 @@ export const enUS: LanguagePack = { 'Choose left and right images with Browse (or paste paths), then click Compare.', 'ui.pictureEmptyReadyHint': 'Press Enter or click Compare to compare these images.', 'ui.pictureIdenticalHint': 'These images match. No pixel differences to show.', + 'ui.textEditEmptyHint': 'Choose a file with Browse (or paste a path), then click Open.', + 'ui.textEditEmptyReadyHint': 'Press Enter or click Open to load this file.', + 'ui.textEditNeedsPath': 'Choose a file path first.', 'ui.registryExportHint': 'Compare exported .reg files, offline REGF hive files (SYSTEM/SOFTWARE/NTUSER.DAT), or live HKLM/HKCU keys on Windows.', 'ui.nextConflict': 'Next Conflict', diff --git a/src/i18n/locales/es-ES.ts b/src/i18n/locales/es-ES.ts index 76e47294..500c5a08 100644 --- a/src/i18n/locales/es-ES.ts +++ b/src/i18n/locales/es-ES.ts @@ -271,7 +271,7 @@ export const esES: LanguagePack = { 'ui.onedrive': 'OneDrive', 'ui.open': 'Abrir', 'ui.openAll': 'Abrir todo', - 'ui.openATextFileToBeginEditing': 'Abra un archivo de texto para comenzar a editar', + 'ui.openATextFileToBeginEditing': 'Examinar o pegar una ruta, luego Abrir para editar', 'ui.openClipboard': 'Abrir portapapeles', 'ui.openSuggestedView': 'Abrir vista sugerida', 'ui.openTextMerge': 'Abrir combinación de texto', @@ -964,6 +964,10 @@ export const esES: LanguagePack = { 'Elija las imágenes izquierda y derecha con Examinar (o pegue rutas) y luego haga clic en Comparar.', 'ui.pictureEmptyReadyHint': 'Pulse Intro o haga clic en Comparar para comparar estas imágenes.', 'ui.pictureIdenticalHint': 'Estas imágenes coinciden. No hay diferencias de píxeles.', + 'ui.textEditEmptyHint': + 'Elija un archivo con Examinar (o pegue una ruta) y luego haga clic en Abrir.', + 'ui.textEditEmptyReadyHint': 'Pulse Intro o haga clic en Abrir para cargar este archivo.', + 'ui.textEditNeedsPath': 'Elija primero una ruta de archivo.', 'ui.registryExportHint': 'Compare exported .reg files, offline REGF hive files (SYSTEM/SOFTWARE/NTUSER.DAT), or live HKLM/HKCU keys on Windows.', 'ui.nextConflict': 'Next Conflict', diff --git a/src/i18n/locales/fr-FR.ts b/src/i18n/locales/fr-FR.ts index 6859e73e..ef1a0c98 100644 --- a/src/i18n/locales/fr-FR.ts +++ b/src/i18n/locales/fr-FR.ts @@ -271,7 +271,7 @@ export const frFR: LanguagePack = { 'ui.onedrive': 'OneDrive', 'ui.open': 'Ouvrir', 'ui.openAll': 'Tout ouvrir', - 'ui.openATextFileToBeginEditing': "Ouvrez un fichier texte pour commencer l'édition", + 'ui.openATextFileToBeginEditing': 'Parcourir ou coller un chemin, puis Ouvrir pour modifier', 'ui.openClipboard': 'Ouvrir le Presse-papiers', 'ui.openSuggestedView': 'Ouvrir la vue suggérée', 'ui.openTextMerge': 'Ouvrir la fusion de texte', @@ -970,6 +970,11 @@ export const frFR: LanguagePack = { 'ui.pictureEmptyReadyHint': 'Appuyez sur Entrée ou cliquez sur Comparer pour comparer ces images.', 'ui.pictureIdenticalHint': 'Ces images correspondent. Aucune différence de pixel.', + 'ui.textEditEmptyHint': + 'Choisissez un fichier avec Parcourir (ou collez un chemin), puis cliquez sur Ouvrir.', + 'ui.textEditEmptyReadyHint': + 'Appuyez sur Entrée ou cliquez sur Ouvrir pour charger ce fichier.', + 'ui.textEditNeedsPath': "Choisissez d'abord un chemin de fichier.", 'ui.registryExportHint': 'Compare exported .reg files, offline REGF hive files (SYSTEM/SOFTWARE/NTUSER.DAT), or live HKLM/HKCU keys on Windows.', 'ui.nextConflict': 'Next Conflict', diff --git a/src/i18n/locales/ja-JP.ts b/src/i18n/locales/ja-JP.ts index b67113f3..501206df 100644 --- a/src/i18n/locales/ja-JP.ts +++ b/src/i18n/locales/ja-JP.ts @@ -318,7 +318,7 @@ export const jaJP: LanguagePack = { 'ui.off': 'Off', 'ui.open': 'Open', 'ui.openAll': 'Open All', - 'ui.openATextFileToBeginEditing': 'Open a text file to begin editing', + 'ui.openATextFileToBeginEditing': 'Browse or paste a path, then Open to begin editing', 'ui.openClipboard': 'Open Clipboard', 'ui.openSuggestedView': 'Open Suggested View', 'ui.openTextMerge': 'Open Text Merge', @@ -945,6 +945,9 @@ export const jaJP: LanguagePack = { 'Choose left and right images with Browse (or paste paths), then click Compare.', 'ui.pictureEmptyReadyHint': 'Press Enter or click Compare to compare these images.', 'ui.pictureIdenticalHint': 'These images match. No pixel differences to show.', + 'ui.textEditEmptyHint': 'Choose a file with Browse (or paste a path), then click Open.', + 'ui.textEditEmptyReadyHint': 'Press Enter or click Open to load this file.', + 'ui.textEditNeedsPath': 'Choose a file path first.', 'ui.registryExportHint': 'Compare exported .reg files, offline REGF hive files (SYSTEM/SOFTWARE/NTUSER.DAT), or live HKLM/HKCU keys on Windows.', 'ui.nextConflict': 'Next Conflict', diff --git a/src/i18n/locales/ko-KR.ts b/src/i18n/locales/ko-KR.ts index e658b055..2acf31ca 100644 --- a/src/i18n/locales/ko-KR.ts +++ b/src/i18n/locales/ko-KR.ts @@ -262,7 +262,7 @@ export const koKR: LanguagePack = { 'ui.onedrive': 'OneDrive', 'ui.open': '열기', 'ui.openAll': '모두 열기', - 'ui.openATextFileToBeginEditing': '편집을 시작하려면 텍스트 파일을 여세요.', + 'ui.openATextFileToBeginEditing': '찾아보거나 경로를 붙여넣은 다음 열기로 편집을 시작하세요', 'ui.openClipboard': '클립보드 열기', 'ui.openSuggestedView': '추천 보기 열기', 'ui.openTextMerge': '텍스트 병합 열기', @@ -938,6 +938,9 @@ export const koKR: LanguagePack = { '찾아보기로 왼쪽·오른쪽 이미지를 선택하거나 경로를 붙여넣은 다음 비교를 클릭하세요.', 'ui.pictureEmptyReadyHint': 'Enter를 누르거나 비교를 클릭해 이미지를 비교하세요.', 'ui.pictureIdenticalHint': '이미지가 일치합니다. 픽셀 차이가 없습니다.', + 'ui.textEditEmptyHint': '찾아보기로 파일을 선택하거나 경로를 붙여넣은 다음 열기를 클릭하세요.', + 'ui.textEditEmptyReadyHint': 'Enter를 누르거나 열기를 클릭해 이 파일을 불러오세요.', + 'ui.textEditNeedsPath': '먼저 파일 경로를 선택하세요.', 'ui.registryExportHint': 'Compare exported .reg files, offline REGF hive files (SYSTEM/SOFTWARE/NTUSER.DAT), or live HKLM/HKCU keys on Windows.', 'ui.nextConflict': 'Next Conflict', diff --git a/src/i18n/locales/zh-CN.ts b/src/i18n/locales/zh-CN.ts index 74aee8a5..c51275e0 100644 --- a/src/i18n/locales/zh-CN.ts +++ b/src/i18n/locales/zh-CN.ts @@ -253,7 +253,7 @@ export const zhCN: LanguagePack = { 'ui.onedrive': 'OneDrive', 'ui.open': '打开', 'ui.openAll': '全部打开', - 'ui.openATextFileToBeginEditing': '打开文本文件开始编辑', + 'ui.openATextFileToBeginEditing': '浏览或粘贴路径,然后点打开开始编辑', 'ui.openClipboard': '打开剪贴板', 'ui.openSuggestedView': '打开建议视图', 'ui.openTextMerge': '打开文本合并', @@ -906,6 +906,9 @@ export const zhCN: LanguagePack = { 'ui.pictureEmptyCompareHint': '用浏览选择左右图像(或粘贴路径),然后点比较。', 'ui.pictureEmptyReadyHint': '按 Enter 或点比较以比较这些图像。', 'ui.pictureIdenticalHint': '这些图像一致。没有像素差异。', + 'ui.textEditEmptyHint': '用浏览选择文件(或粘贴路径),然后点打开。', + 'ui.textEditEmptyReadyHint': '按 Enter 或点打开以加载此文件。', + 'ui.textEditNeedsPath': '请先选择文件路径。', 'ui.registryExportHint': '可比较导出的 .reg、离线 REGF 配置单元(SYSTEM/SOFTWARE/NTUSER.DAT),或在 Windows 上比较实时 HKLM/HKCU 键。', 'ui.nextConflict': '下一冲突', diff --git a/src/i18n/locales/zh-TW.ts b/src/i18n/locales/zh-TW.ts index 0216555a..c841e8f7 100644 --- a/src/i18n/locales/zh-TW.ts +++ b/src/i18n/locales/zh-TW.ts @@ -254,7 +254,7 @@ export const zhTW: LanguagePack = { 'ui.onedrive': 'OneDrive', 'ui.open': '開啟', 'ui.openAll': '全部開啟', - 'ui.openATextFileToBeginEditing': '開啟文字檔開始編輯', + 'ui.openATextFileToBeginEditing': '瀏覽或貼上路徑,然後按開啟開始編輯', 'ui.openClipboard': '開啟剪貼簿', 'ui.openSuggestedView': '開啟建議檢視', 'ui.openTextMerge': '開啟文字合併', @@ -908,6 +908,9 @@ export const zhTW: LanguagePack = { 'ui.pictureEmptyCompareHint': '用瀏覽選擇左右影像(或貼上路徑),然後按比較。', 'ui.pictureEmptyReadyHint': '按 Enter 或點比較以比較這些影像。', 'ui.pictureIdenticalHint': '這些影像一致。沒有像素差異。', + 'ui.textEditEmptyHint': '用瀏覽選擇檔案(或貼上路徑),然後按開啟。', + 'ui.textEditEmptyReadyHint': '按 Enter 或點開啟以載入此檔案。', + 'ui.textEditNeedsPath': '請先選擇檔案路徑。', 'ui.registryExportHint': '可比較匯出的 .reg、離線 REGF 登錄檔(SYSTEM/SOFTWARE/NTUSER.DAT),或在 Windows 上比較即時 HKLM/HKCU 鍵。', 'ui.nextConflict': '下一衝突', diff --git a/src/views/TextEditView.test.ts b/src/views/TextEditView.test.ts index 4d9a10e1..588447d1 100644 --- a/src/views/TextEditView.test.ts +++ b/src/views/TextEditView.test.ts @@ -74,6 +74,37 @@ describe('TextEditView', () => { ).toBeUndefined() }) + it('shows a friendly empty state and path placeholder before open', async () => { + const wrapper = mountTextEditView() + + expect(wrapper.find('[data-testid="text-edit-empty-hint"]').text()).toContain( + 'Choose a file with Browse', + ) + expect(wrapper.find('[data-testid="text-edit-path"]').attributes('placeholder')).toContain( + 'Browse or paste a file path', + ) + expect(wrapper.find('[data-testid="text-edit-open"]').attributes('title')).toContain( + 'file path first', + ) + expect(wrapper.text()).toContain('Text') + + await wrapper.find('[data-testid="text-edit-path"]').setValue('D:/workspace/notes.txt') + expect(wrapper.find('[data-testid="text-edit-empty-hint"]').text()).toContain('Open') + expect(wrapper.find('[data-testid="text-edit-open"]').attributes('disabled')).toBeUndefined() + }) + + it('opens the file on Enter when a path is set', async () => { + const wrapper = mountTextEditView() + + await wrapper.find('[data-testid="text-edit-path"]').setValue('D:/workspace/notes.txt') + await wrapper.find('[data-testid="text-edit-path"]').trigger('keydown.enter') + await flushPromises() + + expect(readTextFile).toHaveBeenCalledWith('D:/workspace/notes.txt') + expect(wrapper.find('[data-testid="text-edit-empty-hint"]').exists()).toBe(false) + expect(wrapper.find('[data-testid="text-edit-editor"]').element).toBeTruthy() + }) + it('opens a text file and shows metadata for the loaded document', async () => { const wrapper = mountTextEditView() diff --git a/src/views/TextEditView.vue b/src/views/TextEditView.vue index cabe2edc..55b36b82 100644 --- a/src/views/TextEditView.vue +++ b/src/views/TextEditView.vue @@ -9,6 +9,7 @@ import { useTabsStore } from '@/stores/tabs' import { useSettingsStore, type FontFamilyId } from '@/stores/settings' import { useStatusBarStore } from '@/stores/statusBar' import { elapsedSecondsSince } from '@/app/statusBarPhrases' +import { formatCompareError } from '@/app/compareError' import { applyOverwriteTyping, isInsertToggleKey, @@ -99,6 +100,28 @@ const fileTitle = computed(() => { const dirty = computed(() => editorText.value !== savedText.value) const dirtyLabel = computed(() => (dirty.value ? t('status.unsavedChanges') : t('status.saved'))) +const openNeedsPath = computed(() => !pathInput.value.trim()) + +const textEditEmptyStateMessage = computed(() => { + if (document.value) { + return '' + } + + if (pathInput.value.trim()) { + return t('ui.textEditEmptyReadyHint') + } + + return t('ui.textEditEmptyHint') +}) + +function onTextEditPathEnter(): void { + if (openNeedsPath.value || loading.value) { + return + } + + void openDocument() +} + watchEffect(() => { let comparisonStatus = t('status.noDocumentLoaded') @@ -177,13 +200,17 @@ async function browseTextEditPath(): Promise { } async function openDocument(): Promise { + if (!pathInput.value.trim()) { + return + } + const startedAt = performance.now() loading.value = true error.value = '' try { - const result = await readTextFile(pathInput.value) + const result = await readTextFile(pathInput.value.trim()) document.value = result loadTimeSeconds.value = elapsedSecondsSince(startedAt) @@ -194,7 +221,7 @@ async function openDocument(): Promise { setSaveStatus('status.loaded') currentFindIndex.value = 0 } catch (event) { - error.value = String(event) + error.value = formatCompareError(event, t) } finally { loading.value = false } @@ -237,7 +264,7 @@ async function saveDocument(): Promise { count: result.bytesWritten, }) } catch (event) { - error.value = String(event) + error.value = formatCompareError(event, t) } finally { saving.value = false } @@ -993,8 +1020,10 @@ const textEditToolbarCommands = computed(() => { class="path-input" data-testid="text-edit-path" type="text" - :title="pathInput" + :title="pathInput || $t('ui.remoteUriHint')" + :placeholder="$t('ui.textPathPlaceholder')" :aria-label="$t('ui.textFilePath')" + @keydown.enter.prevent="onTextEditPathEnter" /> { type="button" class="bc-path-load" data-testid="text-edit-open" - :disabled="loading || !pathInput" + :disabled="loading || openNeedsPath" :aria-label="$t('ui.open')" - :title="$t('ui.open')" + :title="openNeedsPath ? $t('ui.textEditNeedsPath') : $t('ui.open')" @click="openDocument" > {{ $t('ui.open') }} @@ -1027,7 +1056,7 @@ const textEditToolbarCommands = computed(() => { > { {{ error }} +

+ {{ textEditEmptyStateMessage }} +

+
Date: Wed, 7 Oct 2026 02:13:40 +0800 Subject: [PATCH 2/2] Update Text Edit format-chip density expectation Path footer format label is Text instead of Everything Else. --- src/styles/textEditChromeDensity.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/styles/textEditChromeDensity.test.ts b/src/styles/textEditChromeDensity.test.ts index 71a86abb..d5c59875 100644 --- a/src/styles/textEditChromeDensity.test.ts +++ b/src/styles/textEditChromeDensity.test.ts @@ -74,7 +74,7 @@ describe('text-edit path-meta border', () => { }) describe('text edit path meta format chip', () => { - it('shows Text Edit path meta format chip as Everything Else', () => { - expect(editView).toMatch(/format-label="Everything Else"/) + it('shows Text Edit path meta format chip as Text', () => { + expect(editView).toMatch(/:format-label="\$t\('ui\.text'\)"/) }) })