feat: add mobile editor draft save
This commit is contained in:
48
apps/mobile/src/mobileEditorDraftSave.test.ts
Normal file
48
apps/mobile/src/mobileEditorDraftSave.test.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { createMobileEditorDraft } from './mobileEditorDraft'
|
||||
import { saveMobileEditorDraft } from './mobileEditorDraftSave'
|
||||
import { createMobileVaultConfig } from './mobileVaultConfig'
|
||||
import { createMemoryMobileVaultStorage } from './mobileVaultStorage'
|
||||
|
||||
const vault = createVault()
|
||||
|
||||
describe('mobile editor draft save', () => {
|
||||
it('writes persistable editor drafts as canonical Markdown', async () => {
|
||||
const storage = createMemoryMobileVaultStorage([])
|
||||
const draft = createMobileEditorDraft({
|
||||
note: { id: 'notes/workflow', title: 'Workflow', content: '# Workflow' },
|
||||
editorHtml: '<h1>Workflow</h1><p>Edited</p>',
|
||||
})
|
||||
|
||||
await expect(saveMobileEditorDraft({ draft, storage, vault })).resolves.toEqual({
|
||||
status: 'saved',
|
||||
path: 'notes/workflow.md',
|
||||
})
|
||||
|
||||
await expect(storage.readMarkdownFile(vault, 'notes/workflow.md')).resolves.toBe('# Workflow\n\nEdited')
|
||||
})
|
||||
|
||||
it('does not write blocked editor drafts', async () => {
|
||||
const storage = createMemoryMobileVaultStorage([])
|
||||
const draft = createMobileEditorDraft({
|
||||
note: { id: 'workflow', title: 'Workflow', content: '# Workflow' },
|
||||
editorHtml: '<blockquote>Unsupported</blockquote>',
|
||||
})
|
||||
|
||||
await expect(saveMobileEditorDraft({ draft, storage, vault })).resolves.toEqual({
|
||||
status: 'blocked',
|
||||
reason: 'unsupportedEditorHtml',
|
||||
})
|
||||
|
||||
await expect(storage.listMarkdownFiles(vault)).resolves.toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
function createVault() {
|
||||
const result = createMobileVaultConfig({ id: 'personal', name: 'Personal Journal' })
|
||||
if (!result.ok) {
|
||||
throw new Error(result.error)
|
||||
}
|
||||
|
||||
return result.config
|
||||
}
|
||||
36
apps/mobile/src/mobileEditorDraftSave.ts
Normal file
36
apps/mobile/src/mobileEditorDraftSave.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import type { MobileEditorDraft } from './mobileEditorDraft'
|
||||
import type { MobileVaultConfig } from './mobileVaultConfig'
|
||||
import type { MobileVaultStorageDriver } from './mobileVaultStorage'
|
||||
|
||||
export type MobileEditorDraftSaveResult =
|
||||
| {
|
||||
status: 'saved'
|
||||
path: string
|
||||
}
|
||||
| {
|
||||
status: 'blocked'
|
||||
reason: 'unsupportedEditorHtml'
|
||||
}
|
||||
|
||||
export async function saveMobileEditorDraft({
|
||||
draft,
|
||||
storage,
|
||||
vault,
|
||||
}: {
|
||||
draft: MobileEditorDraft
|
||||
storage: MobileVaultStorageDriver
|
||||
vault: MobileVaultConfig
|
||||
}): Promise<MobileEditorDraftSaveResult> {
|
||||
if (!draft.persistable) {
|
||||
return { status: 'blocked', reason: draft.blockedReason }
|
||||
}
|
||||
|
||||
const path = draftPath(draft)
|
||||
await storage.writeMarkdownFile(vault, path, draft.canonicalMarkdown)
|
||||
|
||||
return { status: 'saved', path }
|
||||
}
|
||||
|
||||
function draftPath(draft: MobileEditorDraft) {
|
||||
return `${draft.noteId}.md`
|
||||
}
|
||||
@@ -8,7 +8,7 @@ This file is the resumable working log for Tolaria mobile. The strategy and road
|
||||
|
||||
- Branch: `codex/mobile`
|
||||
- Active phase: Phase 2 - Mobile Shell
|
||||
- Active slice: Expand TenTap Markdown serialization
|
||||
- Active slice: Add mobile editor draft save boundary
|
||||
- Push policy: commit locally; do not push unless explicitly requested
|
||||
- Validation target: iPad/iOS simulator first
|
||||
|
||||
@@ -57,6 +57,7 @@ This file is the resumable working log for Tolaria mobile. The strategy and road
|
||||
- Wired the mobile shell to load its starter notes through the native Expo FileSystem storage driver and stored repository path, with fixture notes retained as the fallback while storage initializes.
|
||||
- Expanded supported TenTap HTML serialization to include H1-H6 headings, ordered lists, task-list markers, inline strong/emphasis/code, and links while continuing to block unsupported block HTML.
|
||||
- Split the mobile editor HTML serializer into its own CodeScene-10 module so the draft boundary stays small.
|
||||
- Added a mobile editor draft save boundary that writes persistable canonical Markdown drafts to vault storage and refuses blocked drafts.
|
||||
|
||||
## Next Action
|
||||
|
||||
@@ -64,7 +65,7 @@ Continue Phase 2 with the next mobile shell slice:
|
||||
|
||||
1. Dismiss or suppress Expo Go's first-run tools modal during simulator QA so screenshots capture the app without the overlay.
|
||||
2. Expand the serializer for additional TenTap output needed by real notes: links, emphasis, code, headings, ordered lists, and task lists.
|
||||
3. Add a save command boundary that writes persistable TenTap Markdown drafts back to mobile vault storage.
|
||||
3. Wire `MobileEditorAdapter` draft callbacks to the save boundary with explicit dirty/saved/blocked UI state.
|
||||
|
||||
## Verification Log
|
||||
|
||||
@@ -176,6 +177,11 @@ Continue Phase 2 with the next mobile shell slice:
|
||||
- `pnpm --filter @tolaria/mobile typecheck` passed after expanded TenTap serialization.
|
||||
- CodeScene after expanded TenTap serialization: `apps/mobile/src/mobileEditorDraft.ts`, `apps/mobile/src/mobileEditorDraft.test.ts`, and `apps/mobile/src/mobileEditorHtmlMarkdown.ts` scored `10`.
|
||||
- `pnpm --filter @tolaria/mobile exec expo export --platform ios --output-dir /tmp/tolaria-mobile-export` passed after expanded TenTap serialization.
|
||||
- `pnpm --filter @tolaria/mobile test -- src/mobileEditorDraftSave.test.ts` passed after editor draft save boundary: 13 files / 44 tests.
|
||||
- `pnpm --filter @tolaria/mobile test` passed after editor draft save boundary: 13 files / 44 tests.
|
||||
- `pnpm --filter @tolaria/mobile typecheck` passed after editor draft save boundary.
|
||||
- CodeScene after editor draft save boundary: `apps/mobile/src/mobileEditorDraftSave.ts` and `apps/mobile/src/mobileEditorDraftSave.test.ts` scored `10`.
|
||||
- `pnpm --filter @tolaria/mobile exec expo export --platform ios --output-dir /tmp/tolaria-mobile-export` passed after editor draft save boundary.
|
||||
|
||||
## Risks / Watch Items
|
||||
|
||||
|
||||
Reference in New Issue
Block a user