Compare commits

..

No commits in common. "d353b5b335bf651ed0b4889a7a852e1f0fe3c2a0" and "41aeefc1828b06576b168373cdf274ded734cb0a" have entirely different histories.

14 changed files with 16 additions and 26 deletions

View File

@ -49,11 +49,11 @@ No account, cloud service or sync server is required for local use.
| Overview: return to a Deal and see its recent work, captures and items that need attention. | Files: manage ordinary folders and documents inside a Deal. | | Overview: return to a Deal and see its recent work, captures and items that need attention. | Files: manage ordinary folders and documents inside a Deal. |
| --- | --- | | --- | --- |
| ![Current Verstak Overview in a test vault](docs/screenshots/overview-en.png) | ![Current Verstak Deal files in a test vault](docs/screenshots/files-en.png) | | ![Verstak Overview in a test vault](docs/screenshots/overview.png) | ![Verstak Deal files in a test vault](docs/screenshots/workspace-files.png) |
| Notes: keep Markdown notes next to the Deal they describe. | Journal: record a completed session and retain its context. | | Notes: keep Markdown notes next to the Deal they describe. | Journal: record a completed session and retain its context. |
| --- | --- | | --- | --- |
| ![Current Verstak notes in a test vault](docs/screenshots/notes-en.png) | ![Current Verstak journal in a test vault](docs/screenshots/journal-en.png) | | ![Verstak notes in a test vault](docs/screenshots/notes.png) | ![Verstak journal in a test vault](docs/screenshots/journal.png) |
## Main features ## Main features

View File

@ -49,11 +49,11 @@
| Обзор: возвращает к делу и показывает недавнюю работу, входящие и то, что требует внимания. | Файлы: обычные папки и документы прямо внутри дела. | | Обзор: возвращает к делу и показывает недавнюю работу, входящие и то, что требует внимания. | Файлы: обычные папки и документы прямо внутри дела. |
| --- | --- | | --- | --- |
| ![Актуальный экран «Обзор» Верстака в тестовом vault](docs/screenshots/overview-ru.png) | ![Актуальные файлы дела в тестовом vault Верстака](docs/screenshots/files-ru.png) | | ![Экран «Обзор» Верстака в тестовом vault](docs/screenshots/overview.png) | ![Файлы дела в тестовом vault Верстака](docs/screenshots/workspace-files.png) |
| Заметки: Markdown-заметки остаются рядом с делом, которое они описывают. | Журнал: фиксирует завершённую работу и её контекст. | | Заметки: Markdown-заметки остаются рядом с делом, которое они описывают. | Журнал: фиксирует завершённую работу и её контекст. |
| --- | --- | | --- | --- |
| ![Актуальные заметки Верстака в тестовом vault](docs/screenshots/notes-ru.png) | ![Актуальный журнал Верстака в тестовом vault](docs/screenshots/journal-ru.png) | | ![Заметки Верстака в тестовом vault](docs/screenshots/notes.png) | ![Журнал Верстака в тестовом vault](docs/screenshots/journal.png) |
## Основные возможности ## Основные возможности

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

View File

