Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate Storylines Editor to Vue3 #242

Merged
merged 12 commits into from
Jan 15, 2024
Merged
35,471 changes: 9,698 additions & 25,773 deletions package-lock.json

Large diffs are not rendered by default.

47 changes: 22 additions & 25 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,58 +1,55 @@
{
"name": "story-ramp",
"version": "0.1.0",
"name": "storylines-editor",
"version": "1.0.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"@kangc/v-md-editor": "^1.7.11",
"@kangc/v-md-editor": "^2.3.17",
"@tailwindcss/typography": "^0.4.0",
"@types/highcharts": "^7.0.0",
"axios": "^1.2.0",
"clone-deep": "^4.0.1",
"core-js": "^3.6.5",
"file-saver": "^2.0.5",
"highcharts": "^9.3.2",
"highcharts-vue": "^1.4.0",
"hooper": "^0.3.4",
"highcharts-vue": "^1.4.3",
"intersection-observer": "^0.12.0",
"jszip": "^3.10.1",
"markdown-it": "^12.0.6",
"nouislider": "^15.5.0",
"ramp-storylines": "^3.0.4",
"uuid": "^9.0.0",
"vue": "^2.6.11",
"vue-class-component": "^7.2.3",
"vue-fullscreen": "^2.6.1",
"vue-i18n": "^8.27.2",
"vue-loading-spinner": "^1.0.11",
"vue-m-message": "^3.1.0",
"vue-papa-parse": "^3.0.4",
"vue-progressive-image": "^3.2.0",
"vue-property-decorator": "^9.1.2",
"vue-router": "^3.5.3",
"vue-scrollama": "^2.0.2",
"vue-tippy": "^4.10.0",
"vue2-modal": "^1.5.1",
"vuedraggable": "^2.24.3"
"vue": "^3.3.4",
"vue-class-component": "^8.0.0-rc.1",
"vue-final-modal": "^4.4.5",
"vue-i18n": "^9.2.2",
"vue-m-message": "^4.0.2",
"vue-property-decorator": "^10.0.0-rc.2",
"vue-router": "^4.2.4",
"vue-tippy": "^6.3.1",
"vue3-spinners": "^1.2.2",
"vuedraggable": "^4.1.0"
},
"devDependencies": {
"@types/clone-deep": "^4.0.1",
"@types/file-saver": "^2.0.5",
"@types/markdown-it": "^12.0.1",
"@typescript-eslint/eslint-plugin": "^4.18.0",
"@typescript-eslint/parser": "^4.18.0",
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-typescript": "~4.5.0",
"@vue/cli-service": "^4.1.1",
"@vue/cli-plugin-babel": "^4.5.19",
"@vue/cli-plugin-eslint": "^4.5.19",
"@vue/cli-plugin-typescript": "^4.5.19",
"@vue/cli-service": "^4.5.19",
"@vue/compiler-sfc": "^3.3.4",
"@vue/eslint-config-prettier": "^6.0.0",
"@vue/eslint-config-typescript": "^7.0.0",
"autoprefixer": "^9.8.6",
"dsv-loader": "^2.0.0",
"eslint": "^6.7.2",
"eslint": "^6.8.0",
"eslint-plugin-prettier": "^3.3.1",
"eslint-plugin-vue": "^6.2.2",
"html-loader": "^0.5.5",
Expand All @@ -62,6 +59,6 @@
"sass-loader": "^8.0.2",
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.1.2",
"typescript": "~4.1.5",
"vue-template-compiler": "^2.6.11"
"vue-eslint-parser": "^9.3.1"
}
}

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<script src="https://code.highcharts.com/highcharts.js" type="text/javascript" charset="utf-8"></script>
<script src="https://code.highcharts.com/modules/data.js" type="text/javascript" charset="utf-8"></script>

<link rel="icon" href="<%= BASE_URL %>favicon.svg" />
<link rel="icon" href="./favicon.svg" />
<link rel="stylesheet" href="scripts/multi-ramp/rv-styles.css" />
<link rel="stylesheet" href="scripts/highcharts-editor/highcharts-editor.min.css" />

