feat: ajout ToC

This commit is contained in:
Kazhnuz 2023-02-07 23:30:55 +01:00
parent 132bf5f060
commit eaa1da8752
11 changed files with 145 additions and 18 deletions

View file

@ -2,6 +2,7 @@
import { RouterView } from "vue-router";
import TopBar from "./components/layout/TopBar.vue";
import SideBar from "./components/layout/SideBar.vue";
import TableOfContent from "./components/layout/TableOfContent.vue";
import { useConfigStore } from "./stores/config";
import { onMounted } from "vue";
import axios from "axios";
@ -17,6 +18,9 @@ onMounted(() => {
<TopBar id="topbar" />
<div id="wrapper">
<SideBar />
<div id="page"><RouterView /></div>
<div id="page">
<RouterView />
</div>
<TableOfContent />
</div>
</template>

View file

@ -1,20 +1,56 @@
<script setup lang="ts">
import { ref, onMounted, onBeforeUpdate } from "vue";
import { marked } from "marked";
import { useTocStore } from "../stores/toc";
import axios from "axios";
import { useRoute } from "vue-router";
const props = defineProps<{
path: string;
order?: number;
}>();
const htmlContent = ref("");
const loadedPage = ref("");
var renderer = new marked.Renderer();
const toc = useTocStore();
const route = useRoute();
var tocNbr = 1;
renderer.heading = function (text, level, raw) {
var anchor = "#" + raw.toLowerCase().replace(/[^\w]+/g, "-");
if (level === 2) {
toc.addTocLine(route.path, {
anchor: anchor,
order: (props.order ?? 1) * 100 + tocNbr,
text: text,
});
tocNbr++;
}
return `<h${level} id="${anchor}">${text}</h${level}>\n`;
};
marked.setOptions({
renderer: renderer,
});
function refresh() {
const markdownFileUrl = `/${props.path}.md`;
if (loadedPage.value === markdownFileUrl) {
return;
}
loadedPage.value = markdownFileUrl;
console.log(`Chargement de l'URL ${markdownFileUrl}`);
axios
.get(markdownFileUrl)
.then((response) => (htmlContent.value = marked.parse(response.data)))
.then((response) => {
tocNbr = 1;
htmlContent.value = marked.parse(response.data);
console.log(toc);
})
.catch(
() =>
(htmlContent.value = marked.parse(

View file

@ -0,0 +1,22 @@
<script setup lang="ts">
import { useTocStore } from "../../stores/toc";
import { computed } from "vue";
const toc = useTocStore();
const tocList = computed(() => {
return toc.getToc();
});
</script>
<template>
<div class="card" id="toc" v-if="tocList.length > 1">
<div class="card-header bg-primary">Sommaire</div>
<ul class="menu fg-dark">
<li v-for="(tocLine, index) in tocList" :key="index">
<router-link :to="`#${tocLine.anchor}`"
><span v-html="tocLine.text"></span
></router-link>
</li>
</ul>
</div>
</template>

View file

@ -1,10 +1,10 @@
import { createRouter, createWebHistory } from "vue-router";
import { createRouter, createWebHashHistory } from "vue-router";
import HomeView from "../views/HomeView.vue";
import RuleView from "../views/RuleView.vue";
import JdrView from "../views/JdrView.vue";
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
history: createWebHashHistory(import.meta.env.BASE_URL),
routes: [
{
path: "/",
@ -28,6 +28,15 @@ const router = createRouter({
component: () => import("../views/AboutView.vue"),
},
],
scrollBehavior(to, from, savedPosition) {
if (to.hash) {
return {
el: to.hash,
behavior: "smooth",
top: 64,
};
}
},
});
export default router;

27
src/stores/toc.ts Normal file
View file

@ -0,0 +1,27 @@
import { ref } from "vue";
import { defineStore } from "pinia";
import type TocLine from "@/types/TocLine";
export const useTocStore = defineStore("toc", () => {
const currentPage = ref("");
const tocLines = ref([] as TocLine[]);
function addTocLine(page: string, line: TocLine) {
if (page !== currentPage.value) {
tocLines.value = [];
currentPage.value = page;
}
tocLines.value.push(line);
}
function getToc(): TocLine[] {
return tocLines.value.sort((a, b) => a.order - b.order);
}
function resetToc() {
tocLines.value = [];
currentPage.value = "";
}
return { currentPage, tocLines, addTocLine, getToc, resetToc };
});

View file

@ -31,6 +31,18 @@
#page {
flex-grow:1;
padding-left:18rem;
padding-right: 18rem;
}
#toc {
position: fixed;
top: 4rem;
right: 1rem;
width: 17rem;
.menu {
padding-left:0.5rem;
padding-right:0.5rem;
}
}
#content {

5
src/types/TocLine.ts Normal file
View file

@ -0,0 +1,5 @@
export default interface TocLine {
order: number;
text: string;
anchor: string;
}

View file

@ -1,15 +1,18 @@
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>
<script setup lang="ts">
import { useConfigStore } from "@/stores/config";
import { onMounted } from "vue";
import { useTocStore } from "@/stores/toc";
import MarkdownFile from "../components/MarkdownFile.vue";
<style>
@media (min-width: 1024px) {
.about {
min-height: 100vh;
display: flex;
align-items: center;
}
}
</style>
const store = useConfigStore();
const toc = useTocStore();
onMounted(() => {
store.resetJdr();
toc.resetToc();
});
</script>
<template>
<MarkdownFile path="pages/about"></MarkdownFile>
</template>

View file

@ -1,12 +1,15 @@
<script setup lang="ts">
import { useConfigStore } from "@/stores/config";
import { onMounted } from "vue";
import { useTocStore } from "@/stores/toc";
import MarkdownFile from "../components/MarkdownFile.vue";
const store = useConfigStore();
const toc = useTocStore();
onMounted(() => {
store.resetJdr();
toc.resetToc();
});
</script>

View file

@ -1,13 +1,16 @@
<script setup lang="ts">
import { useConfigStore } from "@/stores/config";
import { useTocStore } from "@/stores/toc";
import { onMounted } from "vue";
import { useRoute } from "vue-router";
import MarkdownFile from "../components/MarkdownFile.vue";
const store = useConfigStore();
const route = useRoute();
const toc = useTocStore();
onMounted(() => {
toc.resetToc();
store.loadJdr(`${route.params.jdr}`);
});
</script>

View file

@ -1,13 +1,16 @@
<script setup lang="ts">
import { useConfigStore } from "@/stores/config";
import { useTocStore } from "@/stores/toc";
import { onMounted } from "vue";
import { useRoute } from "vue-router";
import MarkdownFile from "../components/MarkdownFile.vue";
const store = useConfigStore();
const toc = useTocStore();
const route = useRoute();
onMounted(() => {
toc.resetToc();
store.loadJdr(`${route.params.jdr}`);
});
</script>