Skip to content

Commit

Permalink
Merge pull request #391 from yileifeng/storylines-vue3-plugin
Browse files Browse the repository at this point in the history
Add Vue 3 version of Storylines plugin
  • Loading branch information
yileifeng authored Feb 26, 2024
2 parents fb841d2 + 1d35f3d commit 40709a4
Show file tree
Hide file tree
Showing 11 changed files with 5,611 additions and 5,774 deletions.
11,108 changes: 5,402 additions & 5,706 deletions package-lock.json

Large diffs are not rendered by default.

22 changes: 16 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
{
"name": "story-ramp",
"version": "0.1.0",
"private": true,
"name": "ramp-storylines",
"description": "A user-configurable story product featuring interactive maps, charts and dynamic multimedia content alongside text.",
"version": "3.0.4",
"private": false,
"license": "MIT",
"repository": "https://github.com/ramp4-pcar4/story-ramp",
"bugs": "https://github.com/ramp4-pcar4/story-ramp/issues",
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"update": "node ./public/scripts/update.js ./public/scripts/ramp4"
"update": "node ./public/scripts/update.js ./public/scripts/ramp4",
"build-plugin": "vue-cli-service build --plugin --target lib --name storylines-viewer ./storylines-plugin.ts",
"lint": "vue-cli-service lint"
},
"main": "dist/storylines-viewer.umd.min.js",
"files": [
"dist"
],
"dependencies": {
"@tailwindcss/typography": "^0.4.0",
"@types/highcharts": "^7.0.0",
Expand Down Expand Up @@ -53,6 +62,7 @@
"sass-loader": "^8.0.2",
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.1.2",
"typescript": "~4.1.5",
"vue-eslint-parser": "^9.3.1"
"vue-eslint-parser": "^9.3.1",
"vue-loader": "^17.2.2"
}
}
4 changes: 2 additions & 2 deletions src/components/panels/dynamic-panel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ const addDynamicURLs = (): void => {
}, 10);
setTimeout(() => {
const elTop = content.value.$el.getBoundingClientRect().top;
const elTop = content.value?.$el.getBoundingClientRect().top;
window.scrollTo({
top: window.pageYOffset + elTop - 63,
left: 0,
Expand All @@ -149,7 +149,7 @@ const clickBack = (): void => {
}, 10);
setTimeout(() => {
const elTop = content.value.$el.getBoundingClientRect().top;
const elTop = content.value?.$el.getBoundingClientRect().top;
window.scrollTo({
top: window.pageYOffset + elTop - 63,
left: 0,
Expand Down
87 changes: 55 additions & 32 deletions src/components/panels/helpers/chart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
:aria-label="title"
v-if="!loading"
>
<chart :options="chartOptions" ref="chart"></chart>
<chart :options="chartOptions"></chart>
</div>
</div>
</template>
Expand Down Expand Up @@ -110,36 +110,29 @@ onMounted(() => {
const assetSrc = `${props.config.src.substring(props.config.src.indexOf('/') + 1)}`;
if (extension === 'json') {
fetch(props.config.src).then((data) => {
// parse JSON data
data.json().then(
(res: DQVChartConfig) => {
chartOptions.value = res;
title.value = chartOptions.value.title.text;
loading.value = false;
// Set up hamburger menu options.
if (chartOptions.value.exporting) {
chartOptions.value.exporting.buttons = {
contextButton: {
menuItems: menuOptions
}
};
} else {
chartOptions.value.exporting = {
buttons: {
contextButton: {
menuItems: menuOptions
}
}
};
if (props.configFileStructure) {
// attempt to fetch JSON file from ZIP folder
const chartJsonFile = props.configFileStructure.zip.file(assetSrc);
if (chartJsonFile) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
chartJsonFile.async('string').then((res: string) => {
const jsonData: DQVChartConfig = JSON.parse(res);
parseJSONFile(jsonData);
});
}
} else {
fetch(props.config.src).then((data) => {
// parse JSON data
data.json().then(
(res: DQVChartConfig) => {
parseJSONFile(res);
},
(err) => {
console.error(`Error fetching chart JSON file: ${err}`);

Check warning on line 131 in src/components/panels/helpers/chart.vue

View workflow job for this annotation

GitHub Actions / Install dependencies and build / Install and build

Unexpected console statement
}
},
(err) => {
console.error(`Error fetching chart JSON file: ${err}`);
}
);
});
);
});
}
} else if (extension === 'csv') {
if (props.configFileStructure) {
// First attempt to fetch the configuration file from the ZIP folder.
Expand All @@ -160,6 +153,34 @@ onMounted(() => {
}
});
/**
* Parse and process CSV file contents and return a properly configured highcharts options object.
*/
const parseJSONFile = (jsonData: DQVChartConfig): void => {
chartOptions.value = jsonData;
title.value = chartOptions.value.title.text;
loading.value = false;
// Set up hamburger menu options.
if (chartOptions.value.exporting) {
chartOptions.value.exporting.buttons = {
contextButton: {
menuItems: menuOptions
}
};
} else {
chartOptions.value.exporting = {
buttons: {
contextButton: {
menuItems: menuOptions
}
}
};
}
emit('loaded', chartOptions.value);
};
/**
* Parse and process CSV file contents and return a properly configured highcharts options object.
*/
Expand Down Expand Up @@ -205,9 +226,11 @@ const parseCSVFile = (data: CSVFile): void => {
complete: (res: any) => {
// construct highcharts objects based on chart type
if (dqvOptions?.type === 'pie') {
makePieChart(res.data, (defaultOptions as unknown) as DQVChartConfig);
// eslint-disable-next-line prettier/prettier
makePieChart(res.data, defaultOptions as DQVChartConfig);
} else {
makeLineChart(res.meta.fields, res.data, (defaultOptions as unknown) as DQVChartConfig);
// eslint-disable-next-line prettier/prettier
makeLineChart(res.meta.fields, res.data, defaultOptions as DQVChartConfig);
}
}
});
Expand Down
2 changes: 1 addition & 1 deletion src/components/panels/video-panel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ const rawTranscript = ref('');
const transcriptContent = ref('');
onBeforeMount(() => {
lang.value = (route.params.lang as string) ? (route.params.lang as string) : 'en';
lang.value = (route?.params.lang as string) ? (route?.params.lang as string) : 'en';
// find file type extension for non-YT videos
if (props.config.videoType === 'external' || props.config.videoType === 'local') {
Expand Down
33 changes: 19 additions & 14 deletions src/components/story/chapter-menu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@
</div>

<ul class="nav-content menu">
<li>
<button
class="flex items-center px-2 py-1 mx-1"
<li v-if="introExists">
<a
class="flex items-center px-2 py-1 mx-1 cursor-pointer"
@click="scrollToChapter('intro')"
v-tippy="{
delay: '200',
Expand All @@ -49,7 +49,7 @@
animation: 'chapter-menu',
offset: isMenuOpen ? [0, -280] : [0, -40]
}"
v-if="editor"
v-if="plugin"
>
<svg
class="flex-shrink-0"
Expand All @@ -68,7 +68,7 @@
<span class="flex-1 ml-4 overflow-hidden leading-normal overflow-ellipsis whitespace-nowrap">{{
$t('chapters.return')
}}</span>
</button>
</a>

<router-link
:to="{ hash: '#intro' }"
Expand Down Expand Up @@ -104,9 +104,9 @@
</router-link>
</li>
<li v-for="(slide, idx) in slides" :key="idx" :class="{ 'is-active': activeChapterIndex === idx }">
<!-- using router-link causes a page refresh which breaks editor preview mode -->
<button
class="flex items-center px-2 py-1 mx-1"
<!-- using router-link causes a page refresh which breaks plugin -->
<a
class="flex items-center px-2 py-1 mx-1 cursor-pointer"
@click="scrollToChapter(`${idx}-${slide.title.toLowerCase().replaceAll(' ', '-')}`)"
v-tippy="{
delay: '200',
Expand All @@ -116,7 +116,7 @@
animation: 'chapter-menu',
offset: isMenuOpen ? [0, -280] : [0, -40]
}"
v-if="editor"
v-if="plugin"
>
<svg
class="flex-shrink-0"
Expand All @@ -135,7 +135,7 @@
<span class="flex-1 ml-4 overflow-hidden leading-normal overflow-ellipsis whitespace-nowrap">{{
slide.title
}}</span>
</button>
</a>

<router-link
:to="{ hash: `#${idx}-${slide.title.toLowerCase().replaceAll(' ', '-')}` }"
Expand Down Expand Up @@ -177,7 +177,7 @@

<script setup lang="ts">
import type { PropType } from 'vue';
import { ref } from 'vue';
import { ref, onMounted } from 'vue';
import { Slide } from '@storylines/definitions';
defineProps({
Expand All @@ -193,13 +193,18 @@ defineProps({
type: String,
required: true
},
editor: {
type: Boolean,
required: true
plugin: {
type: Boolean
}
});
const isMenuOpen = ref(false);
const introExists = ref(false);
onMounted(() => {
const introSection = document.getElementById('intro');
introExists.value = !!introSection;
});
const scrollToChapter = (id: string): void => {
const el = document.getElementById(id);
Expand Down
7 changes: 5 additions & 2 deletions src/components/story/introduction.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
{{ config.subtitle }}
</p>

<!-- using router-link causes a page refresh which breaks editor preview mode -->
<button @click="scrollToStory" v-if="!!configFileStructure">
<!-- using router-link causes a page refresh which breaks plugin -->
<button class="inline-block mt-10 scroll-arrow" @click="scrollToStory" v-if="!!configFileStructure || !!plugin">
<svg
class="w-auto h-24 m-auto"
width="90"
Expand Down Expand Up @@ -85,6 +85,9 @@ const props = defineProps({
},
configFileStructure: {
type: Object as PropType<ConfigFileStructure>
},
plugin: {
type: Boolean
}
});
Expand Down
66 changes: 63 additions & 3 deletions src/components/story/mobile-menu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,28 @@
</div>

<ul v-show="isMenuOpen" class="dropdown-nav-content bg-white pb-10 w-72 z-10 border-r border-gray-200">
<li>
<router-link :to="{ hash: '#intro' }" class="flex py-1 px-3" target>
<li v-if="introExists">
<button class="flex py-1 px-3" @click="scrollToChapter('intro')" v-if="plugin">
<svg
class="flex-shrink-0"
width="24"
height="24"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
fill="#fff"
stroke="#878787"
>
<path
d="m19.325 16.229c-2.4415 1.4096-4.8829 2.8191-7.3244 4.2286-2.4415-1.4096-4.883-2.8192-7.3245-4.2288-3.55e-5 -2.8191-7.1e-5 -5.6383-1.066e-4 -8.4574 2.4415-1.4096 4.8829-2.8191 7.3244-4.2286 2.4415 1.4096 4.883 2.8192 7.3245 4.2288 3.7e-5 2.8191 7.4e-5 5.6383 1.1e-4 8.4574z"
stroke-width=".93974"
/>
</svg>
<span class="flex-1 ml-4 overflow-hidden leading-normal overflow-ellipsis whitespace-nowrap">{{
$t('chapters.return')
}}</span>
</button>

<router-link :to="{ hash: '#intro' }" class="flex py-1 px-3" target v-else>
<svg
class="flex-shrink-0"
width="24"
Expand All @@ -58,10 +78,34 @@
</router-link>
</li>
<li v-for="(slide, idx) in slides" :key="idx" :class="{ 'is-active': activeChapterIndex === idx }">
<button
class="flex py-1 px-3"
@click="scrollToChapter(`${idx}-${slide.title.toLowerCase().replaceAll(' ', '-')}`)"
v-if="plugin"
>
<svg
class="flex-shrink-0"
width="24"
height="24"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
fill="#fff"
stroke="#878787"
>
<path
d="m19.325 16.229c-2.4415 1.4096-4.8829 2.8191-7.3244 4.2286-2.4415-1.4096-4.883-2.8192-7.3245-4.2288-3.55e-5 -2.8191-7.1e-5 -5.6383-1.066e-4 -8.4574 2.4415-1.4096 4.8829-2.8191 7.3244-4.2286 2.4415 1.4096 4.883 2.8192 7.3245 4.2288 3.7e-5 2.8191 7.4e-5 5.6383 1.1e-4 8.4574z"
stroke-width=".93974"
/>
</svg>
<span class="flex-1 ml-4 overflow-hidden leading-normal overflow-ellipsis whitespace-nowrap">{{
slide.title
}}</span>
</button>
<router-link
:to="{ hash: `#${idx}-${slide.title.toLowerCase().replaceAll(' ', '-')}` }"
class="flex py-1 px-3"
target
v-else
>
<svg
class="flex-shrink-0"
Expand All @@ -87,8 +131,8 @@
</template>

<script setup lang="ts">
import { ref } from 'vue';
import type { PropType } from 'vue';
import { ref, onMounted } from 'vue';
import { Slide } from '@storylines/definitions';
defineProps({
Expand All @@ -100,10 +144,26 @@ defineProps({
},
lang: {
type: String
},
plugin: {
type: Boolean
}
});
const isMenuOpen = ref(false);
const introExists = ref(true);
onMounted(() => {
const introSection = document.getElementById('intro');
introExists.value = !!introSection;
});
const scrollToChapter = (id: string): void => {
const el = document.getElementById(id);
if (el) {
el.scrollIntoView({ behavior: 'smooth' });
}
};
</script>

<style lang="scss" scoped>
Expand Down
Loading

0 comments on commit 40709a4

Please sign in to comment.