Skip to content

Commit

Permalink
Horizontal table of contents implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
Mistry authored and Mistry committed Mar 14, 2024
1 parent 72fac09 commit 450a990
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 3 deletions.
165 changes: 165 additions & 0 deletions src/components/story/horizontal-menu.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
<template>
<div class="navbar sticky">
<ul>
<li v-if="introExists">
<a
class="items-center px-2 py-1 mx-1 cursor-pointer"
@click="scrollToChapter('intro')"
v-tippy="{
delay: '200',
placement: 'right',
content: $t('chapters.return'),
animateFill: true,
animation: 'chapter-menu'
}"
v-if="plugin"
>
<span class="flex-1 ml-4 overflow-hidden leading-normal overflow-ellipsis whitespace-nowrap">{{
$t('chapters.return')
}}</span>
</a>

<router-link
:to="{ hash: '#intro' }"
class="flex items-center px-2 py-1 mx-1"
target
v-tippy="{
delay: '200',
placement: 'right',
content: $t('chapters.return'),
animateFill: true,
animation: 'chapter-menu'
}"
v-else
>
<span class="flex-1 overflow-hidden leading-normal overflow-ellipsis whitespace-nowrap">{{
$t('chapters.return')
}}</span>
</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 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',
placement: 'right',
content: slide.title,
animateFill: true,
animation: 'chapter-menu'
}"
v-if="plugin"
>
<span class="flex-1 ml-4 overflow-hidden leading-normal overflow-ellipsis whitespace-nowrap">{{
slide.title
}}</span>
</a>

<router-link
:to="{ hash: `#${idx}-${slide.title.toLowerCase().replaceAll(' ', '-')}` }"
class="flex items-center px-2 py-1 mx-1"
target
v-tippy="{
delay: '200',
placement: 'right',
content: slide.title,
animateFill: true,
animation: 'chapter-menu'
}"
v-else
>
<span class="flex-1 overflow-hidden leading-normal overflow-ellipsis whitespace-nowrap">{{
slide.title
}}</span>
</router-link>
</li>
</ul>
</div>
</template>

<script setup lang="ts">
import type { PropType } from 'vue';
import { ref, onMounted } from 'vue';
import { Slide } from '@storylines/definitions';
defineProps({
slides: {
type: Array as PropType<Array<Slide>>,
required: true
},
activeChapterIndex: {
type: Number,
required: true
},
lang: {
type: String,
required: true
},
plugin: {
type: Boolean
}
});
const introExists = ref(false);
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>
.navbar {
background-color: #fff;
border-bottom: 2px;
border-color: rgba(229, 231, 235, var(--tw-border-opacity));
position: sticky;
height: 100%;
width: 100%;
margin: 0;
}
.navbar ul {
list-style-type: none;
text-align: center;
align-items: center;
justify-content: center;
overflow: hidden;
width: 100%;
padding: 5px;
margin: auto;
}
.navbar ul li {
float: left;
width: 12%;
border-radius: 20px;
a {
text-overflow: ellipsis;
}
a:hover {
text-decoration: none;
color: inherit;
}
a:focus {
text-decoration: none;
color: inherit;
}
a:visited {
color: inherit;
}
&.is-active {
background-color: var(--sr-accent-colour);
font-weight: bold;
}
}
</style>
1 change: 0 additions & 1 deletion src/components/story/introduction.vue
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ onMounted(() => {
// obtain logo from ZIP file if it exists
if (props.configFileStructure) {
const logo = props.config.logo?.src;
if (logo) {
const logoSrc = `${logo.substring(logo.indexOf('/') + 1)}`;
const logoFile = props.configFileStructure.zip.file(logoSrc);
Expand Down
24 changes: 22 additions & 2 deletions src/components/story/story-content.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
<template>
<div class="flex items-stretch">
<div
class="items-stretch"
:class="{ flex: !$props.config?.tocOrientation || $props.config?.tocOrientation === 'vertical' }"
>
<horizontal-menu
class="top-menu block"
:active-chapter-index="activeChapterIndex"
:slides="config.slides"
:plugin="!!configFileStructure || !!plugin"
:lang="lang"
v-if="$props.config?.tocOrientation === 'horizontal'"
/>
<chapter-menu
class="side-menu"
:active-chapter-index="activeChapterIndex"
:slides="config.slides"
:plugin="!!configFileStructure || !!plugin"
:lang="lang"
v-else
/>

<VueScrollama class="relative story-scrollama w-full flex-grow min-w-0" @step-enter="stepEnter">
Expand All @@ -32,6 +44,7 @@ import VueScrollama from 'vue3-scrollama';
import { ConfigFileStructure, StoryRampConfig } from '@storylines/definitions';
import ChapterMenu from './chapter-menu.vue';
import HorizontalMenu from './horizontal-menu.vue';
import Slide from './slide.vue';
const route = useRoute();
Expand Down Expand Up @@ -118,10 +131,17 @@ const stepEnter = ({ element }: { element: HTMLElement }): void => {
box-shadow: 0 3px 6px 0px rgba(0, 0, 0, 0.1), 0 2px 4px 0px rgba(0, 0, 0, 0.06);
}
}
.top-menu {
z-index: 50;
top: 64px;
width: 100%;
}
@media screen and (max-width: 640px) {
.side-menu {
display: none;
}
.top-menu {
display: none;
}
}
</style>
1 change: 1 addition & 0 deletions src/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface StoryRampConfig {
slides: Slide[];
contextLink: string;
contextLabel: string;
tocOrientation: string;
dateModified: string;
}

Expand Down

0 comments on commit 450a990

Please sign in to comment.