2020</template >
2121
2222<script setup lang="ts">
23- import { computed , onMounted , onBeforeUnmount , ref , unref , watch } from ' vue'
23+ import { computed , onMounted , onBeforeUnmount , ref , unref , watch , nextTick } from ' vue'
2424import {
2525 AppLoadingSpinner ,
2626 useThemeStore ,
@@ -64,6 +64,9 @@ const dataSeparatorVertical = '\r?\n--\r?\n'
6464const mdImageRegex = / !\[ . * \]\( (?!(?:http| data))(. * )\) / g
6565
6666let reveal: Reveal .Api
67+ const awesoMd = RevealAwesoMD ()
68+ const baseUrl = ` https://localhost:9200/assets/apps/${appId } `
69+ awesoMd .setBaseUrl (baseUrl )
6770
6871const { url } = defineProps ({
6972 url: {
@@ -102,7 +105,7 @@ onMounted(async () => {
102105 })
103106
104107 reveal = new Reveal (unref (revealContainer ), {
105- plugins: [RevealAwesoMD , RevealHighlight , RevealMermaid ]
108+ plugins: [awesoMd , RevealHighlight , RevealMermaid ]
106109 })
107110
108111 await reveal .initialize ({
@@ -113,6 +116,29 @@ onMounted(async () => {
113116 controlsLayout: ' edges'
114117 })
115118
119+ if (reveal .isReady ()) {
120+ applyTemplateIfNeeded ()
121+ addCustomSlideNumber ()
122+ updateImageStructure ()
123+ fitContent ()
124+ adjustFontSize ()
125+ updateLogoUrl ()
126+ } else {
127+ reveal .addEventListener (' ready' , function () {
128+ applyTemplateIfNeeded ()
129+ addCustomSlideNumber ()
130+ updateImageStructure ()
131+ fitContent ()
132+ adjustFontSize ()
133+ updateLogoUrl ()
134+ })
135+ }
136+
137+ reveal .addEventListener (' slidechanged' , function () {
138+ fitContent ()
139+ adjustFontSize ()
140+ })
141+
116142 isReadyToShow .value = true
117143})
118144onBeforeUnmount (() => {
@@ -207,6 +233,172 @@ function dirname(path: string) {
207233function basename(path : string ) {
208234 return path .split (' /' ).reverse ()[0 ]
209235}
236+
237+ // TEMPLATE RELATED
238+ function addCustomSlideNumber() {
239+ const allSlides = reveal .getSlides ()
240+ for (const [slideNumber, slide] of Array .from (allSlides ).entries ()) {
241+ const customSlideNumber = slide .querySelector (' .custom-slide-number' )
242+ if (! customSlideNumber ) {
243+ continue
244+ }
245+ customSlideNumber .textContent = ` ${slideNumber + 1 } `
246+ }
247+ }
248+ function updateImageStructure() {
249+ const pTags = document .querySelectorAll (' p > img' )
250+ pTags .forEach ((img ) => {
251+ const pTag = img .parentNode
252+ const divContainer = document .createElement (' div' )
253+ divContainer .classList .add (' image-container' )
254+ const divWrapper = document .createElement (' div' )
255+ divWrapper .classList .add (' image-wrapper' )
256+ divWrapper .appendChild (img )
257+ divContainer .appendChild (divWrapper )
258+ pTag .parentNode ?.replaceChild (divContainer , pTag )
259+ })
260+ }
261+ function adjustFontSize() {
262+ const currentSlide = reveal .getCurrentSlide ()
263+
264+ function getTotalHeightOfChildren(container ) {
265+ let totalHeight = 0
266+ for (const child of container .children ) {
267+ if (currentSlide .classList .contains (' title-content-image' )) {
268+ if (child .className !== ' image-container' ) {
269+ totalHeight += getHeightWithMargin (child )
270+ }
271+ } else {
272+ totalHeight += getHeightWithMargin (child )
273+ }
274+ }
275+ return totalHeight
276+ }
277+
278+ function getHeightWithMargin(element ) {
279+ const style = getComputedStyle (element )
280+ const marginTop = parseFloat (style .marginTop )
281+ const marginBottom = parseFloat (style .marginBottom )
282+ const paddingTop = parseFloat (style .paddingTop )
283+ const paddingBottom = parseFloat (style .paddingBottom )
284+ return element .offsetHeight + marginTop + marginBottom + paddingTop + paddingBottom
285+ }
286+
287+ const contentWrapper = currentSlide .querySelector (' .content-wrapper' ) as HTMLElement
288+ const content = currentSlide .querySelector (' .content' ) as HTMLElement
289+
290+ if (! contentWrapper || ! content ) return
291+
292+ const contentWrapperHeight = contentWrapper .offsetHeight
293+ let totalHeight = getTotalHeightOfChildren (content )
294+
295+ // set minimum font size from where the image starts to get reduced as well
296+ // this is to prevent the font size to get too small and becomes hard to read
297+ const fontSizeToStartReducingImage = 12
298+ let fontSize = parseFloat (getComputedStyle (content ).fontSize )
299+
300+ while (totalHeight > contentWrapperHeight ) {
301+ const scaleFactor = contentWrapperHeight / totalHeight
302+ fontSize = Math .floor (scaleFactor * fontSize )
303+
304+ const wrapperElements = Array .from (content .children ) as HTMLElement []
305+ wrapperElements .forEach ((wrapperElement ) => {
306+ wrapperElement .style .fontSize = ` ${fontSize }px `
307+ const style = getComputedStyle (wrapperElement )
308+ const marginTop = Math .floor (parseFloat (style .marginTop ) * scaleFactor )
309+ const marginBottom = Math .floor (parseFloat (style .marginBottom ) * scaleFactor )
310+ wrapperElement .style .marginTop = ` ${marginTop }px `
311+ wrapperElement .style .marginBottom = ` ${marginBottom }px `
312+ })
313+
314+ // reduce image size if font size gets smaller than minimum font size
315+ const images = content .querySelectorAll (
316+ ' .image-container .image-wrapper img'
317+ ) as NodeListOf <HTMLImageElement >
318+ if (fontSize <= fontSizeToStartReducingImage && images .length > 0 ) {
319+ images .forEach ((image ) => {
320+ const currentWidth = image .offsetWidth
321+ const currentHeight = image .offsetHeight
322+ image .style .width = ` ${Math .floor (currentWidth * scaleFactor )}px `
323+ image .style .height = ` ${Math .floor (currentHeight * scaleFactor )}px `
324+ })
325+ }
326+ totalHeight = getTotalHeightOfChildren (content )
327+ }
328+
329+ if (currentSlide .classList .contains (' about-us' )) {
330+ const content = currentSlide .querySelector (' .content' ) as HTMLElement
331+ const infoSection = currentSlide .querySelector (' .info-section' ) as HTMLElement
332+ const contentWidth = content .offsetWidth
333+ let infoSectionWidth = infoSection .scrollWidth
334+ while (infoSectionWidth > contentWidth ) {
335+ const scaleFactor = contentWidth / infoSectionWidth
336+ fontSize = Math .floor (scaleFactor * fontSize )
337+
338+ const infoBoxes = infoSection .querySelectorAll (' .info-box' ) as NodeListOf <HTMLElement >
339+ infoBoxes .forEach ((box ) => {
340+ box .style .fontSize = ` ${fontSize }px `
341+ const style = getComputedStyle (box )
342+ const padding = parseFloat (style .padding ) * scaleFactor
343+ box .style .padding = ` ${Math .max (2 , Math .floor (padding ))}px `
344+ box .style .margin = ` ${Math .max (2 , Math .floor (parseFloat (style .margin ) * scaleFactor ))}px `
345+ })
346+ infoSectionWidth = infoSection .scrollWidth
347+ }
348+ }
349+ }
350+ function fitContent() {
351+ const images = document .querySelectorAll (' img' )
352+ let imagesLoaded = 0
353+
354+ images .forEach ((img ) => {
355+ if (img .complete ) {
356+ imagesLoaded ++
357+ } else {
358+ img .addEventListener (' load' , () => {
359+ imagesLoaded ++
360+ if (imagesLoaded === images .length ) {
361+ adjustFontSize ()
362+ }
363+ })
364+ }
365+ })
366+
367+ if (images .length === 0 ) {
368+ adjustFontSize ()
369+ }
370+ }
371+ function getFrontMatterFromMarkdown() {
372+ const options = {}
373+ const rawMarkdown = unref (mdTextarea ).value
374+ return awesoMd .parseFrontMatter (rawMarkdown , options )[1 ]
375+ }
376+ function setFontColor() {
377+ const frontMatter = getFrontMatterFromMarkdown ()
378+ const color = frontMatter .metadata .color
379+ document .querySelectorAll (' .title p, h1' ).forEach ((el ) => {
380+ el .style .color = color
381+ })
382+ }
383+ function applyTemplateIfNeeded() {
384+ const frontMatter = getFrontMatterFromMarkdown ()
385+ if (frontMatter .metadata ?.slide ) {
386+ // dynamically import CSS file only when needed
387+ import (' ./css/templates.css' )
388+ setFontColor ()
389+ }
390+ }
391+ async function updateLogoUrl() {
392+ const frontMatter = getFrontMatterFromMarkdown ()
393+ if (frontMatter .metadata ?.logo ) {
394+ const newLogoUrl = await updateImageUrls (frontMatter .metadata .logo )
395+ await nextTick ()
396+ const imgs = document .querySelectorAll (' .logo img' )
397+ imgs .forEach ((img ) => {
398+ img .src = newLogoUrl
399+ })
400+ }
401+ }
210402 </script >
211403
212404<style lang="scss">
0 commit comments