triiiceratops 0.9.13 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ArrowCounterClockwise-aFffCOKw.js +136 -0
- package/dist/X-DZEgXrJ8.js +877 -0
- package/dist/annotation_tool_point-CZKsj4Nk.js +290 -0
- package/dist/components/AnnotationOverlay.svelte +179 -86
- package/dist/components/LeftFab.svelte +21 -9
- package/dist/components/OSDViewer.svelte +20 -3
- package/dist/components/TriiiceratopsViewer.svelte +96 -43
- package/dist/components/TriiiceratopsViewer.svelte.d.ts +5 -5
- package/dist/components/TriiiceratopsViewerElement.svelte +2 -2
- package/dist/components/TriiiceratopsViewerElement.svelte.d.ts +2 -2
- package/dist/custom-element.d.ts +10 -0
- package/dist/custom-element.js +13 -0
- package/dist/image_filters_reset-BEIf-_QA.js +108 -0
- package/dist/index.d.ts +1 -2
- package/dist/index.js +0 -1
- package/dist/paraglide/messages/_index.d.ts +30 -0
- package/dist/paraglide/messages/_index.js +31 -1
- package/dist/paraglide/messages/annotation_editor_add_content.d.ts +4 -0
- package/dist/paraglide/messages/annotation_editor_add_content.js +34 -0
- package/dist/paraglide/messages/annotation_editor_cancel.d.ts +4 -0
- package/dist/paraglide/messages/annotation_editor_cancel.js +34 -0
- package/dist/paraglide/messages/annotation_editor_create_mode.d.ts +4 -0
- package/dist/paraglide/messages/annotation_editor_create_mode.js +34 -0
- package/dist/paraglide/messages/annotation_editor_delete.d.ts +4 -0
- package/dist/paraglide/messages/annotation_editor_delete.js +34 -0
- package/dist/paraglide/messages/annotation_editor_delete_message.d.ts +4 -0
- package/dist/paraglide/messages/annotation_editor_delete_message.js +34 -0
- package/dist/paraglide/messages/annotation_editor_delete_title.d.ts +4 -0
- package/dist/paraglide/messages/annotation_editor_delete_title.js +34 -0
- package/dist/paraglide/messages/annotation_editor_delete_tooltip.d.ts +4 -0
- package/dist/paraglide/messages/annotation_editor_delete_tooltip.js +34 -0
- package/dist/paraglide/messages/annotation_editor_edit_mode.d.ts +4 -0
- package/dist/paraglide/messages/annotation_editor_edit_mode.js +34 -0
- package/dist/paraglide/messages/annotation_editor_edit_section.d.ts +4 -0
- package/dist/paraglide/messages/annotation_editor_edit_section.js +34 -0
- package/dist/paraglide/messages/annotation_editor_instruction_create.d.ts +4 -0
- package/dist/paraglide/messages/annotation_editor_instruction_create.js +34 -0
- package/dist/paraglide/messages/annotation_editor_instruction_edit.d.ts +4 -0
- package/dist/paraglide/messages/annotation_editor_instruction_edit.js +34 -0
- package/dist/paraglide/messages/annotation_editor_link_placeholder.d.ts +4 -0
- package/dist/paraglide/messages/annotation_editor_link_placeholder.js +34 -0
- package/dist/paraglide/messages/annotation_editor_redo.d.ts +4 -0
- package/dist/paraglide/messages/annotation_editor_redo.js +34 -0
- package/dist/paraglide/messages/annotation_editor_save.d.ts +4 -0
- package/dist/paraglide/messages/annotation_editor_save.js +34 -0
- package/dist/paraglide/messages/annotation_editor_tag_placeholder.d.ts +4 -0
- package/dist/paraglide/messages/annotation_editor_tag_placeholder.js +34 -0
- package/dist/paraglide/messages/annotation_editor_text_placeholder.d.ts +4 -0
- package/dist/paraglide/messages/annotation_editor_text_placeholder.js +34 -0
- package/dist/paraglide/messages/annotation_editor_title.d.ts +4 -0
- package/dist/paraglide/messages/annotation_editor_title.js +34 -0
- package/dist/paraglide/messages/annotation_editor_tool_label.d.ts +4 -0
- package/dist/paraglide/messages/annotation_editor_tool_label.js +34 -0
- package/dist/paraglide/messages/annotation_editor_undo.d.ts +4 -0
- package/dist/paraglide/messages/annotation_editor_undo.js +34 -0
- package/dist/paraglide/messages/annotation_tool_point.d.ts +4 -0
- package/dist/paraglide/messages/annotation_tool_point.js +34 -0
- package/dist/paraglide/messages/annotation_tool_polygon.d.ts +4 -0
- package/dist/paraglide/messages/annotation_tool_polygon.js +34 -0
- package/dist/paraglide/messages/annotation_tool_rectangle.d.ts +4 -0
- package/dist/paraglide/messages/annotation_tool_rectangle.js +34 -0
- package/dist/paraglide/messages/image_adjustments_title.d.ts +4 -0
- package/dist/paraglide/messages/image_adjustments_title.js +34 -0
- package/dist/paraglide/messages/image_filters_brightness.d.ts +4 -0
- package/dist/paraglide/messages/image_filters_brightness.js +34 -0
- package/dist/paraglide/messages/image_filters_contrast.d.ts +4 -0
- package/dist/paraglide/messages/image_filters_contrast.js +34 -0
- package/dist/paraglide/messages/image_filters_effects.d.ts +4 -0
- package/dist/paraglide/messages/image_filters_effects.js +34 -0
- package/dist/paraglide/messages/image_filters_grayscale.d.ts +4 -0
- package/dist/paraglide/messages/image_filters_grayscale.js +34 -0
- package/dist/paraglide/messages/image_filters_invert.d.ts +4 -0
- package/dist/paraglide/messages/image_filters_invert.js +34 -0
- package/dist/paraglide/messages/image_filters_reset.d.ts +4 -0
- package/dist/paraglide/messages/image_filters_reset.js +34 -0
- package/dist/paraglide/messages/image_filters_saturation.d.ts +4 -0
- package/dist/paraglide/messages/image_filters_saturation.js +34 -0
- package/dist/paraglide/messages/plugins_tooltip.js +1 -1
- package/dist/plugins/annotation-editor/AnnotationEditorController.svelte +166 -0
- package/dist/plugins/annotation-editor/AnnotationEditorController.svelte.d.ts +9 -0
- package/dist/plugins/annotation-editor/AnnotationEditorPanel.svelte +315 -0
- package/dist/plugins/annotation-editor/AnnotationEditorPanel.svelte.d.ts +24 -0
- package/dist/plugins/annotation-editor/AnnotationManager.svelte.d.ts +39 -0
- package/dist/plugins/annotation-editor/AnnotationManager.svelte.js +433 -0
- package/dist/plugins/annotation-editor/adapters/LocalStorageAdapter.d.ts +20 -0
- package/dist/plugins/annotation-editor/adapters/LocalStorageAdapter.js +67 -0
- package/dist/plugins/annotation-editor/adapters/index.d.ts +2 -0
- package/dist/plugins/annotation-editor/adapters/index.js +1 -0
- package/dist/plugins/annotation-editor/adapters/types.d.ts +23 -0
- package/dist/plugins/annotation-editor/adapters/types.js +1 -0
- package/dist/plugins/annotation-editor/iife-entry.d.ts +15 -0
- package/dist/plugins/annotation-editor/iife-entry.js +35 -0
- package/dist/plugins/annotation-editor/index.d.ts +41 -0
- package/dist/plugins/annotation-editor/index.js +57 -0
- package/dist/plugins/annotation-editor/loader.svelte.d.ts +7 -0
- package/dist/plugins/annotation-editor/loader.svelte.js +32 -0
- package/dist/plugins/annotation-editor/types.d.ts +41 -0
- package/dist/plugins/annotation-editor/types.js +13 -0
- package/dist/plugins/annotation-editor.js +32824 -0
- package/dist/plugins/image-manipulation/ImageManipulationController.svelte +54 -0
- package/dist/plugins/image-manipulation/ImageManipulationController.svelte.d.ts +6 -0
- package/dist/plugins/image-manipulation/ImageManipulationPanel.svelte +19 -9
- package/dist/plugins/image-manipulation/ImageManipulationPanel.svelte.d.ts +1 -0
- package/dist/plugins/image-manipulation/iife-entry.d.ts +13 -0
- package/dist/plugins/image-manipulation/iife-entry.js +17 -0
- package/dist/plugins/image-manipulation/index.d.ts +15 -1
- package/dist/plugins/image-manipulation/index.js +21 -1
- package/dist/plugins/image-manipulation.js +265 -0
- package/dist/state/i18n.svelte.js +4 -2
- package/dist/state/manifests.svelte.d.ts +5 -0
- package/dist/state/manifests.svelte.js +42 -13
- package/dist/state/viewer.svelte.d.ts +14 -13
- package/dist/state/viewer.svelte.js +63 -74
- package/dist/triiiceratops-bundle.js +3208 -3126
- package/dist/triiiceratops-element.iife.js +99 -0
- package/dist/triiiceratops.css +1 -1
- package/dist/types/plugin.d.ts +21 -62
- package/dist/types/plugin.js +1 -23
- package/dist/utils/annotationAdapter.d.ts +12 -1
- package/dist/utils/annotationAdapter.js +98 -39
- package/package.json +13 -6
- package/dist/chunks/TriiiceratopsViewer-EViTQO_n.js +0 -10437
- package/dist/chunks/openseadragon-CHvATAD9.js +0 -12427
- package/dist/components/TriiiceratopsViewerElementImage.svelte +0 -143
- package/dist/components/TriiiceratopsViewerElementImage.svelte.d.ts +0 -27
- package/dist/custom-element-image.d.ts +0 -1
- package/dist/custom-element-image.js +0 -2
- package/dist/plugins/image-manipulation/ImageManipulationPlugin.svelte.d.ts +0 -19
- package/dist/plugins/image-manipulation/ImageManipulationPlugin.svelte.js +0 -87
- package/dist/triiiceratops-element-image.js +0 -555
- package/dist/triiiceratops-element.js +0 -114
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { getContext, onMount, onDestroy } from 'svelte';
|
|
3
|
+
import {
|
|
4
|
+
VIEWER_STATE_KEY,
|
|
5
|
+
type ViewerState,
|
|
6
|
+
} from '../../state/viewer.svelte';
|
|
7
|
+
import { AnnotationManager } from './AnnotationManager.svelte';
|
|
8
|
+
import AnnotationEditorPanel from './AnnotationEditorPanel.svelte';
|
|
9
|
+
import type {
|
|
10
|
+
AnnotationEditorConfig,
|
|
11
|
+
DrawingTool,
|
|
12
|
+
W3CAnnotationBody,
|
|
13
|
+
} from './types';
|
|
14
|
+
|
|
15
|
+
// Props from the plugin system
|
|
16
|
+
let {
|
|
17
|
+
isOpen = false,
|
|
18
|
+
close,
|
|
19
|
+
config,
|
|
20
|
+
}: {
|
|
21
|
+
isOpen: boolean;
|
|
22
|
+
close: () => void;
|
|
23
|
+
config: AnnotationEditorConfig;
|
|
24
|
+
} = $props();
|
|
25
|
+
|
|
26
|
+
const viewerState = getContext<ViewerState>(VIEWER_STATE_KEY);
|
|
27
|
+
|
|
28
|
+
// UI state
|
|
29
|
+
let isEditing = $state(false);
|
|
30
|
+
let activeTool = $state<DrawingTool>(config.defaultTool ?? 'rectangle');
|
|
31
|
+
let selectedAnnotation = $state<any>(null);
|
|
32
|
+
let showDeleteConfirm = $state(false);
|
|
33
|
+
let pendingDeleteId = $state<string | null>(null);
|
|
34
|
+
let canUndo = $state(false);
|
|
35
|
+
let canRedo = $state(false);
|
|
36
|
+
|
|
37
|
+
// Create the annotation manager
|
|
38
|
+
let manager: AnnotationManager | null = $state.raw(null);
|
|
39
|
+
|
|
40
|
+
onMount(() => {
|
|
41
|
+
if (viewerState?.osdViewer) {
|
|
42
|
+
const mgr = new AnnotationManager(config);
|
|
43
|
+
|
|
44
|
+
// Set up callbacks
|
|
45
|
+
mgr.onSelectionChange = (annotation) => {
|
|
46
|
+
selectedAnnotation = annotation;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
mgr.onUndoRedoChange = (undo, redo) => {
|
|
50
|
+
canUndo = undo;
|
|
51
|
+
canRedo = redo;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
mgr.onAnnotationCreated = (annotation) => {
|
|
55
|
+
selectedAnnotation = annotation;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
mgr.init(viewerState.osdViewer, viewerState.canvasId);
|
|
59
|
+
|
|
60
|
+
// Load initial annotations
|
|
61
|
+
if (viewerState.manifestId && viewerState.canvasId) {
|
|
62
|
+
mgr.handleCanvasChange(
|
|
63
|
+
viewerState.manifestId,
|
|
64
|
+
viewerState.canvasId,
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
manager = mgr;
|
|
69
|
+
} else {
|
|
70
|
+
console.warn(
|
|
71
|
+
'[AnnotationEditor] No OSD viewer available at mount time',
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
onDestroy(() => {
|
|
77
|
+
manager?.destroy();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Watch for canvas changes
|
|
81
|
+
$effect(() => {
|
|
82
|
+
const manifestId = viewerState?.manifestId;
|
|
83
|
+
const canvasId = viewerState?.canvasId;
|
|
84
|
+
manager?.handleCanvasChange(manifestId ?? null, canvasId ?? null);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Handlers
|
|
88
|
+
function handleToggleEditing() {
|
|
89
|
+
isEditing = !isEditing;
|
|
90
|
+
manager?.setEditing(isEditing);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function handleSetTool(tool: DrawingTool) {
|
|
94
|
+
activeTool = tool;
|
|
95
|
+
manager?.setTool(tool);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function handleSaveBodies(bodies: W3CAnnotationBody[]) {
|
|
99
|
+
if (selectedAnnotation && manager) {
|
|
100
|
+
await manager.updateAnnotationBodies(selectedAnnotation.id, bodies);
|
|
101
|
+
selectedAnnotation = null;
|
|
102
|
+
manager.cancelSelection();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function handleRequestDelete() {
|
|
107
|
+
if (selectedAnnotation) {
|
|
108
|
+
pendingDeleteId = selectedAnnotation.id;
|
|
109
|
+
showDeleteConfirm = true;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function handleConfirmDelete() {
|
|
114
|
+
if (pendingDeleteId && manager) {
|
|
115
|
+
await manager.deleteAnnotation(pendingDeleteId);
|
|
116
|
+
}
|
|
117
|
+
showDeleteConfirm = false;
|
|
118
|
+
pendingDeleteId = null;
|
|
119
|
+
selectedAnnotation = null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function handleCancelDelete() {
|
|
123
|
+
showDeleteConfirm = false;
|
|
124
|
+
pendingDeleteId = null;
|
|
125
|
+
manager?.cancelSelection();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function handleUndo() {
|
|
129
|
+
manager?.undo();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function handleRedo() {
|
|
133
|
+
manager?.redo();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function handleClose() {
|
|
137
|
+
if (isEditing) {
|
|
138
|
+
isEditing = false;
|
|
139
|
+
manager?.setEditing(false);
|
|
140
|
+
}
|
|
141
|
+
close();
|
|
142
|
+
}
|
|
143
|
+
</script>
|
|
144
|
+
|
|
145
|
+
<AnnotationEditorPanel
|
|
146
|
+
{isEditing}
|
|
147
|
+
{activeTool}
|
|
148
|
+
{selectedAnnotation}
|
|
149
|
+
{showDeleteConfirm}
|
|
150
|
+
{canUndo}
|
|
151
|
+
{canRedo}
|
|
152
|
+
availableTools={manager?.availableTools ?? [
|
|
153
|
+
'rectangle',
|
|
154
|
+
'polygon',
|
|
155
|
+
'point',
|
|
156
|
+
]}
|
|
157
|
+
onToggleEditing={handleToggleEditing}
|
|
158
|
+
onSetTool={handleSetTool}
|
|
159
|
+
onSaveBodies={handleSaveBodies}
|
|
160
|
+
onRequestDelete={handleRequestDelete}
|
|
161
|
+
onConfirmDelete={handleConfirmDelete}
|
|
162
|
+
onCancelDelete={handleCancelDelete}
|
|
163
|
+
onUndo={handleUndo}
|
|
164
|
+
onRedo={handleRedo}
|
|
165
|
+
onClose={handleClose}
|
|
166
|
+
/>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AnnotationEditorConfig } from './types';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
isOpen: boolean;
|
|
4
|
+
close: () => void;
|
|
5
|
+
config: AnnotationEditorConfig;
|
|
6
|
+
};
|
|
7
|
+
declare const AnnotationEditorController: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
8
|
+
type AnnotationEditorController = ReturnType<typeof AnnotationEditorController>;
|
|
9
|
+
export default AnnotationEditorController;
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import X from 'phosphor-svelte/lib/X';
|
|
3
|
+
import PencilSimple from 'phosphor-svelte/lib/PencilSimple';
|
|
4
|
+
import Rectangle from 'phosphor-svelte/lib/Rectangle';
|
|
5
|
+
import Polygon from 'phosphor-svelte/lib/Polygon';
|
|
6
|
+
import Trash from 'phosphor-svelte/lib/Trash';
|
|
7
|
+
import ArrowCounterClockwise from 'phosphor-svelte/lib/ArrowCounterClockwise';
|
|
8
|
+
import ArrowClockwise from 'phosphor-svelte/lib/ArrowClockwise';
|
|
9
|
+
import Plus from 'phosphor-svelte/lib/Plus';
|
|
10
|
+
import Warning from 'phosphor-svelte/lib/Warning';
|
|
11
|
+
import Target from 'phosphor-svelte/lib/Target';
|
|
12
|
+
import Check from 'phosphor-svelte/lib/Check';
|
|
13
|
+
import type { DrawingTool, W3CAnnotationBody } from './types';
|
|
14
|
+
import { W3C_PURPOSES } from './types';
|
|
15
|
+
import { setLocale, locales } from '../../paraglide/runtime';
|
|
16
|
+
import { m } from '../../paraglide/messages';
|
|
17
|
+
|
|
18
|
+
// Import Annotorious CSS for the drawing overlay to ensure it's loaded by Vite
|
|
19
|
+
import '@annotorious/openseadragon/annotorious-openseadragon.css';
|
|
20
|
+
|
|
21
|
+
// Props
|
|
22
|
+
let {
|
|
23
|
+
isEditing = false,
|
|
24
|
+
activeTool = 'rectangle' as DrawingTool,
|
|
25
|
+
selectedAnnotation = null as any,
|
|
26
|
+
showDeleteConfirm = false,
|
|
27
|
+
canUndo = false,
|
|
28
|
+
canRedo = false,
|
|
29
|
+
availableTools = ['rectangle', 'polygon', 'point'] as DrawingTool[],
|
|
30
|
+
onToggleEditing,
|
|
31
|
+
onSetTool,
|
|
32
|
+
onSaveBodies,
|
|
33
|
+
onRequestDelete,
|
|
34
|
+
onConfirmDelete,
|
|
35
|
+
onCancelDelete,
|
|
36
|
+
onUndo,
|
|
37
|
+
onRedo,
|
|
38
|
+
onClose,
|
|
39
|
+
locale,
|
|
40
|
+
}: {
|
|
41
|
+
isEditing: boolean;
|
|
42
|
+
activeTool: DrawingTool;
|
|
43
|
+
selectedAnnotation: any;
|
|
44
|
+
showDeleteConfirm: boolean;
|
|
45
|
+
canUndo: boolean;
|
|
46
|
+
canRedo: boolean;
|
|
47
|
+
availableTools: DrawingTool[];
|
|
48
|
+
onToggleEditing: () => void;
|
|
49
|
+
onSetTool: (tool: DrawingTool) => void;
|
|
50
|
+
onSaveBodies: (bodies: W3CAnnotationBody[]) => void;
|
|
51
|
+
onRequestDelete: () => void;
|
|
52
|
+
onConfirmDelete: () => void;
|
|
53
|
+
onCancelDelete: () => void;
|
|
54
|
+
onUndo: () => void;
|
|
55
|
+
onRedo: () => void;
|
|
56
|
+
onClose: () => void;
|
|
57
|
+
locale?: string;
|
|
58
|
+
} = $props();
|
|
59
|
+
|
|
60
|
+
// Tool icons
|
|
61
|
+
const toolIcons: Record<string, any> = {
|
|
62
|
+
rectangle: Rectangle,
|
|
63
|
+
polygon: Polygon,
|
|
64
|
+
point: Target,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// Body editor state (local copy for editing)
|
|
68
|
+
let editableBodies = $state<W3CAnnotationBody[]>([]);
|
|
69
|
+
|
|
70
|
+
// Sync when a new annotation is selected
|
|
71
|
+
$effect(() => {
|
|
72
|
+
if (selectedAnnotation) {
|
|
73
|
+
const body = selectedAnnotation.body;
|
|
74
|
+
if (Array.isArray(body)) {
|
|
75
|
+
editableBodies = body.map((b: any) => ({ ...b }));
|
|
76
|
+
} else if (body) {
|
|
77
|
+
editableBodies = [{ ...body }];
|
|
78
|
+
} else {
|
|
79
|
+
editableBodies = [];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
$effect(() => {
|
|
85
|
+
if (locale && locales.includes(locale as any)) {
|
|
86
|
+
setLocale(locale as any);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
function addBody() {
|
|
91
|
+
editableBodies = [
|
|
92
|
+
...editableBodies,
|
|
93
|
+
{ purpose: 'commenting', value: '' },
|
|
94
|
+
];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function removeBody(index: number) {
|
|
98
|
+
editableBodies = editableBodies.filter((_, i) => i !== index);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function handleSaveBodies() {
|
|
102
|
+
// Filter empty bodies
|
|
103
|
+
const valid = editableBodies.filter((b) => b.value?.trim());
|
|
104
|
+
onSaveBodies(valid);
|
|
105
|
+
}
|
|
106
|
+
</script>
|
|
107
|
+
|
|
108
|
+
<div
|
|
109
|
+
class="w-80 h-full bg-base-200 border-r border-base-300 shadow-xl flex flex-col"
|
|
110
|
+
>
|
|
111
|
+
<!-- Header -->
|
|
112
|
+
<div class="flex items-center justify-between p-4 border-b border-base-300">
|
|
113
|
+
<h2 class="text-lg font-semibold flex items-center gap-2">
|
|
114
|
+
<PencilSimple size={20} />
|
|
115
|
+
{m.annotation_editor_title()}
|
|
116
|
+
</h2>
|
|
117
|
+
<button
|
|
118
|
+
class="btn btn-sm btn-ghost btn-circle"
|
|
119
|
+
onclick={onClose}
|
|
120
|
+
aria-label={m.close()}
|
|
121
|
+
>
|
|
122
|
+
<X size={20} />
|
|
123
|
+
</button>
|
|
124
|
+
</div>
|
|
125
|
+
|
|
126
|
+
<div class="flex-1 overflow-y-auto p-4 space-y-6">
|
|
127
|
+
<!-- Drawing Mode Toggle -->
|
|
128
|
+
<div class="flex flex-col gap-2">
|
|
129
|
+
<div class="join grid grid-cols-2 w-full">
|
|
130
|
+
<button
|
|
131
|
+
class="join-item btn btn-sm {!isEditing
|
|
132
|
+
? 'btn-secondary'
|
|
133
|
+
: ''}"
|
|
134
|
+
onclick={() => isEditing && onToggleEditing()}
|
|
135
|
+
>
|
|
136
|
+
{m.annotation_editor_edit_mode()}
|
|
137
|
+
</button>
|
|
138
|
+
<button
|
|
139
|
+
class="join-item btn btn-sm {isEditing
|
|
140
|
+
? 'btn-primary'
|
|
141
|
+
: ''}"
|
|
142
|
+
onclick={() => !isEditing && onToggleEditing()}
|
|
143
|
+
>
|
|
144
|
+
{m.annotation_editor_create_mode()}
|
|
145
|
+
</button>
|
|
146
|
+
</div>
|
|
147
|
+
<p class="text-xs opacity-60 text-center">
|
|
148
|
+
{isEditing
|
|
149
|
+
? m.annotation_editor_instruction_create()
|
|
150
|
+
: m.annotation_editor_instruction_edit()}
|
|
151
|
+
</p>
|
|
152
|
+
</div>
|
|
153
|
+
|
|
154
|
+
<!-- Tool Selection -->
|
|
155
|
+
{#if isEditing}
|
|
156
|
+
<div class="space-y-2">
|
|
157
|
+
<p class="text-sm font-medium">
|
|
158
|
+
{m.annotation_editor_tool_label()}
|
|
159
|
+
</p>
|
|
160
|
+
<div class="join">
|
|
161
|
+
{#each availableTools as tool}
|
|
162
|
+
{@const Icon = toolIcons[tool] ?? Rectangle}
|
|
163
|
+
{@const toolName =
|
|
164
|
+
{
|
|
165
|
+
rectangle: m.annotation_tool_rectangle(),
|
|
166
|
+
polygon: m.annotation_tool_polygon(),
|
|
167
|
+
point: m.annotation_tool_point(),
|
|
168
|
+
}[tool] ?? tool}
|
|
169
|
+
<button
|
|
170
|
+
class="join-item btn btn-sm tooltip tooltip-bottom {activeTool ===
|
|
171
|
+
tool
|
|
172
|
+
? 'btn-primary'
|
|
173
|
+
: ''}"
|
|
174
|
+
data-tip={toolName}
|
|
175
|
+
onclick={() => onSetTool(tool)}
|
|
176
|
+
aria-label={toolName}
|
|
177
|
+
>
|
|
178
|
+
<Icon size={18} />
|
|
179
|
+
</button>
|
|
180
|
+
{/each}
|
|
181
|
+
</div>
|
|
182
|
+
</div>
|
|
183
|
+
|
|
184
|
+
<!-- Undo/Redo -->
|
|
185
|
+
<div class="flex gap-2">
|
|
186
|
+
<button
|
|
187
|
+
class="btn btn-sm btn-outline flex-1"
|
|
188
|
+
disabled={!canUndo}
|
|
189
|
+
onclick={onUndo}
|
|
190
|
+
>
|
|
191
|
+
<ArrowCounterClockwise size={16} />
|
|
192
|
+
{m.annotation_editor_undo()}
|
|
193
|
+
</button>
|
|
194
|
+
<button
|
|
195
|
+
class="btn btn-sm btn-outline flex-1"
|
|
196
|
+
disabled={!canRedo}
|
|
197
|
+
onclick={onRedo}
|
|
198
|
+
>
|
|
199
|
+
<ArrowClockwise size={16} />
|
|
200
|
+
{m.annotation_editor_redo()}
|
|
201
|
+
</button>
|
|
202
|
+
</div>
|
|
203
|
+
{/if}
|
|
204
|
+
|
|
205
|
+
<!-- Selected Annotation Editor (Inline) -->
|
|
206
|
+
{#if selectedAnnotation}
|
|
207
|
+
<div class="card bg-base-100 p-4 space-y-3">
|
|
208
|
+
<div class="flex items-center justify-between mb-2">
|
|
209
|
+
<h3 class="font-medium text-sm">
|
|
210
|
+
{m.annotation_editor_edit_section()}
|
|
211
|
+
</h3>
|
|
212
|
+
<div class="flex gap-1">
|
|
213
|
+
<button
|
|
214
|
+
class="btn btn-sm btn-error btn-ghost btn-circle"
|
|
215
|
+
onclick={onRequestDelete}
|
|
216
|
+
aria-label={m.annotation_editor_delete_tooltip()}
|
|
217
|
+
>
|
|
218
|
+
<Trash size={16} />
|
|
219
|
+
</button>
|
|
220
|
+
</div>
|
|
221
|
+
</div>
|
|
222
|
+
|
|
223
|
+
<div class="space-y-3 max-h-[40vh] overflow-y-auto pr-1">
|
|
224
|
+
{#each editableBodies as body, i}
|
|
225
|
+
<div class="card bg-base-200 p-2 space-y-2">
|
|
226
|
+
<div class="flex items-center gap-2">
|
|
227
|
+
<select
|
|
228
|
+
class="select select-xs select-bordered flex-1"
|
|
229
|
+
bind:value={body.purpose}
|
|
230
|
+
>
|
|
231
|
+
{#each W3C_PURPOSES as purpose}
|
|
232
|
+
<option
|
|
233
|
+
value={purpose}
|
|
234
|
+
class="capitalize">{purpose}</option
|
|
235
|
+
>
|
|
236
|
+
{/each}
|
|
237
|
+
</select>
|
|
238
|
+
<button
|
|
239
|
+
class="btn btn-xs btn-ghost btn-circle text-error"
|
|
240
|
+
onclick={() => removeBody(i)}
|
|
241
|
+
>
|
|
242
|
+
<X size={14} />
|
|
243
|
+
</button>
|
|
244
|
+
</div>
|
|
245
|
+
|
|
246
|
+
{#if body.purpose === 'tagging'}
|
|
247
|
+
<input
|
|
248
|
+
type="text"
|
|
249
|
+
class="input input-xs input-bordered w-full"
|
|
250
|
+
placeholder={m.annotation_editor_tag_placeholder()}
|
|
251
|
+
bind:value={body.value}
|
|
252
|
+
/>
|
|
253
|
+
{:else if body.purpose === 'linking'}
|
|
254
|
+
<input
|
|
255
|
+
type="url"
|
|
256
|
+
class="input input-xs input-bordered w-full"
|
|
257
|
+
placeholder={m.annotation_editor_link_placeholder()}
|
|
258
|
+
bind:value={body.value}
|
|
259
|
+
/>
|
|
260
|
+
{:else}
|
|
261
|
+
<textarea
|
|
262
|
+
class="textarea textarea-xs textarea-bordered w-full"
|
|
263
|
+
rows="2"
|
|
264
|
+
placeholder={m.annotation_editor_text_placeholder()}
|
|
265
|
+
bind:value={body.value}
|
|
266
|
+
></textarea>
|
|
267
|
+
{/if}
|
|
268
|
+
</div>
|
|
269
|
+
{/each}
|
|
270
|
+
</div>
|
|
271
|
+
|
|
272
|
+
<button class="btn btn-xs btn-ghost w-full" onclick={addBody}>
|
|
273
|
+
<Plus size={14} />
|
|
274
|
+
{m.annotation_editor_add_content()}
|
|
275
|
+
</button>
|
|
276
|
+
|
|
277
|
+
<div class="pt-2">
|
|
278
|
+
<button
|
|
279
|
+
class="btn btn-sm btn-primary w-full"
|
|
280
|
+
onclick={handleSaveBodies}
|
|
281
|
+
>
|
|
282
|
+
<Check size={16} />
|
|
283
|
+
{m.annotation_editor_save()}
|
|
284
|
+
</button>
|
|
285
|
+
</div>
|
|
286
|
+
</div>
|
|
287
|
+
{/if}
|
|
288
|
+
</div>
|
|
289
|
+
</div>
|
|
290
|
+
|
|
291
|
+
<!-- Delete Confirmation Modal (Keep as modal for safety) -->
|
|
292
|
+
{#if showDeleteConfirm}
|
|
293
|
+
<dialog class="modal modal-open">
|
|
294
|
+
<div class="modal-box">
|
|
295
|
+
<h3 class="font-bold text-lg flex items-center gap-2">
|
|
296
|
+
<Warning size={24} class="text-warning" />
|
|
297
|
+
{m.annotation_editor_delete_title()}
|
|
298
|
+
</h3>
|
|
299
|
+
<p class="py-4">
|
|
300
|
+
{m.annotation_editor_delete_message()}
|
|
301
|
+
</p>
|
|
302
|
+
<div class="modal-action">
|
|
303
|
+
<button class="btn btn-ghost" onclick={onCancelDelete}>
|
|
304
|
+
{m.annotation_editor_cancel()}
|
|
305
|
+
</button>
|
|
306
|
+
<button class="btn btn-error" onclick={onConfirmDelete}>
|
|
307
|
+
{m.annotation_editor_delete()}
|
|
308
|
+
</button>
|
|
309
|
+
</div>
|
|
310
|
+
</div>
|
|
311
|
+
<form method="dialog" class="modal-backdrop">
|
|
312
|
+
<button onclick={onCancelDelete}>close</button>
|
|
313
|
+
</form>
|
|
314
|
+
</dialog>
|
|
315
|
+
{/if}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { DrawingTool, W3CAnnotationBody } from './types';
|
|
2
|
+
import '@annotorious/openseadragon/annotorious-openseadragon.css';
|
|
3
|
+
type $$ComponentProps = {
|
|
4
|
+
isEditing: boolean;
|
|
5
|
+
activeTool: DrawingTool;
|
|
6
|
+
selectedAnnotation: any;
|
|
7
|
+
showDeleteConfirm: boolean;
|
|
8
|
+
canUndo: boolean;
|
|
9
|
+
canRedo: boolean;
|
|
10
|
+
availableTools: DrawingTool[];
|
|
11
|
+
onToggleEditing: () => void;
|
|
12
|
+
onSetTool: (tool: DrawingTool) => void;
|
|
13
|
+
onSaveBodies: (bodies: W3CAnnotationBody[]) => void;
|
|
14
|
+
onRequestDelete: () => void;
|
|
15
|
+
onConfirmDelete: () => void;
|
|
16
|
+
onCancelDelete: () => void;
|
|
17
|
+
onUndo: () => void;
|
|
18
|
+
onRedo: () => void;
|
|
19
|
+
onClose: () => void;
|
|
20
|
+
locale?: string;
|
|
21
|
+
};
|
|
22
|
+
declare const AnnotationEditorPanel: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
23
|
+
type AnnotationEditorPanel = ReturnType<typeof AnnotationEditorPanel>;
|
|
24
|
+
export default AnnotationEditorPanel;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { AnnotationEditorConfig, DrawingTool, W3CAnnotationBody } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Manages the Annotorious instance and annotation CRUD operations.
|
|
4
|
+
* Instantiated within the controller component.
|
|
5
|
+
*/
|
|
6
|
+
export declare class AnnotationManager {
|
|
7
|
+
private config;
|
|
8
|
+
private adapter;
|
|
9
|
+
private annotorious;
|
|
10
|
+
private osdViewer;
|
|
11
|
+
private currentManifestId;
|
|
12
|
+
private currentCanvasId;
|
|
13
|
+
private isDrawingEnabled;
|
|
14
|
+
private activeTool;
|
|
15
|
+
onSelectionChange?: (annotation: any | null) => void;
|
|
16
|
+
onUndoRedoChange?: (canUndo: boolean, canRedo: boolean) => void;
|
|
17
|
+
onAnnotationCreated?: (annotation: any) => void;
|
|
18
|
+
constructor(config: AnnotationEditorConfig);
|
|
19
|
+
init(viewer: any, canvasId: string | null): void;
|
|
20
|
+
private initAnnotorious;
|
|
21
|
+
private handlePointClick;
|
|
22
|
+
setEditing(enabled: boolean): void;
|
|
23
|
+
private updateDrawingMode;
|
|
24
|
+
setTool(tool: DrawingTool): void;
|
|
25
|
+
get availableTools(): DrawingTool[];
|
|
26
|
+
private injectStyles;
|
|
27
|
+
private setupEvents;
|
|
28
|
+
private updateUndoRedoState;
|
|
29
|
+
handleCanvasChange(manifestId: string | null, canvasId: string | null): Promise<void>;
|
|
30
|
+
private loadAnnotations;
|
|
31
|
+
saveAnnotation(annotation: any): Promise<void>;
|
|
32
|
+
private ensureTargetSource;
|
|
33
|
+
deleteAnnotation(annotationId: string): Promise<void>;
|
|
34
|
+
updateAnnotationBodies(annotationId: string, bodies: W3CAnnotationBody[]): Promise<void>;
|
|
35
|
+
cancelSelection(): void;
|
|
36
|
+
undo(): void;
|
|
37
|
+
redo(): void;
|
|
38
|
+
destroy(): void;
|
|
39
|
+
}
|