diff --git a/src/App.svelte b/src/App.svelte index 6cd1bc9f3..6b3fcff87 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -35,6 +35,7 @@ import Explorer from './components/editors/Explorer.svelte' import TextEditorWindow from './components/editors/TextEditorWindow.svelte' import FilePreviewWindow from './components/editors/FilePreviewWindow.svelte' + import ImageEditorWindow from './components/editors/ImageEditorWindow.svelte' import { previewWindows } from './lib/fileWindows' import ModelPreviewWindow from './components/editors/ModelPreviewWindow.svelte' import DungeonMinimap from './components/play/DungeonMinimap.svelte' @@ -387,6 +388,8 @@ import { startMusicToolbox } from './lib/musicToolbox' {#await import('./components/editors/CodeWorkspace.svelte') then m}{/await} {/if} + + {#each $previewWindows as w, i (w.id)} diff --git a/src/components/editors/Explorer.svelte b/src/components/editors/Explorer.svelte index 27a2467cb..766a0f521 100644 --- a/src/components/editors/Explorer.svelte +++ b/src/components/editors/Explorer.svelte @@ -4783,6 +4783,19 @@ } ] : []), + // 40-image (F13): an image in YOUR library opens in the Image editor (crop, rotate, + // resize, adjust, versions). A pack item is a reference to bytes on a CDN, so it + // has nothing to save into — copy it into the Library first. + ...(item.kind === 'image' && !item.packEntry && !item.dataUrl + ? [ + { + label: 'Edit image…', + icon: 'square-pen', + tooltip: 'Crop, rotate, resize and adjust it; saving updates every texture made from it', + action: () => import('$lib/image/imageEditor').then((m) => m.openImageEditor(item.id)) + } + ] + : []), ...(item.kind === 'text' ? [ { diff --git a/src/components/editors/FilePreviewWindow.svelte b/src/components/editors/FilePreviewWindow.svelte index 9fc3eeb1a..c1cdd84bf 100644 --- a/src/components/editors/FilePreviewWindow.svelte +++ b/src/components/editors/FilePreviewWindow.svelte @@ -32,7 +32,7 @@ stepPreview, clampPreviewOpacity } from '$lib/filePreview'; - import { activeFolder, explorerFolders, itemBlob } from '$lib/explorer'; + import { activeFolder, explorerFolders, explorerItems, itemBlob } from '$lib/explorer'; // R22 round 13 P3: the arrows may walk into a MOUNTED project's folder, whose files are // not in the library's blob store — `volumeBlob` reads them from the saved payload. import { volumeOf, volumeFolders, volumeKey, volumeBlob } from '$lib/mountedVolumes'; @@ -209,6 +209,9 @@ * Users popover makes for Watch when a peer is in another scene. */ const opacityApplies = $derived(face === 'image' || face === 'object'); + /** 40-image (F13): an image in YOUR library can be edited — a pack card or a mounted + * project's file has no record to save into */ + const editable = $derived(face === 'image' && !!target?.itemId && $explorerItems.some((i: any) => i.id === target?.itemId)); const walkId = $derived(String(target?.itemId ?? target?.folderId ?? '')); const place = $derived(previewPosition($previewSiblings.entries, walkId)); const canPrev = $derived(!!stepPreview($previewSiblings.entries, walkId, -1)); @@ -626,6 +629,16 @@ {/if} + {#if editable} + + {/if}