|
11 | 11 | <b-button v-if="IS_SCRIPT_EDITOR" v-b-modal.new-config-modal variant="outline-success"> |
12 | 12 | New Style |
13 | 13 | </b-button> |
| 14 | + <b-button |
| 15 | + v-if="IS_SCRIPT_EDITOR" |
| 16 | + variant="outline-info" |
| 17 | + class="ml-2" |
| 18 | + @click="openImportModal" |
| 19 | + > |
| 20 | + Import Style |
| 21 | + </b-button> |
| 22 | + <b-modal |
| 23 | + id="import-style-modal" |
| 24 | + ref="import-style-modal" |
| 25 | + title="Import Stage Direction Style" |
| 26 | + size="xl" |
| 27 | + ok-only |
| 28 | + ok-title="Close" |
| 29 | + @hidden="resetImportState" |
| 30 | + > |
| 31 | + <div v-if="isLoadingImport" class="text-center py-3"> |
| 32 | + <b-spinner /> |
| 33 | + </div> |
| 34 | + <div v-else-if="importStyleGroups.length === 0" class="text-muted text-center py-3"> |
| 35 | + No styles available to import from other shows. |
| 36 | + </div> |
| 37 | + <div v-else> |
| 38 | + <b-card v-for="show in importStyleGroups" :key="show.id" no-body class="mb-2"> |
| 39 | + <b-card-header class="section-card-header" @click="toggleImportShow(show.id)"> |
| 40 | + <div class="d-flex justify-content-between align-items-center"> |
| 41 | + <span>{{ show.name }}</span> |
| 42 | + <b-icon-chevron-down v-if="styleGroupExpanded[show.id]" font-scale="0.8" /> |
| 43 | + <b-icon-chevron-up v-else font-scale="0.8" /> |
| 44 | + </div> |
| 45 | + </b-card-header> |
| 46 | + <b-collapse :visible="styleGroupExpanded[show.id]"> |
| 47 | + <b-card-body class="p-0"> |
| 48 | + <b-table :items="show.styles" :fields="importColumns" small show-empty class="mb-0"> |
| 49 | + <template #cell(example)="row"> |
| 50 | + <i class="example-stage-direction" :style="exampleCss(row.item)"> |
| 51 | + <template v-if="row.item.text_format === 'upper'"> |
| 52 | + {{ exampleText | uppercase }} |
| 53 | + </template> |
| 54 | + <template v-else-if="row.item.text_format === 'lower'"> |
| 55 | + {{ exampleText | lowercase }} |
| 56 | + </template> |
| 57 | + <template v-else> |
| 58 | + {{ exampleText }} |
| 59 | + </template> |
| 60 | + </i> |
| 61 | + </template> |
| 62 | + <template #cell(btn)="row"> |
| 63 | + <b-button |
| 64 | + variant="outline-success" |
| 65 | + size="sm" |
| 66 | + :disabled="!!isImporting[row.item.id]" |
| 67 | + @click="importStyle(row.item)" |
| 68 | + > |
| 69 | + <b-spinner v-if="isImporting[row.item.id]" small /> |
| 70 | + <span v-else>Import</span> |
| 71 | + </b-button> |
| 72 | + </template> |
| 73 | + </b-table> |
| 74 | + </b-card-body> |
| 75 | + </b-collapse> |
| 76 | + </b-card> |
| 77 | + </div> |
| 78 | + </b-modal> |
14 | 79 | <b-modal |
15 | 80 | id="new-config-modal" |
16 | 81 | ref="new-config-modal" |
@@ -292,6 +357,11 @@ export default { |
292 | 357 | { key: 'example', label: 'Example Stage Direction' }, |
293 | 358 | { key: 'btn', label: '' }, |
294 | 359 | ], |
| 360 | + importColumns: [ |
| 361 | + 'description', |
| 362 | + { key: 'example', label: 'Example Stage Direction' }, |
| 363 | + { key: 'btn', label: '' }, |
| 364 | + ], |
295 | 365 | rowsPerPage: 15, |
296 | 366 | currentPage: 1, |
297 | 367 | newStyleFormState: { |
@@ -322,6 +392,10 @@ export default { |
322 | 392 | isSubmittingNew: false, |
323 | 393 | isSubmittingEdit: false, |
324 | 394 | isDeleting: false, |
| 395 | + importStyleGroups: [], |
| 396 | + styleGroupExpanded: {}, |
| 397 | + isLoadingImport: false, |
| 398 | + isImporting: {}, |
325 | 399 | }; |
326 | 400 | }, |
327 | 401 | computed: { |
@@ -587,11 +661,60 @@ export default { |
587 | 661 | } |
588 | 662 | return style; |
589 | 663 | }, |
| 664 | + async openImportModal() { |
| 665 | + this.$bvModal.show('import-style-modal'); |
| 666 | + this.isLoadingImport = true; |
| 667 | + try { |
| 668 | + const data = await this.GET_IMPORTABLE_STAGE_DIRECTION_STYLES(); |
| 669 | + this.importStyleGroups = data.style_groups; |
| 670 | + const expanded = {}; |
| 671 | + data.style_groups.forEach((group) => { |
| 672 | + expanded[group.id] = true; |
| 673 | + }); |
| 674 | + this.styleGroupExpanded = expanded; |
| 675 | + } catch (error) { |
| 676 | + log.error('Error fetching importable stage direction styles:', error); |
| 677 | + this.$toast.error('Failed to load styles for import'); |
| 678 | + } finally { |
| 679 | + this.isLoadingImport = false; |
| 680 | + } |
| 681 | + }, |
| 682 | + resetImportState() { |
| 683 | + this.importStyleGroups = []; |
| 684 | + this.styleGroupExpanded = {}; |
| 685 | + this.isLoadingImport = false; |
| 686 | + this.isImporting = {}; |
| 687 | + }, |
| 688 | + toggleImportShow(showId) { |
| 689 | + this.$set(this.styleGroupExpanded, showId, !this.styleGroupExpanded[showId]); |
| 690 | + }, |
| 691 | + async importStyle(style) { |
| 692 | + this.$set(this.isImporting, style.id, true); |
| 693 | + try { |
| 694 | + await this.ADD_STAGE_DIRECTION_STYLE({ |
| 695 | + description: style.description, |
| 696 | + bold: style.bold, |
| 697 | + italic: style.italic, |
| 698 | + underline: style.underline, |
| 699 | + textFormat: style.text_format, |
| 700 | + textColour: style.text_colour, |
| 701 | + enableBackgroundColour: style.enable_background_colour, |
| 702 | + backgroundColour: style.background_colour, |
| 703 | + }); |
| 704 | + this.$toast.success(`Imported "${style.description}"`); |
| 705 | + } catch (error) { |
| 706 | + log.error('Error importing stage direction style:', error); |
| 707 | + this.$toast.error(`Failed to import "${style.description}"`); |
| 708 | + } finally { |
| 709 | + this.$set(this.isImporting, style.id, false); |
| 710 | + } |
| 711 | + }, |
590 | 712 | ...mapActions([ |
591 | 713 | 'GET_STAGE_DIRECTION_STYLES', |
592 | 714 | 'ADD_STAGE_DIRECTION_STYLE', |
593 | 715 | 'DELETE_STAGE_DIRECTION_STYLE', |
594 | 716 | 'UPDATE_STAGE_DIRECTION_STYLE', |
| 717 | + 'GET_IMPORTABLE_STAGE_DIRECTION_STYLES', |
595 | 718 | ]), |
596 | 719 | }, |
597 | 720 | }; |
|
0 commit comments