+
@@ -22,6 +23,7 @@ import Panel from '@storylines/components/panels/panel.vue';
const key = getCurrentInstance()?.vnode.key as string;
+const emit = defineEmits(['slide-changed']);
const props = defineProps({
config: {
type: Object as PropType
,
@@ -35,13 +37,30 @@ const props = defineProps({
},
lang: {
type: String
+ },
+ background: {
+ type: Boolean
}
});
const defaultRatio = ref(false);
+const slide = ref();
+const observer = ref(undefined);
+
onMounted(() => {
const panels = props.config.panel;
+
+ observer.value = new IntersectionObserver(
+ ([slide]) => {
+ // emit a `slide-changed` event when a new slide hits the middle of the screen.
+ if (slide.isIntersecting) {
+ emit('slide-changed', props.slideIdx);
+ }
+ },
+ { rootMargin: '0px', threshold: 0.45 }
+ );
+
// check if there is one text panel and one non-text panel in the slide and user did not specify a width in config
if (panels.length == 2 && !panels[0]?.width && !panels[1]?.width) {
const panelText1 = panels[0]?.type === PanelType.Text;
@@ -52,6 +71,8 @@ onMounted(() => {
defaultRatio.value = true;
}
}
+
+ observer.value?.observe(slide.value as Element);
});
/**
diff --git a/src/components/story/story-content.vue b/src/components/story/story-content.vue
index e33c763b..f126539c 100644
--- a/src/components/story/story-content.vue
+++ b/src/components/story/story-content.vue
@@ -21,22 +21,27 @@
v-else
/>
-
-
@@ -52,12 +57,13 @@ import { ConfigFileStructure, StoryRampConfig } from '@storylines/definitions';
import ChapterMenu from './chapter-menu.vue';
import HorizontalMenu from './horizontal-menu.vue';
+import BackgroundImage from './background-image.vue';
import Slide from './slide.vue';
const route = useRoute();
const emit = defineEmits(['step']);
-defineProps({
+const props = defineProps({
config: {
type: Object as PropType,
required: true
@@ -79,6 +85,8 @@ defineProps({
const activeChapterIndex = ref(-1);
const horizontalNavHeight = ref(0);
+const backgroundImage = ref('none');
+const hasBackground = ref(false); // different from above; this considers animation time
onMounted(() => {
const hash = route?.hash.substring(1);
@@ -90,8 +98,24 @@ onMounted(() => {
el?.scrollIntoView();
}, 200);
}
+
+ // See if the first slide has a background image applied. If so, set it early to it appears as soon
+ // as you scroll down.
+ handleSlideChange(0);
});
+const handleSlideChange = (event: number): void => {
+ const img = props.config.slides[event].backgroundImage;
+ backgroundImage.value = img ?? 'none';
+};
+
+/**
+ * This event is fired when the background image actually switches backgrounds (after the animation).
+ */
+const handleBackgroundChange = (event: boolean): void => {
+ hasBackground.value = event;
+};
+
const stepEnter = ({ element }: { element: HTMLElement }): void => {
activeChapterIndex.value = parseInt(element.dataset.chapterIndex || '-1');
emit('step', activeChapterIndex.value);
@@ -103,6 +127,24 @@ const stepEnter = ({ element }: { element: HTMLElement }): void => {