diff --git a/libs/features/spell/src/spell-copy/spell-copy.component.html b/libs/features/spell/src/spell-copy/spell-copy.component.html
new file mode 100644
index 0000000000..eef15371cc
--- /dev/null
+++ b/libs/features/spell/src/spell-copy/spell-copy.component.html
@@ -0,0 +1,10 @@
+@if (sourceId && newId) {
+
+}
diff --git a/libs/features/spell/src/spell-copy/spell-copy.component.ts b/libs/features/spell/src/spell-copy/spell-copy.component.ts
new file mode 100644
index 0000000000..e974873280
--- /dev/null
+++ b/libs/features/spell/src/spell-copy/spell-copy.component.ts
@@ -0,0 +1,34 @@
+import { ChangeDetectionStrategy, Component, inject, OnInit } from '@angular/core';
+import { CopyOutputComponent } from '@keira/shared/base-editor-components';
+import { SpellHandlerService } from '../spell-handler.service';
+import { Router } from '@angular/router';
+import { SPELL_DBC_TABLE, SPELL_DBC_ID, SPELL_LOOT_TEMPLATE_TABLE, LOOT_TEMPLATE_ID } from '@keira/shared/acore-world-model';
+
+@Component({
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ selector: 'keira-spell-copy',
+ templateUrl: './spell-copy.component.html',
+
+ imports: [CopyOutputComponent],
+})
+export class SpellCopyComponent implements OnInit {
+ private readonly router = inject(Router);
+ protected readonly handlerService = inject(SpellHandlerService);
+
+ protected readonly tableName = SPELL_DBC_TABLE;
+ protected readonly idField = SPELL_DBC_ID;
+ protected sourceId!: string | number;
+ protected newId!: string | number;
+
+ protected readonly relatedTables = [{ tableName: SPELL_LOOT_TEMPLATE_TABLE, idField: LOOT_TEMPLATE_ID }];
+
+ ngOnInit(): void {
+ if (!this.handlerService.sourceId || !this.handlerService.selected) {
+ this.router.navigate(['/spell/select']);
+ return;
+ }
+
+ this.sourceId = this.handlerService.sourceId;
+ this.newId = this.handlerService.selected;
+ }
+}
diff --git a/libs/features/spell/src/spell-handler.service.ts b/libs/features/spell/src/spell-handler.service.ts
index 384e006401..135ae1bb2e 100644
--- a/libs/features/spell/src/spell-handler.service.ts
+++ b/libs/features/spell/src/spell-handler.service.ts
@@ -7,6 +7,7 @@ import { SPELL_DBC_TABLE, SpellDbc } from '@keira/shared/acore-world-model';
})
export class SpellHandlerService extends HandlerService
{
protected readonly mainEditorRoutePath = 'spell/spell-dbc';
+ protected override readonly copyRoutePath = 'spell/copy';
get isSpellDbcUnsaved(): Signal {
return this.statusMap[SPELL_DBC_TABLE].asReadonly();
diff --git a/libs/features/texts/src/acore-string/acore-string-copy.component.html b/libs/features/texts/src/acore-string/acore-string-copy.component.html
new file mode 100644
index 0000000000..eef15371cc
--- /dev/null
+++ b/libs/features/texts/src/acore-string/acore-string-copy.component.html
@@ -0,0 +1,10 @@
+@if (sourceId && newId) {
+
+}
diff --git a/libs/features/texts/src/acore-string/acore-string-copy.component.ts b/libs/features/texts/src/acore-string/acore-string-copy.component.ts
new file mode 100644
index 0000000000..629fe50506
--- /dev/null
+++ b/libs/features/texts/src/acore-string/acore-string-copy.component.ts
@@ -0,0 +1,34 @@
+import { ChangeDetectionStrategy, Component, inject, OnInit } from '@angular/core';
+import { CopyOutputComponent } from '@keira/shared/base-editor-components';
+import { AcoreStringHandlerService } from './acore-string-handler.service';
+import { Router } from '@angular/router';
+import { ACORE_STRING_TABLE, ACORE_STRING_ENTRY } from '@keira/shared/acore-world-model';
+
+@Component({
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ selector: 'keira-acore-string-copy',
+ templateUrl: './acore-string-copy.component.html',
+
+ imports: [CopyOutputComponent],
+})
+export class AcoreStringCopyComponent implements OnInit {
+ private readonly router = inject(Router);
+ protected readonly handlerService = inject(AcoreStringHandlerService);
+
+ protected readonly tableName = ACORE_STRING_TABLE;
+ protected readonly idField = ACORE_STRING_ENTRY;
+ protected sourceId!: string | number;
+ protected newId!: string | number;
+
+ protected readonly relatedTables: Array<{ tableName: string; idField: string }> = [];
+
+ ngOnInit(): void {
+ if (!this.handlerService.sourceId || !this.handlerService.selected) {
+ this.router.navigate(['/texts/select-acore-string']);
+ return;
+ }
+
+ this.sourceId = this.handlerService.sourceId;
+ this.newId = this.handlerService.selected;
+ }
+}
diff --git a/libs/features/texts/src/acore-string/acore-string-handler.service.ts b/libs/features/texts/src/acore-string/acore-string-handler.service.ts
index 6112bd75fc..f835352a85 100644
--- a/libs/features/texts/src/acore-string/acore-string-handler.service.ts
+++ b/libs/features/texts/src/acore-string/acore-string-handler.service.ts
@@ -7,6 +7,7 @@ import { ACORE_STRING_TABLE, AcoreString } from '@keira/shared/acore-world-model
})
export class AcoreStringHandlerService extends HandlerService {
protected readonly mainEditorRoutePath = 'texts/acore-string';
+ protected override readonly copyRoutePath = 'texts/acore-string-copy';
get isUnsaved(): Signal {
return this.statusMap[ACORE_STRING_TABLE].asReadonly();
diff --git a/libs/features/texts/src/acore-string/select-acore-string.component.html b/libs/features/texts/src/acore-string/select-acore-string.component.html
index d6bfd767bd..a4ae495dee 100644
--- a/libs/features/texts/src/acore-string/select-acore-string.component.html
+++ b/libs/features/texts/src/acore-string/select-acore-string.component.html
@@ -8,6 +8,7 @@
[customStartingId]="customStartingId"
[handlerService]="handlerService"
[queryService]="queryService"
+ [allowCopy]="true"
/>
diff --git a/libs/features/texts/src/index.ts b/libs/features/texts/src/index.ts
index c4209b8c94..e2d315f57f 100644
--- a/libs/features/texts/src/index.ts
+++ b/libs/features/texts/src/index.ts
@@ -1,6 +1,7 @@
export { PageTextHandlerService } from './page-text/page-text-handler.service';
export { SelectPageTextComponent } from './page-text/select-page-text.component';
export { PageTextComponent } from './page-text/page-text.component';
+export { PageTextCopyComponent } from './page-text/page-text-copy.component';
export { BroadcastTextHandlerService } from './broadcast-text/broadcast-text-handler.service';
export { SelectBroadcastTextComponent } from './broadcast-text/select-broadcast-text.component';
@@ -9,7 +10,9 @@ export { BroadcastTextComponent } from './broadcast-text/broadcast-text.componen
export { NpcTextHandlerService } from './npc-text/npc-text-handler.service';
export { SelectNpcTextComponent } from './npc-text/select-npc-text.component';
export { NpcTextComponent } from './npc-text/npc-text.component';
+export { NpcTextCopyComponent } from './npc-text/npc-text-copy.component';
export { AcoreStringHandlerService } from './acore-string/acore-string-handler.service';
export { SelectAcoreStringComponent } from './acore-string/select-acore-string.component';
export { AcoreStringComponent } from './acore-string/acore-string.component';
+export { AcoreStringCopyComponent } from './acore-string/acore-string-copy.component';
diff --git a/libs/features/texts/src/npc-text/npc-text-copy.component.html b/libs/features/texts/src/npc-text/npc-text-copy.component.html
new file mode 100644
index 0000000000..eef15371cc
--- /dev/null
+++ b/libs/features/texts/src/npc-text/npc-text-copy.component.html
@@ -0,0 +1,10 @@
+@if (sourceId && newId) {
+