@ -175,10 +175,10 @@ test.describe('F: Default Editor Plugin', () => {
const workbench = page.locator('.workbench-host'); const workbench = page.locator('.workbench-host');
await expect(workbench).toBeVisible({ timeout: 10000 }); await expect(workbench).toBeVisible({ timeout: 10000 });
const title = workbench.locator('.workbench-title'); const title = workbench.locator('.workbench-title');
await expect(title).toHaveText('readme.md'); await expect(title).toHaveText('Docs/readme.md');
}); });
test('opening a note uses its title rather than its technical path', async ({ page }) => { test('open .md with notes context routes to highest-priority provider', async ({ page }) => {
await page.evaluate(async () => { await page.evaluate(async () => {
const [result, err] = await window.go.api.App.OpenWorkbenchResource('verstak.platform-test', { const [result, err] = await window.go.api.App.OpenWorkbenchResource('verstak.platform-test', {
kind: 'vault-file', kind: 'vault-file',
@ -193,7 +193,7 @@ test.describe('F: Default Editor Plugin', () => {
const workbench = page.locator('.workbench-host'); const workbench = page.locator('.workbench-host');
await expect(workbench).toBeVisible({ timeout: 10000 }); await expect(workbench).toBeVisible({ timeout: 10000 });
const title = workbench.locator('.workbench-title'); const title = workbench.locator('.workbench-title');
await expect(title).toHaveText('Overview'); await expect(title).toHaveText('Notes/Overview.md');
}); });
test('default-editor plugin is listed as loaded in plugin manager', async ({ page }) => { test('default-editor plugin is listed as loaded in plugin manager', async ({ page }) => {

View File

@ -513,7 +513,7 @@ test.describe('G: Files Plugin', () => {
const workbench = page.locator('.workbench-host'); const workbench = page.locator('.workbench-host');
await expect(workbench).toBeVisible({ timeout: 10000 }); await expect(workbench).toBeVisible({ timeout: 10000 });
await expect(workbench.locator('.workbench-title')).toHaveText('readme.md'); await expect(workbench.locator('.workbench-title')).toHaveText('Docs/readme.md');
const preview = page.locator('.de-preview'); const preview = page.locator('.de-preview');
await expect(preview).toBeVisible({ timeout: 10000 }); await expect(preview).toBeVisible({ timeout: 10000 });
@ -535,7 +535,7 @@ test.describe('G: Files Plugin', () => {
const workbench = page.locator('.workbench-host'); const workbench = page.locator('.workbench-host');
await expect(workbench).toBeVisible({ timeout: 10000 }); await expect(workbench).toBeVisible({ timeout: 10000 });
await expect(workbench.locator('.workbench-title')).toHaveText('Overview'); await expect(workbench.locator('.workbench-title')).toHaveText('Notes/Overview.md');
}); });
test('files plugin card shows openProviders in contributions', async ({ page }) => { test('files plugin card shows openProviders in contributions', async ({ page }) => {

View File

@ -58,7 +58,7 @@ test.describe('D: Plugin API bridge', () => {
const workbench = page.locator('.workbench-host'); const workbench = page.locator('.workbench-host');
await expect(workbench).toBeVisible({ timeout: 10000 }); await expect(workbench).toBeVisible({ timeout: 10000 });
await expect(workbench.locator('.workbench-title')).toHaveText('Overview'); await expect(workbench.locator('.workbench-title')).toHaveText('Notes/Overview.md');
}); });
test('workbench routes markdown files to default-editor provider', async ({ page }) => { test('workbench routes markdown files to default-editor provider', async ({ page }) => {
@ -76,7 +76,7 @@ test.describe('D: Plugin API bridge', () => {
const workbench = page.locator('.workbench-host'); const workbench = page.locator('.workbench-host');
await expect(workbench).toBeVisible({ timeout: 10000 }); await expect(workbench).toBeVisible({ timeout: 10000 });
const title = workbench.locator('.workbench-title'); const title = workbench.locator('.workbench-title');
await expect(title).toHaveText('readme.md'); await expect(title).toHaveText('Docs/readme.md');
}); });
test('workbench shows no-provider fallback when no provider matches', async ({ page }) => { test('workbench shows no-provider fallback when no provider matches', async ({ page }) => {
@ -91,10 +91,8 @@ test.describe('D: Plugin API bridge', () => {
window.dispatchEvent(new CustomEvent('verstak:workbench-opened', { detail: result })); window.dispatchEvent(new CustomEvent('verstak:workbench-opened', { detail: result }));
}); });
const fallback = page.locator('[data-workbench-status="no-provider"]'); await expect(page.locator('[data-workbench-status="no-provider"]')).toBeVisible();
await expect(fallback).toBeVisible(); await expect(page.locator('[data-workbench-status="no-provider"]')).toContainText('No viewer/editor available');
await expect(fallback).toContainText('No viewer/editor available');
await expect(fallback).not.toContainText('generic-text');
}); });
test('sync plugin API routes through mocked Wails bridge', async ({ page }) => { test('sync plugin API routes through mocked Wails bridge', async ({ page }) => {

View File

@ -22,7 +22,6 @@
$: requestContext = openedResource?.request?.context?.notesMode || openedResource?.request?.context?.isInsideNotesFolder $: requestContext = openedResource?.request?.context?.notesMode || openedResource?.request?.context?.isInsideNotesFolder
? 'notes-markdown' ? 'notes-markdown'
: ((openedResource?.request?.extension === '.md' || openedResource?.request?.extension === '.markdown') ? 'generic-markdown' : 'generic-text'); : ((openedResource?.request?.extension === '.md' || openedResource?.request?.extension === '.markdown') ? 'generic-markdown' : 'generic-text');
$: resourceTitle = resourceDisplayTitle(resourcePath, requestContext);
$: componentProps = openedResource || {}; $: componentProps = openedResource || {};
$: mountKey = [ $: mountKey = [
providerPluginId, providerPluginId,
@ -32,11 +31,6 @@
requestContext, requestContext,
].join(':'); ].join(':');
function resourceDisplayTitle(path, context) {
const fileName = String(path || '').split('/').filter(Boolean).pop() || String(path || '');
return context === 'notes-markdown' ? fileName.replace(/\.(md|markdown)$/i, '') : fileName;
}
function closeWorkbench() { function closeWorkbench() {
window.dispatchEvent(new CustomEvent('verstak:close-workbench', { cancelable: true })); window.dispatchEvent(new CustomEvent('verstak:close-workbench', { cancelable: true }));
} }
@ -47,7 +41,7 @@
<div class="workbench-host vt-page"> <div class="workbench-host vt-page">
{#if openedResource?.status === 'no-provider'} {#if openedResource?.status === 'no-provider'}
<div class="workbench-header vt-page-header"> <div class="workbench-header vt-page-header">
<span class="workbench-title vt-page-title">{resourceTitle}</span> <span class="workbench-title vt-page-title">{resourcePath}</span>
<span class="workbench-provider vt-badge">{tr('workbench.noProvider')}</span> <span class="workbench-provider vt-badge">{tr('workbench.noProvider')}</span>
<button class="close-btn btn-ghost btn-icon" type="button" title={tr('common.close')} aria-label={tr('common.close')} on:click={closeWorkbench}> <button class="close-btn btn-ghost btn-icon" type="button" title={tr('common.close')} aria-label={tr('common.close')} on:click={closeWorkbench}>
<Icon name="x" size={18} /> <Icon name="x" size={18} />
@ -55,13 +49,11 @@
</div> </div>
<div class="workbench-empty no-provider vt-empty-state" data-workbench-status="no-provider"> <div class="workbench-empty no-provider vt-empty-state" data-workbench-status="no-provider">
<p class="vt-empty-title">{tr('workbench.noViewer')}</p> <p class="vt-empty-title">{tr('workbench.noViewer')}</p>
{#if debug.isEnabled()} <p class="workbench-meta">{requestMode} · {requestContext}</p>
<p class="workbench-meta">{requestMode} · {requestContext}</p>
{/if}
</div> </div>
{:else if openedResource} {:else if openedResource}
<div class="workbench-header vt-page-header"> <div class="workbench-header vt-page-header">
<span class="workbench-title vt-page-title">{resourceTitle}</span> <span class="workbench-title vt-page-title">{resourcePath}</span>
{#if debug.isEnabled() && providerId} {#if debug.isEnabled() && providerId}
<span class="workbench-provider vt-badge accent" data-debug-provider>{providerId}</span> <span class="workbench-provider vt-badge accent" data-debug-provider>{providerId}</span>
{/if} {/if}