Expand Down
13 changes: 7 additions & 6 deletions src/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@
</template>

<script lang="ts">
import { Component, Vue, Watch } from 'vue-property-decorator';
import { Route } from 'vue-router';
import { Vue, Watch } from 'vue-property-decorator';
import { RouteLocationNormalized } from 'vue-router';

@Component({})
export default class App extends Vue {
@Watch('$route', { immediate: true })
onRouteUpdate(to: Route): void {
this.$i18n.locale = to.params.lang ?? 'en';
document.title = this.$t(to.meta?.title).toString();
onRouteUpdate(to: RouteLocationNormalized): void {
this.$i18n.locale = (to.params.lang as string) ?? 'en';
if (to.params.lang) {
document.title = this.$t(to.meta.title);
}
}
}
</script>
Expand Down
30 changes: 16 additions & 14 deletions src/components/editor/chart-editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,38 +37,40 @@
handle=".handle"
@update="onChartsEdited"
class="flex flex-wrap list-none"
item-key="name"
>
<ChartPreview
v-for="(chart, idx) in chartConfigs"
:key="`${chart.name}-${idx}`"
:chart="chart"
:configFileStructure="configFileStructure"
@delete="$modals.show(`${chart.name}-${idx}`)"
@edit="editChart"
></ChartPreview>
<template #item="{ element, index }">
<ChartPreview
:key="`${element.name}-${index}`"
:chart="element"
:configFileStructure="configFileStructure"
@edit="editChart"
@delete="$vfm.open(`${element.name}-${index}`)"
></ChartPreview>
</template>
</draggable>
</ul>
<confirmation-modal
v-for="(chart, idx) in chartConfigs"
:key="`${chart.name}-${idx}`"
:name="`${chart.name}-${idx}`"
:message="$t('editor.chart.delete.confirm', { name: chart.name })"
@Ok="deleteChart(chart)"
@ok="deleteChart(chart)"
></confirmation-modal>
</div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import { Options, Prop, Vue } from 'vue-property-decorator';
import { ChartConfig, ChartPanel, ConfigFileStructure, Highchart, SourceCounts } from '@/definitions';
import ChartPanelV from '@/components/panels/chart-panel.vue';
import ChartPreviewV from '@/components/editor/helpers/chart-preview.vue';
import ConfirmationModalV from '@/components/editor/helpers/confirmation-modal.vue';
import draggable from 'vuedraggable';

@Component({
@Options({
components: {
'chart-panel': ChartPanelV,
// TODO: fix when storylines plugin updated to Vue 3
// 'chart-panel': ChartPanelV,
ChartPreview: ChartPreviewV,
'confirmation-modal': ConfirmationModalV,
draggable
Expand Down Expand Up @@ -219,7 +221,7 @@ export default class ChartEditorV extends Vue {

onChartsEdited(): void {
this.edited = true;
this.$parent.$emit('slide-edit');
this.$emit('slide-edit');
}
}
</script>
Expand Down
4 changes: 2 additions & 2 deletions src/components/editor/dynamic-editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import { Options, Prop, Vue } from 'vue-property-decorator';
import {
ChartConfig,
ChartPanel,
Expand All @@ -108,7 +108,7 @@ import ImageEditorV from './image-editor.vue';
import TextEditorV from './text-editor.vue';
import MapEditorV from './map-editor.vue';

@Component({
@Options({
components: {
'chart-editor': ChartEditorV,
'image-editor': ImageEditorV,
Expand Down
76 changes: 50 additions & 26 deletions src/components/editor/editor.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
<template>
<!-- If the configuration file is being fetched, display a spinner to indicate loading. -->
<div class="editor-container">
<div class="editor-header sticky flex items-center border-b border-black bg-gray-200 py-2 px-2 z-10">
<span class="mx-1">
<router-link :to="{ name: 'home' }" class="mt-1 flex justify-center h-full w-full" target>
<router-link
:to="{ name: 'home' }"
class="mt-1 flex justify-center h-full w-full"
v-tippy="{
delay: '200',
placement: 'right',
content: $t('editor.returnToLanding'),
animateFill: true
}"
target
>
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18.001" viewBox="0 0 18 18.001">
<path
id="logout-Icon-SVG-098767893"
d="M5.808,13.782v1.406A2.816,2.816,0,0,0,8.621,18h7.067A2.816,2.816,0,0,0,18.5,15.188V2.813A2.816,2.816,0,0,0,15.687,0H8.621A2.816,2.816,0,0,0,5.808,2.813V4.219a.7.7,0,0,0,1.406,0V2.813A1.408,1.408,0,0,1,8.621,1.406h7.067a1.408,1.408,0,0,1,1.406,1.406V15.188a1.408,1.408,0,0,1-1.406,1.406H8.621a1.408,1.408,0,0,1-1.406-1.406V13.782a.7.7,0,0,0-1.406,0ZM1.014,7.793,2.589,6.218a.7.7,0,0,1,.994.994l-1.12,1.12h8.443a.7.7,0,1,1,0,1.406H2.463l1.12,1.12a.7.7,0,1,1-.994.994L1.014,10.279A1.76,1.76,0,0,1,1.014,7.793Zm0,0"
transform="translate(-0.5)"
/>
</svg>
<tippy delay="200" placement="right">{{ $t('editor.returnToLanding') }}</tippy>
</router-link>
</span>
<div class="ml-3 flex flex-col">
Expand All @@ -21,16 +29,21 @@
<span class="ml-auto"></span>
<button
v-if="unsavedChanges"
@click="$modals.show(`reload-config`)"
@click="$vfm.open(`reload-config`)"
class="border-2 border-red-700 text-red-700 rounded p-1 mr-2"
v-tippy="{
delay: '200',
placement: 'bottom',
content: $t('editor.resetChanges'),
animateFill: true
}"
>
<svg class="inline" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="18px" height="18px">
<path
d="M 2 2 L 4.9394531 4.9394531 C 3.1262684 6.7482143 2 9.2427079 2 12 C 2 17.514 6.486 22 12 22 C 17.514 22 22 17.514 22 12 C 22 6.486 17.514 2 12 2 L 12 4 C 16.411 4 20 7.589 20 12 C 20 16.411 16.411 20 12 20 C 7.589 20 4 16.411 4 12 C 4 9.7940092 4.9004767 7.7972757 6.3496094 6.3496094 L 9 9 L 9 2 L 2 2 z"
/>
</svg>
<span class="font-normal ml-1">{{ $t('editor.resetChanges') }}</span>
<tippy delay="200" placement="bottom">{{ $t('editor.resetChanges') }}</tippy>
</button>
<transition name="fade">
<span v-if="unsavedChanges" class="border-2 border-red-700 text-red-700 rounded p-1 mr-2">
Expand Down Expand Up @@ -61,15 +74,15 @@
</button>
<button @click="saveChanges" class="bg-black text-white hover:bg-gray-900" :disabled="saving">
<span class="inline-block">{{ saving ? $t('editor.savingChanges') : $t('editor.saveChanges') }}</span>
<span v-if="saving" class="align-middle inline-block px-1"
><spinner size="16px" background="#6B7280" color="#FFFFFF" stroke="2px" class="ml-1 mb-1"></spinner>
<span v-if="saving" class="align-middle inline-block px-1">
<spinner size="16px" color="#009cd1" class="ml-1 mb-1"></spinner>
</span>
</button>
</div>
<div class="flex">
<div class="w-80 flex-shrink-0 border-r border-black editor-toc">
<div class="flex items-center justify-center border-b p-2">
<button @click.stop="$modals.show('metadata-edit-modal')">
<button @click.stop="$vfm.open('metadata-edit-modal')">
<span class="align-middle inline-block px-1"
><svg
clip-rule="evenodd"
Expand Down Expand Up @@ -118,26 +131,26 @@
<confirmation-modal
:name="`reload-config`"
:message="$t('editor.refreshChanges.modal')"
@Ok="$emit('refresh-config')"
@ok="$emit('refresh-config')"
/>
</div>
</template>

<script lang="ts">
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
import { Options, Prop, Vue, Watch } from 'vue-property-decorator';
import { ConfigFileStructure, MetadataContent, Slide, SourceCounts, StoryRampConfig } from '@/definitions';

import Circle2 from 'vue-loading-spinner/src/components/Circle2.vue';
import { VueSpinnerOval } from 'vue3-spinners';
import SlideEditorV from './slide-editor.vue';
import SlideTocV from './slide-toc.vue';
import MetadataContentV from './helpers/metadata-content.vue';
import ConfirmationModalV from './helpers/confirmation-modal.vue';

@Component({
@Options({
components: {
'metadata-content': MetadataContentV,
'confirmation-modal': ConfirmationModalV,
spinner: Circle2,
spinner: VueSpinnerOval,
'slide-editor': SlideEditorV,
'slide-toc': SlideTocV
}
Expand All @@ -157,6 +170,7 @@ export default class EditorV extends Vue {
// Form properties.
uuid = '';
logoImage: undefined | File = undefined;
loadSlides: undefined | Slide[] = undefined;
currentSlide: Slide | string = '';
slideIndex = -1;

Expand All @@ -171,7 +185,8 @@ export default class EditorV extends Vue {
}

created(): void {
this.uuid = this.$route.params.uid;
this.loadSlides = this.slides;
this.uuid = this.$route.params.uid as string;
window.addEventListener('beforeunload', this.beforeWindowUnload);
}

Expand All @@ -194,7 +209,9 @@ export default class EditorV extends Vue {
selectSlide(index: number): void {
// save changes to current slide before changing slides
if (this.$refs.slide !== undefined) {
(this.$refs.slide as SlideEditorV).saveChanges();
this.$nextTick(() => {
(this.$refs.slide as SlideEditorV).saveChanges();
});
}

// Quickly swap to loading page, and then swap to new slide. Allows Vue to re-draw page correctly.
Expand All @@ -204,7 +221,7 @@ export default class EditorV extends Vue {
};

setTimeout(() => {
this.currentSlide = index === -1 ? '' : (this.slides as Slide[])[index];
this.currentSlide = index === -1 ? '' : (this.loadSlides as Slide[])[index];
this.slideIndex = index;
(this.$refs.slide as SlideEditorV).panelIndex = 0;
window.scrollTo(0, 0);
Expand All @@ -215,8 +232,8 @@ export default class EditorV extends Vue {
* Updates slides after adding, removing, or reordering.
*/
updateSlides(slides: Slide[]): void {
this.slides = slides;
this.slideIndex = this.slides.indexOf(this.currentSlide as Slide);
this.loadSlides = slides;
this.slideIndex = this.loadSlides.indexOf(this.currentSlide as Slide);
}

/**
Expand All @@ -225,20 +242,27 @@ export default class EditorV extends Vue {
preview(): void {
// save current slide final changes before previewing product
if (this.$refs.slide !== undefined) {
(this.$refs.slide as SlideEditorV).saveChanges();
this.$nextTick(() => {
(this.$refs.slide as SlideEditorV).saveChanges();
});
}
const routeData = this.$router.resolve({ name: 'preview' });
const previewTab = window.open(routeData.href, '_blank');
(previewTab as Window).props = {
config: JSON.parse(JSON.stringify(this.configs[this.configLang])),
configFileStructure: this.configFileStructure
};

setTimeout(() => {
const routeData = this.$router.resolve({ name: 'preview' });
const previewTab = window.open(routeData.href, '_blank');
(previewTab as Window).props = {
config: JSON.parse(JSON.stringify(this.configs[this.configLang])),
configFileStructure: this.configFileStructure
};
}, 5);
}

saveChanges(): void {
// save current slide final changes before generating config file
if (this.$refs.slide !== undefined) {
(this.$refs.slide as SlideEditorV).saveChanges();
this.$nextTick(() => {
(this.$refs.slide as SlideEditorV).saveChanges();
});
}

// emit save changes event
Expand Down
Loading
Loading